Annotation of src/usr.bin/ssh/ssh-agent.c, Revision 1.10
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.10 ! markus 17: RCSID("$Id: ssh-agent.c,v 1.9 1999/10/04 20:45:01 markus 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.10 ! markus 54: /* pid of agent == parent of shell */
! 55: int parent_pid = -1;
! 56:
! 57: /* pathname and directory for AUTH_SOCKET */
! 58: char socket_name[1024];
! 59: char socket_dir[1024];
! 60:
1.2 provos 61: void
62: process_request_identity(SocketEntry *e)
1.1 deraadt 63: {
64: Buffer msg;
65: int i;
66:
67: buffer_init(&msg);
68: buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
69: buffer_put_int(&msg, num_identities);
70: for (i = 0; i < num_identities; i++)
71: {
1.2 provos 72: buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
73: buffer_put_bignum(&msg, identities[i].key->e);
74: buffer_put_bignum(&msg, identities[i].key->n);
1.1 deraadt 75: buffer_put_string(&msg, identities[i].comment,
76: strlen(identities[i].comment));
77: }
78: buffer_put_int(&e->output, buffer_len(&msg));
79: buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
80: buffer_free(&msg);
81: }
82:
1.2 provos 83: void
84: process_authentication_challenge(SocketEntry *e)
1.1 deraadt 85: {
1.2 provos 86: int i, pub_bits, len;
87: BIGNUM *pub_e, *pub_n, *challenge;
1.1 deraadt 88: Buffer msg;
1.7 deraadt 89: MD5_CTX md;
1.1 deraadt 90: unsigned char buf[32], mdbuf[16], session_id[16];
91: unsigned int response_type;
92:
93: buffer_init(&msg);
1.2 provos 94: pub_e = BN_new();
95: pub_n = BN_new();
96: challenge = BN_new();
1.1 deraadt 97: pub_bits = buffer_get_int(&e->input);
1.2 provos 98: buffer_get_bignum(&e->input, pub_e);
99: buffer_get_bignum(&e->input, pub_n);
100: buffer_get_bignum(&e->input, challenge);
1.1 deraadt 101: if (buffer_len(&e->input) == 0)
102: {
103: /* Compatibility code for old servers. */
104: memset(session_id, 0, 16);
105: response_type = 0;
106: }
107: else
108: {
109: /* New code. */
110: buffer_get(&e->input, (char *)session_id, 16);
111: response_type = buffer_get_int(&e->input);
112: }
113: for (i = 0; i < num_identities; i++)
1.2 provos 114: if (pub_bits == BN_num_bits(identities[i].key->n) &&
115: BN_cmp(pub_e, identities[i].key->e) == 0 &&
116: BN_cmp(pub_n, identities[i].key->n) == 0)
1.1 deraadt 117: {
118: /* Decrypt the challenge using the private key. */
1.2 provos 119: rsa_private_decrypt(challenge, challenge, identities[i].key);
1.1 deraadt 120:
121: /* Compute the desired response. */
122: switch (response_type)
123: {
124: case 0: /* As of protocol 1.0 */
125: /* This response type is no longer supported. */
126: log("Compatibility with ssh protocol 1.0 no longer supported.");
127: buffer_put_char(&msg, SSH_AGENT_FAILURE);
128: goto send;
129:
130: case 1: /* As of protocol 1.1 */
131: /* The response is MD5 of decrypted challenge plus session id. */
1.2 provos 132: len = BN_num_bytes(challenge);
133: assert(len <= 32 && len);
134: memset(buf, 0, 32);
135: BN_bn2bin(challenge, buf + 32 - len);
1.1 deraadt 136: MD5Init(&md);
137: MD5Update(&md, buf, 32);
138: MD5Update(&md, session_id, 16);
139: MD5Final(mdbuf, &md);
140: break;
141:
142: default:
143: fatal("process_authentication_challenge: bad response_type %d",
144: response_type);
145: break;
146: }
147:
148: /* Send the response. */
149: buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
150: for (i = 0; i < 16; i++)
151: buffer_put_char(&msg, mdbuf[i]);
152:
153: goto send;
154: }
155: /* Unknown identity. Send failure. */
156: buffer_put_char(&msg, SSH_AGENT_FAILURE);
157: send:
158: buffer_put_int(&e->output, buffer_len(&msg));
159: buffer_append(&e->output, buffer_ptr(&msg),
160: buffer_len(&msg));
161: buffer_free(&msg);
1.2 provos 162: BN_clear_free(pub_e);
163: BN_clear_free(pub_n);
164: BN_clear_free(challenge);
1.1 deraadt 165: }
166:
1.2 provos 167: void
168: process_remove_identity(SocketEntry *e)
1.1 deraadt 169: {
170: unsigned int bits;
171: unsigned int i;
1.2 provos 172: BIGNUM *dummy, *n;
1.1 deraadt 173:
1.2 provos 174: dummy = BN_new();
175: n = BN_new();
1.1 deraadt 176:
177: /* Get the key from the packet. */
178: bits = buffer_get_int(&e->input);
1.2 provos 179: buffer_get_bignum(&e->input, dummy);
180: buffer_get_bignum(&e->input, n);
1.1 deraadt 181:
182: /* Check if we have the key. */
183: for (i = 0; i < num_identities; i++)
1.2 provos 184: if (BN_cmp(identities[i].key->n, n) == 0)
1.1 deraadt 185: {
186: /* We have this key. Free the old key. Since we don\'t want to leave
187: empty slots in the middle of the array, we actually free the
188: key there and copy data from the last entry. */
1.2 provos 189: RSA_free(identities[i].key);
1.1 deraadt 190: xfree(identities[i].comment);
191: if (i < num_identities - 1)
192: identities[i] = identities[num_identities - 1];
193: num_identities--;
1.2 provos 194: BN_clear_free(dummy);
195: BN_clear_free(n);
1.1 deraadt 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. */
1.2 provos 203: BN_clear(dummy);
204: BN_clear(n);
1.1 deraadt 205:
206: /* Send failure. */
207: buffer_put_int(&e->output, 1);
208: buffer_put_char(&e->output, SSH_AGENT_FAILURE);
209: }
210:
211: /* Removes all identities from the agent. */
212:
1.2 provos 213: void
214: process_remove_all_identities(SocketEntry *e)
1.1 deraadt 215: {
216: unsigned int i;
217:
218: /* Loop over all identities and clear the keys. */
219: for (i = 0; i < num_identities; i++)
220: {
1.2 provos 221: RSA_free(identities[i].key);
1.1 deraadt 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;
232: }
233:
234: /* Adds an identity to the agent. */
235:
1.2 provos 236: void
237: process_add_identity(SocketEntry *e)
1.1 deraadt 238: {
1.2 provos 239: RSA *k;
1.1 deraadt 240: int i;
1.2 provos 241: BIGNUM *aux;
242: BN_CTX *ctx;
243:
1.1 deraadt 244: if (num_identities == 0)
245: identities = xmalloc(sizeof(Identity));
246: else
247: identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
1.2 provos 248:
249: identities[num_identities].key = RSA_new();
250: k = identities[num_identities].key;
251: buffer_get_int(&e->input); /* bits */
252: k->n = BN_new();
253: buffer_get_bignum(&e->input, k->n);
254: k->e = BN_new();
255: buffer_get_bignum(&e->input, k->e);
256: k->d = BN_new();
257: buffer_get_bignum(&e->input, k->d);
258: k->iqmp = BN_new();
259: buffer_get_bignum(&e->input, k->iqmp);
260: /* SSH and SSL have p and q swapped */
261: k->q = BN_new();
262: buffer_get_bignum(&e->input, k->q); /* p */
263: k->p = BN_new();
264: buffer_get_bignum(&e->input, k->p); /* q */
265:
266: /* Generate additional parameters */
267: aux = BN_new();
268: ctx = BN_CTX_new();
269:
270: BN_sub(aux, k->q, BN_value_one());
271: k->dmq1 = BN_new();
272: BN_mod(k->dmq1, k->d, aux, ctx);
273:
274: BN_sub(aux, k->p, BN_value_one());
275: k->dmp1 = BN_new();
276: BN_mod(k->dmp1, k->d, aux, ctx);
277:
278: BN_clear_free(aux);
279: BN_CTX_free(ctx);
280:
1.1 deraadt 281: identities[num_identities].comment = buffer_get_string(&e->input, NULL);
282:
283: /* Check if we already have the key. */
284: for (i = 0; i < num_identities; i++)
1.2 provos 285: if (BN_cmp(identities[i].key->n, k->n) == 0)
1.1 deraadt 286: {
287: /* We already have this key. Clear and free the new data and
288: return success. */
1.2 provos 289: RSA_free(k);
1.1 deraadt 290: xfree(identities[num_identities].comment);
291:
292: /* Send success. */
293: buffer_put_int(&e->output, 1);
294: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
295: return;
296: }
297:
298: /* Increment the number of identities. */
299: num_identities++;
300:
301: /* Send a success message. */
302: buffer_put_int(&e->output, 1);
303: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
304: }
305:
1.2 provos 306: void
307: process_message(SocketEntry *e)
1.1 deraadt 308: {
309: unsigned int msg_len;
310: unsigned int type;
311: unsigned char *cp;
312: if (buffer_len(&e->input) < 5)
313: return; /* Incomplete message. */
314: cp = (unsigned char *)buffer_ptr(&e->input);
315: msg_len = GET_32BIT(cp);
316: if (msg_len > 256 * 1024)
317: {
1.8 deraadt 318: shutdown(e->fd, SHUT_RDWR);
1.1 deraadt 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: switch (type)
328: {
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: }
352: }
353:
1.2 provos 354: void
355: new_socket(int type, int fd)
1.1 deraadt 356: {
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: {
367: sockets[i].fd = fd;
368: sockets[i].type = type;
369: buffer_init(&sockets[i].input);
370: buffer_init(&sockets[i].output);
371: return;
372: }
373: old_alloc = sockets_alloc;
374: sockets_alloc += 10;
375: if (sockets)
376: sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
377: else
378: sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
379: for (i = old_alloc; i < sockets_alloc; i++)
380: sockets[i].type = AUTH_UNUSED;
381: sockets[old_alloc].type = type;
382: sockets[old_alloc].fd = fd;
383: buffer_init(&sockets[old_alloc].input);
384: buffer_init(&sockets[old_alloc].output);
385: }
386:
1.2 provos 387: void
388: prepare_select(fd_set *readset, fd_set *writeset)
1.1 deraadt 389: {
390: unsigned int i;
391: for (i = 0; i < sockets_alloc; i++)
392: switch (sockets[i].type)
393: {
394: case AUTH_FD:
395: case AUTH_CONNECTION:
396: case AUTH_SOCKET:
397: case AUTH_SOCKET_FD:
398: FD_SET(sockets[i].fd, readset);
399: if (buffer_len(&sockets[i].output) > 0)
400: FD_SET(sockets[i].fd, writeset);
401: break;
402: case AUTH_UNUSED:
403: break;
404: default:
405: fatal("Unknown socket type %d", sockets[i].type);
406: break;
407: }
408: }
409:
410: void after_select(fd_set *readset, fd_set *writeset)
411: {
412: unsigned int i;
413: int len, sock, port;
414: char buf[1024];
415: struct sockaddr_in sin;
416: struct sockaddr_un sunaddr;
417:
418: for (i = 0; i < sockets_alloc; i++)
419: switch (sockets[i].type)
420: {
421: case AUTH_UNUSED:
422: break;
423: case AUTH_FD:
424: if (FD_ISSET(sockets[i].fd, readset))
425: {
426: len = recv(sockets[i].fd, buf, sizeof(buf), 0);
427: if (len <= 0)
428: { /* All instances of the other side have been closed. */
429: log("Authentication agent exiting.");
430: exit(0);
431: }
432: process_auth_fd_input:
433: if (len != 3 || (unsigned char)buf[0] != SSH_AUTHFD_CONNECT)
434: break; /* Incorrect message; ignore it. */
435: /* It is a connection request message. */
436: port = (unsigned char)buf[1] * 256 + (unsigned char)buf[2];
437: memset(&sin, 0, sizeof(sin));
438: sin.sin_family = AF_INET;
439: sin.sin_addr.s_addr = htonl(0x7f000001); /* localhost */
440: sin.sin_port = htons(port);
441: sock = socket(AF_INET, SOCK_STREAM, 0);
442: if (sock < 0)
443: {
444: perror("socket");
445: break;
446: }
447: if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
448: {
449: perror("connecting to port requested in authfd message");
450: close(sock);
451: break;
452: }
453: new_socket(AUTH_CONNECTION, sock);
454: }
455: break;
456: case AUTH_SOCKET:
457: if (FD_ISSET(sockets[i].fd, readset))
458: {
459: len = sizeof(sunaddr);
460: sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len);
461: if (sock < 0)
462: {
463: perror("accept from AUTH_SOCKET");
464: break;
465: }
466: new_socket(AUTH_SOCKET_FD, sock);
467: }
468: break;
469: case AUTH_SOCKET_FD:
470: if (FD_ISSET(sockets[i].fd, readset))
471: {
472: len = recv(sockets[i].fd, buf, sizeof(buf), 0);
473: if (len <= 0)
474: { /* The other side has closed the socket. */
1.8 deraadt 475: shutdown(sockets[i].fd, SHUT_RDWR);
1.1 deraadt 476: close(sockets[i].fd);
477: sockets[i].type = AUTH_UNUSED;
478: break;
479: }
480: goto process_auth_fd_input;
481: }
482: break;
483: case AUTH_CONNECTION:
484: if (buffer_len(&sockets[i].output) > 0 &&
485: FD_ISSET(sockets[i].fd, writeset))
486: {
487: len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
488: buffer_len(&sockets[i].output));
489: if (len <= 0)
490: {
1.8 deraadt 491: shutdown(sockets[i].fd, SHUT_RDWR);
1.1 deraadt 492: close(sockets[i].fd);
493: sockets[i].type = AUTH_UNUSED;
494: break;
495: }
496: buffer_consume(&sockets[i].output, len);
497: }
498: if (FD_ISSET(sockets[i].fd, readset))
499: {
500: len = read(sockets[i].fd, buf, sizeof(buf));
501: if (len <= 0)
502: {
1.8 deraadt 503: shutdown(sockets[i].fd, SHUT_RDWR);
1.1 deraadt 504: close(sockets[i].fd);
505: sockets[i].type = AUTH_UNUSED;
506: break;
507: }
508: buffer_append(&sockets[i].input, buf, len);
509: process_message(&sockets[i]);
510: }
511: break;
512: default:
513: fatal("Unknown type %d", sockets[i].type);
514: }
515: }
516:
1.6 deraadt 517: void
1.2 provos 518: check_parent_exists(int sig)
1.1 deraadt 519: {
520: if (kill(parent_pid, 0) < 0)
521: {
522: /* printf("Parent has died - Authentication agent exiting.\n"); */
523: exit(1);
524: }
525: signal(SIGALRM, check_parent_exists);
526: alarm(10);
527: }
528:
1.10 ! markus 529: void cleanup_socket(void) {
! 530: remove(socket_name);
! 531: rmdir(socket_dir);
! 532: }
! 533:
1.2 provos 534: int
535: main(int ac, char **av)
1.1 deraadt 536: {
537: fd_set readset, writeset;
538: int sock;
539: struct sockaddr_un sunaddr;
540:
1.3 deraadt 541: /* check if RSA support exists */
542: if (rsa_alive() == 0) {
543: extern char *__progname;
544: fprintf(stderr,
545: "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
546: __progname);
547: exit(1);
548: }
1.1 deraadt 549:
550: if (ac < 2)
551: {
552: fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
553: fprintf(stderr, "Usage: %s command\n", av[0]);
554: exit(1);
555: }
556:
1.9 markus 557: parent_pid = getpid();
1.10 ! markus 558:
! 559: /* Create private directory for agent socket */
! 560: strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
! 561: if (mkdtemp(socket_dir) == NULL) {
! 562: perror("mkdtemp: private socket dir");
! 563: exit(1);
! 564: }
! 565: snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, parent_pid);
1.9 markus 566:
567: /* Fork, and have the parent execute the command. The child continues as
568: the authentication agent. */
569: if (fork() != 0)
570: { /* Parent - execute the given command. */
1.10 ! markus 571: setenv("SSH_AUTHENTICATION_SOCKET", socket_name, 1);
1.9 markus 572: execvp(av[1], av + 1);
573: perror(av[1]);
574: exit(1);
575: }
1.10 ! markus 576:
! 577: if (atexit(cleanup_socket) < 0) {
! 578: perror("atexit");
! 579: cleanup_socket();
! 580: exit(1);
! 581: }
! 582:
1.9 markus 583: sock = socket(AF_UNIX, SOCK_STREAM, 0);
584: if (sock < 0)
1.1 deraadt 585: {
1.9 markus 586: perror("socket");
587: exit(1);
588: }
589: memset(&sunaddr, 0, sizeof(sunaddr));
590: sunaddr.sun_family = AF_UNIX;
591: strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
592: if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
593: {
594: perror("bind");
595: exit(1);
596: }
597: if (listen(sock, 5) < 0)
598: {
599: perror("listen");
600: exit(1);
1.1 deraadt 601: }
1.9 markus 602: new_socket(AUTH_SOCKET, sock);
603: signal(SIGALRM, check_parent_exists);
604: alarm(10);
1.1 deraadt 605:
606: signal(SIGINT, SIG_IGN);
607: while (1)
608: {
609: FD_ZERO(&readset);
610: FD_ZERO(&writeset);
611: prepare_select(&readset, &writeset);
612: if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
613: {
614: if (errno == EINTR)
615: continue;
616: perror("select");
617: exit(1);
618: }
619: after_select(&readset, &writeset);
620: }
621: /*NOTREACHED*/
622: }