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