Annotation of src/usr.bin/ssh/ssh-agent.c, Revision 1.22
1.22 ! deraadt 1: /* $OpenBSD: ssh-agent.c,v 1.21 1999/11/23 22:25:55 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.22 ! deraadt 12: RCSID("$OpenBSD: ssh-agent.c,v 1.21 1999/11/23 22:25:55 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.13 deraadt 24: #include <ssl/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.10 markus 49: int parent_pid = -1;
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))
177: error("Warning: keysize mismatch: actual %d, announced %d",
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) {
183: /* We have this key. Free the old key. Since we
184: don\'t want to leave empty slots in the middle
185: of the array, we actually free the key there
186: and copy data from the last entry. */
187: RSA_free(identities[i].key);
188: xfree(identities[i].comment);
189: if (i < num_identities - 1)
190: identities[i] = identities[num_identities - 1];
191: num_identities--;
192: BN_clear_free(dummy);
193: BN_clear_free(n);
194:
195: /* Send success. */
196: buffer_put_int(&e->output, 1);
197: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
198: return;
199: }
200: /* We did not have the key. */
201: BN_clear(dummy);
202: BN_clear(n);
1.1 deraadt 203:
1.21 markus 204: /* Send failure. */
1.1 deraadt 205: buffer_put_int(&e->output, 1);
1.21 markus 206: buffer_put_char(&e->output, SSH_AGENT_FAILURE);
1.1 deraadt 207: }
208:
1.22 ! deraadt 209: /*
! 210: * Removes all identities from the agent.
! 211: */
1.2 provos 212: void
213: process_remove_all_identities(SocketEntry *e)
1.1 deraadt 214: {
1.21 markus 215: unsigned int i;
216:
217: /* Loop over all identities and clear the keys. */
218: for (i = 0; i < num_identities; i++) {
219: RSA_free(identities[i].key);
220: xfree(identities[i].comment);
221: }
222:
223: /* Mark that there are no identities. */
224: num_identities = 0;
225:
226: /* Send success. */
227: buffer_put_int(&e->output, 1);
228: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
229: return;
1.1 deraadt 230: }
231:
1.22 ! deraadt 232: /*
! 233: * Adds an identity to the agent.
! 234: */
1.2 provos 235: void
236: process_add_identity(SocketEntry *e)
1.1 deraadt 237: {
1.21 markus 238: RSA *k;
239: int i;
240: BIGNUM *aux;
241: BN_CTX *ctx;
242:
243: if (num_identities == 0)
244: identities = xmalloc(sizeof(Identity));
245: else
246: identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
247:
248: identities[num_identities].key = RSA_new();
249: k = identities[num_identities].key;
250: buffer_get_int(&e->input); /* bits */
251: k->n = BN_new();
252: buffer_get_bignum(&e->input, k->n);
253: k->e = BN_new();
254: buffer_get_bignum(&e->input, k->e);
255: k->d = BN_new();
256: buffer_get_bignum(&e->input, k->d);
257: k->iqmp = BN_new();
258: buffer_get_bignum(&e->input, k->iqmp);
259: /* SSH and SSL have p and q swapped */
260: k->q = BN_new();
261: buffer_get_bignum(&e->input, k->q); /* p */
262: k->p = BN_new();
263: buffer_get_bignum(&e->input, k->p); /* q */
264:
265: /* Generate additional parameters */
266: aux = BN_new();
267: ctx = BN_CTX_new();
268:
269: BN_sub(aux, k->q, BN_value_one());
270: k->dmq1 = BN_new();
271: BN_mod(k->dmq1, k->d, aux, ctx);
272:
273: BN_sub(aux, k->p, BN_value_one());
274: k->dmp1 = BN_new();
275: BN_mod(k->dmp1, k->d, aux, ctx);
276:
277: BN_clear_free(aux);
278: BN_CTX_free(ctx);
279:
280: identities[num_identities].comment = buffer_get_string(&e->input, NULL);
281:
282: /* Check if we already have the key. */
283: for (i = 0; i < num_identities; i++)
284: if (BN_cmp(identities[i].key->n, k->n) == 0) {
285: /* We already have this key. Clear and free the
286: new data and return success. */
287: RSA_free(k);
288: xfree(identities[num_identities].comment);
289:
290: /* Send success. */
291: buffer_put_int(&e->output, 1);
292: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
293: return;
294: }
295: /* Increment the number of identities. */
296: num_identities++;
1.1 deraadt 297:
1.21 markus 298: /* Send a success message. */
1.1 deraadt 299: buffer_put_int(&e->output, 1);
300: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
301: }
302:
1.2 provos 303: void
304: process_message(SocketEntry *e)
1.1 deraadt 305: {
1.21 markus 306: unsigned int msg_len;
307: unsigned int type;
308: unsigned char *cp;
309: if (buffer_len(&e->input) < 5)
310: return; /* Incomplete message. */
311: cp = (unsigned char *) buffer_ptr(&e->input);
312: msg_len = GET_32BIT(cp);
313: if (msg_len > 256 * 1024) {
314: shutdown(e->fd, SHUT_RDWR);
315: close(e->fd);
316: e->type = AUTH_UNUSED;
317: return;
318: }
319: if (buffer_len(&e->input) < msg_len + 4)
320: return;
321: buffer_consume(&e->input, 4);
322: type = buffer_get_char(&e->input);
323:
324: switch (type) {
325: case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
326: process_request_identity(e);
327: break;
328: case SSH_AGENTC_RSA_CHALLENGE:
329: process_authentication_challenge(e);
330: break;
331: case SSH_AGENTC_ADD_RSA_IDENTITY:
332: process_add_identity(e);
333: break;
334: case SSH_AGENTC_REMOVE_RSA_IDENTITY:
335: process_remove_identity(e);
336: break;
337: case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
338: process_remove_all_identities(e);
339: break;
340: default:
341: /* Unknown message. Respond with failure. */
342: error("Unknown message %d", type);
343: buffer_clear(&e->input);
344: buffer_put_int(&e->output, 1);
345: buffer_put_char(&e->output, SSH_AGENT_FAILURE);
346: break;
347: }
1.1 deraadt 348: }
349:
1.2 provos 350: void
351: new_socket(int type, int fd)
1.1 deraadt 352: {
1.21 markus 353: unsigned int i, old_alloc;
354: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
355: error("fcntl O_NONBLOCK: %s", strerror(errno));
356:
357: if (fd > max_fd)
358: max_fd = fd;
359:
360: for (i = 0; i < sockets_alloc; i++)
361: if (sockets[i].type == AUTH_UNUSED) {
362: sockets[i].fd = fd;
363: sockets[i].type = type;
364: buffer_init(&sockets[i].input);
365: buffer_init(&sockets[i].output);
366: return;
367: }
368: old_alloc = sockets_alloc;
369: sockets_alloc += 10;
370: if (sockets)
371: sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
372: else
373: sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
374: for (i = old_alloc; i < sockets_alloc; i++)
375: sockets[i].type = AUTH_UNUSED;
376: sockets[old_alloc].type = type;
377: sockets[old_alloc].fd = fd;
378: buffer_init(&sockets[old_alloc].input);
379: buffer_init(&sockets[old_alloc].output);
1.1 deraadt 380: }
381:
1.2 provos 382: void
383: prepare_select(fd_set *readset, fd_set *writeset)
1.1 deraadt 384: {
1.21 markus 385: unsigned int i;
386: for (i = 0; i < sockets_alloc; i++)
387: switch (sockets[i].type) {
388: case AUTH_SOCKET:
389: case AUTH_CONNECTION:
390: FD_SET(sockets[i].fd, readset);
391: if (buffer_len(&sockets[i].output) > 0)
392: FD_SET(sockets[i].fd, writeset);
393: break;
394: case AUTH_UNUSED:
395: break;
396: default:
397: fatal("Unknown socket type %d", sockets[i].type);
398: break;
399: }
400: }
401:
402: void
403: after_select(fd_set *readset, fd_set *writeset)
404: {
405: unsigned int i;
406: int len, sock;
407: char buf[1024];
408: struct sockaddr_un sunaddr;
409:
410: for (i = 0; i < sockets_alloc; i++)
411: switch (sockets[i].type) {
412: case AUTH_UNUSED:
413: break;
414: case AUTH_SOCKET:
415: if (FD_ISSET(sockets[i].fd, readset)) {
416: len = sizeof(sunaddr);
417: sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &len);
418: if (sock < 0) {
419: perror("accept from AUTH_SOCKET");
420: break;
421: }
422: new_socket(AUTH_CONNECTION, sock);
423: }
424: break;
425: case AUTH_CONNECTION:
426: if (buffer_len(&sockets[i].output) > 0 &&
427: FD_ISSET(sockets[i].fd, writeset)) {
428: len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
429: buffer_len(&sockets[i].output));
430: if (len <= 0) {
431: shutdown(sockets[i].fd, SHUT_RDWR);
432: close(sockets[i].fd);
433: sockets[i].type = AUTH_UNUSED;
434: break;
435: }
436: buffer_consume(&sockets[i].output, len);
437: }
438: if (FD_ISSET(sockets[i].fd, readset)) {
439: len = read(sockets[i].fd, buf, sizeof(buf));
440: if (len <= 0) {
441: shutdown(sockets[i].fd, SHUT_RDWR);
442: close(sockets[i].fd);
443: sockets[i].type = AUTH_UNUSED;
444: break;
445: }
446: buffer_append(&sockets[i].input, buf, len);
447: process_message(&sockets[i]);
448: }
449: break;
450: default:
451: fatal("Unknown type %d", sockets[i].type);
452: }
1.1 deraadt 453: }
454:
1.6 deraadt 455: void
1.2 provos 456: check_parent_exists(int sig)
1.1 deraadt 457: {
1.21 markus 458: if (kill(parent_pid, 0) < 0) {
459: /* printf("Parent has died - Authentication agent exiting.\n"); */
460: exit(1);
461: }
462: signal(SIGALRM, check_parent_exists);
463: alarm(10);
1.1 deraadt 464: }
465:
1.15 markus 466: void
467: cleanup_socket(void)
468: {
1.21 markus 469: remove(socket_name);
470: rmdir(socket_dir);
1.10 markus 471: }
472:
1.15 markus 473: void
474: cleanup_exit(int i)
475: {
1.21 markus 476: cleanup_socket();
477: exit(i);
1.15 markus 478: }
479:
480: void
481: usage()
482: {
1.21 markus 483: fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
484: fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
485: __progname);
486: exit(1);
1.15 markus 487: }
488:
1.2 provos 489: int
490: main(int ac, char **av)
1.1 deraadt 491: {
1.21 markus 492: fd_set readset, writeset;
493: int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
494: struct sockaddr_un sunaddr;
495: pid_t pid;
496: char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
497:
498: /* check if RSA support exists */
499: if (rsa_alive() == 0) {
500: fprintf(stderr,
501: "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
502: __progname);
503: exit(1);
504: }
505: while ((ch = getopt(ac, av, "cks")) != -1) {
506: switch (ch) {
507: case 'c':
508: if (s_flag)
509: usage();
510: c_flag++;
511: break;
512: case 'k':
513: k_flag++;
514: break;
515: case 's':
516: if (c_flag)
517: usage();
518: s_flag++;
519: break;
520: default:
521: usage();
522: }
523: }
524: ac -= optind;
525: av += optind;
526:
527: if (ac > 0 && (c_flag || k_flag || s_flag))
528: usage();
529:
530: if (ac == 0 && !c_flag && !k_flag && !s_flag) {
531: shell = getenv("SHELL");
532: if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
533: c_flag = 1;
534: }
535: if (k_flag) {
536: pidstr = getenv(SSH_AGENTPID_ENV_NAME);
537: if (pidstr == NULL) {
538: fprintf(stderr, "%s not set, cannot kill agent\n",
539: SSH_AGENTPID_ENV_NAME);
540: exit(1);
541: }
542: pid = atoi(pidstr);
543: if (pid < 1) { /* XXX PID_MAX check too */
544: fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
545: SSH_AGENTPID_ENV_NAME, pidstr);
546: exit(1);
547: }
548: if (kill(pid, SIGTERM) == -1) {
549: perror("kill");
550: exit(1);
551: }
552: format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
553: printf(format, SSH_AUTHSOCKET_ENV_NAME);
554: printf(format, SSH_AGENTPID_ENV_NAME);
555: printf("echo Agent pid %d killed;\n", pid);
556: exit(0);
557: }
558: parent_pid = getpid();
559:
560: /* Create private directory for agent socket */
561: strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
562: if (mkdtemp(socket_dir) == NULL) {
563: perror("mkdtemp: private socket dir");
564: exit(1);
565: }
566: snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
567: parent_pid);
568:
569: /* Create socket early so it will exist before command gets run
570: from the parent. */
571: sock = socket(AF_UNIX, SOCK_STREAM, 0);
572: if (sock < 0) {
573: perror("socket");
574: cleanup_exit(1);
575: }
576: memset(&sunaddr, 0, sizeof(sunaddr));
577: sunaddr.sun_family = AF_UNIX;
578: strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
579: if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
580: perror("bind");
581: cleanup_exit(1);
582: }
583: if (listen(sock, 5) < 0) {
584: perror("listen");
585: cleanup_exit(1);
586: }
587: /* Fork, and have the parent execute the command, if any, or
588: present the socket data. The child continues as the
589: authentication agent. */
590: pid = fork();
591: if (pid == -1) {
592: perror("fork");
593: exit(1);
594: }
595: if (pid != 0) { /* Parent - execute the given command. */
596: close(sock);
597: snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
598: if (ac == 0) {
599: format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
600: printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
601: SSH_AUTHSOCKET_ENV_NAME);
602: printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
603: SSH_AGENTPID_ENV_NAME);
604: printf("echo Agent pid %d;\n", pid);
605: exit(0);
606: }
607: setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
608: setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1);
609: execvp(av[0], av);
610: perror(av[0]);
611: exit(1);
612: }
613: close(0);
614: close(1);
615: close(2);
616:
617: if (setsid() == -1) {
618: perror("setsid");
619: cleanup_exit(1);
620: }
621: if (atexit(cleanup_socket) < 0) {
622: perror("atexit");
623: cleanup_exit(1);
624: }
625: new_socket(AUTH_SOCKET, sock);
626: if (ac > 0) {
627: signal(SIGALRM, check_parent_exists);
628: alarm(10);
629: }
630: signal(SIGINT, SIG_IGN);
631: signal(SIGPIPE, SIG_IGN);
632: while (1) {
633: FD_ZERO(&readset);
634: FD_ZERO(&writeset);
635: prepare_select(&readset, &writeset);
636: if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) {
637: if (errno == EINTR)
638: continue;
639: exit(1);
640: }
641: after_select(&readset, &writeset);
1.15 markus 642: }
1.21 markus 643: /* NOTREACHED */
1.1 deraadt 644: }