diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 450 |
1 files changed, 326 insertions, 124 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index d225359d0..855833c06 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: sshconnect2.c,v 1.18 2000/09/07 20:27:55 deraadt Exp $"); | 26 | RCSID("$OpenBSD: sshconnect2.c,v 1.20 2000/09/21 11:25:07 markus Exp $"); |
27 | 27 | ||
28 | #include <openssl/bn.h> | 28 | #include <openssl/bn.h> |
29 | #include <openssl/rsa.h> | 29 | #include <openssl/rsa.h> |
@@ -49,6 +49,7 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.18 2000/09/07 20:27:55 deraadt Exp $"); | |||
49 | #include "dsa.h" | 49 | #include "dsa.h" |
50 | #include "sshconnect.h" | 50 | #include "sshconnect.h" |
51 | #include "authfile.h" | 51 | #include "authfile.h" |
52 | #include "dispatch.h" | ||
52 | #include "authfd.h" | 53 | #include "authfd.h" |
53 | 54 | ||
54 | /* import */ | 55 | /* import */ |
@@ -67,6 +68,9 @@ void | |||
67 | ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, | 68 | ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, |
68 | Buffer *client_kexinit, Buffer *server_kexinit) | 69 | Buffer *client_kexinit, Buffer *server_kexinit) |
69 | { | 70 | { |
71 | #ifdef DEBUG_KEXDH | ||
72 | int i; | ||
73 | #endif | ||
70 | int plen, dlen; | 74 | int plen, dlen; |
71 | unsigned int klen, kout; | 75 | unsigned int klen, kout; |
72 | char *signature = NULL; | 76 | char *signature = NULL; |
@@ -90,11 +94,11 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, | |||
90 | 94 | ||
91 | #ifdef DEBUG_KEXDH | 95 | #ifdef DEBUG_KEXDH |
92 | fprintf(stderr, "\np= "); | 96 | fprintf(stderr, "\np= "); |
93 | bignum_print(dh->p); | 97 | BN_print_fp(stderr, dh->p); |
94 | fprintf(stderr, "\ng= "); | 98 | fprintf(stderr, "\ng= "); |
95 | bignum_print(dh->g); | 99 | BN_print_fp(stderr, dh->g); |
96 | fprintf(stderr, "\npub= "); | 100 | fprintf(stderr, "\npub= "); |
97 | bignum_print(dh->pub_key); | 101 | BN_print_fp(stderr, dh->pub_key); |
98 | fprintf(stderr, "\n"); | 102 | fprintf(stderr, "\n"); |
99 | DHparams_print_fp(stderr, dh); | 103 | DHparams_print_fp(stderr, dh); |
100 | #endif | 104 | #endif |
@@ -122,7 +126,7 @@ ssh_kex_dh(Kex *kex, char *host, struct sockaddr *hostaddr, | |||
122 | 126 | ||
123 | #ifdef DEBUG_KEXDH | 127 | #ifdef DEBUG_KEXDH |
124 | fprintf(stderr, "\ndh_server_pub= "); | 128 | fprintf(stderr, "\ndh_server_pub= "); |
125 | bignum_print(dh_server_pub); | 129 | BN_print_fp(stderr, dh_server_pub); |
126 | fprintf(stderr, "\n"); | 130 | fprintf(stderr, "\n"); |
127 | debug("bits %d", BN_num_bits(dh_server_pub)); | 131 | debug("bits %d", BN_num_bits(dh_server_pub)); |
128 | #endif | 132 | #endif |
@@ -253,8 +257,156 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
253 | /* | 257 | /* |
254 | * Authenticate user | 258 | * Authenticate user |
255 | */ | 259 | */ |
260 | |||
261 | typedef struct Authctxt Authctxt; | ||
262 | typedef struct Authmethod Authmethod; | ||
263 | |||
264 | typedef int sign_cb_fn( | ||
265 | Authctxt *authctxt, Key *key, | ||
266 | unsigned char **sigp, int *lenp, unsigned char *data, int datalen); | ||
267 | |||
268 | struct Authctxt { | ||
269 | const char *server_user; | ||
270 | const char *host; | ||
271 | const char *service; | ||
272 | AuthenticationConnection *agent; | ||
273 | int success; | ||
274 | Authmethod *method; | ||
275 | }; | ||
276 | struct Authmethod { | ||
277 | char *name; /* string to compare against server's list */ | ||
278 | int (*userauth)(Authctxt *authctxt); | ||
279 | int *enabled; /* flag in option struct that enables method */ | ||
280 | int *batch_flag; /* flag in option struct that disables method */ | ||
281 | }; | ||
282 | |||
283 | void input_userauth_success(int type, int plen, void *ctxt); | ||
284 | void input_userauth_failure(int type, int plen, void *ctxt); | ||
285 | void input_userauth_error(int type, int plen, void *ctxt); | ||
286 | int userauth_pubkey(Authctxt *authctxt); | ||
287 | int userauth_passwd(Authctxt *authctxt); | ||
288 | |||
289 | void authmethod_clear(); | ||
290 | Authmethod *authmethod_get(char *auth_list); | ||
291 | |||
292 | Authmethod authmethods[] = { | ||
293 | {"publickey", | ||
294 | userauth_pubkey, | ||
295 | &options.dsa_authentication, | ||
296 | NULL}, | ||
297 | {"password", | ||
298 | userauth_passwd, | ||
299 | &options.password_authentication, | ||
300 | &options.batch_mode}, | ||
301 | {NULL, NULL, NULL, NULL} | ||
302 | }; | ||
303 | |||
304 | void | ||
305 | ssh_userauth2(const char *server_user, char *host) | ||
306 | { | ||
307 | Authctxt authctxt; | ||
308 | int type; | ||
309 | int plen; | ||
310 | |||
311 | debug("send SSH2_MSG_SERVICE_REQUEST"); | ||
312 | packet_start(SSH2_MSG_SERVICE_REQUEST); | ||
313 | packet_put_cstring("ssh-userauth"); | ||
314 | packet_send(); | ||
315 | packet_write_wait(); | ||
316 | type = packet_read(&plen); | ||
317 | if (type != SSH2_MSG_SERVICE_ACCEPT) { | ||
318 | fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type); | ||
319 | } | ||
320 | if (packet_remaining() > 0) { | ||
321 | char *reply = packet_get_string(&plen); | ||
322 | debug("service_accept: %s", reply); | ||
323 | xfree(reply); | ||
324 | packet_done(); | ||
325 | } else { | ||
326 | debug("buggy server: service_accept w/o service"); | ||
327 | } | ||
328 | packet_done(); | ||
329 | debug("got SSH2_MSG_SERVICE_ACCEPT"); | ||
330 | |||
331 | /* setup authentication context */ | ||
332 | authctxt.agent = ssh_get_authentication_connection(); | ||
333 | authctxt.server_user = server_user; | ||
334 | authctxt.host = host; | ||
335 | authctxt.service = "ssh-connection"; /* service name */ | ||
336 | authctxt.success = 0; | ||
337 | authctxt.method = NULL; | ||
338 | |||
339 | /* initial userauth request */ | ||
340 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
341 | packet_put_cstring(authctxt.server_user); | ||
342 | packet_put_cstring(authctxt.service); | ||
343 | packet_put_cstring("none"); | ||
344 | packet_send(); | ||
345 | packet_write_wait(); | ||
346 | |||
347 | authmethod_clear(); | ||
348 | |||
349 | dispatch_init(&input_userauth_error); | ||
350 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); | ||
351 | dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); | ||
352 | dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ | ||
353 | |||
354 | if (authctxt.agent != NULL) | ||
355 | ssh_close_authentication_connection(authctxt.agent); | ||
356 | |||
357 | debug("ssh-userauth2 successfull"); | ||
358 | } | ||
359 | void | ||
360 | input_userauth_error(int type, int plen, void *ctxt) | ||
361 | { | ||
362 | fatal("input_userauth_error: bad message during authentication"); | ||
363 | } | ||
364 | void | ||
365 | input_userauth_success(int type, int plen, void *ctxt) | ||
366 | { | ||
367 | Authctxt *authctxt = ctxt; | ||
368 | if (authctxt == NULL) | ||
369 | fatal("input_userauth_success: no authentication context"); | ||
370 | authctxt->success = 1; /* break out */ | ||
371 | } | ||
372 | void | ||
373 | input_userauth_failure(int type, int plen, void *ctxt) | ||
374 | { | ||
375 | Authmethod *method = NULL; | ||
376 | Authctxt *authctxt = ctxt; | ||
377 | char *authlist = NULL; | ||
378 | int partial; | ||
379 | int dlen; | ||
380 | |||
381 | if (authctxt == NULL) | ||
382 | fatal("input_userauth_failure: no authentication context"); | ||
383 | |||
384 | authlist = packet_get_string(&dlen); | ||
385 | partial = packet_get_char(); | ||
386 | packet_done(); | ||
387 | |||
388 | if (partial != 0) | ||
389 | debug("partial success"); | ||
390 | debug("authentications that can continue: %s", authlist); | ||
391 | |||
392 | for (;;) { | ||
393 | /* try old method or get next method */ | ||
394 | method = authmethod_get(authlist); | ||
395 | if (method == NULL) | ||
396 | fatal("Unable to find an authentication method"); | ||
397 | if (method->userauth(authctxt) != 0) { | ||
398 | debug2("we sent a packet, wait for reply"); | ||
399 | break; | ||
400 | } else { | ||
401 | debug2("we did not send a packet, disable method"); | ||
402 | method->enabled = NULL; | ||
403 | } | ||
404 | } | ||
405 | xfree(authlist); | ||
406 | } | ||
407 | |||
256 | int | 408 | int |
257 | ssh2_try_passwd(const char *server_user, const char *host, const char *service) | 409 | userauth_passwd(Authctxt *authctxt) |
258 | { | 410 | { |
259 | static int attempt = 0; | 411 | static int attempt = 0; |
260 | char prompt[80]; | 412 | char prompt[80]; |
@@ -267,11 +419,11 @@ ssh2_try_passwd(const char *server_user, const char *host, const char *service) | |||
267 | error("Permission denied, please try again."); | 419 | error("Permission denied, please try again."); |
268 | 420 | ||
269 | snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", | 421 | snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", |
270 | server_user, host); | 422 | authctxt->server_user, authctxt->host); |
271 | password = read_passphrase(prompt, 0); | 423 | password = read_passphrase(prompt, 0); |
272 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | 424 | packet_start(SSH2_MSG_USERAUTH_REQUEST); |
273 | packet_put_cstring(server_user); | 425 | packet_put_cstring(authctxt->server_user); |
274 | packet_put_cstring(service); | 426 | packet_put_cstring(authctxt->service); |
275 | packet_put_cstring("password"); | 427 | packet_put_cstring("password"); |
276 | packet_put_char(0); | 428 | packet_put_char(0); |
277 | packet_put_cstring(password); | 429 | packet_put_cstring(password); |
@@ -282,14 +434,8 @@ ssh2_try_passwd(const char *server_user, const char *host, const char *service) | |||
282 | return 1; | 434 | return 1; |
283 | } | 435 | } |
284 | 436 | ||
285 | typedef int sign_fn( | ||
286 | Key *key, | ||
287 | unsigned char **sigp, int *lenp, | ||
288 | unsigned char *data, int datalen); | ||
289 | |||
290 | int | 437 | int |
291 | ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, | 438 | sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) |
292 | const char *server_user, const char *host, const char *service) | ||
293 | { | 439 | { |
294 | Buffer b; | 440 | Buffer b; |
295 | unsigned char *blob, *signature; | 441 | unsigned char *blob, *signature; |
@@ -309,18 +455,18 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, | |||
309 | skip = session_id2_len; | 455 | skip = session_id2_len; |
310 | } | 456 | } |
311 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); | 457 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); |
312 | buffer_put_cstring(&b, server_user); | 458 | buffer_put_cstring(&b, authctxt->server_user); |
313 | buffer_put_cstring(&b, | 459 | buffer_put_cstring(&b, |
314 | datafellows & SSH_BUG_PUBKEYAUTH ? | 460 | datafellows & SSH_BUG_PUBKEYAUTH ? |
315 | "ssh-userauth" : | 461 | "ssh-userauth" : |
316 | service); | 462 | authctxt->service); |
317 | buffer_put_cstring(&b, "publickey"); | 463 | buffer_put_cstring(&b, "publickey"); |
318 | buffer_put_char(&b, 1); | 464 | buffer_put_char(&b, 1); |
319 | buffer_put_cstring(&b, KEX_DSS); | 465 | buffer_put_cstring(&b, KEX_DSS); |
320 | buffer_put_string(&b, blob, bloblen); | 466 | buffer_put_string(&b, blob, bloblen); |
321 | 467 | ||
322 | /* generate signature */ | 468 | /* generate signature */ |
323 | ret = do_sign(k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); | 469 | ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); |
324 | if (ret == -1) { | 470 | if (ret == -1) { |
325 | xfree(blob); | 471 | xfree(blob); |
326 | buffer_free(&b); | 472 | buffer_free(&b); |
@@ -333,8 +479,8 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, | |||
333 | buffer_clear(&b); | 479 | buffer_clear(&b); |
334 | buffer_append(&b, session_id2, session_id2_len); | 480 | buffer_append(&b, session_id2, session_id2_len); |
335 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); | 481 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); |
336 | buffer_put_cstring(&b, server_user); | 482 | buffer_put_cstring(&b, authctxt->server_user); |
337 | buffer_put_cstring(&b, service); | 483 | buffer_put_cstring(&b, authctxt->service); |
338 | buffer_put_cstring(&b, "publickey"); | 484 | buffer_put_cstring(&b, "publickey"); |
339 | buffer_put_char(&b, 1); | 485 | buffer_put_char(&b, 1); |
340 | buffer_put_cstring(&b, KEX_DSS); | 486 | buffer_put_cstring(&b, KEX_DSS); |
@@ -347,7 +493,7 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, | |||
347 | 493 | ||
348 | /* skip session id and packet type */ | 494 | /* skip session id and packet type */ |
349 | if (buffer_len(&b) < skip + 1) | 495 | if (buffer_len(&b) < skip + 1) |
350 | fatal("ssh2_try_pubkey: internal error"); | 496 | fatal("userauth_pubkey: internal error"); |
351 | buffer_consume(&b, skip + 1); | 497 | buffer_consume(&b, skip + 1); |
352 | 498 | ||
353 | /* put remaining data from buffer into packet */ | 499 | /* put remaining data from buffer into packet */ |
@@ -362,12 +508,18 @@ ssh2_sign_and_send_pubkey(Key *k, sign_fn *do_sign, | |||
362 | return 1; | 508 | return 1; |
363 | } | 509 | } |
364 | 510 | ||
511 | /* sign callback */ | ||
512 | int dsa_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, | ||
513 | unsigned char *data, int datalen) | ||
514 | { | ||
515 | return dsa_sign(key, sigp, lenp, data, datalen); | ||
516 | } | ||
517 | |||
365 | int | 518 | int |
366 | ssh2_try_pubkey(char *filename, | 519 | userauth_pubkey_identity(Authctxt *authctxt, char *filename) |
367 | const char *server_user, const char *host, const char *service) | ||
368 | { | 520 | { |
369 | Key *k; | 521 | Key *k; |
370 | int ret = 0; | 522 | int i, ret, try_next; |
371 | struct stat st; | 523 | struct stat st; |
372 | 524 | ||
373 | if (stat(filename, &st) != 0) { | 525 | if (stat(filename, &st) != 0) { |
@@ -384,37 +536,40 @@ ssh2_try_pubkey(char *filename, | |||
384 | snprintf(prompt, sizeof prompt, | 536 | snprintf(prompt, sizeof prompt, |
385 | "Enter passphrase for DSA key '%.100s': ", | 537 | "Enter passphrase for DSA key '%.100s': ", |
386 | filename); | 538 | filename); |
387 | passphrase = read_passphrase(prompt, 0); | 539 | for (i = 0; i < options.number_of_password_prompts; i++) { |
388 | success = load_private_key(filename, passphrase, k, NULL); | 540 | passphrase = read_passphrase(prompt, 0); |
389 | memset(passphrase, 0, strlen(passphrase)); | 541 | if (strcmp(passphrase, "") != 0) { |
390 | xfree(passphrase); | 542 | success = load_private_key(filename, passphrase, k, NULL); |
543 | try_next = 0; | ||
544 | } else { | ||
545 | debug2("no passphrase given, try next key"); | ||
546 | try_next = 1; | ||
547 | } | ||
548 | memset(passphrase, 0, strlen(passphrase)); | ||
549 | xfree(passphrase); | ||
550 | if (success || try_next) | ||
551 | break; | ||
552 | debug2("bad passphrase given, try again..."); | ||
553 | } | ||
391 | if (!success) { | 554 | if (!success) { |
392 | key_free(k); | 555 | key_free(k); |
393 | return 0; | 556 | return 0; |
394 | } | 557 | } |
395 | } | 558 | } |
396 | ret = ssh2_sign_and_send_pubkey(k, dsa_sign, server_user, host, service); | 559 | ret = sign_and_send_pubkey(authctxt, k, dsa_sign_cb); |
397 | key_free(k); | 560 | key_free(k); |
398 | return ret; | 561 | return ret; |
399 | } | 562 | } |
400 | 563 | ||
401 | int agent_sign( | 564 | /* sign callback */ |
402 | Key *key, | 565 | int agent_sign_cb(Authctxt *authctxt, Key *key, unsigned char **sigp, int *lenp, |
403 | unsigned char **sigp, int *lenp, | ||
404 | unsigned char *data, int datalen) | 566 | unsigned char *data, int datalen) |
405 | { | 567 | { |
406 | int ret = -1; | 568 | return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen); |
407 | AuthenticationConnection *ac = ssh_get_authentication_connection(); | ||
408 | if (ac != NULL) { | ||
409 | ret = ssh_agent_sign(ac, key, sigp, lenp, data, datalen); | ||
410 | ssh_close_authentication_connection(ac); | ||
411 | } | ||
412 | return ret; | ||
413 | } | 569 | } |
414 | 570 | ||
415 | int | 571 | int |
416 | ssh2_try_agent(AuthenticationConnection *ac, | 572 | userauth_pubkey_agent(Authctxt *authctxt) |
417 | const char *server_user, const char *host, const char *service) | ||
418 | { | 573 | { |
419 | static int called = 0; | 574 | static int called = 0; |
420 | char *comment; | 575 | char *comment; |
@@ -422,104 +577,151 @@ ssh2_try_agent(AuthenticationConnection *ac, | |||
422 | int ret; | 577 | int ret; |
423 | 578 | ||
424 | if (called == 0) { | 579 | if (called == 0) { |
425 | k = ssh_get_first_identity(ac, &comment, 2); | 580 | k = ssh_get_first_identity(authctxt->agent, &comment, 2); |
426 | called ++; | 581 | called = 1; |
427 | } else { | 582 | } else { |
428 | k = ssh_get_next_identity(ac, &comment, 2); | 583 | k = ssh_get_next_identity(authctxt->agent, &comment, 2); |
429 | } | 584 | } |
430 | if (k == NULL) | 585 | if (k == NULL) { |
586 | debug2("no more DSA keys from agent"); | ||
431 | return 0; | 587 | return 0; |
588 | } | ||
432 | debug("trying DSA agent key %s", comment); | 589 | debug("trying DSA agent key %s", comment); |
433 | xfree(comment); | 590 | xfree(comment); |
434 | ret = ssh2_sign_and_send_pubkey(k, agent_sign, server_user, host, service); | 591 | ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb); |
435 | key_free(k); | 592 | key_free(k); |
436 | return ret; | 593 | return ret; |
437 | } | 594 | } |
438 | 595 | ||
439 | void | 596 | int |
440 | ssh_userauth2(const char *server_user, char *host) | 597 | userauth_pubkey(Authctxt *authctxt) |
441 | { | 598 | { |
442 | AuthenticationConnection *ac = ssh_get_authentication_connection(); | 599 | static int idx = 0; |
443 | int type; | 600 | int sent = 0; |
444 | int plen; | 601 | |
445 | int sent; | 602 | if (authctxt->agent != NULL) |
446 | unsigned int dlen; | 603 | sent = userauth_pubkey_agent(authctxt); |
447 | int partial; | 604 | while (sent == 0 && idx < options.num_identity_files2) |
448 | int i = 0; | 605 | sent = userauth_pubkey_identity(authctxt, options.identity_files2[idx++]); |
449 | char *auths; | 606 | return sent; |
450 | char *service = "ssh-connection"; /* service name */ | 607 | } |
451 | 608 | ||
452 | debug("send SSH2_MSG_SERVICE_REQUEST"); | ||
453 | packet_start(SSH2_MSG_SERVICE_REQUEST); | ||
454 | packet_put_cstring("ssh-userauth"); | ||
455 | packet_send(); | ||
456 | packet_write_wait(); | ||
457 | 609 | ||
458 | type = packet_read(&plen); | 610 | /* find auth method */ |
459 | if (type != SSH2_MSG_SERVICE_ACCEPT) { | 611 | |
460 | fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type); | 612 | #define DELIM "," |
613 | |||
614 | static char *def_authlist = "publickey,password"; | ||
615 | static char *authlist_current = NULL; /* clean copy used for comparison */ | ||
616 | static char *authname_current = NULL; /* last used auth method */ | ||
617 | static char *authlist_working = NULL; /* copy that gets modified by strtok_r() */ | ||
618 | static char *authlist_state = NULL; /* state variable for strtok_r() */ | ||
619 | |||
620 | /* | ||
621 | * Before starting to use a new authentication method list sent by the | ||
622 | * server, reset internal variables. This should also be called when | ||
623 | * finished processing server list to free resources. | ||
624 | */ | ||
625 | void | ||
626 | authmethod_clear() | ||
627 | { | ||
628 | if (authlist_current != NULL) { | ||
629 | xfree(authlist_current); | ||
630 | authlist_current = NULL; | ||
461 | } | 631 | } |
462 | if (packet_remaining() > 0) { | 632 | if (authlist_working != NULL) { |
463 | char *reply = packet_get_string(&plen); | 633 | xfree(authlist_working); |
464 | debug("service_accept: %s", reply); | 634 | authlist_working = NULL; |
465 | xfree(reply); | ||
466 | } else { | ||
467 | /* payload empty for ssh-2.0.13 ?? */ | ||
468 | debug("buggy server: service_accept w/o service"); | ||
469 | } | 635 | } |
470 | packet_done(); | 636 | if (authname_current != NULL) { |
471 | debug("got SSH2_MSG_SERVICE_ACCEPT"); | 637 | xfree(authname_current); |
638 | authlist_state = NULL; | ||
639 | } | ||
640 | if (authlist_state != NULL) | ||
641 | authlist_state = NULL; | ||
642 | return; | ||
643 | } | ||
472 | 644 | ||
473 | /* INITIAL request for auth */ | 645 | /* |
474 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | 646 | * given auth method name, if configurable options permit this method fill |
475 | packet_put_cstring(server_user); | 647 | * in auth_ident field and return true, otherwise return false. |
476 | packet_put_cstring(service); | 648 | */ |
477 | packet_put_cstring("none"); | 649 | int |
478 | packet_send(); | 650 | authmethod_is_enabled(Authmethod *method) |
479 | packet_write_wait(); | 651 | { |
652 | if (method == NULL) | ||
653 | return 0; | ||
654 | /* return false if options indicate this method is disabled */ | ||
655 | if (method->enabled == NULL || *method->enabled == 0) | ||
656 | return 0; | ||
657 | /* return false if batch mode is enabled but method needs interactive mode */ | ||
658 | if (method->batch_flag != NULL && *method->batch_flag != 0) | ||
659 | return 0; | ||
660 | return 1; | ||
661 | } | ||
480 | 662 | ||
481 | for (;;) { | 663 | Authmethod * |
482 | sent = 0; | 664 | authmethod_lookup(const char *name) |
483 | type = packet_read(&plen); | 665 | { |
484 | if (type == SSH2_MSG_USERAUTH_SUCCESS) | 666 | Authmethod *method = NULL; |
667 | if (name != NULL) | ||
668 | for (method = authmethods; method->name != NULL; method++) | ||
669 | if (strcmp(name, method->name) == 0) | ||
670 | return method; | ||
671 | debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); | ||
672 | return NULL; | ||
673 | } | ||
674 | |||
675 | /* | ||
676 | * Given the authentication method list sent by the server, return the | ||
677 | * next method we should try. If the server initially sends a nil list, | ||
678 | * use a built-in default list. If the server sends a nil list after | ||
679 | * previously sending a valid list, continue using the list originally | ||
680 | * sent. | ||
681 | */ | ||
682 | |||
683 | Authmethod * | ||
684 | authmethod_get(char *authlist) | ||
685 | { | ||
686 | char *name = NULL; | ||
687 | Authmethod *method = NULL; | ||
688 | |||
689 | /* Use a suitable default if we're passed a nil list. */ | ||
690 | if (authlist == NULL || strlen(authlist) == 0) | ||
691 | authlist = def_authlist; | ||
692 | |||
693 | if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) { | ||
694 | /* start over if passed a different list */ | ||
695 | authmethod_clear(); | ||
696 | authlist_current = xstrdup(authlist); | ||
697 | authlist_working = xstrdup(authlist); | ||
698 | name = strtok_r(authlist_working, DELIM, &authlist_state); | ||
699 | } else { | ||
700 | /* | ||
701 | * try to use previously used authentication method | ||
702 | * or continue to use previously passed list | ||
703 | */ | ||
704 | name = (authname_current != NULL) ? | ||
705 | authname_current : strtok_r(NULL, DELIM, &authlist_state); | ||
706 | } | ||
707 | |||
708 | while (name != NULL) { | ||
709 | method = authmethod_lookup(name); | ||
710 | if (method != NULL && authmethod_is_enabled(method)) | ||
485 | break; | 711 | break; |
486 | if (type != SSH2_MSG_USERAUTH_FAILURE) | 712 | name = strtok_r(NULL, DELIM, &authlist_state); |
487 | fatal("access denied: %d", type); | 713 | } |
488 | /* SSH2_MSG_USERAUTH_FAILURE means: try again */ | 714 | |
489 | auths = packet_get_string(&dlen); | 715 | if (authname_current != NULL) |
490 | debug("authentications that can continue: %s", auths); | 716 | xfree(authname_current); |
491 | partial = packet_get_char(); | 717 | |
492 | packet_done(); | 718 | if (name != NULL) { |
493 | if (partial) | 719 | debug("next auth method to try is %s", name); |
494 | debug("partial success"); | 720 | authname_current = xstrdup(name); |
495 | if (options.dsa_authentication && | 721 | return method; |
496 | strstr(auths, "publickey") != NULL) { | 722 | } else { |
497 | if (ac != NULL) | 723 | debug("no more auth methods to try"); |
498 | sent = ssh2_try_agent(ac, | 724 | authname_current = NULL; |
499 | server_user, host, service); | 725 | return NULL; |
500 | if (!sent) { | ||
501 | while (i < options.num_identity_files2) { | ||
502 | sent = ssh2_try_pubkey( | ||
503 | options.identity_files2[i++], | ||
504 | server_user, host, service); | ||
505 | if (sent) | ||
506 | break; | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | if (!sent) { | ||
511 | if (options.password_authentication && | ||
512 | !options.batch_mode && | ||
513 | strstr(auths, "password") != NULL) { | ||
514 | sent = ssh2_try_passwd(server_user, host, service); | ||
515 | } | ||
516 | } | ||
517 | if (!sent) | ||
518 | fatal("Permission denied (%s).", auths); | ||
519 | xfree(auths); | ||
520 | } | 726 | } |
521 | if (ac != NULL) | ||
522 | ssh_close_authentication_connection(ac); | ||
523 | packet_done(); | ||
524 | debug("ssh-userauth2 successfull"); | ||
525 | } | 727 | } |