diff options
Diffstat (limited to 'ssh-agent.c')
-rw-r--r-- | ssh-agent.c | 79 |
1 files changed, 70 insertions, 9 deletions
diff --git a/ssh-agent.c b/ssh-agent.c index cca720ee2..eb593de73 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -35,7 +35,7 @@ | |||
35 | 35 | ||
36 | #include "includes.h" | 36 | #include "includes.h" |
37 | #include "openbsd-compat/sys-queue.h" | 37 | #include "openbsd-compat/sys-queue.h" |
38 | RCSID("$OpenBSD: ssh-agent.c,v 1.105 2002/10/01 20:34:12 markus Exp $"); | 38 | RCSID("$OpenBSD: ssh-agent.c,v 1.108 2003/03/13 11:44:50 markus Exp $"); |
39 | 39 | ||
40 | #include <openssl/evp.h> | 40 | #include <openssl/evp.h> |
41 | #include <openssl/md5.h> | 41 | #include <openssl/md5.h> |
@@ -50,6 +50,8 @@ RCSID("$OpenBSD: ssh-agent.c,v 1.105 2002/10/01 20:34:12 markus Exp $"); | |||
50 | #include "authfd.h" | 50 | #include "authfd.h" |
51 | #include "compat.h" | 51 | #include "compat.h" |
52 | #include "log.h" | 52 | #include "log.h" |
53 | #include "readpass.h" | ||
54 | #include "misc.h" | ||
53 | 55 | ||
54 | #ifdef SMARTCARD | 56 | #ifdef SMARTCARD |
55 | #include "scard.h" | 57 | #include "scard.h" |
@@ -77,6 +79,7 @@ typedef struct identity { | |||
77 | Key *key; | 79 | Key *key; |
78 | char *comment; | 80 | char *comment; |
79 | u_int death; | 81 | u_int death; |
82 | u_int confirm; | ||
80 | } Identity; | 83 | } Identity; |
81 | 84 | ||
82 | typedef struct { | 85 | typedef struct { |
@@ -106,6 +109,9 @@ extern char *__progname; | |||
106 | char *__progname; | 109 | char *__progname; |
107 | #endif | 110 | #endif |
108 | 111 | ||
112 | /* Default lifetime (0 == forever) */ | ||
113 | static int lifetime = 0; | ||
114 | |||
109 | static void | 115 | static void |
110 | close_socket(SocketEntry *e) | 116 | close_socket(SocketEntry *e) |
111 | { | 117 | { |
@@ -159,6 +165,30 @@ lookup_identity(Key *key, int version) | |||
159 | return (NULL); | 165 | return (NULL); |
160 | } | 166 | } |
161 | 167 | ||
168 | /* Check confirmation of keysign request */ | ||
169 | static int | ||
170 | confirm_key(Identity *id) | ||
171 | { | ||
172 | char *p, prompt[1024]; | ||
173 | int ret = -1; | ||
174 | |||
175 | p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); | ||
176 | snprintf(prompt, sizeof(prompt), "Allow use of key %s?\n" | ||
177 | "Key fingerprint %s.", id->comment, p); | ||
178 | xfree(p); | ||
179 | p = read_passphrase(prompt, RP_ALLOW_EOF); | ||
180 | if (p != NULL) { | ||
181 | /* | ||
182 | * Accept empty responses and responses consisting | ||
183 | * of the word "yes" as affirmative. | ||
184 | */ | ||
185 | if (*p == '\0' || *p == '\n' || strcasecmp(p, "yes") == 0) | ||
186 | ret = 0; | ||
187 | xfree(p); | ||
188 | } | ||
189 | return (ret); | ||
190 | } | ||
191 | |||
162 | /* send list of supported public keys to 'client' */ | 192 | /* send list of supported public keys to 'client' */ |
163 | static void | 193 | static void |
164 | process_request_identities(SocketEntry *e, int version) | 194 | process_request_identities(SocketEntry *e, int version) |
@@ -222,7 +252,7 @@ process_authentication_challenge1(SocketEntry *e) | |||
222 | goto failure; | 252 | goto failure; |
223 | 253 | ||
224 | id = lookup_identity(key, 1); | 254 | id = lookup_identity(key, 1); |
225 | if (id != NULL) { | 255 | if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { |
226 | Key *private = id->key; | 256 | Key *private = id->key; |
227 | /* Decrypt the challenge using the private key. */ | 257 | /* Decrypt the challenge using the private key. */ |
228 | if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) | 258 | if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) |
@@ -282,7 +312,7 @@ process_sign_request2(SocketEntry *e) | |||
282 | key = key_from_blob(blob, blen); | 312 | key = key_from_blob(blob, blen); |
283 | if (key != NULL) { | 313 | if (key != NULL) { |
284 | Identity *id = lookup_identity(key, 2); | 314 | Identity *id = lookup_identity(key, 2); |
285 | if (id != NULL) | 315 | if (id != NULL && (!id->confirm || confirm_key(id) == 0)) |
286 | ok = key_sign(id->key, &signature, &slen, data, dlen); | 316 | ok = key_sign(id->key, &signature, &slen, data, dlen); |
287 | } | 317 | } |
288 | key_free(key); | 318 | key_free(key); |
@@ -402,7 +432,7 @@ static void | |||
402 | process_add_identity(SocketEntry *e, int version) | 432 | process_add_identity(SocketEntry *e, int version) |
403 | { | 433 | { |
404 | Idtab *tab = idtab_lookup(version); | 434 | Idtab *tab = idtab_lookup(version); |
405 | int type, success = 0, death = 0; | 435 | int type, success = 0, death = 0, confirm = 0; |
406 | char *type_name, *comment; | 436 | char *type_name, *comment; |
407 | Key *k = NULL; | 437 | Key *k = NULL; |
408 | 438 | ||
@@ -453,6 +483,17 @@ process_add_identity(SocketEntry *e, int version) | |||
453 | } | 483 | } |
454 | break; | 484 | break; |
455 | } | 485 | } |
486 | /* enable blinding */ | ||
487 | switch (k->type) { | ||
488 | case KEY_RSA: | ||
489 | case KEY_RSA1: | ||
490 | if (RSA_blinding_on(k->rsa, NULL) != 1) { | ||
491 | error("process_add_identity: RSA_blinding_on failed"); | ||
492 | key_free(k); | ||
493 | goto send; | ||
494 | } | ||
495 | break; | ||
496 | } | ||
456 | comment = buffer_get_string(&e->request, NULL); | 497 | comment = buffer_get_string(&e->request, NULL); |
457 | if (k == NULL) { | 498 | if (k == NULL) { |
458 | xfree(comment); | 499 | xfree(comment); |
@@ -464,15 +505,21 @@ process_add_identity(SocketEntry *e, int version) | |||
464 | case SSH_AGENT_CONSTRAIN_LIFETIME: | 505 | case SSH_AGENT_CONSTRAIN_LIFETIME: |
465 | death = time(NULL) + buffer_get_int(&e->request); | 506 | death = time(NULL) + buffer_get_int(&e->request); |
466 | break; | 507 | break; |
508 | case SSH_AGENT_CONSTRAIN_CONFIRM: | ||
509 | confirm = 1; | ||
510 | break; | ||
467 | default: | 511 | default: |
468 | break; | 512 | break; |
469 | } | 513 | } |
470 | } | 514 | } |
515 | if (lifetime && !death) | ||
516 | death = time(NULL) + lifetime; | ||
471 | if (lookup_identity(k, version) == NULL) { | 517 | if (lookup_identity(k, version) == NULL) { |
472 | Identity *id = xmalloc(sizeof(Identity)); | 518 | Identity *id = xmalloc(sizeof(Identity)); |
473 | id->key = k; | 519 | id->key = k; |
474 | id->comment = comment; | 520 | id->comment = comment; |
475 | id->death = death; | 521 | id->death = death; |
522 | id->confirm = confirm; | ||
476 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); | 523 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
477 | /* Increment the number of identities. */ | 524 | /* Increment the number of identities. */ |
478 | tab->nentries++; | 525 | tab->nentries++; |
@@ -557,6 +604,7 @@ process_add_smartcard_key (SocketEntry *e) | |||
557 | id->key = k; | 604 | id->key = k; |
558 | id->comment = xstrdup("smartcard key"); | 605 | id->comment = xstrdup("smartcard key"); |
559 | id->death = 0; | 606 | id->death = 0; |
607 | id->confirm = 0; | ||
560 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); | 608 | TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
561 | tab->nentries++; | 609 | tab->nentries++; |
562 | success = 1; | 610 | success = 1; |
@@ -930,13 +978,15 @@ usage(void) | |||
930 | fprintf(stderr, " -k Kill the current agent.\n"); | 978 | fprintf(stderr, " -k Kill the current agent.\n"); |
931 | fprintf(stderr, " -d Debug mode.\n"); | 979 | fprintf(stderr, " -d Debug mode.\n"); |
932 | fprintf(stderr, " -a socket Bind agent socket to given name.\n"); | 980 | fprintf(stderr, " -a socket Bind agent socket to given name.\n"); |
981 | fprintf(stderr, " -t life Default identity lifetime (seconds).\n"); | ||
933 | exit(1); | 982 | exit(1); |
934 | } | 983 | } |
935 | 984 | ||
936 | int | 985 | int |
937 | main(int ac, char **av) | 986 | main(int ac, char **av) |
938 | { | 987 | { |
939 | int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc; | 988 | int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0; |
989 | int sock, fd, ch, nalloc; | ||
940 | char *shell, *format, *pidstr, *agentsocket = NULL; | 990 | char *shell, *format, *pidstr, *agentsocket = NULL; |
941 | fd_set *readsetp = NULL, *writesetp = NULL; | 991 | fd_set *readsetp = NULL, *writesetp = NULL; |
942 | struct sockaddr_un sunaddr; | 992 | struct sockaddr_un sunaddr; |
@@ -961,7 +1011,7 @@ main(int ac, char **av) | |||
961 | init_rng(); | 1011 | init_rng(); |
962 | seed_rng(); | 1012 | seed_rng(); |
963 | 1013 | ||
964 | while ((ch = getopt(ac, av, "cdksa:")) != -1) { | 1014 | while ((ch = getopt(ac, av, "cdksa:t:")) != -1) { |
965 | switch (ch) { | 1015 | switch (ch) { |
966 | case 'c': | 1016 | case 'c': |
967 | if (s_flag) | 1017 | if (s_flag) |
@@ -984,6 +1034,12 @@ main(int ac, char **av) | |||
984 | case 'a': | 1034 | case 'a': |
985 | agentsocket = optarg; | 1035 | agentsocket = optarg; |
986 | break; | 1036 | break; |
1037 | case 't': | ||
1038 | if ((lifetime = convtime(optarg)) == -1) { | ||
1039 | fprintf(stderr, "Invalid lifetime\n"); | ||
1040 | usage(); | ||
1041 | } | ||
1042 | break; | ||
987 | default: | 1043 | default: |
988 | usage(); | 1044 | usage(); |
989 | } | 1045 | } |
@@ -1116,9 +1172,14 @@ main(int ac, char **av) | |||
1116 | } | 1172 | } |
1117 | 1173 | ||
1118 | (void)chdir("/"); | 1174 | (void)chdir("/"); |
1119 | close(0); | 1175 | if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { |
1120 | close(1); | 1176 | /* XXX might close listen socket */ |
1121 | close(2); | 1177 | (void)dup2(fd, STDIN_FILENO); |
1178 | (void)dup2(fd, STDOUT_FILENO); | ||
1179 | (void)dup2(fd, STDERR_FILENO); | ||
1180 | if (fd > 2) | ||
1181 | close(fd); | ||
1182 | } | ||
1122 | 1183 | ||
1123 | #ifdef HAVE_SETRLIMIT | 1184 | #ifdef HAVE_SETRLIMIT |
1124 | /* deny core dumps, since memory contains unencrypted private keys */ | 1185 | /* deny core dumps, since memory contains unencrypted private keys */ |