diff options
author | Colin Watson <cjwatson@debian.org> | 2010-03-31 10:46:28 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2010-03-31 10:46:28 +0100 |
commit | efd3d4522636ae029488c2e9730b60c88e257d2e (patch) | |
tree | 31e02ac3f16090ce8c53448677356b2b7f423683 /ssh-agent.c | |
parent | bbec4db36d464ea1d464a707625125f9fd5c7b5e (diff) | |
parent | d1a87e462e1db89f19cd960588d0c6b287cb5ccc (diff) |
* New upstream release (LP: #535029).
- After a transition period of about 10 years, this release disables SSH
protocol 1 by default. Clients and servers that need to use the
legacy protocol must explicitly enable it in ssh_config / sshd_config
or on the command-line.
- Remove the libsectok/OpenSC-based smartcard code and add support for
PKCS#11 tokens. This support is enabled by default in the Debian
packaging, since it now doesn't involve additional library
dependencies (closes: #231472, LP: #16918).
- Add support for certificate authentication of users and hosts using a
new, minimal OpenSSH certificate format (closes: #482806).
- Added a 'netcat mode' to ssh(1): "ssh -W host:port ...".
- Add the ability to revoke keys in sshd(8) and ssh(1). (For the Debian
package, this overlaps with the key blacklisting facility added in
openssh 1:4.7p1-9, but with different file formats and slightly
different scopes; for the moment, I've roughly merged the two.)
- Various multiplexing improvements, including support for requesting
port-forwardings via the multiplex protocol (closes: #360151).
- Allow setting an explicit umask on the sftp-server(8) commandline to
override whatever default the user has (closes: #496843).
- Many sftp client improvements, including tab-completion, more options,
and recursive transfer support for get/put (LP: #33378). The old
mget/mput commands never worked properly and have been removed
(closes: #270399, #428082).
- Do not prompt for a passphrase if we fail to open a keyfile, and log
the reason why the open failed to debug (closes: #431538).
- Prevent sftp from crashing when given a "-" without a command. Also,
allow whitespace to follow a "-" (closes: #531561).
Diffstat (limited to 'ssh-agent.c')
-rw-r--r-- | ssh-agent.c | 158 |
1 files changed, 88 insertions, 70 deletions
diff --git a/ssh-agent.c b/ssh-agent.c index f77dea3a6..b5c565271 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-agent.c,v 1.161 2009/03/23 19:38:04 tobias Exp $ */ | 1 | /* $OpenBSD: ssh-agent.c,v 1.165 2010/02/26 20:29:54 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -76,8 +76,8 @@ | |||
76 | #include "log.h" | 76 | #include "log.h" |
77 | #include "misc.h" | 77 | #include "misc.h" |
78 | 78 | ||
79 | #ifdef SMARTCARD | 79 | #ifdef ENABLE_PKCS11 |
80 | #include "scard.h" | 80 | #include "ssh-pkcs11.h" |
81 | #endif | 81 | #endif |
82 | 82 | ||
83 | #if defined(HAVE_SYS_PRCTL_H) | 83 | #if defined(HAVE_SYS_PRCTL_H) |
@@ -105,6 +105,7 @@ typedef struct identity { | |||
105 | TAILQ_ENTRY(identity) next; | 105 | TAILQ_ENTRY(identity) next; |
106 | Key *key; | 106 | Key *key; |
107 | char *comment; | 107 | char *comment; |
108 | char *provider; | ||
108 | u_int death; | 109 | u_int death; |
109 | u_int confirm; | 110 | u_int confirm; |
110 | } Identity; | 111 | } Identity; |
@@ -171,6 +172,8 @@ static void | |||
171 | free_identity(Identity *id) | 172 | free_identity(Identity *id) |
172 | { | 173 | { |
173 | key_free(id->key); | 174 | key_free(id->key); |
175 | if (id->provider != NULL) | ||
176 | xfree(id->provider); | ||
174 | xfree(id->comment); | 177 | xfree(id->comment); |
175 | xfree(id); | 178 | xfree(id); |
176 | } | 179 | } |
@@ -465,6 +468,8 @@ process_add_identity(SocketEntry *e, int version) | |||
465 | int type, success = 0, death = 0, confirm = 0; | 468 | int type, success = 0, death = 0, confirm = 0; |
466 | char *type_name, *comment; | 469 | char *type_name, *comment; |
467 | Key *k = NULL; | 470 | Key *k = NULL; |
471 | u_char *cert; | ||
472 | u_int len; | ||
468 | 473 | ||
469 | switch (version) { | 474 | switch (version) { |
470 | case 1: | 475 | case 1: |
@@ -495,6 +500,14 @@ process_add_identity(SocketEntry *e, int version) | |||
495 | buffer_get_bignum2(&e->request, k->dsa->pub_key); | 500 | buffer_get_bignum2(&e->request, k->dsa->pub_key); |
496 | buffer_get_bignum2(&e->request, k->dsa->priv_key); | 501 | buffer_get_bignum2(&e->request, k->dsa->priv_key); |
497 | break; | 502 | break; |
503 | case KEY_DSA_CERT: | ||
504 | cert = buffer_get_string(&e->request, &len); | ||
505 | if ((k = key_from_blob(cert, len)) == NULL) | ||
506 | fatal("Certificate parse failed"); | ||
507 | xfree(cert); | ||
508 | key_add_private(k); | ||
509 | buffer_get_bignum2(&e->request, k->dsa->priv_key); | ||
510 | break; | ||
498 | case KEY_RSA: | 511 | case KEY_RSA: |
499 | k = key_new_private(type); | 512 | k = key_new_private(type); |
500 | buffer_get_bignum2(&e->request, k->rsa->n); | 513 | buffer_get_bignum2(&e->request, k->rsa->n); |
@@ -507,6 +520,17 @@ process_add_identity(SocketEntry *e, int version) | |||
507 | /* Generate additional parameters */ | 520 | /* Generate additional parameters */ |
508 | rsa_generate_additional_parameters(k->rsa); | 521 | rsa_generate_additional_parameters(k->rsa); |
509 | break; | 522 | break; |
523 | case KEY_RSA_CERT: | ||
524 | cert = buffer_get_string(&e->request, &len); | ||
525 | if ((k = key_from_blob(cert, len)) == NULL) | ||
526 | fatal("Certificate parse failed"); | ||
527 | xfree(cert); | ||
528 | key_add_private(k); | ||
529 | buffer_get_bignum2(&e->request, k->rsa->d); | ||
530 | buffer_get_bignum2(&e->request, k->rsa->iqmp); | ||
531 | buffer_get_bignum2(&e->request, k->rsa->p); | ||
532 | buffer_get_bignum2(&e->request, k->rsa->q); | ||
533 | break; | ||
510 | default: | 534 | default: |
511 | buffer_clear(&e->request); | 535 | buffer_clear(&e->request); |
512 | goto send; | 536 | goto send; |
@@ -516,6 +540,7 @@ process_add_identity(SocketEntry *e, int version) | |||
516 | /* enable blinding */ | 540 | /* enable blinding */ |
517 | switch (k->type) { | 541 | switch (k->type) { |
518 | case KEY_RSA: | 542 | case KEY_RSA: |
543 | case KEY_RSA_CERT: | ||
519 | case KEY_RSA1: | 544 | case KEY_RSA1: |
520 | if (RSA_blinding_on(k->rsa, NULL) != 1) { | 545 | if (RSA_blinding_on(k->rsa, NULL) != 1) { |
521 | error("process_add_identity: RSA_blinding_on failed"); | 546 | error("process_add_identity: RSA_blinding_on failed"); |
@@ -549,7 +574,7 @@ process_add_identity(SocketEntry *e, int version) | |||
549 | if (lifetime && !death) | 574 | if (lifetime && !death) |
550 | death = time(NULL) + lifetime; | 575 | death = time(NULL) + lifetime; |
551 | if ((id = lookup_identity(k, version)) == NULL) { | 576 | if ((id = lookup_identity(k, version)) == NULL) { |
552 | id = xmalloc(sizeof(Identity)); | 577 | id = xcalloc(1, sizeof(Identity)); |
553 | id->key = k; | 578 | id->key = k; |
554 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); | 579 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
555 | /* Increment the number of identities. */ | 580 | /* Increment the number of identities. */ |
@@ -609,17 +634,17 @@ no_identities(SocketEntry *e, u_int type) | |||
609 | buffer_free(&msg); | 634 | buffer_free(&msg); |
610 | } | 635 | } |
611 | 636 | ||
612 | #ifdef SMARTCARD | 637 | #ifdef ENABLE_PKCS11 |
613 | static void | 638 | static void |
614 | process_add_smartcard_key(SocketEntry *e) | 639 | process_add_smartcard_key(SocketEntry *e) |
615 | { | 640 | { |
616 | char *sc_reader_id = NULL, *pin; | 641 | char *provider = NULL, *pin; |
617 | int i, type, version, success = 0, death = 0, confirm = 0; | 642 | int i, type, version, count = 0, success = 0, death = 0, confirm = 0; |
618 | Key **keys, *k; | 643 | Key **keys = NULL, *k; |
619 | Identity *id; | 644 | Identity *id; |
620 | Idtab *tab; | 645 | Idtab *tab; |
621 | 646 | ||
622 | sc_reader_id = buffer_get_string(&e->request, NULL); | 647 | provider = buffer_get_string(&e->request, NULL); |
623 | pin = buffer_get_string(&e->request, NULL); | 648 | pin = buffer_get_string(&e->request, NULL); |
624 | 649 | ||
625 | while (buffer_len(&e->request)) { | 650 | while (buffer_len(&e->request)) { |
@@ -633,30 +658,22 @@ process_add_smartcard_key(SocketEntry *e) | |||
633 | default: | 658 | default: |
634 | error("process_add_smartcard_key: " | 659 | error("process_add_smartcard_key: " |
635 | "Unknown constraint type %d", type); | 660 | "Unknown constraint type %d", type); |
636 | xfree(sc_reader_id); | ||
637 | xfree(pin); | ||
638 | goto send; | 661 | goto send; |
639 | } | 662 | } |
640 | } | 663 | } |
641 | if (lifetime && !death) | 664 | if (lifetime && !death) |
642 | death = time(NULL) + lifetime; | 665 | death = time(NULL) + lifetime; |
643 | 666 | ||
644 | keys = sc_get_keys(sc_reader_id, pin); | 667 | count = pkcs11_add_provider(provider, pin, &keys); |
645 | xfree(sc_reader_id); | 668 | for (i = 0; i < count; i++) { |
646 | xfree(pin); | ||
647 | |||
648 | if (keys == NULL || keys[0] == NULL) { | ||
649 | error("sc_get_keys failed"); | ||
650 | goto send; | ||
651 | } | ||
652 | for (i = 0; keys[i] != NULL; i++) { | ||
653 | k = keys[i]; | 669 | k = keys[i]; |
654 | version = k->type == KEY_RSA1 ? 1 : 2; | 670 | version = k->type == KEY_RSA1 ? 1 : 2; |
655 | tab = idtab_lookup(version); | 671 | tab = idtab_lookup(version); |
656 | if (lookup_identity(k, version) == NULL) { | 672 | if (lookup_identity(k, version) == NULL) { |
657 | id = xmalloc(sizeof(Identity)); | 673 | id = xcalloc(1, sizeof(Identity)); |
658 | id->key = k; | 674 | id->key = k; |
659 | id->comment = sc_get_key_label(k); | 675 | id->provider = xstrdup(provider); |
676 | id->comment = xstrdup(provider); /* XXX */ | ||
660 | id->death = death; | 677 | id->death = death; |
661 | id->confirm = confirm; | 678 | id->confirm = confirm; |
662 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); | 679 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
@@ -667,8 +684,13 @@ process_add_smartcard_key(SocketEntry *e) | |||
667 | } | 684 | } |
668 | keys[i] = NULL; | 685 | keys[i] = NULL; |
669 | } | 686 | } |
670 | xfree(keys); | ||
671 | send: | 687 | send: |
688 | if (pin) | ||
689 | xfree(pin); | ||
690 | if (provider) | ||
691 | xfree(provider); | ||
692 | if (keys) | ||
693 | xfree(keys); | ||
672 | buffer_put_int(&e->output, 1); | 694 | buffer_put_int(&e->output, 1); |
673 | buffer_put_char(&e->output, | 695 | buffer_put_char(&e->output, |
674 | success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); | 696 | success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); |
@@ -677,42 +699,37 @@ send: | |||
677 | static void | 699 | static void |
678 | process_remove_smartcard_key(SocketEntry *e) | 700 | process_remove_smartcard_key(SocketEntry *e) |
679 | { | 701 | { |
680 | char *sc_reader_id = NULL, *pin; | 702 | char *provider = NULL, *pin = NULL; |
681 | int i, version, success = 0; | 703 | int version, success = 0; |
682 | Key **keys, *k = NULL; | 704 | Identity *id, *nxt; |
683 | Identity *id; | ||
684 | Idtab *tab; | 705 | Idtab *tab; |
685 | 706 | ||
686 | sc_reader_id = buffer_get_string(&e->request, NULL); | 707 | provider = buffer_get_string(&e->request, NULL); |
687 | pin = buffer_get_string(&e->request, NULL); | 708 | pin = buffer_get_string(&e->request, NULL); |
688 | keys = sc_get_keys(sc_reader_id, pin); | ||
689 | xfree(sc_reader_id); | ||
690 | xfree(pin); | 709 | xfree(pin); |
691 | 710 | ||
692 | if (keys == NULL || keys[0] == NULL) { | 711 | for (version = 1; version < 3; version++) { |
693 | error("sc_get_keys failed"); | 712 | tab = idtab_lookup(version); |
694 | goto send; | 713 | for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) { |
695 | } | 714 | nxt = TAILQ_NEXT(id, next); |
696 | for (i = 0; keys[i] != NULL; i++) { | 715 | if (!strcmp(provider, id->provider)) { |
697 | k = keys[i]; | 716 | TAILQ_REMOVE(&tab->idlist, id, next); |
698 | version = k->type == KEY_RSA1 ? 1 : 2; | 717 | free_identity(id); |
699 | if ((id = lookup_identity(k, version)) != NULL) { | 718 | tab->nentries--; |
700 | tab = idtab_lookup(version); | 719 | } |
701 | TAILQ_REMOVE(&tab->idlist, id, next); | ||
702 | tab->nentries--; | ||
703 | free_identity(id); | ||
704 | success = 1; | ||
705 | } | 720 | } |
706 | key_free(k); | ||
707 | keys[i] = NULL; | ||
708 | } | 721 | } |
709 | xfree(keys); | 722 | if (pkcs11_del_provider(provider) == 0) |
710 | send: | 723 | success = 1; |
724 | else | ||
725 | error("process_remove_smartcard_key:" | ||
726 | " pkcs11_del_provider failed"); | ||
727 | xfree(provider); | ||
711 | buffer_put_int(&e->output, 1); | 728 | buffer_put_int(&e->output, 1); |
712 | buffer_put_char(&e->output, | 729 | buffer_put_char(&e->output, |
713 | success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); | 730 | success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); |
714 | } | 731 | } |
715 | #endif /* SMARTCARD */ | 732 | #endif /* ENABLE_PKCS11 */ |
716 | 733 | ||
717 | /* dispatch incoming messages */ | 734 | /* dispatch incoming messages */ |
718 | 735 | ||
@@ -797,7 +814,7 @@ process_message(SocketEntry *e) | |||
797 | case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: | 814 | case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: |
798 | process_remove_all_identities(e, 2); | 815 | process_remove_all_identities(e, 2); |
799 | break; | 816 | break; |
800 | #ifdef SMARTCARD | 817 | #ifdef ENABLE_PKCS11 |
801 | case SSH_AGENTC_ADD_SMARTCARD_KEY: | 818 | case SSH_AGENTC_ADD_SMARTCARD_KEY: |
802 | case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED: | 819 | case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED: |
803 | process_add_smartcard_key(e); | 820 | process_add_smartcard_key(e); |
@@ -805,7 +822,7 @@ process_message(SocketEntry *e) | |||
805 | case SSH_AGENTC_REMOVE_SMARTCARD_KEY: | 822 | case SSH_AGENTC_REMOVE_SMARTCARD_KEY: |
806 | process_remove_smartcard_key(e); | 823 | process_remove_smartcard_key(e); |
807 | break; | 824 | break; |
808 | #endif /* SMARTCARD */ | 825 | #endif /* ENABLE_PKCS11 */ |
809 | default: | 826 | default: |
810 | /* Unknown message. Respond with failure. */ | 827 | /* Unknown message. Respond with failure. */ |
811 | error("Unknown message %d", type); | 828 | error("Unknown message %d", type); |
@@ -919,11 +936,11 @@ after_select(fd_set *readset, fd_set *writeset) | |||
919 | socklen_t slen; | 936 | socklen_t slen; |
920 | char buf[1024]; | 937 | char buf[1024]; |
921 | int len, sock; | 938 | int len, sock; |
922 | u_int i; | 939 | u_int i, orig_alloc; |
923 | uid_t euid; | 940 | uid_t euid; |
924 | gid_t egid; | 941 | gid_t egid; |
925 | 942 | ||
926 | for (i = 0; i < sockets_alloc; i++) | 943 | for (i = 0, orig_alloc = sockets_alloc; i < orig_alloc; i++) |
927 | switch (sockets[i].type) { | 944 | switch (sockets[i].type) { |
928 | case AUTH_UNUSED: | 945 | case AUTH_UNUSED: |
929 | break; | 946 | break; |
@@ -956,16 +973,13 @@ after_select(fd_set *readset, fd_set *writeset) | |||
956 | case AUTH_CONNECTION: | 973 | case AUTH_CONNECTION: |
957 | if (buffer_len(&sockets[i].output) > 0 && | 974 | if (buffer_len(&sockets[i].output) > 0 && |
958 | FD_ISSET(sockets[i].fd, writeset)) { | 975 | FD_ISSET(sockets[i].fd, writeset)) { |
959 | do { | 976 | len = write(sockets[i].fd, |
960 | len = write(sockets[i].fd, | 977 | buffer_ptr(&sockets[i].output), |
961 | buffer_ptr(&sockets[i].output), | 978 | buffer_len(&sockets[i].output)); |
962 | buffer_len(&sockets[i].output)); | 979 | if (len == -1 && (errno == EAGAIN || |
963 | if (len == -1 && (errno == EAGAIN || | 980 | errno == EWOULDBLOCK || |
964 | errno == EINTR || | 981 | errno == EINTR)) |
965 | errno == EWOULDBLOCK)) | 982 | continue; |
966 | continue; | ||
967 | break; | ||
968 | } while (1); | ||
969 | if (len <= 0) { | 983 | if (len <= 0) { |
970 | close_socket(&sockets[i]); | 984 | close_socket(&sockets[i]); |
971 | break; | 985 | break; |
@@ -973,14 +987,11 @@ after_select(fd_set *readset, fd_set *writeset) | |||
973 | buffer_consume(&sockets[i].output, len); | 987 | buffer_consume(&sockets[i].output, len); |
974 | } | 988 | } |
975 | if (FD_ISSET(sockets[i].fd, readset)) { | 989 | if (FD_ISSET(sockets[i].fd, readset)) { |
976 | do { | 990 | len = read(sockets[i].fd, buf, sizeof(buf)); |
977 | len = read(sockets[i].fd, buf, sizeof(buf)); | 991 | if (len == -1 && (errno == EAGAIN || |
978 | if (len == -1 && (errno == EAGAIN || | 992 | errno == EWOULDBLOCK || |
979 | errno == EINTR || | 993 | errno == EINTR)) |
980 | errno == EWOULDBLOCK)) | 994 | continue; |
981 | continue; | ||
982 | break; | ||
983 | } while (1); | ||
984 | if (len <= 0) { | 995 | if (len <= 0) { |
985 | close_socket(&sockets[i]); | 996 | close_socket(&sockets[i]); |
986 | break; | 997 | break; |
@@ -1015,6 +1026,9 @@ static void | |||
1015 | cleanup_handler(int sig) | 1026 | cleanup_handler(int sig) |
1016 | { | 1027 | { |
1017 | cleanup_socket(); | 1028 | cleanup_socket(); |
1029 | #ifdef ENABLE_PKCS11 | ||
1030 | pkcs11_terminate(); | ||
1031 | #endif | ||
1018 | _exit(2); | 1032 | _exit(2); |
1019 | } | 1033 | } |
1020 | 1034 | ||
@@ -1261,6 +1275,10 @@ main(int ac, char **av) | |||
1261 | #endif | 1275 | #endif |
1262 | 1276 | ||
1263 | skip: | 1277 | skip: |
1278 | |||
1279 | #ifdef ENABLE_PKCS11 | ||
1280 | pkcs11_init(0); | ||
1281 | #endif | ||
1264 | new_socket(AUTH_SOCKET, sock); | 1282 | new_socket(AUTH_SOCKET, sock); |
1265 | if (ac > 0) | 1283 | if (ac > 0) |
1266 | parent_alive_interval = 10; | 1284 | parent_alive_interval = 10; |