diff options
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 1356 |
1 files changed, 31 insertions, 1325 deletions
diff --git a/sshconnect.c b/sshconnect.c index f58289e7b..5554c0643 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -5,48 +5,29 @@ | |||
5 | * Created: Sat Mar 18 22:15:47 1995 ylo | 5 | * Created: Sat Mar 18 22:15:47 1995 ylo |
6 | * Code to connect to a remote host, and to perform the client side of the | 6 | * Code to connect to a remote host, and to perform the client side of the |
7 | * login (authentication) dialog. | 7 | * login (authentication) dialog. |
8 | * | ||
9 | * SSH2 support added by Markus Friedl. | ||
10 | */ | 8 | */ |
11 | 9 | ||
12 | #include "includes.h" | 10 | #include "includes.h" |
13 | RCSID("$OpenBSD: sshconnect.c,v 1.69 2000/04/19 07:05:50 deraadt Exp $"); | 11 | RCSID("$OpenBSD: sshconnect.c,v 1.71 2000/04/26 21:28:33 markus Exp $"); |
14 | 12 | ||
15 | #include <openssl/bn.h> | 13 | #include <openssl/bn.h> |
14 | #include <openssl/dsa.h> | ||
15 | #include <openssl/rsa.h> | ||
16 | |||
16 | #include "xmalloc.h" | 17 | #include "xmalloc.h" |
17 | #include "rsa.h" | 18 | #include "rsa.h" |
18 | #include "ssh.h" | 19 | #include "ssh.h" |
19 | #include "buffer.h" | 20 | #include "buffer.h" |
20 | #include "packet.h" | 21 | #include "packet.h" |
21 | #include "authfd.h" | ||
22 | #include "cipher.h" | ||
23 | #include "mpaux.h" | ||
24 | #include "uidswap.h" | 22 | #include "uidswap.h" |
25 | #include "compat.h" | 23 | #include "compat.h" |
26 | #include "readconf.h" | 24 | #include "readconf.h" |
27 | |||
28 | #include "bufaux.h" | ||
29 | #include <openssl/rsa.h> | ||
30 | #include <openssl/dsa.h> | ||
31 | |||
32 | #include "ssh2.h" | ||
33 | #include <openssl/md5.h> | ||
34 | #include <openssl/dh.h> | ||
35 | #include <openssl/hmac.h> | ||
36 | #include "kex.h" | ||
37 | #include "myproposal.h" | ||
38 | #include "key.h" | 25 | #include "key.h" |
39 | #include "dsa.h" | 26 | #include "sshconnect.h" |
40 | #include "hostfile.h" | 27 | #include "hostfile.h" |
41 | 28 | ||
42 | /* Session id for the current session. */ | 29 | char *client_version_string = NULL; |
43 | unsigned char session_id[16]; | 30 | char *server_version_string = NULL; |
44 | |||
45 | /* authentications supported by server */ | ||
46 | unsigned int supported_authentications; | ||
47 | |||
48 | static char *client_version_string = NULL; | ||
49 | static char *server_version_string = NULL; | ||
50 | 31 | ||
51 | extern Options options; | 32 | extern Options options; |
52 | extern char *__progname; | 33 | extern char *__progname; |
@@ -316,653 +297,6 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
316 | return 1; | 297 | return 1; |
317 | } | 298 | } |
318 | 299 | ||
319 | /* | ||
320 | * Checks if the user has an authentication agent, and if so, tries to | ||
321 | * authenticate using the agent. | ||
322 | */ | ||
323 | int | ||
324 | try_agent_authentication() | ||
325 | { | ||
326 | int status, type; | ||
327 | char *comment; | ||
328 | AuthenticationConnection *auth; | ||
329 | unsigned char response[16]; | ||
330 | unsigned int i; | ||
331 | BIGNUM *e, *n, *challenge; | ||
332 | |||
333 | /* Get connection to the agent. */ | ||
334 | auth = ssh_get_authentication_connection(); | ||
335 | if (!auth) | ||
336 | return 0; | ||
337 | |||
338 | e = BN_new(); | ||
339 | n = BN_new(); | ||
340 | challenge = BN_new(); | ||
341 | |||
342 | /* Loop through identities served by the agent. */ | ||
343 | for (status = ssh_get_first_identity(auth, e, n, &comment); | ||
344 | status; | ||
345 | status = ssh_get_next_identity(auth, e, n, &comment)) { | ||
346 | int plen, clen; | ||
347 | |||
348 | /* Try this identity. */ | ||
349 | debug("Trying RSA authentication via agent with '%.100s'", comment); | ||
350 | xfree(comment); | ||
351 | |||
352 | /* Tell the server that we are willing to authenticate using this key. */ | ||
353 | packet_start(SSH_CMSG_AUTH_RSA); | ||
354 | packet_put_bignum(n); | ||
355 | packet_send(); | ||
356 | packet_write_wait(); | ||
357 | |||
358 | /* Wait for server's response. */ | ||
359 | type = packet_read(&plen); | ||
360 | |||
361 | /* The server sends failure if it doesn\'t like our key or | ||
362 | does not support RSA authentication. */ | ||
363 | if (type == SSH_SMSG_FAILURE) { | ||
364 | debug("Server refused our key."); | ||
365 | continue; | ||
366 | } | ||
367 | /* Otherwise it should have sent a challenge. */ | ||
368 | if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) | ||
369 | packet_disconnect("Protocol error during RSA authentication: %d", | ||
370 | type); | ||
371 | |||
372 | packet_get_bignum(challenge, &clen); | ||
373 | |||
374 | packet_integrity_check(plen, clen, type); | ||
375 | |||
376 | debug("Received RSA challenge from server."); | ||
377 | |||
378 | /* Ask the agent to decrypt the challenge. */ | ||
379 | if (!ssh_decrypt_challenge(auth, e, n, challenge, | ||
380 | session_id, 1, response)) { | ||
381 | /* The agent failed to authenticate this identifier although it | ||
382 | advertised it supports this. Just return a wrong value. */ | ||
383 | log("Authentication agent failed to decrypt challenge."); | ||
384 | memset(response, 0, sizeof(response)); | ||
385 | } | ||
386 | debug("Sending response to RSA challenge."); | ||
387 | |||
388 | /* Send the decrypted challenge back to the server. */ | ||
389 | packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); | ||
390 | for (i = 0; i < 16; i++) | ||
391 | packet_put_char(response[i]); | ||
392 | packet_send(); | ||
393 | packet_write_wait(); | ||
394 | |||
395 | /* Wait for response from the server. */ | ||
396 | type = packet_read(&plen); | ||
397 | |||
398 | /* The server returns success if it accepted the authentication. */ | ||
399 | if (type == SSH_SMSG_SUCCESS) { | ||
400 | debug("RSA authentication accepted by server."); | ||
401 | BN_clear_free(e); | ||
402 | BN_clear_free(n); | ||
403 | BN_clear_free(challenge); | ||
404 | return 1; | ||
405 | } | ||
406 | /* Otherwise it should return failure. */ | ||
407 | if (type != SSH_SMSG_FAILURE) | ||
408 | packet_disconnect("Protocol error waiting RSA auth response: %d", | ||
409 | type); | ||
410 | } | ||
411 | |||
412 | BN_clear_free(e); | ||
413 | BN_clear_free(n); | ||
414 | BN_clear_free(challenge); | ||
415 | |||
416 | debug("RSA authentication using agent refused."); | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * Computes the proper response to a RSA challenge, and sends the response to | ||
422 | * the server. | ||
423 | */ | ||
424 | void | ||
425 | respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) | ||
426 | { | ||
427 | unsigned char buf[32], response[16]; | ||
428 | MD5_CTX md; | ||
429 | int i, len; | ||
430 | |||
431 | /* Decrypt the challenge using the private key. */ | ||
432 | rsa_private_decrypt(challenge, challenge, prv); | ||
433 | |||
434 | /* Compute the response. */ | ||
435 | /* The response is MD5 of decrypted challenge plus session id. */ | ||
436 | len = BN_num_bytes(challenge); | ||
437 | if (len <= 0 || len > sizeof(buf)) | ||
438 | packet_disconnect("respond_to_rsa_challenge: bad challenge length %d", | ||
439 | len); | ||
440 | |||
441 | memset(buf, 0, sizeof(buf)); | ||
442 | BN_bn2bin(challenge, buf + sizeof(buf) - len); | ||
443 | MD5_Init(&md); | ||
444 | MD5_Update(&md, buf, 32); | ||
445 | MD5_Update(&md, session_id, 16); | ||
446 | MD5_Final(response, &md); | ||
447 | |||
448 | debug("Sending response to host key RSA challenge."); | ||
449 | |||
450 | /* Send the response back to the server. */ | ||
451 | packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); | ||
452 | for (i = 0; i < 16; i++) | ||
453 | packet_put_char(response[i]); | ||
454 | packet_send(); | ||
455 | packet_write_wait(); | ||
456 | |||
457 | memset(buf, 0, sizeof(buf)); | ||
458 | memset(response, 0, sizeof(response)); | ||
459 | memset(&md, 0, sizeof(md)); | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * Checks if the user has authentication file, and if so, tries to authenticate | ||
464 | * the user using it. | ||
465 | */ | ||
466 | int | ||
467 | try_rsa_authentication(const char *authfile) | ||
468 | { | ||
469 | BIGNUM *challenge; | ||
470 | RSA *private_key; | ||
471 | RSA *public_key; | ||
472 | char *passphrase, *comment; | ||
473 | int type, i; | ||
474 | int plen, clen; | ||
475 | |||
476 | /* Try to load identification for the authentication key. */ | ||
477 | public_key = RSA_new(); | ||
478 | if (!load_public_key(authfile, public_key, &comment)) { | ||
479 | RSA_free(public_key); | ||
480 | /* Could not load it. Fail. */ | ||
481 | return 0; | ||
482 | } | ||
483 | debug("Trying RSA authentication with key '%.100s'", comment); | ||
484 | |||
485 | /* Tell the server that we are willing to authenticate using this key. */ | ||
486 | packet_start(SSH_CMSG_AUTH_RSA); | ||
487 | packet_put_bignum(public_key->n); | ||
488 | packet_send(); | ||
489 | packet_write_wait(); | ||
490 | |||
491 | /* We no longer need the public key. */ | ||
492 | RSA_free(public_key); | ||
493 | |||
494 | /* Wait for server's response. */ | ||
495 | type = packet_read(&plen); | ||
496 | |||
497 | /* | ||
498 | * The server responds with failure if it doesn\'t like our key or | ||
499 | * doesn\'t support RSA authentication. | ||
500 | */ | ||
501 | if (type == SSH_SMSG_FAILURE) { | ||
502 | debug("Server refused our key."); | ||
503 | xfree(comment); | ||
504 | return 0; | ||
505 | } | ||
506 | /* Otherwise, the server should respond with a challenge. */ | ||
507 | if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) | ||
508 | packet_disconnect("Protocol error during RSA authentication: %d", type); | ||
509 | |||
510 | /* Get the challenge from the packet. */ | ||
511 | challenge = BN_new(); | ||
512 | packet_get_bignum(challenge, &clen); | ||
513 | |||
514 | packet_integrity_check(plen, clen, type); | ||
515 | |||
516 | debug("Received RSA challenge from server."); | ||
517 | |||
518 | private_key = RSA_new(); | ||
519 | /* | ||
520 | * Load the private key. Try first with empty passphrase; if it | ||
521 | * fails, ask for a passphrase. | ||
522 | */ | ||
523 | if (!load_private_key(authfile, "", private_key, NULL)) { | ||
524 | char buf[300]; | ||
525 | snprintf(buf, sizeof buf, "Enter passphrase for RSA key '%.100s': ", | ||
526 | comment); | ||
527 | if (!options.batch_mode) | ||
528 | passphrase = read_passphrase(buf, 0); | ||
529 | else { | ||
530 | debug("Will not query passphrase for %.100s in batch mode.", | ||
531 | comment); | ||
532 | passphrase = xstrdup(""); | ||
533 | } | ||
534 | |||
535 | /* Load the authentication file using the pasphrase. */ | ||
536 | if (!load_private_key(authfile, passphrase, private_key, NULL)) { | ||
537 | memset(passphrase, 0, strlen(passphrase)); | ||
538 | xfree(passphrase); | ||
539 | error("Bad passphrase."); | ||
540 | |||
541 | /* Send a dummy response packet to avoid protocol error. */ | ||
542 | packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); | ||
543 | for (i = 0; i < 16; i++) | ||
544 | packet_put_char(0); | ||
545 | packet_send(); | ||
546 | packet_write_wait(); | ||
547 | |||
548 | /* Expect the server to reject it... */ | ||
549 | packet_read_expect(&plen, SSH_SMSG_FAILURE); | ||
550 | xfree(comment); | ||
551 | return 0; | ||
552 | } | ||
553 | /* Destroy the passphrase. */ | ||
554 | memset(passphrase, 0, strlen(passphrase)); | ||
555 | xfree(passphrase); | ||
556 | } | ||
557 | /* We no longer need the comment. */ | ||
558 | xfree(comment); | ||
559 | |||
560 | /* Compute and send a response to the challenge. */ | ||
561 | respond_to_rsa_challenge(challenge, private_key); | ||
562 | |||
563 | /* Destroy the private key. */ | ||
564 | RSA_free(private_key); | ||
565 | |||
566 | /* We no longer need the challenge. */ | ||
567 | BN_clear_free(challenge); | ||
568 | |||
569 | /* Wait for response from the server. */ | ||
570 | type = packet_read(&plen); | ||
571 | if (type == SSH_SMSG_SUCCESS) { | ||
572 | debug("RSA authentication accepted by server."); | ||
573 | return 1; | ||
574 | } | ||
575 | if (type != SSH_SMSG_FAILURE) | ||
576 | packet_disconnect("Protocol error waiting RSA auth response: %d", type); | ||
577 | debug("RSA authentication refused."); | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | /* | ||
582 | * Tries to authenticate the user using combined rhosts or /etc/hosts.equiv | ||
583 | * authentication and RSA host authentication. | ||
584 | */ | ||
585 | int | ||
586 | try_rhosts_rsa_authentication(const char *local_user, RSA * host_key) | ||
587 | { | ||
588 | int type; | ||
589 | BIGNUM *challenge; | ||
590 | int plen, clen; | ||
591 | |||
592 | debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication."); | ||
593 | |||
594 | /* Tell the server that we are willing to authenticate using this key. */ | ||
595 | packet_start(SSH_CMSG_AUTH_RHOSTS_RSA); | ||
596 | packet_put_string(local_user, strlen(local_user)); | ||
597 | packet_put_int(BN_num_bits(host_key->n)); | ||
598 | packet_put_bignum(host_key->e); | ||
599 | packet_put_bignum(host_key->n); | ||
600 | packet_send(); | ||
601 | packet_write_wait(); | ||
602 | |||
603 | /* Wait for server's response. */ | ||
604 | type = packet_read(&plen); | ||
605 | |||
606 | /* The server responds with failure if it doesn't admit our | ||
607 | .rhosts authentication or doesn't know our host key. */ | ||
608 | if (type == SSH_SMSG_FAILURE) { | ||
609 | debug("Server refused our rhosts authentication or host key."); | ||
610 | return 0; | ||
611 | } | ||
612 | /* Otherwise, the server should respond with a challenge. */ | ||
613 | if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) | ||
614 | packet_disconnect("Protocol error during RSA authentication: %d", type); | ||
615 | |||
616 | /* Get the challenge from the packet. */ | ||
617 | challenge = BN_new(); | ||
618 | packet_get_bignum(challenge, &clen); | ||
619 | |||
620 | packet_integrity_check(plen, clen, type); | ||
621 | |||
622 | debug("Received RSA challenge for host key from server."); | ||
623 | |||
624 | /* Compute a response to the challenge. */ | ||
625 | respond_to_rsa_challenge(challenge, host_key); | ||
626 | |||
627 | /* We no longer need the challenge. */ | ||
628 | BN_clear_free(challenge); | ||
629 | |||
630 | /* Wait for response from the server. */ | ||
631 | type = packet_read(&plen); | ||
632 | if (type == SSH_SMSG_SUCCESS) { | ||
633 | debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server."); | ||
634 | return 1; | ||
635 | } | ||
636 | if (type != SSH_SMSG_FAILURE) | ||
637 | packet_disconnect("Protocol error waiting RSA auth response: %d", type); | ||
638 | debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused."); | ||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | #ifdef KRB4 | ||
643 | int | ||
644 | try_kerberos_authentication() | ||
645 | { | ||
646 | KTEXT_ST auth; /* Kerberos data */ | ||
647 | char *reply; | ||
648 | char inst[INST_SZ]; | ||
649 | char *realm; | ||
650 | CREDENTIALS cred; | ||
651 | int r, type, plen; | ||
652 | socklen_t slen; | ||
653 | Key_schedule schedule; | ||
654 | u_long checksum, cksum; | ||
655 | MSG_DAT msg_data; | ||
656 | struct sockaddr_in local, foreign; | ||
657 | struct stat st; | ||
658 | |||
659 | /* Don't do anything if we don't have any tickets. */ | ||
660 | if (stat(tkt_string(), &st) < 0) | ||
661 | return 0; | ||
662 | |||
663 | strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ); | ||
664 | |||
665 | realm = (char *) krb_realmofhost(get_canonical_hostname()); | ||
666 | if (!realm) { | ||
667 | debug("Kerberos V4: no realm for %s", get_canonical_hostname()); | ||
668 | return 0; | ||
669 | } | ||
670 | /* This can really be anything. */ | ||
671 | checksum = (u_long) getpid(); | ||
672 | |||
673 | r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum); | ||
674 | if (r != KSUCCESS) { | ||
675 | debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]); | ||
676 | return 0; | ||
677 | } | ||
678 | /* Get session key to decrypt the server's reply with. */ | ||
679 | r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred); | ||
680 | if (r != KSUCCESS) { | ||
681 | debug("get_cred failed: %s", krb_err_txt[r]); | ||
682 | return 0; | ||
683 | } | ||
684 | des_key_sched((des_cblock *) cred.session, schedule); | ||
685 | |||
686 | /* Send authentication info to server. */ | ||
687 | packet_start(SSH_CMSG_AUTH_KERBEROS); | ||
688 | packet_put_string((char *) auth.dat, auth.length); | ||
689 | packet_send(); | ||
690 | packet_write_wait(); | ||
691 | |||
692 | /* Zero the buffer. */ | ||
693 | (void) memset(auth.dat, 0, MAX_KTXT_LEN); | ||
694 | |||
695 | slen = sizeof(local); | ||
696 | memset(&local, 0, sizeof(local)); | ||
697 | if (getsockname(packet_get_connection_in(), | ||
698 | (struct sockaddr *) & local, &slen) < 0) | ||
699 | debug("getsockname failed: %s", strerror(errno)); | ||
700 | |||
701 | slen = sizeof(foreign); | ||
702 | memset(&foreign, 0, sizeof(foreign)); | ||
703 | if (getpeername(packet_get_connection_in(), | ||
704 | (struct sockaddr *) & foreign, &slen) < 0) { | ||
705 | debug("getpeername failed: %s", strerror(errno)); | ||
706 | fatal_cleanup(); | ||
707 | } | ||
708 | /* Get server reply. */ | ||
709 | type = packet_read(&plen); | ||
710 | switch (type) { | ||
711 | case SSH_SMSG_FAILURE: | ||
712 | /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ | ||
713 | debug("Kerberos V4 authentication failed."); | ||
714 | return 0; | ||
715 | break; | ||
716 | |||
717 | case SSH_SMSG_AUTH_KERBEROS_RESPONSE: | ||
718 | /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ | ||
719 | debug("Kerberos V4 authentication accepted."); | ||
720 | |||
721 | /* Get server's response. */ | ||
722 | reply = packet_get_string((unsigned int *) &auth.length); | ||
723 | memcpy(auth.dat, reply, auth.length); | ||
724 | xfree(reply); | ||
725 | |||
726 | packet_integrity_check(plen, 4 + auth.length, type); | ||
727 | |||
728 | /* | ||
729 | * If his response isn't properly encrypted with the session | ||
730 | * key, and the decrypted checksum fails to match, he's | ||
731 | * bogus. Bail out. | ||
732 | */ | ||
733 | r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, | ||
734 | &foreign, &local, &msg_data); | ||
735 | if (r != KSUCCESS) { | ||
736 | debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]); | ||
737 | packet_disconnect("Kerberos V4 challenge failed!"); | ||
738 | } | ||
739 | /* Fetch the (incremented) checksum that we supplied in the request. */ | ||
740 | (void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum)); | ||
741 | cksum = ntohl(cksum); | ||
742 | |||
743 | /* If it matches, we're golden. */ | ||
744 | if (cksum == checksum + 1) { | ||
745 | debug("Kerberos V4 challenge successful."); | ||
746 | return 1; | ||
747 | } else | ||
748 | packet_disconnect("Kerberos V4 challenge failed!"); | ||
749 | break; | ||
750 | |||
751 | default: | ||
752 | packet_disconnect("Protocol error on Kerberos V4 response: %d", type); | ||
753 | } | ||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | #endif /* KRB4 */ | ||
758 | |||
759 | #ifdef AFS | ||
760 | int | ||
761 | send_kerberos_tgt() | ||
762 | { | ||
763 | CREDENTIALS *creds; | ||
764 | char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; | ||
765 | int r, type, plen; | ||
766 | char buffer[8192]; | ||
767 | struct stat st; | ||
768 | |||
769 | /* Don't do anything if we don't have any tickets. */ | ||
770 | if (stat(tkt_string(), &st) < 0) | ||
771 | return 0; | ||
772 | |||
773 | creds = xmalloc(sizeof(*creds)); | ||
774 | |||
775 | if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) { | ||
776 | debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]); | ||
777 | return 0; | ||
778 | } | ||
779 | if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) { | ||
780 | debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]); | ||
781 | return 0; | ||
782 | } | ||
783 | if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) { | ||
784 | debug("Kerberos V4 ticket expired: %s", TKT_FILE); | ||
785 | return 0; | ||
786 | } | ||
787 | creds_to_radix(creds, (unsigned char *)buffer); | ||
788 | xfree(creds); | ||
789 | |||
790 | packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); | ||
791 | packet_put_string(buffer, strlen(buffer)); | ||
792 | packet_send(); | ||
793 | packet_write_wait(); | ||
794 | |||
795 | type = packet_read(&plen); | ||
796 | |||
797 | if (type == SSH_SMSG_FAILURE) | ||
798 | debug("Kerberos TGT for realm %s rejected.", prealm); | ||
799 | else if (type != SSH_SMSG_SUCCESS) | ||
800 | packet_disconnect("Protocol error on Kerberos TGT response: %d", type); | ||
801 | |||
802 | return 1; | ||
803 | } | ||
804 | |||
805 | void | ||
806 | send_afs_tokens(void) | ||
807 | { | ||
808 | CREDENTIALS creds; | ||
809 | struct ViceIoctl parms; | ||
810 | struct ClearToken ct; | ||
811 | int i, type, len, plen; | ||
812 | char buf[2048], *p, *server_cell; | ||
813 | char buffer[8192]; | ||
814 | |||
815 | /* Move over ktc_GetToken, here's something leaner. */ | ||
816 | for (i = 0; i < 100; i++) { /* just in case */ | ||
817 | parms.in = (char *) &i; | ||
818 | parms.in_size = sizeof(i); | ||
819 | parms.out = buf; | ||
820 | parms.out_size = sizeof(buf); | ||
821 | if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0) | ||
822 | break; | ||
823 | p = buf; | ||
824 | |||
825 | /* Get secret token. */ | ||
826 | memcpy(&creds.ticket_st.length, p, sizeof(unsigned int)); | ||
827 | if (creds.ticket_st.length > MAX_KTXT_LEN) | ||
828 | break; | ||
829 | p += sizeof(unsigned int); | ||
830 | memcpy(creds.ticket_st.dat, p, creds.ticket_st.length); | ||
831 | p += creds.ticket_st.length; | ||
832 | |||
833 | /* Get clear token. */ | ||
834 | memcpy(&len, p, sizeof(len)); | ||
835 | if (len != sizeof(struct ClearToken)) | ||
836 | break; | ||
837 | p += sizeof(len); | ||
838 | memcpy(&ct, p, len); | ||
839 | p += len; | ||
840 | p += sizeof(len); /* primary flag */ | ||
841 | server_cell = p; | ||
842 | |||
843 | /* Flesh out our credentials. */ | ||
844 | strlcpy(creds.service, "afs", sizeof creds.service); | ||
845 | creds.instance[0] = '\0'; | ||
846 | strlcpy(creds.realm, server_cell, REALM_SZ); | ||
847 | memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ); | ||
848 | creds.issue_date = ct.BeginTimestamp; | ||
849 | creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp); | ||
850 | creds.kvno = ct.AuthHandle; | ||
851 | snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId); | ||
852 | creds.pinst[0] = '\0'; | ||
853 | |||
854 | /* Encode token, ship it off. */ | ||
855 | if (!creds_to_radix(&creds, (unsigned char*) buffer)) | ||
856 | break; | ||
857 | packet_start(SSH_CMSG_HAVE_AFS_TOKEN); | ||
858 | packet_put_string(buffer, strlen(buffer)); | ||
859 | packet_send(); | ||
860 | packet_write_wait(); | ||
861 | |||
862 | /* Roger, Roger. Clearance, Clarence. What's your vector, | ||
863 | Victor? */ | ||
864 | type = packet_read(&plen); | ||
865 | |||
866 | if (type == SSH_SMSG_FAILURE) | ||
867 | debug("AFS token for cell %s rejected.", server_cell); | ||
868 | else if (type != SSH_SMSG_SUCCESS) | ||
869 | packet_disconnect("Protocol error on AFS token response: %d", type); | ||
870 | } | ||
871 | } | ||
872 | |||
873 | #endif /* AFS */ | ||
874 | |||
875 | /* | ||
876 | * Tries to authenticate with any string-based challenge/response system. | ||
877 | * Note that the client code is not tied to s/key or TIS. | ||
878 | */ | ||
879 | int | ||
880 | try_skey_authentication() | ||
881 | { | ||
882 | int type, i; | ||
883 | int payload_len; | ||
884 | unsigned int clen; | ||
885 | char *challenge, *response; | ||
886 | |||
887 | debug("Doing skey authentication."); | ||
888 | |||
889 | /* request a challenge */ | ||
890 | packet_start(SSH_CMSG_AUTH_TIS); | ||
891 | packet_send(); | ||
892 | packet_write_wait(); | ||
893 | |||
894 | type = packet_read(&payload_len); | ||
895 | if (type != SSH_SMSG_FAILURE && | ||
896 | type != SSH_SMSG_AUTH_TIS_CHALLENGE) { | ||
897 | packet_disconnect("Protocol error: got %d in response " | ||
898 | "to skey-auth", type); | ||
899 | } | ||
900 | if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) { | ||
901 | debug("No challenge for skey authentication."); | ||
902 | return 0; | ||
903 | } | ||
904 | challenge = packet_get_string(&clen); | ||
905 | packet_integrity_check(payload_len, (4 + clen), type); | ||
906 | if (options.cipher == SSH_CIPHER_NONE) | ||
907 | log("WARNING: Encryption is disabled! " | ||
908 | "Reponse will be transmitted in clear text."); | ||
909 | fprintf(stderr, "%s\n", challenge); | ||
910 | xfree(challenge); | ||
911 | fflush(stderr); | ||
912 | for (i = 0; i < options.number_of_password_prompts; i++) { | ||
913 | if (i != 0) | ||
914 | error("Permission denied, please try again."); | ||
915 | response = read_passphrase("Response: ", 0); | ||
916 | packet_start(SSH_CMSG_AUTH_TIS_RESPONSE); | ||
917 | packet_put_string(response, strlen(response)); | ||
918 | memset(response, 0, strlen(response)); | ||
919 | xfree(response); | ||
920 | packet_send(); | ||
921 | packet_write_wait(); | ||
922 | type = packet_read(&payload_len); | ||
923 | if (type == SSH_SMSG_SUCCESS) | ||
924 | return 1; | ||
925 | if (type != SSH_SMSG_FAILURE) | ||
926 | packet_disconnect("Protocol error: got %d in response " | ||
927 | "to skey-auth-reponse", type); | ||
928 | } | ||
929 | /* failure */ | ||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | /* | ||
934 | * Tries to authenticate with plain passwd authentication. | ||
935 | */ | ||
936 | int | ||
937 | try_password_authentication(char *prompt) | ||
938 | { | ||
939 | int type, i, payload_len; | ||
940 | char *password; | ||
941 | |||
942 | debug("Doing password authentication."); | ||
943 | if (options.cipher == SSH_CIPHER_NONE) | ||
944 | log("WARNING: Encryption is disabled! Password will be transmitted in clear text."); | ||
945 | for (i = 0; i < options.number_of_password_prompts; i++) { | ||
946 | if (i != 0) | ||
947 | error("Permission denied, please try again."); | ||
948 | password = read_passphrase(prompt, 0); | ||
949 | packet_start(SSH_CMSG_AUTH_PASSWORD); | ||
950 | packet_put_string(password, strlen(password)); | ||
951 | memset(password, 0, strlen(password)); | ||
952 | xfree(password); | ||
953 | packet_send(); | ||
954 | packet_write_wait(); | ||
955 | |||
956 | type = packet_read(&payload_len); | ||
957 | if (type == SSH_SMSG_SUCCESS) | ||
958 | return 1; | ||
959 | if (type != SSH_SMSG_FAILURE) | ||
960 | packet_disconnect("Protocol error: got %d in response to passwd auth", type); | ||
961 | } | ||
962 | /* failure */ | ||
963 | return 0; | ||
964 | } | ||
965 | |||
966 | char * | 300 | char * |
967 | chop(char *s) | 301 | chop(char *s) |
968 | { | 302 | { |
@@ -1060,7 +394,8 @@ ssh_exchange_identification() | |||
1060 | fatal("Protocol major versions differ: %d vs. %d", | 394 | fatal("Protocol major versions differ: %d vs. %d", |
1061 | (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, | 395 | (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, |
1062 | remote_major); | 396 | remote_major); |
1063 | 397 | if (compat20) | |
398 | packet_set_ssh2_format(); | ||
1064 | /* Send our own protocol version identification. */ | 399 | /* Send our own protocol version identification. */ |
1065 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", | 400 | snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", |
1066 | compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, | 401 | compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, |
@@ -1122,7 +457,8 @@ read_yes_or_no(const char *prompt, int defval) | |||
1122 | */ | 457 | */ |
1123 | 458 | ||
1124 | void | 459 | void |
1125 | check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | 460 | check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, |
461 | const char *user_hostfile, const char *system_hostfile) | ||
1126 | { | 462 | { |
1127 | Key *file_key; | 463 | Key *file_key; |
1128 | char *ip = NULL; | 464 | char *ip = NULL; |
@@ -1141,6 +477,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1141 | * essentially disables host authentication for localhost; however, | 477 | * essentially disables host authentication for localhost; however, |
1142 | * this is probably not a real problem. | 478 | * this is probably not a real problem. |
1143 | */ | 479 | */ |
480 | /** hostaddr == 0! */ | ||
1144 | switch (hostaddr->sa_family) { | 481 | switch (hostaddr->sa_family) { |
1145 | case AF_INET: | 482 | case AF_INET: |
1146 | local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; | 483 | local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; |
@@ -1184,19 +521,19 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1184 | * Check if the host key is present in the user\'s list of known | 521 | * Check if the host key is present in the user\'s list of known |
1185 | * hosts or in the systemwide list. | 522 | * hosts or in the systemwide list. |
1186 | */ | 523 | */ |
1187 | host_status = check_host_in_hostfile(options.user_hostfile, host, host_key, file_key); | 524 | host_status = check_host_in_hostfile(user_hostfile, host, host_key, file_key); |
1188 | if (host_status == HOST_NEW) | 525 | if (host_status == HOST_NEW) |
1189 | host_status = check_host_in_hostfile(options.system_hostfile, host, host_key, file_key); | 526 | host_status = check_host_in_hostfile(system_hostfile, host, host_key, file_key); |
1190 | /* | 527 | /* |
1191 | * Also perform check for the ip address, skip the check if we are | 528 | * Also perform check for the ip address, skip the check if we are |
1192 | * localhost or the hostname was an ip address to begin with | 529 | * localhost or the hostname was an ip address to begin with |
1193 | */ | 530 | */ |
1194 | if (options.check_host_ip && !local && strcmp(host, ip)) { | 531 | if (options.check_host_ip && !local && strcmp(host, ip)) { |
1195 | Key *ip_key = key_new(host_key->type); | 532 | Key *ip_key = key_new(host_key->type); |
1196 | ip_status = check_host_in_hostfile(options.user_hostfile, ip, host_key, ip_key); | 533 | ip_status = check_host_in_hostfile(user_hostfile, ip, host_key, ip_key); |
1197 | 534 | ||
1198 | if (ip_status == HOST_NEW) | 535 | if (ip_status == HOST_NEW) |
1199 | ip_status = check_host_in_hostfile(options.system_hostfile, ip, host_key, ip_key); | 536 | ip_status = check_host_in_hostfile(system_hostfile, ip, host_key, ip_key); |
1200 | if (host_status == HOST_CHANGED && | 537 | if (host_status == HOST_CHANGED && |
1201 | (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) | 538 | (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) |
1202 | host_ip_differ = 1; | 539 | host_ip_differ = 1; |
@@ -1213,9 +550,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1213 | debug("Host '%.200s' is known and matches the host key.", host); | 550 | debug("Host '%.200s' is known and matches the host key.", host); |
1214 | if (options.check_host_ip) { | 551 | if (options.check_host_ip) { |
1215 | if (ip_status == HOST_NEW) { | 552 | if (ip_status == HOST_NEW) { |
1216 | if (!add_host_to_hostfile(options.user_hostfile, ip, host_key)) | 553 | if (!add_host_to_hostfile(user_hostfile, ip, host_key)) |
1217 | log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).", | 554 | log("Failed to add the host key for IP address '%.30s' to the list of known hosts (%.30s).", |
1218 | ip, options.user_hostfile); | 555 | ip, user_hostfile); |
1219 | else | 556 | else |
1220 | log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.", | 557 | log("Warning: Permanently added host key for IP address '%.30s' to the list of known hosts.", |
1221 | ip); | 558 | ip); |
@@ -1249,9 +586,9 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1249 | hostp = host; | 586 | hostp = host; |
1250 | 587 | ||
1251 | /* If not in strict mode, add the key automatically to the local known_hosts file. */ | 588 | /* If not in strict mode, add the key automatically to the local known_hosts file. */ |
1252 | if (!add_host_to_hostfile(options.user_hostfile, hostp, host_key)) | 589 | if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) |
1253 | log("Failed to add the host to the list of known hosts (%.500s).", | 590 | log("Failed to add the host to the list of known hosts (%.500s).", |
1254 | options.user_hostfile); | 591 | user_hostfile); |
1255 | else | 592 | else |
1256 | log("Warning: Permanently added '%.200s' to the list of known hosts.", | 593 | log("Warning: Permanently added '%.200s' to the list of known hosts.", |
1257 | hostp); | 594 | hostp); |
@@ -1283,7 +620,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1283 | error("It is also possible that the host key has just been changed."); | 620 | error("It is also possible that the host key has just been changed."); |
1284 | error("Please contact your system administrator."); | 621 | error("Please contact your system administrator."); |
1285 | error("Add correct host key in %.100s to get rid of this message.", | 622 | error("Add correct host key in %.100s to get rid of this message.", |
1286 | options.user_hostfile); | 623 | user_hostfile); |
1287 | 624 | ||
1288 | /* | 625 | /* |
1289 | * If strict host key checking is in use, the user will have | 626 | * If strict host key checking is in use, the user will have |
@@ -1317,260 +654,22 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | |||
1317 | if (options.check_host_ip) | 654 | if (options.check_host_ip) |
1318 | xfree(ip); | 655 | xfree(ip); |
1319 | } | 656 | } |
1320 | void | ||
1321 | check_rsa_host_key(char *host, struct sockaddr *hostaddr, RSA *host_key) | ||
1322 | { | ||
1323 | Key k; | ||
1324 | k.type = KEY_RSA; | ||
1325 | k.rsa = host_key; | ||
1326 | check_host_key(host, hostaddr, &k); | ||
1327 | } | ||
1328 | 657 | ||
1329 | /* | 658 | /* |
1330 | * SSH2 key exchange | 659 | * Starts a dialog with the server, and authenticates the current user on the |
1331 | */ | 660 | * server. This does not need any extra privileges. The basic connection |
1332 | void | 661 | * to the server must already have been established before this is called. |
1333 | ssh_kex2(char *host, struct sockaddr *hostaddr) | 662 | * If login fails, this function prints an error and never returns. |
1334 | { | 663 | * This function does not require super-user privileges. |
1335 | Kex *kex; | ||
1336 | char *cprop[PROPOSAL_MAX]; | ||
1337 | char *sprop[PROPOSAL_MAX]; | ||
1338 | Buffer *client_kexinit; | ||
1339 | Buffer *server_kexinit; | ||
1340 | int payload_len, dlen; | ||
1341 | unsigned int klen, kout; | ||
1342 | char *ptr; | ||
1343 | char *signature = NULL; | ||
1344 | unsigned int slen; | ||
1345 | char *server_host_key_blob = NULL; | ||
1346 | Key *server_host_key; | ||
1347 | unsigned int sbloblen; | ||
1348 | DH *dh; | ||
1349 | BIGNUM *dh_server_pub = 0; | ||
1350 | BIGNUM *shared_secret = 0; | ||
1351 | int i; | ||
1352 | unsigned char *kbuf; | ||
1353 | unsigned char *hash; | ||
1354 | |||
1355 | /* KEXINIT */ | ||
1356 | |||
1357 | debug("Sending KEX init."); | ||
1358 | if (options.ciphers != NULL) { | ||
1359 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = | ||
1360 | myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; | ||
1361 | } else if ( | ||
1362 | options.cipher == SSH_CIPHER_ARCFOUR || | ||
1363 | options.cipher == SSH_CIPHER_3DES_CBC || | ||
1364 | options.cipher == SSH_CIPHER_CAST128_CBC || | ||
1365 | options.cipher == SSH_CIPHER_BLOWFISH_CBC) { | ||
1366 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = | ||
1367 | myproposal[PROPOSAL_ENC_ALGS_STOC] = cipher_name(options.cipher); | ||
1368 | } | ||
1369 | if (options.compression) { | ||
1370 | myproposal[PROPOSAL_COMP_ALGS_CTOS] = "zlib"; | ||
1371 | myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib"; | ||
1372 | } else { | ||
1373 | myproposal[PROPOSAL_COMP_ALGS_CTOS] = "none"; | ||
1374 | myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; | ||
1375 | } | ||
1376 | for (i = 0; i < PROPOSAL_MAX; i++) | ||
1377 | cprop[i] = xstrdup(myproposal[i]); | ||
1378 | |||
1379 | client_kexinit = kex_init(cprop); | ||
1380 | packet_start(SSH2_MSG_KEXINIT); | ||
1381 | packet_put_raw(buffer_ptr(client_kexinit), buffer_len(client_kexinit)); | ||
1382 | packet_send(); | ||
1383 | packet_write_wait(); | ||
1384 | |||
1385 | debug("done"); | ||
1386 | |||
1387 | packet_read_expect(&payload_len, SSH2_MSG_KEXINIT); | ||
1388 | |||
1389 | /* save payload for session_id */ | ||
1390 | server_kexinit = xmalloc(sizeof(*server_kexinit)); | ||
1391 | buffer_init(server_kexinit); | ||
1392 | ptr = packet_get_raw(&payload_len); | ||
1393 | buffer_append(server_kexinit, ptr, payload_len); | ||
1394 | |||
1395 | /* skip cookie */ | ||
1396 | for (i = 0; i < 16; i++) | ||
1397 | (void) packet_get_char(); | ||
1398 | /* kex init proposal strings */ | ||
1399 | for (i = 0; i < PROPOSAL_MAX; i++) { | ||
1400 | sprop[i] = packet_get_string(NULL); | ||
1401 | debug("got kexinit string: %s", sprop[i]); | ||
1402 | } | ||
1403 | i = (int) packet_get_char(); | ||
1404 | debug("first kex follow == %d", i); | ||
1405 | i = packet_get_int(); | ||
1406 | debug("reserved == %d", i); | ||
1407 | packet_done(); | ||
1408 | |||
1409 | debug("done read kexinit"); | ||
1410 | kex = kex_choose_conf(cprop, sprop, 0); | ||
1411 | |||
1412 | /* KEXDH */ | ||
1413 | |||
1414 | debug("Sending SSH2_MSG_KEXDH_INIT."); | ||
1415 | |||
1416 | /* generate and send 'e', client DH public key */ | ||
1417 | dh = dh_new_group1(); | ||
1418 | packet_start(SSH2_MSG_KEXDH_INIT); | ||
1419 | packet_put_bignum2(dh->pub_key); | ||
1420 | packet_send(); | ||
1421 | packet_write_wait(); | ||
1422 | |||
1423 | #ifdef DEBUG_KEXDH | ||
1424 | fprintf(stderr, "\np= "); | ||
1425 | bignum_print(dh->p); | ||
1426 | fprintf(stderr, "\ng= "); | ||
1427 | bignum_print(dh->g); | ||
1428 | fprintf(stderr, "\npub= "); | ||
1429 | bignum_print(dh->pub_key); | ||
1430 | fprintf(stderr, "\n"); | ||
1431 | DHparams_print_fp(stderr, dh); | ||
1432 | #endif | ||
1433 | |||
1434 | debug("Wait SSH2_MSG_KEXDH_REPLY."); | ||
1435 | |||
1436 | packet_read_expect(&payload_len, SSH2_MSG_KEXDH_REPLY); | ||
1437 | |||
1438 | debug("Got SSH2_MSG_KEXDH_REPLY."); | ||
1439 | |||
1440 | /* key, cert */ | ||
1441 | server_host_key_blob = packet_get_string(&sbloblen); | ||
1442 | server_host_key = dsa_serverkey_from_blob(server_host_key_blob, sbloblen); | ||
1443 | if (server_host_key == NULL) | ||
1444 | fatal("cannot decode server_host_key_blob"); | ||
1445 | |||
1446 | check_host_key(host, hostaddr, server_host_key); | ||
1447 | |||
1448 | /* DH paramter f, server public DH key */ | ||
1449 | dh_server_pub = BN_new(); | ||
1450 | if (dh_server_pub == NULL) | ||
1451 | fatal("dh_server_pub == NULL"); | ||
1452 | packet_get_bignum2(dh_server_pub, &dlen); | ||
1453 | |||
1454 | #ifdef DEBUG_KEXDH | ||
1455 | fprintf(stderr, "\ndh_server_pub= "); | ||
1456 | bignum_print(dh_server_pub); | ||
1457 | fprintf(stderr, "\n"); | ||
1458 | debug("bits %d", BN_num_bits(dh_server_pub)); | ||
1459 | #endif | ||
1460 | |||
1461 | /* signed H */ | ||
1462 | signature = packet_get_string(&slen); | ||
1463 | packet_done(); | ||
1464 | |||
1465 | if (!dh_pub_is_valid(dh, dh_server_pub)) | ||
1466 | packet_disconnect("bad server public DH value"); | ||
1467 | |||
1468 | klen = DH_size(dh); | ||
1469 | kbuf = xmalloc(klen); | ||
1470 | kout = DH_compute_key(kbuf, dh_server_pub, dh); | ||
1471 | #ifdef DEBUG_KEXDH | ||
1472 | debug("shared secret: len %d/%d", klen, kout); | ||
1473 | fprintf(stderr, "shared secret == "); | ||
1474 | for (i = 0; i< kout; i++) | ||
1475 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
1476 | fprintf(stderr, "\n"); | ||
1477 | #endif | ||
1478 | shared_secret = BN_new(); | ||
1479 | |||
1480 | BN_bin2bn(kbuf, kout, shared_secret); | ||
1481 | memset(kbuf, 0, klen); | ||
1482 | xfree(kbuf); | ||
1483 | |||
1484 | /* calc and verify H */ | ||
1485 | hash = kex_hash( | ||
1486 | client_version_string, | ||
1487 | server_version_string, | ||
1488 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
1489 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
1490 | server_host_key_blob, sbloblen, | ||
1491 | dh->pub_key, | ||
1492 | dh_server_pub, | ||
1493 | shared_secret | ||
1494 | ); | ||
1495 | buffer_free(client_kexinit); | ||
1496 | buffer_free(server_kexinit); | ||
1497 | xfree(client_kexinit); | ||
1498 | xfree(server_kexinit); | ||
1499 | #ifdef DEBUG_KEXDH | ||
1500 | fprintf(stderr, "hash == "); | ||
1501 | for (i = 0; i< 20; i++) | ||
1502 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
1503 | fprintf(stderr, "\n"); | ||
1504 | #endif | ||
1505 | dsa_verify(server_host_key, (unsigned char *)signature, slen, hash, 20); | ||
1506 | key_free(server_host_key); | ||
1507 | |||
1508 | kex_derive_keys(kex, hash, shared_secret); | ||
1509 | packet_set_kex(kex); | ||
1510 | |||
1511 | /* have keys, free DH */ | ||
1512 | DH_free(dh); | ||
1513 | |||
1514 | debug("Wait SSH2_MSG_NEWKEYS."); | ||
1515 | packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); | ||
1516 | packet_done(); | ||
1517 | debug("GOT SSH2_MSG_NEWKEYS."); | ||
1518 | |||
1519 | debug("send SSH2_MSG_NEWKEYS."); | ||
1520 | packet_start(SSH2_MSG_NEWKEYS); | ||
1521 | packet_send(); | ||
1522 | packet_write_wait(); | ||
1523 | debug("done: send SSH2_MSG_NEWKEYS."); | ||
1524 | |||
1525 | #ifdef DEBUG_KEXDH | ||
1526 | /* send 1st encrypted/maced/compressed message */ | ||
1527 | packet_start(SSH2_MSG_IGNORE); | ||
1528 | packet_put_cstring("markus"); | ||
1529 | packet_send(); | ||
1530 | packet_write_wait(); | ||
1531 | #endif | ||
1532 | debug("done: KEX2."); | ||
1533 | } | ||
1534 | /* | ||
1535 | * Authenticate user | ||
1536 | */ | 664 | */ |
1537 | void | 665 | void |
1538 | ssh_userauth2(int host_key_valid, RSA *own_host_key, | 666 | ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost, |
1539 | uid_t original_real_uid, char *host) | 667 | struct sockaddr *hostaddr, uid_t original_real_uid) |
1540 | { | 668 | { |
1541 | int type; | ||
1542 | int plen; | ||
1543 | unsigned int dlen; | ||
1544 | int partial; | ||
1545 | struct passwd *pw; | 669 | struct passwd *pw; |
1546 | char prompt[80]; | 670 | char *host, *cp; |
1547 | char *server_user, *local_user; | 671 | char *server_user, *local_user; |
1548 | char *auths; | ||
1549 | char *password; | ||
1550 | char *service = "ssh-connection"; /* service name */ | ||
1551 | |||
1552 | debug("send SSH2_MSG_SERVICE_REQUEST"); | ||
1553 | packet_start(SSH2_MSG_SERVICE_REQUEST); | ||
1554 | packet_put_cstring("ssh-userauth"); | ||
1555 | packet_send(); | ||
1556 | packet_write_wait(); | ||
1557 | |||
1558 | type = packet_read(&plen); | ||
1559 | if (type != SSH2_MSG_SERVICE_ACCEPT) { | ||
1560 | fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type); | ||
1561 | } | ||
1562 | if (packet_remaining() > 0) { | ||
1563 | char *reply = packet_get_string(&plen); | ||
1564 | debug("service_accept: %s", reply); | ||
1565 | xfree(reply); | ||
1566 | } else { | ||
1567 | /* payload empty for ssh-2.0.13 ?? */ | ||
1568 | log("buggy server: service_accept w/o service"); | ||
1569 | } | ||
1570 | packet_done(); | ||
1571 | debug("got SSH2_MSG_SERVICE_ACCEPT"); | ||
1572 | 672 | ||
1573 | /*XX COMMONCODE: */ | ||
1574 | /* Get local user name. Use it as server user if no user name was given. */ | 673 | /* Get local user name. Use it as server user if no user name was given. */ |
1575 | pw = getpwuid(original_real_uid); | 674 | pw = getpwuid(original_real_uid); |
1576 | if (!pw) | 675 | if (!pw) |
@@ -1578,396 +677,6 @@ ssh_userauth2(int host_key_valid, RSA *own_host_key, | |||
1578 | local_user = xstrdup(pw->pw_name); | 677 | local_user = xstrdup(pw->pw_name); |
1579 | server_user = options.user ? options.user : local_user; | 678 | server_user = options.user ? options.user : local_user; |
1580 | 679 | ||
1581 | /* INITIAL request for auth */ | ||
1582 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
1583 | packet_put_cstring(server_user); | ||
1584 | packet_put_cstring(service); | ||
1585 | packet_put_cstring("none"); | ||
1586 | packet_send(); | ||
1587 | packet_write_wait(); | ||
1588 | |||
1589 | for (;;) { | ||
1590 | type = packet_read(&plen); | ||
1591 | if (type == SSH2_MSG_USERAUTH_SUCCESS) | ||
1592 | break; | ||
1593 | if (type != SSH2_MSG_USERAUTH_FAILURE) | ||
1594 | fatal("access denied: %d", type); | ||
1595 | /* SSH2_MSG_USERAUTH_FAILURE means: try again */ | ||
1596 | auths = packet_get_string(&dlen); | ||
1597 | debug("authentications that can continue: %s", auths); | ||
1598 | partial = packet_get_char(); | ||
1599 | packet_done(); | ||
1600 | if (partial) | ||
1601 | debug("partial success"); | ||
1602 | if (strstr(auths, "password") == NULL) | ||
1603 | fatal("passwd auth not supported: %s", auths); | ||
1604 | xfree(auths); | ||
1605 | /* try passwd */ | ||
1606 | snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", | ||
1607 | server_user, host); | ||
1608 | password = read_passphrase(prompt, 0); | ||
1609 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
1610 | packet_put_cstring(server_user); | ||
1611 | packet_put_cstring(service); | ||
1612 | packet_put_cstring("password"); | ||
1613 | packet_put_char(0); | ||
1614 | packet_put_cstring(password); | ||
1615 | memset(password, 0, strlen(password)); | ||
1616 | xfree(password); | ||
1617 | packet_send(); | ||
1618 | packet_write_wait(); | ||
1619 | } | ||
1620 | packet_done(); | ||
1621 | debug("ssh-userauth2 successfull"); | ||
1622 | } | ||
1623 | |||
1624 | /* | ||
1625 | * SSH1 key exchange | ||
1626 | */ | ||
1627 | void | ||
1628 | ssh_kex(char *host, struct sockaddr *hostaddr) | ||
1629 | { | ||
1630 | int i; | ||
1631 | BIGNUM *key; | ||
1632 | RSA *host_key; | ||
1633 | RSA *public_key; | ||
1634 | int bits, rbits; | ||
1635 | int ssh_cipher_default = SSH_CIPHER_3DES; | ||
1636 | unsigned char session_key[SSH_SESSION_KEY_LENGTH]; | ||
1637 | unsigned char cookie[8]; | ||
1638 | unsigned int supported_ciphers; | ||
1639 | unsigned int server_flags, client_flags; | ||
1640 | int payload_len, clen, sum_len = 0; | ||
1641 | u_int32_t rand = 0; | ||
1642 | |||
1643 | debug("Waiting for server public key."); | ||
1644 | |||
1645 | /* Wait for a public key packet from the server. */ | ||
1646 | packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY); | ||
1647 | |||
1648 | /* Get cookie from the packet. */ | ||
1649 | for (i = 0; i < 8; i++) | ||
1650 | cookie[i] = packet_get_char(); | ||
1651 | |||
1652 | /* Get the public key. */ | ||
1653 | public_key = RSA_new(); | ||
1654 | bits = packet_get_int();/* bits */ | ||
1655 | public_key->e = BN_new(); | ||
1656 | packet_get_bignum(public_key->e, &clen); | ||
1657 | sum_len += clen; | ||
1658 | public_key->n = BN_new(); | ||
1659 | packet_get_bignum(public_key->n, &clen); | ||
1660 | sum_len += clen; | ||
1661 | |||
1662 | rbits = BN_num_bits(public_key->n); | ||
1663 | if (bits != rbits) { | ||
1664 | log("Warning: Server lies about size of server public key: " | ||
1665 | "actual size is %d bits vs. announced %d.", rbits, bits); | ||
1666 | log("Warning: This may be due to an old implementation of ssh."); | ||
1667 | } | ||
1668 | /* Get the host key. */ | ||
1669 | host_key = RSA_new(); | ||
1670 | bits = packet_get_int();/* bits */ | ||
1671 | host_key->e = BN_new(); | ||
1672 | packet_get_bignum(host_key->e, &clen); | ||
1673 | sum_len += clen; | ||
1674 | host_key->n = BN_new(); | ||
1675 | packet_get_bignum(host_key->n, &clen); | ||
1676 | sum_len += clen; | ||
1677 | |||
1678 | rbits = BN_num_bits(host_key->n); | ||
1679 | if (bits != rbits) { | ||
1680 | log("Warning: Server lies about size of server host key: " | ||
1681 | "actual size is %d bits vs. announced %d.", rbits, bits); | ||
1682 | log("Warning: This may be due to an old implementation of ssh."); | ||
1683 | } | ||
1684 | |||
1685 | /* Get protocol flags. */ | ||
1686 | server_flags = packet_get_int(); | ||
1687 | packet_set_protocol_flags(server_flags); | ||
1688 | |||
1689 | supported_ciphers = packet_get_int(); | ||
1690 | supported_authentications = packet_get_int(); | ||
1691 | |||
1692 | debug("Received server public key (%d bits) and host key (%d bits).", | ||
1693 | BN_num_bits(public_key->n), BN_num_bits(host_key->n)); | ||
1694 | |||
1695 | packet_integrity_check(payload_len, | ||
1696 | 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, | ||
1697 | SSH_SMSG_PUBLIC_KEY); | ||
1698 | |||
1699 | check_rsa_host_key(host, hostaddr, host_key); | ||
1700 | |||
1701 | client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN; | ||
1702 | |||
1703 | compute_session_id(session_id, cookie, host_key->n, public_key->n); | ||
1704 | |||
1705 | /* Generate a session key. */ | ||
1706 | arc4random_stir(); | ||
1707 | |||
1708 | /* | ||
1709 | * Generate an encryption key for the session. The key is a 256 bit | ||
1710 | * random number, interpreted as a 32-byte key, with the least | ||
1711 | * significant 8 bits being the first byte of the key. | ||
1712 | */ | ||
1713 | for (i = 0; i < 32; i++) { | ||
1714 | if (i % 4 == 0) | ||
1715 | rand = arc4random(); | ||
1716 | session_key[i] = rand & 0xff; | ||
1717 | rand >>= 8; | ||
1718 | } | ||
1719 | |||
1720 | /* | ||
1721 | * According to the protocol spec, the first byte of the session key | ||
1722 | * is the highest byte of the integer. The session key is xored with | ||
1723 | * the first 16 bytes of the session id. | ||
1724 | */ | ||
1725 | key = BN_new(); | ||
1726 | BN_set_word(key, 0); | ||
1727 | for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { | ||
1728 | BN_lshift(key, key, 8); | ||
1729 | if (i < 16) | ||
1730 | BN_add_word(key, session_key[i] ^ session_id[i]); | ||
1731 | else | ||
1732 | BN_add_word(key, session_key[i]); | ||
1733 | } | ||
1734 | |||
1735 | /* | ||
1736 | * Encrypt the integer using the public key and host key of the | ||
1737 | * server (key with smaller modulus first). | ||
1738 | */ | ||
1739 | if (BN_cmp(public_key->n, host_key->n) < 0) { | ||
1740 | /* Public key has smaller modulus. */ | ||
1741 | if (BN_num_bits(host_key->n) < | ||
1742 | BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED) { | ||
1743 | fatal("respond_to_rsa_challenge: host_key %d < public_key %d + " | ||
1744 | "SSH_KEY_BITS_RESERVED %d", | ||
1745 | BN_num_bits(host_key->n), | ||
1746 | BN_num_bits(public_key->n), | ||
1747 | SSH_KEY_BITS_RESERVED); | ||
1748 | } | ||
1749 | rsa_public_encrypt(key, key, public_key); | ||
1750 | rsa_public_encrypt(key, key, host_key); | ||
1751 | } else { | ||
1752 | /* Host key has smaller modulus (or they are equal). */ | ||
1753 | if (BN_num_bits(public_key->n) < | ||
1754 | BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED) { | ||
1755 | fatal("respond_to_rsa_challenge: public_key %d < host_key %d + " | ||
1756 | "SSH_KEY_BITS_RESERVED %d", | ||
1757 | BN_num_bits(public_key->n), | ||
1758 | BN_num_bits(host_key->n), | ||
1759 | SSH_KEY_BITS_RESERVED); | ||
1760 | } | ||
1761 | rsa_public_encrypt(key, key, host_key); | ||
1762 | rsa_public_encrypt(key, key, public_key); | ||
1763 | } | ||
1764 | |||
1765 | /* Destroy the public keys since we no longer need them. */ | ||
1766 | RSA_free(public_key); | ||
1767 | RSA_free(host_key); | ||
1768 | |||
1769 | if (options.cipher == SSH_CIPHER_NOT_SET) { | ||
1770 | if (cipher_mask1() & supported_ciphers & (1 << ssh_cipher_default)) | ||
1771 | options.cipher = ssh_cipher_default; | ||
1772 | else { | ||
1773 | debug("Cipher %s not supported, using %.100s instead.", | ||
1774 | cipher_name(ssh_cipher_default), | ||
1775 | cipher_name(SSH_FALLBACK_CIPHER)); | ||
1776 | options.cipher = SSH_FALLBACK_CIPHER; | ||
1777 | } | ||
1778 | } | ||
1779 | /* Check that the selected cipher is supported. */ | ||
1780 | if (!(supported_ciphers & (1 << options.cipher))) | ||
1781 | fatal("Selected cipher type %.100s not supported by server.", | ||
1782 | cipher_name(options.cipher)); | ||
1783 | |||
1784 | debug("Encryption type: %.100s", cipher_name(options.cipher)); | ||
1785 | |||
1786 | /* Send the encrypted session key to the server. */ | ||
1787 | packet_start(SSH_CMSG_SESSION_KEY); | ||
1788 | packet_put_char(options.cipher); | ||
1789 | |||
1790 | /* Send the cookie back to the server. */ | ||
1791 | for (i = 0; i < 8; i++) | ||
1792 | packet_put_char(cookie[i]); | ||
1793 | |||
1794 | /* Send and destroy the encrypted encryption key integer. */ | ||
1795 | packet_put_bignum(key); | ||
1796 | BN_clear_free(key); | ||
1797 | |||
1798 | /* Send protocol flags. */ | ||
1799 | packet_put_int(client_flags); | ||
1800 | |||
1801 | /* Send the packet now. */ | ||
1802 | packet_send(); | ||
1803 | packet_write_wait(); | ||
1804 | |||
1805 | debug("Sent encrypted session key."); | ||
1806 | |||
1807 | /* Set the encryption key. */ | ||
1808 | packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher); | ||
1809 | |||
1810 | /* We will no longer need the session key here. Destroy any extra copies. */ | ||
1811 | memset(session_key, 0, sizeof(session_key)); | ||
1812 | |||
1813 | /* | ||
1814 | * Expect a success message from the server. Note that this message | ||
1815 | * will be received in encrypted form. | ||
1816 | */ | ||
1817 | packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); | ||
1818 | |||
1819 | debug("Received encrypted confirmation."); | ||
1820 | } | ||
1821 | |||
1822 | /* | ||
1823 | * Authenticate user | ||
1824 | */ | ||
1825 | void | ||
1826 | ssh_userauth(int host_key_valid, RSA *own_host_key, | ||
1827 | uid_t original_real_uid, char *host) | ||
1828 | { | ||
1829 | int i, type; | ||
1830 | int payload_len; | ||
1831 | struct passwd *pw; | ||
1832 | const char *server_user, *local_user; | ||
1833 | |||
1834 | /* Get local user name. Use it as server user if no user name was given. */ | ||
1835 | pw = getpwuid(original_real_uid); | ||
1836 | if (!pw) | ||
1837 | fatal("User id %d not found from user database.", original_real_uid); | ||
1838 | local_user = xstrdup(pw->pw_name); | ||
1839 | server_user = options.user ? options.user : local_user; | ||
1840 | |||
1841 | /* Send the name of the user to log in as on the server. */ | ||
1842 | packet_start(SSH_CMSG_USER); | ||
1843 | packet_put_string(server_user, strlen(server_user)); | ||
1844 | packet_send(); | ||
1845 | packet_write_wait(); | ||
1846 | |||
1847 | /* | ||
1848 | * The server should respond with success if no authentication is | ||
1849 | * needed (the user has no password). Otherwise the server responds | ||
1850 | * with failure. | ||
1851 | */ | ||
1852 | type = packet_read(&payload_len); | ||
1853 | |||
1854 | /* check whether the connection was accepted without authentication. */ | ||
1855 | if (type == SSH_SMSG_SUCCESS) | ||
1856 | return; | ||
1857 | if (type != SSH_SMSG_FAILURE) | ||
1858 | packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", | ||
1859 | type); | ||
1860 | |||
1861 | #ifdef AFS | ||
1862 | /* Try Kerberos tgt passing if the server supports it. */ | ||
1863 | if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && | ||
1864 | options.kerberos_tgt_passing) { | ||
1865 | if (options.cipher == SSH_CIPHER_NONE) | ||
1866 | log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); | ||
1867 | (void) send_kerberos_tgt(); | ||
1868 | } | ||
1869 | /* Try AFS token passing if the server supports it. */ | ||
1870 | if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) && | ||
1871 | options.afs_token_passing && k_hasafs()) { | ||
1872 | if (options.cipher == SSH_CIPHER_NONE) | ||
1873 | log("WARNING: Encryption is disabled! Token will be transmitted in the clear!"); | ||
1874 | send_afs_tokens(); | ||
1875 | } | ||
1876 | #endif /* AFS */ | ||
1877 | |||
1878 | #ifdef KRB4 | ||
1879 | if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && | ||
1880 | options.kerberos_authentication) { | ||
1881 | debug("Trying Kerberos authentication."); | ||
1882 | if (try_kerberos_authentication()) { | ||
1883 | /* The server should respond with success or failure. */ | ||
1884 | type = packet_read(&payload_len); | ||
1885 | if (type == SSH_SMSG_SUCCESS) | ||
1886 | return; | ||
1887 | if (type != SSH_SMSG_FAILURE) | ||
1888 | packet_disconnect("Protocol error: got %d in response to Kerberos auth", type); | ||
1889 | } | ||
1890 | } | ||
1891 | #endif /* KRB4 */ | ||
1892 | |||
1893 | /* | ||
1894 | * Use rhosts authentication if running in privileged socket and we | ||
1895 | * do not wish to remain anonymous. | ||
1896 | */ | ||
1897 | if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) && | ||
1898 | options.rhosts_authentication) { | ||
1899 | debug("Trying rhosts authentication."); | ||
1900 | packet_start(SSH_CMSG_AUTH_RHOSTS); | ||
1901 | packet_put_string(local_user, strlen(local_user)); | ||
1902 | packet_send(); | ||
1903 | packet_write_wait(); | ||
1904 | |||
1905 | /* The server should respond with success or failure. */ | ||
1906 | type = packet_read(&payload_len); | ||
1907 | if (type == SSH_SMSG_SUCCESS) | ||
1908 | return; | ||
1909 | if (type != SSH_SMSG_FAILURE) | ||
1910 | packet_disconnect("Protocol error: got %d in response to rhosts auth", | ||
1911 | type); | ||
1912 | } | ||
1913 | /* | ||
1914 | * Try .rhosts or /etc/hosts.equiv authentication with RSA host | ||
1915 | * authentication. | ||
1916 | */ | ||
1917 | if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && | ||
1918 | options.rhosts_rsa_authentication && host_key_valid) { | ||
1919 | if (try_rhosts_rsa_authentication(local_user, own_host_key)) | ||
1920 | return; | ||
1921 | } | ||
1922 | /* Try RSA authentication if the server supports it. */ | ||
1923 | if ((supported_authentications & (1 << SSH_AUTH_RSA)) && | ||
1924 | options.rsa_authentication) { | ||
1925 | /* | ||
1926 | * Try RSA authentication using the authentication agent. The | ||
1927 | * agent is tried first because no passphrase is needed for | ||
1928 | * it, whereas identity files may require passphrases. | ||
1929 | */ | ||
1930 | if (try_agent_authentication()) | ||
1931 | return; | ||
1932 | |||
1933 | /* Try RSA authentication for each identity. */ | ||
1934 | for (i = 0; i < options.num_identity_files; i++) | ||
1935 | if (try_rsa_authentication(options.identity_files[i])) | ||
1936 | return; | ||
1937 | } | ||
1938 | /* Try skey authentication if the server supports it. */ | ||
1939 | if ((supported_authentications & (1 << SSH_AUTH_TIS)) && | ||
1940 | options.skey_authentication && !options.batch_mode) { | ||
1941 | if (try_skey_authentication()) | ||
1942 | return; | ||
1943 | } | ||
1944 | /* Try password authentication if the server supports it. */ | ||
1945 | if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && | ||
1946 | options.password_authentication && !options.batch_mode) { | ||
1947 | char prompt[80]; | ||
1948 | |||
1949 | snprintf(prompt, sizeof(prompt), "%.30s@%.40s's password: ", | ||
1950 | server_user, host); | ||
1951 | if (try_password_authentication(prompt)) | ||
1952 | return; | ||
1953 | } | ||
1954 | /* All authentication methods have failed. Exit with an error message. */ | ||
1955 | fatal("Permission denied."); | ||
1956 | /* NOTREACHED */ | ||
1957 | } | ||
1958 | /* | ||
1959 | * Starts a dialog with the server, and authenticates the current user on the | ||
1960 | * server. This does not need any extra privileges. The basic connection | ||
1961 | * to the server must already have been established before this is called. | ||
1962 | * If login fails, this function prints an error and never returns. | ||
1963 | * This function does not require super-user privileges. | ||
1964 | */ | ||
1965 | void | ||
1966 | ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost, | ||
1967 | struct sockaddr *hostaddr, uid_t original_real_uid) | ||
1968 | { | ||
1969 | char *host, *cp; | ||
1970 | |||
1971 | /* Convert the user-supplied hostname into all lowercase. */ | 680 | /* Convert the user-supplied hostname into all lowercase. */ |
1972 | host = xstrdup(orighost); | 681 | host = xstrdup(orighost); |
1973 | for (cp = host; *cp; cp++) | 682 | for (cp = host; *cp; cp++) |
@@ -1984,12 +693,9 @@ ssh_login(int host_key_valid, RSA *own_host_key, const char *orighost, | |||
1984 | /* authenticate user */ | 693 | /* authenticate user */ |
1985 | if (compat20) { | 694 | if (compat20) { |
1986 | ssh_kex2(host, hostaddr); | 695 | ssh_kex2(host, hostaddr); |
1987 | ssh_userauth2(host_key_valid, own_host_key, original_real_uid, host); | 696 | ssh_userauth2(server_user, host); |
1988 | } else { | 697 | } else { |
1989 | supported_authentications = 0; | ||
1990 | ssh_kex(host, hostaddr); | 698 | ssh_kex(host, hostaddr); |
1991 | if (supported_authentications == 0) | 699 | ssh_userauth(local_user, server_user, host, host_key_valid, own_host_key); |
1992 | fatal("supported_authentications == 0."); | ||
1993 | ssh_userauth(host_key_valid, own_host_key, original_real_uid, host); | ||
1994 | } | 700 | } |
1995 | } | 701 | } |