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