diff options
Diffstat (limited to 'sshconnect1.c')
-rw-r--r-- | sshconnect1.c | 448 |
1 files changed, 340 insertions, 108 deletions
diff --git a/sshconnect1.c b/sshconnect1.c index ec0a5c96c..09203d714 100644 --- a/sshconnect1.c +++ b/sshconnect1.c | |||
@@ -13,7 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include "includes.h" | 15 | #include "includes.h" |
16 | RCSID("$OpenBSD: sshconnect1.c,v 1.36 2001/06/23 22:37:46 markus Exp $"); | 16 | RCSID("$OpenBSD: sshconnect1.c,v 1.37 2001/06/26 16:15:24 dugsong Exp $"); |
17 | 17 | ||
18 | #include <openssl/bn.h> | 18 | #include <openssl/bn.h> |
19 | #include <openssl/evp.h> | 19 | #include <openssl/evp.h> |
@@ -21,6 +21,9 @@ RCSID("$OpenBSD: sshconnect1.c,v 1.36 2001/06/23 22:37:46 markus Exp $"); | |||
21 | #ifdef KRB4 | 21 | #ifdef KRB4 |
22 | #include <krb.h> | 22 | #include <krb.h> |
23 | #endif | 23 | #endif |
24 | #ifdef KRB5 | ||
25 | #include <krb5.h> | ||
26 | #endif | ||
24 | #ifdef AFS | 27 | #ifdef AFS |
25 | #include <kafs.h> | 28 | #include <kafs.h> |
26 | #include "radix.h" | 29 | #include "radix.h" |
@@ -43,6 +46,7 @@ RCSID("$OpenBSD: sshconnect1.c,v 1.36 2001/06/23 22:37:46 markus Exp $"); | |||
43 | #include "readpass.h" | 46 | #include "readpass.h" |
44 | #include "cipher.h" | 47 | #include "cipher.h" |
45 | #include "canohost.h" | 48 | #include "canohost.h" |
49 | #include "auth.h" | ||
46 | 50 | ||
47 | /* Session id for the current session. */ | 51 | /* Session id for the current session. */ |
48 | u_char session_id[16]; | 52 | u_char session_id[16]; |
@@ -379,7 +383,7 @@ try_rhosts_rsa_authentication(const char *local_user, Key * host_key) | |||
379 | 383 | ||
380 | #ifdef KRB4 | 384 | #ifdef KRB4 |
381 | static int | 385 | static int |
382 | try_kerberos_authentication(void) | 386 | try_krb4_authentication(void) |
383 | { | 387 | { |
384 | KTEXT_ST auth; /* Kerberos data */ | 388 | KTEXT_ST auth; /* Kerberos data */ |
385 | char *reply; | 389 | char *reply; |
@@ -397,20 +401,21 @@ try_kerberos_authentication(void) | |||
397 | /* Don't do anything if we don't have any tickets. */ | 401 | /* Don't do anything if we don't have any tickets. */ |
398 | if (stat(tkt_string(), &st) < 0) | 402 | if (stat(tkt_string(), &st) < 0) |
399 | return 0; | 403 | return 0; |
400 | 404 | ||
401 | strncpy(inst, (char *) krb_get_phost(get_canonical_hostname(1)), INST_SZ); | 405 | strlcpy(inst, (char *)krb_get_phost(get_canonical_hostname(1)), |
402 | 406 | INST_SZ); | |
403 | realm = (char *) krb_realmofhost(get_canonical_hostname(1)); | 407 | |
408 | realm = (char *)krb_realmofhost(get_canonical_hostname(1)); | ||
404 | if (!realm) { | 409 | if (!realm) { |
405 | debug("Kerberos V4: no realm for %s", get_canonical_hostname(1)); | 410 | debug("Kerberos v4: no realm for %s", get_canonical_hostname(1)); |
406 | return 0; | 411 | return 0; |
407 | } | 412 | } |
408 | /* This can really be anything. */ | 413 | /* This can really be anything. */ |
409 | checksum = (u_long) getpid(); | 414 | checksum = (u_long)getpid(); |
410 | 415 | ||
411 | r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum); | 416 | r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum); |
412 | if (r != KSUCCESS) { | 417 | if (r != KSUCCESS) { |
413 | debug("Kerberos V4 krb_mk_req failed: %s", krb_err_txt[r]); | 418 | debug("Kerberos v4 krb_mk_req failed: %s", krb_err_txt[r]); |
414 | return 0; | 419 | return 0; |
415 | } | 420 | } |
416 | /* Get session key to decrypt the server's reply with. */ | 421 | /* Get session key to decrypt the server's reply with. */ |
@@ -420,26 +425,26 @@ try_kerberos_authentication(void) | |||
420 | return 0; | 425 | return 0; |
421 | } | 426 | } |
422 | des_key_sched((des_cblock *) cred.session, schedule); | 427 | des_key_sched((des_cblock *) cred.session, schedule); |
423 | 428 | ||
424 | /* Send authentication info to server. */ | 429 | /* Send authentication info to server. */ |
425 | packet_start(SSH_CMSG_AUTH_KERBEROS); | 430 | packet_start(SSH_CMSG_AUTH_KERBEROS); |
426 | packet_put_string((char *) auth.dat, auth.length); | 431 | packet_put_string((char *) auth.dat, auth.length); |
427 | packet_send(); | 432 | packet_send(); |
428 | packet_write_wait(); | 433 | packet_write_wait(); |
429 | 434 | ||
430 | /* Zero the buffer. */ | 435 | /* Zero the buffer. */ |
431 | (void) memset(auth.dat, 0, MAX_KTXT_LEN); | 436 | (void) memset(auth.dat, 0, MAX_KTXT_LEN); |
432 | 437 | ||
433 | slen = sizeof(local); | 438 | slen = sizeof(local); |
434 | memset(&local, 0, sizeof(local)); | 439 | memset(&local, 0, sizeof(local)); |
435 | if (getsockname(packet_get_connection_in(), | 440 | if (getsockname(packet_get_connection_in(), |
436 | (struct sockaddr *) & local, &slen) < 0) | 441 | (struct sockaddr *)&local, &slen) < 0) |
437 | debug("getsockname failed: %s", strerror(errno)); | 442 | debug("getsockname failed: %s", strerror(errno)); |
438 | 443 | ||
439 | slen = sizeof(foreign); | 444 | slen = sizeof(foreign); |
440 | memset(&foreign, 0, sizeof(foreign)); | 445 | memset(&foreign, 0, sizeof(foreign)); |
441 | if (getpeername(packet_get_connection_in(), | 446 | if (getpeername(packet_get_connection_in(), |
442 | (struct sockaddr *) & foreign, &slen) < 0) { | 447 | (struct sockaddr *)&foreign, &slen) < 0) { |
443 | debug("getpeername failed: %s", strerror(errno)); | 448 | debug("getpeername failed: %s", strerror(errno)); |
444 | fatal_cleanup(); | 449 | fatal_cleanup(); |
445 | } | 450 | } |
@@ -448,96 +453,288 @@ try_kerberos_authentication(void) | |||
448 | switch (type) { | 453 | switch (type) { |
449 | case SSH_SMSG_FAILURE: | 454 | case SSH_SMSG_FAILURE: |
450 | /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ | 455 | /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ |
451 | debug("Kerberos V4 authentication failed."); | 456 | debug("Kerberos v4 authentication failed."); |
452 | return 0; | 457 | return 0; |
453 | break; | 458 | break; |
454 | 459 | ||
455 | case SSH_SMSG_AUTH_KERBEROS_RESPONSE: | 460 | case SSH_SMSG_AUTH_KERBEROS_RESPONSE: |
456 | /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ | 461 | /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ |
457 | debug("Kerberos V4 authentication accepted."); | 462 | debug("Kerberos v4 authentication accepted."); |
458 | 463 | ||
459 | /* Get server's response. */ | 464 | /* Get server's response. */ |
460 | reply = packet_get_string((u_int *) &auth.length); | 465 | reply = packet_get_string((u_int *) &auth.length); |
461 | memcpy(auth.dat, reply, auth.length); | 466 | memcpy(auth.dat, reply, auth.length); |
462 | xfree(reply); | 467 | xfree(reply); |
463 | 468 | ||
464 | packet_integrity_check(plen, 4 + auth.length, type); | 469 | packet_integrity_check(plen, 4 + auth.length, type); |
465 | 470 | ||
466 | /* | 471 | /* |
467 | * If his response isn't properly encrypted with the session | 472 | * If his response isn't properly encrypted with the session |
468 | * key, and the decrypted checksum fails to match, he's | 473 | * key, and the decrypted checksum fails to match, he's |
469 | * bogus. Bail out. | 474 | * bogus. Bail out. |
470 | */ | 475 | */ |
471 | r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, | 476 | r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, |
472 | &foreign, &local, &msg_data); | 477 | &foreign, &local, &msg_data); |
473 | if (r != KSUCCESS) { | 478 | if (r != KSUCCESS) { |
474 | debug("Kerberos V4 krb_rd_priv failed: %s", krb_err_txt[r]); | 479 | debug("Kerberos v4 krb_rd_priv failed: %s", |
475 | packet_disconnect("Kerberos V4 challenge failed!"); | 480 | krb_err_txt[r]); |
481 | packet_disconnect("Kerberos v4 challenge failed!"); | ||
476 | } | 482 | } |
477 | /* Fetch the (incremented) checksum that we supplied in the request. */ | 483 | /* Fetch the (incremented) checksum that we supplied in the request. */ |
478 | (void) memcpy((char *) &cksum, (char *) msg_data.app_data, sizeof(cksum)); | 484 | memcpy((char *)&cksum, (char *)msg_data.app_data, |
485 | sizeof(cksum)); | ||
479 | cksum = ntohl(cksum); | 486 | cksum = ntohl(cksum); |
480 | 487 | ||
481 | /* If it matches, we're golden. */ | 488 | /* If it matches, we're golden. */ |
482 | if (cksum == checksum + 1) { | 489 | if (cksum == checksum + 1) { |
483 | debug("Kerberos V4 challenge successful."); | 490 | debug("Kerberos v4 challenge successful."); |
484 | return 1; | 491 | return 1; |
485 | } else | 492 | } else |
486 | packet_disconnect("Kerberos V4 challenge failed!"); | 493 | packet_disconnect("Kerberos v4 challenge failed!"); |
487 | break; | 494 | break; |
488 | 495 | ||
489 | default: | 496 | default: |
490 | packet_disconnect("Protocol error on Kerberos V4 response: %d", type); | 497 | packet_disconnect("Protocol error on Kerberos v4 response: %d", type); |
491 | } | 498 | } |
492 | return 0; | 499 | return 0; |
493 | } | 500 | } |
494 | 501 | ||
495 | #endif /* KRB4 */ | 502 | #endif /* KRB4 */ |
496 | 503 | ||
497 | #ifdef AFS | 504 | #ifdef KRB5 |
498 | static int | 505 | static int |
499 | send_kerberos_tgt(void) | 506 | try_krb5_authentication(krb5_context *context, krb5_auth_context *auth_context) |
507 | { | ||
508 | krb5_error_code problem; | ||
509 | const char *tkfile; | ||
510 | struct stat buf; | ||
511 | krb5_ccache ccache = NULL; | ||
512 | const char *remotehost; | ||
513 | krb5_data ap; | ||
514 | int type, payload_len; | ||
515 | krb5_ap_rep_enc_part *reply = NULL; | ||
516 | int ret; | ||
517 | |||
518 | memset(&ap, 0, sizeof(ap)); | ||
519 | |||
520 | problem = krb5_init_context(context); | ||
521 | if (problem) { | ||
522 | debug("Kerberos v5: krb5_init_context failed"); | ||
523 | ret = 0; | ||
524 | goto out; | ||
525 | } | ||
526 | |||
527 | tkfile = krb5_cc_default_name(*context); | ||
528 | if (strncmp(tkfile, "FILE:", 5) == 0) | ||
529 | tkfile += 5; | ||
530 | |||
531 | if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) { | ||
532 | debug("Kerberos v5: could not get default ccache (permission denied)."); | ||
533 | ret = 0; | ||
534 | goto out; | ||
535 | } | ||
536 | |||
537 | problem = krb5_cc_default(*context, &ccache); | ||
538 | if (problem) { | ||
539 | debug("Kerberos v5: krb5_cc_default failed: %s", | ||
540 | krb5_get_err_text(*context, problem)); | ||
541 | ret = 0; | ||
542 | goto out; | ||
543 | } | ||
544 | |||
545 | remotehost = get_canonical_hostname(1); | ||
546 | |||
547 | problem = krb5_mk_req(*context, auth_context, AP_OPTS_MUTUAL_REQUIRED, | ||
548 | "host", remotehost, NULL, ccache, &ap); | ||
549 | if (problem) { | ||
550 | debug("Kerberos v5: krb5_mk_req failed: %s", | ||
551 | krb5_get_err_text(*context, problem)); | ||
552 | ret = 0; | ||
553 | goto out; | ||
554 | } | ||
555 | |||
556 | packet_start(SSH_CMSG_AUTH_KERBEROS); | ||
557 | packet_put_string((char *) ap.data, ap.length); | ||
558 | packet_send(); | ||
559 | packet_write_wait(); | ||
560 | |||
561 | xfree(ap.data); | ||
562 | ap.length = 0; | ||
563 | |||
564 | type = packet_read(&payload_len); | ||
565 | switch (type) { | ||
566 | case SSH_SMSG_FAILURE: | ||
567 | /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ | ||
568 | debug("Kerberos v5 authentication failed."); | ||
569 | ret = 0; | ||
570 | break; | ||
571 | |||
572 | case SSH_SMSG_AUTH_KERBEROS_RESPONSE: | ||
573 | /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ | ||
574 | debug("Kerberos v5 authentication accepted."); | ||
575 | |||
576 | /* Get server's response. */ | ||
577 | ap.data = packet_get_string((unsigned int *) &ap.length); | ||
578 | |||
579 | packet_integrity_check(payload_len, 4 + ap.length, type); | ||
580 | /* XXX je to dobre? */ | ||
581 | |||
582 | problem = krb5_rd_rep(*context, *auth_context, &ap, &reply); | ||
583 | if (problem) { | ||
584 | ret = 0; | ||
585 | } | ||
586 | ret = 1; | ||
587 | break; | ||
588 | |||
589 | default: | ||
590 | packet_disconnect("Protocol error on Kerberos v5 response: %d", | ||
591 | type); | ||
592 | ret = 0; | ||
593 | break; | ||
594 | |||
595 | } | ||
596 | |||
597 | out: | ||
598 | if (ccache != NULL) | ||
599 | krb5_cc_close(*context, ccache); | ||
600 | if (reply != NULL) | ||
601 | krb5_free_ap_rep_enc_part(*context, reply); | ||
602 | if (ap.length > 0) | ||
603 | krb5_data_free(&ap); | ||
604 | |||
605 | return (ret); | ||
606 | } | ||
607 | |||
608 | static void | ||
609 | send_krb5_tgt(krb5_context context, krb5_auth_context auth_context) | ||
610 | { | ||
611 | int fd, type, payload_len; | ||
612 | krb5_error_code problem; | ||
613 | krb5_data outbuf; | ||
614 | krb5_ccache ccache = NULL; | ||
615 | krb5_creds creds; | ||
616 | krb5_kdc_flags flags; | ||
617 | const char *remotehost; | ||
618 | |||
619 | memset(&creds, 0, sizeof(creds)); | ||
620 | memset(&outbuf, 0, sizeof(outbuf)); | ||
621 | |||
622 | fd = packet_get_connection_in(); | ||
623 | |||
624 | problem = krb5_auth_con_setaddrs_from_fd(context, auth_context, &fd); | ||
625 | if (problem) | ||
626 | goto out; | ||
627 | |||
628 | problem = krb5_cc_default(context, &ccache); | ||
629 | if (problem) | ||
630 | goto out; | ||
631 | |||
632 | problem = krb5_cc_get_principal(context, ccache, &creds.client); | ||
633 | if (problem) | ||
634 | goto out; | ||
635 | |||
636 | problem = krb5_build_principal(context, &creds.server, | ||
637 | strlen(creds.client->realm), creds.client->realm, | ||
638 | "krbtgt", creds.client->realm, NULL); | ||
639 | if (problem) | ||
640 | goto out; | ||
641 | |||
642 | creds.times.endtime = 0; | ||
643 | |||
644 | flags.i = 0; | ||
645 | flags.b.forwarded = 1; | ||
646 | flags.b.forwardable = krb5_config_get_bool(context, NULL, | ||
647 | "libdefaults", "forwardable", NULL); | ||
648 | |||
649 | remotehost = get_canonical_hostname(1); | ||
650 | |||
651 | problem = krb5_get_forwarded_creds(context, auth_context, | ||
652 | ccache, flags.i, remotehost, &creds, &outbuf); | ||
653 | if (problem) | ||
654 | goto out; | ||
655 | |||
656 | packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); | ||
657 | packet_put_string((char *)outbuf.data, outbuf.length); | ||
658 | packet_send(); | ||
659 | packet_write_wait(); | ||
660 | |||
661 | type = packet_read(&payload_len); | ||
662 | |||
663 | if (type == SSH_SMSG_SUCCESS) { | ||
664 | char *pname; | ||
665 | |||
666 | krb5_unparse_name(context, creds.client, &pname); | ||
667 | debug("Kerberos v5 TGT forwarded (%s).", pname); | ||
668 | xfree(pname); | ||
669 | } else | ||
670 | debug("Kerberos v5 TGT forwarding failed."); | ||
671 | |||
672 | return; | ||
673 | |||
674 | out: | ||
675 | if (problem) | ||
676 | debug("Kerberos v5 TGT forwarding failed: %s", | ||
677 | krb5_get_err_text(context, problem)); | ||
678 | if (creds.client) | ||
679 | krb5_free_principal(context, creds.client); | ||
680 | if (creds.server) | ||
681 | krb5_free_principal(context, creds.server); | ||
682 | if (ccache) | ||
683 | krb5_cc_close(context, ccache); | ||
684 | if (outbuf.data) | ||
685 | xfree(outbuf.data); | ||
686 | } | ||
687 | #endif /* KRB5 */ | ||
688 | |||
689 | #ifdef AFS | ||
690 | static void | ||
691 | send_krb4_tgt(void) | ||
500 | { | 692 | { |
501 | CREDENTIALS *creds; | 693 | CREDENTIALS *creds; |
502 | char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; | ||
503 | int r, type, plen; | ||
504 | char buffer[8192]; | ||
505 | struct stat st; | 694 | struct stat st; |
506 | 695 | char buffer[4096], pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; | |
696 | int problem, type, len; | ||
697 | |||
507 | /* Don't do anything if we don't have any tickets. */ | 698 | /* Don't do anything if we don't have any tickets. */ |
508 | if (stat(tkt_string(), &st) < 0) | 699 | if (stat(tkt_string(), &st) < 0) |
509 | return 0; | 700 | return; |
510 | 701 | ||
511 | creds = xmalloc(sizeof(*creds)); | 702 | creds = xmalloc(sizeof(*creds)); |
512 | 703 | ||
513 | if ((r = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm)) != KSUCCESS) { | 704 | problem = krb_get_tf_fullname(TKT_FILE, pname, pinst, prealm); |
514 | debug("Kerberos V4 tf_fullname failed: %s", krb_err_txt[r]); | 705 | if (problem) |
515 | return 0; | 706 | goto out; |
516 | } | 707 | |
517 | if ((r = krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) { | 708 | problem = krb_get_cred("krbtgt", prealm, prealm, creds); |
518 | debug("Kerberos V4 get_cred failed: %s", krb_err_txt[r]); | 709 | if (problem) |
519 | return 0; | 710 | goto out; |
520 | } | 711 | |
521 | if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) { | 712 | if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) { |
522 | debug("Kerberos V4 ticket expired: %s", TKT_FILE); | 713 | problem = RD_AP_EXP; |
523 | return 0; | 714 | goto out; |
524 | } | 715 | } |
525 | creds_to_radix(creds, (u_char *)buffer, sizeof buffer); | 716 | creds_to_radix(creds, (u_char *)buffer, sizeof(buffer)); |
526 | xfree(creds); | 717 | |
527 | |||
528 | packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); | 718 | packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); |
529 | packet_put_cstring(buffer); | 719 | packet_put_cstring(buffer); |
530 | packet_send(); | 720 | packet_send(); |
531 | packet_write_wait(); | 721 | packet_write_wait(); |
532 | 722 | ||
533 | type = packet_read(&plen); | 723 | type = packet_read(&len); |
534 | 724 | ||
535 | if (type == SSH_SMSG_FAILURE) | 725 | if (type == SSH_SMSG_SUCCESS) |
536 | debug("Kerberos TGT for realm %s rejected.", prealm); | 726 | debug("Kerberos v4 TGT forwarded (%s%s%s@%s).", |
537 | else if (type != SSH_SMSG_SUCCESS) | 727 | creds->pname, creds->pinst[0] ? "." : "", |
538 | packet_disconnect("Protocol error on Kerberos TGT response: %d", type); | 728 | creds->pinst, creds->realm); |
539 | 729 | else | |
540 | return 1; | 730 | debug("Kerberos v4 TGT rejected."); |
731 | |||
732 | xfree(creds); | ||
733 | return; | ||
734 | |||
735 | out: | ||
736 | debug("Kerberos v4 TGT passing failed: %s", krb_err_txt[problem]); | ||
737 | xfree(creds); | ||
541 | } | 738 | } |
542 | 739 | ||
543 | static void | 740 | static void |
@@ -546,10 +743,10 @@ send_afs_tokens(void) | |||
546 | CREDENTIALS creds; | 743 | CREDENTIALS creds; |
547 | struct ViceIoctl parms; | 744 | struct ViceIoctl parms; |
548 | struct ClearToken ct; | 745 | struct ClearToken ct; |
549 | int i, type, len, plen; | 746 | int i, type, len; |
550 | char buf[2048], *p, *server_cell; | 747 | char buf[2048], *p, *server_cell; |
551 | char buffer[8192]; | 748 | char buffer[8192]; |
552 | 749 | ||
553 | /* Move over ktc_GetToken, here's something leaner. */ | 750 | /* Move over ktc_GetToken, here's something leaner. */ |
554 | for (i = 0; i < 100; i++) { /* just in case */ | 751 | for (i = 0; i < 100; i++) { /* just in case */ |
555 | parms.in = (char *) &i; | 752 | parms.in = (char *) &i; |
@@ -559,7 +756,7 @@ send_afs_tokens(void) | |||
559 | if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0) | 756 | if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0) |
560 | break; | 757 | break; |
561 | p = buf; | 758 | p = buf; |
562 | 759 | ||
563 | /* Get secret token. */ | 760 | /* Get secret token. */ |
564 | memcpy(&creds.ticket_st.length, p, sizeof(u_int)); | 761 | memcpy(&creds.ticket_st.length, p, sizeof(u_int)); |
565 | if (creds.ticket_st.length > MAX_KTXT_LEN) | 762 | if (creds.ticket_st.length > MAX_KTXT_LEN) |
@@ -567,7 +764,7 @@ send_afs_tokens(void) | |||
567 | p += sizeof(u_int); | 764 | p += sizeof(u_int); |
568 | memcpy(creds.ticket_st.dat, p, creds.ticket_st.length); | 765 | memcpy(creds.ticket_st.dat, p, creds.ticket_st.length); |
569 | p += creds.ticket_st.length; | 766 | p += creds.ticket_st.length; |
570 | 767 | ||
571 | /* Get clear token. */ | 768 | /* Get clear token. */ |
572 | memcpy(&len, p, sizeof(len)); | 769 | memcpy(&len, p, sizeof(len)); |
573 | if (len != sizeof(struct ClearToken)) | 770 | if (len != sizeof(struct ClearToken)) |
@@ -577,20 +774,22 @@ send_afs_tokens(void) | |||
577 | p += len; | 774 | p += len; |
578 | p += sizeof(len); /* primary flag */ | 775 | p += sizeof(len); /* primary flag */ |
579 | server_cell = p; | 776 | server_cell = p; |
580 | 777 | ||
581 | /* Flesh out our credentials. */ | 778 | /* Flesh out our credentials. */ |
582 | strlcpy(creds.service, "afs", sizeof creds.service); | 779 | strlcpy(creds.service, "afs", sizeof(creds.service)); |
583 | creds.instance[0] = '\0'; | 780 | creds.instance[0] = '\0'; |
584 | strlcpy(creds.realm, server_cell, REALM_SZ); | 781 | strlcpy(creds.realm, server_cell, REALM_SZ); |
585 | memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ); | 782 | memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ); |
586 | creds.issue_date = ct.BeginTimestamp; | 783 | creds.issue_date = ct.BeginTimestamp; |
587 | creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp); | 784 | creds.lifetime = krb_time_to_life(creds.issue_date, |
785 | ct.EndTimestamp); | ||
588 | creds.kvno = ct.AuthHandle; | 786 | creds.kvno = ct.AuthHandle; |
589 | snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId); | 787 | snprintf(creds.pname, sizeof(creds.pname), "AFS ID %d", ct.ViceId); |
590 | creds.pinst[0] = '\0'; | 788 | creds.pinst[0] = '\0'; |
591 | 789 | ||
592 | /* Encode token, ship it off. */ | 790 | /* Encode token, ship it off. */ |
593 | if (creds_to_radix(&creds, (u_char *) buffer, sizeof buffer) <= 0) | 791 | if (creds_to_radix(&creds, (u_char *)buffer, |
792 | sizeof(buffer)) <= 0) | ||
594 | break; | 793 | break; |
595 | packet_start(SSH_CMSG_HAVE_AFS_TOKEN); | 794 | packet_start(SSH_CMSG_HAVE_AFS_TOKEN); |
596 | packet_put_cstring(buffer); | 795 | packet_put_cstring(buffer); |
@@ -599,8 +798,8 @@ send_afs_tokens(void) | |||
599 | 798 | ||
600 | /* Roger, Roger. Clearance, Clarence. What's your vector, | 799 | /* Roger, Roger. Clearance, Clarence. What's your vector, |
601 | Victor? */ | 800 | Victor? */ |
602 | type = packet_read(&plen); | 801 | type = packet_read(&len); |
603 | 802 | ||
604 | if (type == SSH_SMSG_FAILURE) | 803 | if (type == SSH_SMSG_FAILURE) |
605 | debug("AFS token for cell %s rejected.", server_cell); | 804 | debug("AFS token for cell %s rejected.", server_cell); |
606 | else if (type != SSH_SMSG_SUCCESS) | 805 | else if (type != SSH_SMSG_SUCCESS) |
@@ -622,9 +821,9 @@ try_challenge_response_authentication(void) | |||
622 | u_int clen; | 821 | u_int clen; |
623 | char prompt[1024]; | 822 | char prompt[1024]; |
624 | char *challenge, *response; | 823 | char *challenge, *response; |
625 | 824 | ||
626 | debug("Doing challenge reponse authentication."); | 825 | debug("Doing challenge reponse authentication."); |
627 | 826 | ||
628 | for (i = 0; i < options.number_of_password_prompts; i++) { | 827 | for (i = 0; i < options.number_of_password_prompts; i++) { |
629 | /* request a challenge */ | 828 | /* request a challenge */ |
630 | packet_start(SSH_CMSG_AUTH_TIS); | 829 | packet_start(SSH_CMSG_AUTH_TIS); |
@@ -913,9 +1112,13 @@ void | |||
913 | ssh_userauth1(const char *local_user, const char *server_user, char *host, | 1112 | ssh_userauth1(const char *local_user, const char *server_user, char *host, |
914 | Key **keys, int nkeys) | 1113 | Key **keys, int nkeys) |
915 | { | 1114 | { |
1115 | #ifdef KRB5 | ||
1116 | krb5_context context = NULL; | ||
1117 | krb5_auth_context auth_context = NULL; | ||
1118 | #endif | ||
916 | int i, type; | 1119 | int i, type; |
917 | int payload_len; | 1120 | int payload_len; |
918 | 1121 | ||
919 | if (supported_authentications == 0) | 1122 | if (supported_authentications == 0) |
920 | fatal("ssh_userauth1: server supports no auth methods"); | 1123 | fatal("ssh_userauth1: server supports no auth methods"); |
921 | 1124 | ||
@@ -934,43 +1137,40 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, | |||
934 | 1137 | ||
935 | /* check whether the connection was accepted without authentication. */ | 1138 | /* check whether the connection was accepted without authentication. */ |
936 | if (type == SSH_SMSG_SUCCESS) | 1139 | if (type == SSH_SMSG_SUCCESS) |
937 | return; | 1140 | goto success; |
938 | if (type != SSH_SMSG_FAILURE) | 1141 | if (type != SSH_SMSG_FAILURE) |
939 | packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", | 1142 | packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type); |
940 | type); | 1143 | |
941 | 1144 | #ifdef KRB5 | |
942 | #ifdef AFS | 1145 | if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && |
943 | /* Try Kerberos tgt passing if the server supports it. */ | 1146 | options.kerberos_authentication) { |
944 | if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && | 1147 | debug("Trying Kerberos v5 authentication."); |
945 | options.kerberos_tgt_passing) { | 1148 | |
946 | if (options.cipher == SSH_CIPHER_NONE) | 1149 | if (try_krb5_authentication(&context, &auth_context)) { |
947 | log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); | 1150 | type = packet_read(&payload_len); |
948 | (void) send_kerberos_tgt(); | 1151 | if (type == SSH_SMSG_SUCCESS) |
949 | } | 1152 | goto success; |
950 | /* Try AFS token passing if the server supports it. */ | 1153 | if (type != SSH_SMSG_FAILURE) |
951 | if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) && | 1154 | packet_disconnect("Protocol error: got %d in response to Kerberos v5 auth", type); |
952 | options.afs_token_passing && k_hasafs()) { | 1155 | } |
953 | if (options.cipher == SSH_CIPHER_NONE) | ||
954 | log("WARNING: Encryption is disabled! Token will be transmitted in the clear!"); | ||
955 | send_afs_tokens(); | ||
956 | } | 1156 | } |
957 | #endif /* AFS */ | 1157 | #endif /* KRB5 */ |
958 | 1158 | ||
959 | #ifdef KRB4 | 1159 | #ifdef KRB4 |
960 | if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && | 1160 | if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && |
961 | options.kerberos_authentication) { | 1161 | options.kerberos_authentication) { |
962 | debug("Trying Kerberos authentication."); | 1162 | debug("Trying Kerberos v4 authentication."); |
963 | if (try_kerberos_authentication()) { | 1163 | |
964 | /* The server should respond with success or failure. */ | 1164 | if (try_krb4_authentication()) { |
965 | type = packet_read(&payload_len); | 1165 | type = packet_read(&payload_len); |
966 | if (type == SSH_SMSG_SUCCESS) | 1166 | if (type == SSH_SMSG_SUCCESS) |
967 | return; | 1167 | goto success; |
968 | if (type != SSH_SMSG_FAILURE) | 1168 | if (type != SSH_SMSG_FAILURE) |
969 | packet_disconnect("Protocol error: got %d in response to Kerberos auth", type); | 1169 | packet_disconnect("Protocol error: got %d in response to Kerberos v4 auth", type); |
970 | } | 1170 | } |
971 | } | 1171 | } |
972 | #endif /* KRB4 */ | 1172 | #endif /* KRB4 */ |
973 | 1173 | ||
974 | /* | 1174 | /* |
975 | * Use rhosts authentication if running in privileged socket and we | 1175 | * Use rhosts authentication if running in privileged socket and we |
976 | * do not wish to remain anonymous. | 1176 | * do not wish to remain anonymous. |
@@ -986,7 +1186,7 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, | |||
986 | /* The server should respond with success or failure. */ | 1186 | /* The server should respond with success or failure. */ |
987 | type = packet_read(&payload_len); | 1187 | type = packet_read(&payload_len); |
988 | if (type == SSH_SMSG_SUCCESS) | 1188 | if (type == SSH_SMSG_SUCCESS) |
989 | return; | 1189 | goto success; |
990 | if (type != SSH_SMSG_FAILURE) | 1190 | if (type != SSH_SMSG_FAILURE) |
991 | packet_disconnect("Protocol error: got %d in response to rhosts auth", | 1191 | packet_disconnect("Protocol error: got %d in response to rhosts auth", |
992 | type); | 1192 | type); |
@@ -1000,7 +1200,7 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, | |||
1000 | for (i = 0; i < nkeys; i++) { | 1200 | for (i = 0; i < nkeys; i++) { |
1001 | if (keys[i] != NULL && keys[i]->type == KEY_RSA1 && | 1201 | if (keys[i] != NULL && keys[i]->type == KEY_RSA1 && |
1002 | try_rhosts_rsa_authentication(local_user, keys[i])) | 1202 | try_rhosts_rsa_authentication(local_user, keys[i])) |
1003 | return; | 1203 | goto success; |
1004 | } | 1204 | } |
1005 | } | 1205 | } |
1006 | /* Try RSA authentication if the server supports it. */ | 1206 | /* Try RSA authentication if the server supports it. */ |
@@ -1012,20 +1212,20 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, | |||
1012 | * it, whereas identity files may require passphrases. | 1212 | * it, whereas identity files may require passphrases. |
1013 | */ | 1213 | */ |
1014 | if (try_agent_authentication()) | 1214 | if (try_agent_authentication()) |
1015 | return; | 1215 | goto success; |
1016 | 1216 | ||
1017 | /* Try RSA authentication for each identity. */ | 1217 | /* Try RSA authentication for each identity. */ |
1018 | for (i = 0; i < options.num_identity_files; i++) | 1218 | for (i = 0; i < options.num_identity_files; i++) |
1019 | if (options.identity_keys[i] != NULL && | 1219 | if (options.identity_keys[i] != NULL && |
1020 | options.identity_keys[i]->type == KEY_RSA1 && | 1220 | options.identity_keys[i]->type == KEY_RSA1 && |
1021 | try_rsa_authentication(options.identity_files[i])) | 1221 | try_rsa_authentication(options.identity_files[i])) |
1022 | return; | 1222 | goto success; |
1023 | } | 1223 | } |
1024 | /* Try challenge response authentication if the server supports it. */ | 1224 | /* Try challenge response authentication if the server supports it. */ |
1025 | if ((supported_authentications & (1 << SSH_AUTH_TIS)) && | 1225 | if ((supported_authentications & (1 << SSH_AUTH_TIS)) && |
1026 | options.challenge_response_authentication && !options.batch_mode) { | 1226 | options.challenge_response_authentication && !options.batch_mode) { |
1027 | if (try_challenge_response_authentication()) | 1227 | if (try_challenge_response_authentication()) |
1028 | return; | 1228 | goto success; |
1029 | } | 1229 | } |
1030 | /* Try password authentication if the server supports it. */ | 1230 | /* Try password authentication if the server supports it. */ |
1031 | if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && | 1231 | if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && |
@@ -1035,9 +1235,41 @@ ssh_userauth1(const char *local_user, const char *server_user, char *host, | |||
1035 | snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", | 1235 | snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", |
1036 | server_user, host); | 1236 | server_user, host); |
1037 | if (try_password_authentication(prompt)) | 1237 | if (try_password_authentication(prompt)) |
1038 | return; | 1238 | goto success; |
1039 | } | 1239 | } |
1040 | /* All authentication methods have failed. Exit with an error message. */ | 1240 | /* All authentication methods have failed. Exit with an error message. */ |
1041 | fatal("Permission denied."); | 1241 | fatal("Permission denied."); |
1042 | /* NOTREACHED */ | 1242 | /* NOTREACHED */ |
1243 | |||
1244 | success: | ||
1245 | #ifdef KRB5 | ||
1246 | /* Try Kerberos v5 TGT passing. */ | ||
1247 | if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && | ||
1248 | options.kerberos_tgt_passing && context && auth_context) { | ||
1249 | if (options.cipher == SSH_CIPHER_NONE) | ||
1250 | log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); | ||
1251 | send_krb5_tgt(context, auth_context); | ||
1252 | } | ||
1253 | if (auth_context) | ||
1254 | krb5_auth_con_free(context, auth_context); | ||
1255 | if (context) | ||
1256 | krb5_free_context(context); | ||
1257 | #endif | ||
1258 | |||
1259 | #ifdef AFS | ||
1260 | /* Try Kerberos v4 TGT passing if the server supports it. */ | ||
1261 | if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && | ||
1262 | options.kerberos_tgt_passing) { | ||
1263 | if (options.cipher == SSH_CIPHER_NONE) | ||
1264 | log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); | ||
1265 | send_krb4_tgt(); | ||
1266 | } | ||
1267 | /* Try AFS token passing if the server supports it. */ | ||
1268 | if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) && | ||
1269 | options.afs_token_passing && k_hasafs()) { | ||
1270 | if (options.cipher == SSH_CIPHER_NONE) | ||
1271 | log("WARNING: Encryption is disabled! Token will be transmitted in the clear!"); | ||
1272 | send_afs_tokens(); | ||
1273 | } | ||
1274 | #endif /* AFS */ | ||
1043 | } | 1275 | } |