Annotation of src/usr.bin/ssh/ssh-agent.c, Revision 1.29
1.29 ! deraadt 1: /* $OpenBSD: ssh-agent.c,v 1.28 2000/04/14 10:30:33 markus Exp $ */
1.15 markus 2:
1.1 deraadt 3: /*
1.22 deraadt 4: * Author: Tatu Ylonen <ylo@cs.hut.fi>
5: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6: * All rights reserved
7: * Created: Wed Mar 29 03:46:59 1995 ylo
8: * The authentication agent program.
9: */
1.1 deraadt 10:
11: #include "includes.h"
1.29 ! deraadt 12: RCSID("$OpenBSD: ssh-agent.c,v 1.28 2000/04/14 10:30:33 markus Exp $");
1.1 deraadt 13:
14: #include "ssh.h"
15: #include "rsa.h"
16: #include "authfd.h"
17: #include "buffer.h"
18: #include "bufaux.h"
19: #include "xmalloc.h"
20: #include "packet.h"
21: #include "getput.h"
22: #include "mpaux.h"
23:
1.27 markus 24: #include <openssl/md5.h>
1.7 deraadt 25:
1.21 markus 26: typedef struct {
27: int fd;
28: enum {
29: AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION
30: } type;
31: Buffer input;
32: Buffer output;
1.1 deraadt 33: } SocketEntry;
34:
35: unsigned int sockets_alloc = 0;
36: SocketEntry *sockets = NULL;
37:
1.21 markus 38: typedef struct {
39: RSA *key;
40: char *comment;
1.1 deraadt 41: } Identity;
42:
43: unsigned int num_identities = 0;
44: Identity *identities = NULL;
45:
46: int max_fd = 0;
47:
1.11 markus 48: /* pid of shell == parent of agent */
1.29 ! deraadt 49: pid_t parent_pid = -1;
1.10 markus 50:
51: /* pathname and directory for AUTH_SOCKET */
52: char socket_name[1024];
53: char socket_dir[1024];
54:
1.20 markus 55: extern char *__progname;
56:
1.2 provos 57: void
58: process_request_identity(SocketEntry *e)
1.1 deraadt 59: {
1.21 markus 60: Buffer msg;
61: int i;
1.1 deraadt 62:
1.21 markus 63: buffer_init(&msg);
64: buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
65: buffer_put_int(&msg, num_identities);
66: for (i = 0; i < num_identities; i++) {
67: buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
68: buffer_put_bignum(&msg, identities[i].key->e);
69: buffer_put_bignum(&msg, identities[i].key->n);
70: buffer_put_string(&msg, identities[i].comment,
71: strlen(identities[i].comment));
72: }
73: buffer_put_int(&e->output, buffer_len(&msg));
74: buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
75: buffer_free(&msg);
1.1 deraadt 76: }
77:
1.2 provos 78: void
79: process_authentication_challenge(SocketEntry *e)
1.1 deraadt 80: {
1.21 markus 81: int i, pub_bits, len;
82: BIGNUM *pub_e, *pub_n, *challenge;
83: Buffer msg;
84: MD5_CTX md;
85: unsigned char buf[32], mdbuf[16], session_id[16];
86: unsigned int response_type;
87:
88: buffer_init(&msg);
89: pub_e = BN_new();
90: pub_n = BN_new();
91: challenge = BN_new();
92: pub_bits = buffer_get_int(&e->input);
93: buffer_get_bignum(&e->input, pub_e);
94: buffer_get_bignum(&e->input, pub_n);
95: buffer_get_bignum(&e->input, challenge);
96: if (buffer_len(&e->input) == 0) {
97: /* Compatibility code for old servers. */
98: memset(session_id, 0, 16);
99: response_type = 0;
100: } else {
101: /* New code. */
102: buffer_get(&e->input, (char *) session_id, 16);
103: response_type = buffer_get_int(&e->input);
104: }
105: for (i = 0; i < num_identities; i++)
106: if (pub_bits == BN_num_bits(identities[i].key->n) &&
107: BN_cmp(pub_e, identities[i].key->e) == 0 &&
108: BN_cmp(pub_n, identities[i].key->n) == 0) {
109: /* Decrypt the challenge using the private key. */
110: rsa_private_decrypt(challenge, challenge, identities[i].key);
111:
112: /* Compute the desired response. */
113: switch (response_type) {
114: case 0:/* As of protocol 1.0 */
115: /* This response type is no longer supported. */
116: log("Compatibility with ssh protocol 1.0 no longer supported.");
117: buffer_put_char(&msg, SSH_AGENT_FAILURE);
118: goto send;
119:
120: case 1:/* As of protocol 1.1 */
121: /* The response is MD5 of decrypted challenge plus session id. */
122: len = BN_num_bytes(challenge);
123:
124: if (len <= 0 || len > 32) {
125: fatal("process_authentication_challenge: "
126: "bad challenge length %d", len);
127: }
128: memset(buf, 0, 32);
129: BN_bn2bin(challenge, buf + 32 - len);
130: MD5_Init(&md);
131: MD5_Update(&md, buf, 32);
132: MD5_Update(&md, session_id, 16);
133: MD5_Final(mdbuf, &md);
134: break;
135:
136: default:
137: fatal("process_authentication_challenge: bad response_type %d",
138: response_type);
139: break;
140: }
141:
142: /* Send the response. */
143: buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
144: for (i = 0; i < 16; i++)
145: buffer_put_char(&msg, mdbuf[i]);
146:
147: goto send;
148: }
149: /* Unknown identity. Send failure. */
150: buffer_put_char(&msg, SSH_AGENT_FAILURE);
151: send:
152: buffer_put_int(&e->output, buffer_len(&msg));
153: buffer_append(&e->output, buffer_ptr(&msg),
154: buffer_len(&msg));
155: buffer_free(&msg);
156: BN_clear_free(pub_e);
157: BN_clear_free(pub_n);
158: BN_clear_free(challenge);
1.1 deraadt 159: }
160:
1.2 provos 161: void
162: process_remove_identity(SocketEntry *e)
1.1 deraadt 163: {
1.21 markus 164: unsigned int bits;
165: unsigned int i;
166: BIGNUM *dummy, *n;
167:
168: dummy = BN_new();
169: n = BN_new();
170:
171: /* Get the key from the packet. */
172: bits = buffer_get_int(&e->input);
173: buffer_get_bignum(&e->input, dummy);
174: buffer_get_bignum(&e->input, n);
175:
176: if (bits != BN_num_bits(n))
1.24 markus 177: error("Warning: identity keysize mismatch: actual %d, announced %d",
1.21 markus 178: BN_num_bits(n), bits);
179:
180: /* Check if we have the key. */
181: for (i = 0; i < num_identities; i++)
182: if (BN_cmp(identities[i].key->n, n) == 0) {
1.23 markus 183: /*
184: * We have this key. Free the old key. Since we
185: * don\'t want to leave empty slots in the middle of
186: * the array, we actually free the key there and copy
187: * data from the last entry.
188: */
1.21 markus 189: RSA_free(identities[i].key);
190: xfree(identities[i].comment);
191: if (i < num_identities - 1)
192: identities[i] = identities[num_identities - 1];
193: num_identities--;
194: BN_clear_free(dummy);
195: BN_clear_free(n);
196:
197: /* Send success. */
198: buffer_put_int(&e->output, 1);
199: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
200: return;
201: }
202: /* We did not have the key. */
203: BN_clear(dummy);
204: BN_clear(n);
1.1 deraadt 205:
1.21 markus 206: /* Send failure. */
1.1 deraadt 207: buffer_put_int(&e->output, 1);
1.21 markus 208: buffer_put_char(&e->output, SSH_AGENT_FAILURE);
1.1 deraadt 209: }
210:
1.22 deraadt 211: /*
212: * Removes all identities from the agent.
213: */
1.2 provos 214: void
215: process_remove_all_identities(SocketEntry *e)
1.1 deraadt 216: {
1.21 markus 217: unsigned int i;
218:
219: /* Loop over all identities and clear the keys. */
220: for (i = 0; i < num_identities; i++) {
221: RSA_free(identities[i].key);
222: xfree(identities[i].comment);
223: }
224:
225: /* Mark that there are no identities. */
226: num_identities = 0;
227:
228: /* Send success. */
229: buffer_put_int(&e->output, 1);
230: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
231: return;
1.1 deraadt 232: }
233:
1.22 deraadt 234: /*
235: * Adds an identity to the agent.
236: */
1.2 provos 237: void
238: process_add_identity(SocketEntry *e)
1.1 deraadt 239: {
1.21 markus 240: RSA *k;
241: int i;
242: BIGNUM *aux;
243: BN_CTX *ctx;
244:
245: if (num_identities == 0)
246: identities = xmalloc(sizeof(Identity));
247: else
248: identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
249:
250: identities[num_identities].key = RSA_new();
251: k = identities[num_identities].key;
252: buffer_get_int(&e->input); /* bits */
253: k->n = BN_new();
254: buffer_get_bignum(&e->input, k->n);
255: k->e = BN_new();
256: buffer_get_bignum(&e->input, k->e);
257: k->d = BN_new();
258: buffer_get_bignum(&e->input, k->d);
259: k->iqmp = BN_new();
260: buffer_get_bignum(&e->input, k->iqmp);
261: /* SSH and SSL have p and q swapped */
262: k->q = BN_new();
263: buffer_get_bignum(&e->input, k->q); /* p */
264: k->p = BN_new();
265: buffer_get_bignum(&e->input, k->p); /* q */
266:
267: /* Generate additional parameters */
268: aux = BN_new();
269: ctx = BN_CTX_new();
270:
271: BN_sub(aux, k->q, BN_value_one());
272: k->dmq1 = BN_new();
273: BN_mod(k->dmq1, k->d, aux, ctx);
274:
275: BN_sub(aux, k->p, BN_value_one());
276: k->dmp1 = BN_new();
277: BN_mod(k->dmp1, k->d, aux, ctx);
278:
279: BN_clear_free(aux);
280: BN_CTX_free(ctx);
281:
282: identities[num_identities].comment = buffer_get_string(&e->input, NULL);
283:
284: /* Check if we already have the key. */
285: for (i = 0; i < num_identities; i++)
286: if (BN_cmp(identities[i].key->n, k->n) == 0) {
1.23 markus 287: /*
288: * We already have this key. Clear and free the new
289: * data and return success.
290: */
1.21 markus 291: RSA_free(k);
292: xfree(identities[num_identities].comment);
293:
294: /* Send success. */
295: buffer_put_int(&e->output, 1);
296: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
297: return;
298: }
299: /* Increment the number of identities. */
300: num_identities++;
1.1 deraadt 301:
1.21 markus 302: /* Send a success message. */
1.1 deraadt 303: buffer_put_int(&e->output, 1);
304: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
305: }
306:
1.2 provos 307: void
308: process_message(SocketEntry *e)
1.1 deraadt 309: {
1.21 markus 310: unsigned int msg_len;
311: unsigned int type;
312: unsigned char *cp;
313: if (buffer_len(&e->input) < 5)
314: return; /* Incomplete message. */
315: cp = (unsigned char *) buffer_ptr(&e->input);
316: msg_len = GET_32BIT(cp);
317: if (msg_len > 256 * 1024) {
318: shutdown(e->fd, SHUT_RDWR);
319: close(e->fd);
320: e->type = AUTH_UNUSED;
321: return;
322: }
323: if (buffer_len(&e->input) < msg_len + 4)
324: return;
325: buffer_consume(&e->input, 4);
326: type = buffer_get_char(&e->input);
327:
328: switch (type) {
329: case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
330: process_request_identity(e);
331: break;
332: case SSH_AGENTC_RSA_CHALLENGE:
333: process_authentication_challenge(e);
334: break;
335: case SSH_AGENTC_ADD_RSA_IDENTITY:
336: process_add_identity(e);
337: break;
338: case SSH_AGENTC_REMOVE_RSA_IDENTITY:
339: process_remove_identity(e);
340: break;
341: case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
342: process_remove_all_identities(e);
343: break;
344: default:
345: /* Unknown message. Respond with failure. */
346: error("Unknown message %d", type);
347: buffer_clear(&e->input);
348: buffer_put_int(&e->output, 1);
349: buffer_put_char(&e->output, SSH_AGENT_FAILURE);
350: break;
351: }
1.1 deraadt 352: }
353:
1.2 provos 354: void
355: new_socket(int type, int fd)
1.1 deraadt 356: {
1.21 markus 357: unsigned int i, old_alloc;
358: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
359: error("fcntl O_NONBLOCK: %s", strerror(errno));
360:
361: if (fd > max_fd)
362: max_fd = fd;
363:
364: for (i = 0; i < sockets_alloc; i++)
365: if (sockets[i].type == AUTH_UNUSED) {
366: sockets[i].fd = fd;
367: sockets[i].type = type;
368: buffer_init(&sockets[i].input);
369: buffer_init(&sockets[i].output);
370: return;
371: }
372: old_alloc = sockets_alloc;
373: sockets_alloc += 10;
374: if (sockets)
375: sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
376: else
377: sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
378: for (i = old_alloc; i < sockets_alloc; i++)
379: sockets[i].type = AUTH_UNUSED;
380: sockets[old_alloc].type = type;
381: sockets[old_alloc].fd = fd;
382: buffer_init(&sockets[old_alloc].input);
383: buffer_init(&sockets[old_alloc].output);
1.1 deraadt 384: }
385:
1.2 provos 386: void
387: prepare_select(fd_set *readset, fd_set *writeset)
1.1 deraadt 388: {
1.21 markus 389: unsigned int i;
390: for (i = 0; i < sockets_alloc; i++)
391: switch (sockets[i].type) {
392: case AUTH_SOCKET:
393: case AUTH_CONNECTION:
394: FD_SET(sockets[i].fd, readset);
395: if (buffer_len(&sockets[i].output) > 0)
396: FD_SET(sockets[i].fd, writeset);
397: break;
398: case AUTH_UNUSED:
399: break;
400: default:
401: fatal("Unknown socket type %d", sockets[i].type);
402: break;
403: }
404: }
405:
1.28 markus 406: void
1.21 markus 407: after_select(fd_set *readset, fd_set *writeset)
408: {
409: unsigned int i;
410: int len, sock;
1.26 markus 411: socklen_t slen;
1.21 markus 412: char buf[1024];
413: struct sockaddr_un sunaddr;
414:
415: for (i = 0; i < sockets_alloc; i++)
416: switch (sockets[i].type) {
417: case AUTH_UNUSED:
418: break;
419: case AUTH_SOCKET:
420: if (FD_ISSET(sockets[i].fd, readset)) {
1.26 markus 421: slen = sizeof(sunaddr);
422: sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &slen);
1.21 markus 423: if (sock < 0) {
424: perror("accept from AUTH_SOCKET");
425: break;
426: }
427: new_socket(AUTH_CONNECTION, sock);
428: }
429: break;
430: case AUTH_CONNECTION:
431: if (buffer_len(&sockets[i].output) > 0 &&
432: FD_ISSET(sockets[i].fd, writeset)) {
433: len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
434: buffer_len(&sockets[i].output));
435: if (len <= 0) {
436: shutdown(sockets[i].fd, SHUT_RDWR);
437: close(sockets[i].fd);
438: sockets[i].type = AUTH_UNUSED;
439: break;
440: }
441: buffer_consume(&sockets[i].output, len);
442: }
443: if (FD_ISSET(sockets[i].fd, readset)) {
444: len = read(sockets[i].fd, buf, sizeof(buf));
445: if (len <= 0) {
446: shutdown(sockets[i].fd, SHUT_RDWR);
447: close(sockets[i].fd);
448: sockets[i].type = AUTH_UNUSED;
449: break;
450: }
451: buffer_append(&sockets[i].input, buf, len);
452: process_message(&sockets[i]);
453: }
454: break;
455: default:
456: fatal("Unknown type %d", sockets[i].type);
457: }
1.1 deraadt 458: }
459:
1.6 deraadt 460: void
1.2 provos 461: check_parent_exists(int sig)
1.1 deraadt 462: {
1.29 ! deraadt 463: if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
1.21 markus 464: /* printf("Parent has died - Authentication agent exiting.\n"); */
465: exit(1);
466: }
467: signal(SIGALRM, check_parent_exists);
468: alarm(10);
1.1 deraadt 469: }
470:
1.15 markus 471: void
472: cleanup_socket(void)
473: {
1.21 markus 474: remove(socket_name);
475: rmdir(socket_dir);
1.10 markus 476: }
477:
1.15 markus 478: void
479: cleanup_exit(int i)
480: {
1.21 markus 481: cleanup_socket();
482: exit(i);
1.15 markus 483: }
484:
485: void
486: usage()
487: {
1.21 markus 488: fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
489: fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
490: __progname);
491: exit(1);
1.15 markus 492: }
493:
1.2 provos 494: int
495: main(int ac, char **av)
1.1 deraadt 496: {
1.21 markus 497: fd_set readset, writeset;
498: int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
499: struct sockaddr_un sunaddr;
500: pid_t pid;
501: char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
502:
503: /* check if RSA support exists */
504: if (rsa_alive() == 0) {
505: fprintf(stderr,
506: "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
507: __progname);
508: exit(1);
509: }
510: while ((ch = getopt(ac, av, "cks")) != -1) {
511: switch (ch) {
512: case 'c':
513: if (s_flag)
514: usage();
515: c_flag++;
516: break;
517: case 'k':
518: k_flag++;
519: break;
520: case 's':
521: if (c_flag)
522: usage();
523: s_flag++;
524: break;
525: default:
526: usage();
527: }
528: }
529: ac -= optind;
530: av += optind;
531:
532: if (ac > 0 && (c_flag || k_flag || s_flag))
533: usage();
534:
535: if (ac == 0 && !c_flag && !k_flag && !s_flag) {
536: shell = getenv("SHELL");
537: if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
538: c_flag = 1;
539: }
540: if (k_flag) {
541: pidstr = getenv(SSH_AGENTPID_ENV_NAME);
542: if (pidstr == NULL) {
543: fprintf(stderr, "%s not set, cannot kill agent\n",
544: SSH_AGENTPID_ENV_NAME);
545: exit(1);
546: }
547: pid = atoi(pidstr);
548: if (pid < 1) { /* XXX PID_MAX check too */
1.29 ! deraadt 549: /* Yes, PID_MAX check please */
1.21 markus 550: fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
551: SSH_AGENTPID_ENV_NAME, pidstr);
552: exit(1);
553: }
554: if (kill(pid, SIGTERM) == -1) {
555: perror("kill");
556: exit(1);
557: }
558: format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
559: printf(format, SSH_AUTHSOCKET_ENV_NAME);
560: printf(format, SSH_AGENTPID_ENV_NAME);
561: printf("echo Agent pid %d killed;\n", pid);
562: exit(0);
563: }
564: parent_pid = getpid();
565:
566: /* Create private directory for agent socket */
567: strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
568: if (mkdtemp(socket_dir) == NULL) {
569: perror("mkdtemp: private socket dir");
570: exit(1);
571: }
572: snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
573: parent_pid);
574:
1.23 markus 575: /*
576: * Create socket early so it will exist before command gets run from
577: * the parent.
578: */
1.21 markus 579: sock = socket(AF_UNIX, SOCK_STREAM, 0);
580: if (sock < 0) {
581: perror("socket");
582: cleanup_exit(1);
583: }
584: memset(&sunaddr, 0, sizeof(sunaddr));
585: sunaddr.sun_family = AF_UNIX;
586: strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
587: if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
588: perror("bind");
589: cleanup_exit(1);
590: }
591: if (listen(sock, 5) < 0) {
592: perror("listen");
593: cleanup_exit(1);
594: }
1.23 markus 595: /*
596: * Fork, and have the parent execute the command, if any, or present
597: * the socket data. The child continues as the authentication agent.
598: */
1.21 markus 599: pid = fork();
600: if (pid == -1) {
601: perror("fork");
602: exit(1);
603: }
604: if (pid != 0) { /* Parent - execute the given command. */
605: close(sock);
606: snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
607: if (ac == 0) {
608: format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
609: printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
610: SSH_AUTHSOCKET_ENV_NAME);
611: printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
612: SSH_AGENTPID_ENV_NAME);
613: printf("echo Agent pid %d;\n", pid);
614: exit(0);
615: }
616: setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
617: setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1);
618: execvp(av[0], av);
619: perror(av[0]);
620: exit(1);
621: }
622: close(0);
623: close(1);
624: close(2);
625:
626: if (setsid() == -1) {
627: perror("setsid");
628: cleanup_exit(1);
629: }
630: if (atexit(cleanup_socket) < 0) {
631: perror("atexit");
632: cleanup_exit(1);
633: }
634: new_socket(AUTH_SOCKET, sock);
635: if (ac > 0) {
636: signal(SIGALRM, check_parent_exists);
637: alarm(10);
638: }
639: signal(SIGINT, SIG_IGN);
640: signal(SIGPIPE, SIG_IGN);
1.28 markus 641: signal(SIGHUP, cleanup_exit);
642: signal(SIGTERM, cleanup_exit);
1.21 markus 643: while (1) {
644: FD_ZERO(&readset);
645: FD_ZERO(&writeset);
646: prepare_select(&readset, &writeset);
647: if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) {
648: if (errno == EINTR)
649: continue;
650: exit(1);
651: }
652: after_select(&readset, &writeset);
1.15 markus 653: }
1.21 markus 654: /* NOTREACHED */
1.1 deraadt 655: }