Annotation of src/usr.bin/ssh/ssh-agent.c, Revision 1.12
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.12 ! markus 17: RCSID("$Id: ssh-agent.c,v 1.11 1999/10/07 22:46:32 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;
1.12 ! markus 34: enum { AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION } type;
1.1 deraadt 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.11 markus 53: /* pid of shell == parent of agent */
1.10 markus 54: int parent_pid = -1;
55:
56: /* pathname and directory for AUTH_SOCKET */
57: char socket_name[1024];
58: char socket_dir[1024];
59:
1.2 provos 60: void
61: process_request_identity(SocketEntry *e)
1.1 deraadt 62: {
63: Buffer msg;
64: int i;
65:
66: buffer_init(&msg);
67: buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
68: buffer_put_int(&msg, num_identities);
69: for (i = 0; i < num_identities; i++)
70: {
1.2 provos 71: buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
72: buffer_put_bignum(&msg, identities[i].key->e);
73: buffer_put_bignum(&msg, identities[i].key->n);
1.1 deraadt 74: buffer_put_string(&msg, identities[i].comment,
75: strlen(identities[i].comment));
76: }
77: buffer_put_int(&e->output, buffer_len(&msg));
78: buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
79: buffer_free(&msg);
80: }
81:
1.2 provos 82: void
83: process_authentication_challenge(SocketEntry *e)
1.1 deraadt 84: {
1.2 provos 85: int i, pub_bits, len;
86: BIGNUM *pub_e, *pub_n, *challenge;
1.1 deraadt 87: Buffer msg;
1.7 deraadt 88: MD5_CTX md;
1.1 deraadt 89: unsigned char buf[32], mdbuf[16], session_id[16];
90: unsigned int response_type;
91:
92: buffer_init(&msg);
1.2 provos 93: pub_e = BN_new();
94: pub_n = BN_new();
95: challenge = BN_new();
1.1 deraadt 96: pub_bits = buffer_get_int(&e->input);
1.2 provos 97: buffer_get_bignum(&e->input, pub_e);
98: buffer_get_bignum(&e->input, pub_n);
99: buffer_get_bignum(&e->input, challenge);
1.1 deraadt 100: if (buffer_len(&e->input) == 0)
101: {
102: /* Compatibility code for old servers. */
103: memset(session_id, 0, 16);
104: response_type = 0;
105: }
106: else
107: {
108: /* New code. */
109: buffer_get(&e->input, (char *)session_id, 16);
110: response_type = buffer_get_int(&e->input);
111: }
112: for (i = 0; i < num_identities; i++)
1.2 provos 113: if (pub_bits == BN_num_bits(identities[i].key->n) &&
114: BN_cmp(pub_e, identities[i].key->e) == 0 &&
115: BN_cmp(pub_n, identities[i].key->n) == 0)
1.1 deraadt 116: {
117: /* Decrypt the challenge using the private key. */
1.2 provos 118: rsa_private_decrypt(challenge, challenge, identities[i].key);
1.1 deraadt 119:
120: /* Compute the desired response. */
121: switch (response_type)
122: {
123: case 0: /* As of protocol 1.0 */
124: /* This response type is no longer supported. */
125: log("Compatibility with ssh protocol 1.0 no longer supported.");
126: buffer_put_char(&msg, SSH_AGENT_FAILURE);
127: goto send;
128:
129: case 1: /* As of protocol 1.1 */
130: /* The response is MD5 of decrypted challenge plus session id. */
1.2 provos 131: len = BN_num_bytes(challenge);
132: assert(len <= 32 && len);
133: memset(buf, 0, 32);
134: BN_bn2bin(challenge, buf + 32 - len);
1.1 deraadt 135: MD5Init(&md);
136: MD5Update(&md, buf, 32);
137: MD5Update(&md, session_id, 16);
138: MD5Final(mdbuf, &md);
139: break;
140:
141: default:
142: fatal("process_authentication_challenge: bad response_type %d",
143: response_type);
144: break;
145: }
146:
147: /* Send the response. */
148: buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
149: for (i = 0; i < 16; i++)
150: buffer_put_char(&msg, mdbuf[i]);
151:
152: goto send;
153: }
154: /* Unknown identity. Send failure. */
155: buffer_put_char(&msg, SSH_AGENT_FAILURE);
156: send:
157: buffer_put_int(&e->output, buffer_len(&msg));
158: buffer_append(&e->output, buffer_ptr(&msg),
159: buffer_len(&msg));
160: buffer_free(&msg);
1.2 provos 161: BN_clear_free(pub_e);
162: BN_clear_free(pub_n);
163: BN_clear_free(challenge);
1.1 deraadt 164: }
165:
1.2 provos 166: void
167: process_remove_identity(SocketEntry *e)
1.1 deraadt 168: {
169: unsigned int bits;
170: unsigned int i;
1.2 provos 171: BIGNUM *dummy, *n;
1.1 deraadt 172:
1.2 provos 173: dummy = BN_new();
174: n = BN_new();
1.1 deraadt 175:
176: /* Get the key from the packet. */
177: bits = buffer_get_int(&e->input);
1.2 provos 178: buffer_get_bignum(&e->input, dummy);
179: buffer_get_bignum(&e->input, n);
1.1 deraadt 180:
181: /* Check if we have the key. */
182: for (i = 0; i < num_identities; i++)
1.2 provos 183: if (BN_cmp(identities[i].key->n, n) == 0)
1.1 deraadt 184: {
185: /* We have this key. Free the old key. Since we don\'t want to leave
186: empty slots in the middle of the array, we actually free the
187: key there and copy data from the last entry. */
1.2 provos 188: RSA_free(identities[i].key);
1.1 deraadt 189: xfree(identities[i].comment);
190: if (i < num_identities - 1)
191: identities[i] = identities[num_identities - 1];
192: num_identities--;
1.2 provos 193: BN_clear_free(dummy);
194: BN_clear_free(n);
1.1 deraadt 195:
196: /* Send success. */
197: buffer_put_int(&e->output, 1);
198: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
199: return;
200: }
201: /* We did not have the key. */
1.2 provos 202: BN_clear(dummy);
203: BN_clear(n);
1.1 deraadt 204:
205: /* Send failure. */
206: buffer_put_int(&e->output, 1);
207: buffer_put_char(&e->output, SSH_AGENT_FAILURE);
208: }
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: {
215: unsigned int i;
216:
217: /* Loop over all identities and clear the keys. */
218: for (i = 0; i < num_identities; i++)
219: {
1.2 provos 220: RSA_free(identities[i].key);
1.1 deraadt 221: xfree(identities[i].comment);
222: }
223:
224: /* Mark that there are no identities. */
225: num_identities = 0;
226:
227: /* Send success. */
228: buffer_put_int(&e->output, 1);
229: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
230: return;
231: }
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.2 provos 238: RSA *k;
1.1 deraadt 239: int i;
1.2 provos 240: BIGNUM *aux;
241: BN_CTX *ctx;
242:
1.1 deraadt 243: if (num_identities == 0)
244: identities = xmalloc(sizeof(Identity));
245: else
246: identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
1.2 provos 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:
1.1 deraadt 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++)
1.2 provos 284: if (BN_cmp(identities[i].key->n, k->n) == 0)
1.1 deraadt 285: {
286: /* We already have this key. Clear and free the new data and
287: return success. */
1.2 provos 288: RSA_free(k);
1.1 deraadt 289: xfree(identities[num_identities].comment);
290:
291: /* Send success. */
292: buffer_put_int(&e->output, 1);
293: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
294: return;
295: }
296:
297: /* Increment the number of identities. */
298: num_identities++;
299:
300: /* Send a success message. */
301: buffer_put_int(&e->output, 1);
302: buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
303: }
304:
1.2 provos 305: void
306: process_message(SocketEntry *e)
1.1 deraadt 307: {
308: unsigned int msg_len;
309: unsigned int type;
310: unsigned char *cp;
311: if (buffer_len(&e->input) < 5)
312: return; /* Incomplete message. */
313: cp = (unsigned char *)buffer_ptr(&e->input);
314: msg_len = GET_32BIT(cp);
315: if (msg_len > 256 * 1024)
316: {
1.8 deraadt 317: shutdown(e->fd, SHUT_RDWR);
1.1 deraadt 318: close(e->fd);
319: e->type = AUTH_UNUSED;
320: return;
321: }
322: if (buffer_len(&e->input) < msg_len + 4)
323: return;
324: buffer_consume(&e->input, 4);
325: type = buffer_get_char(&e->input);
1.12 ! markus 326:
1.1 deraadt 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: {
1.12 ! markus 394: case AUTH_SOCKET:
1.1 deraadt 395: case AUTH_CONNECTION:
396: FD_SET(sockets[i].fd, readset);
397: if (buffer_len(&sockets[i].output) > 0)
398: FD_SET(sockets[i].fd, writeset);
399: break;
400: case AUTH_UNUSED:
401: break;
402: default:
403: fatal("Unknown socket type %d", sockets[i].type);
404: break;
405: }
406: }
407:
408: void after_select(fd_set *readset, fd_set *writeset)
409: {
410: unsigned int i;
1.12 ! markus 411: int len, sock;
1.1 deraadt 412: char buf[1024];
413: struct sockaddr_un sunaddr;
414:
415: for (i = 0; i < sockets_alloc; i++)
416: switch (sockets[i].type)
417: {
418: case AUTH_UNUSED:
419: break;
420: case AUTH_SOCKET:
421: if (FD_ISSET(sockets[i].fd, readset))
422: {
423: len = sizeof(sunaddr);
424: sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len);
425: if (sock < 0)
426: {
427: perror("accept from AUTH_SOCKET");
428: break;
429: }
1.12 ! markus 430: new_socket(AUTH_CONNECTION, sock);
1.1 deraadt 431: }
432: break;
433: case AUTH_CONNECTION:
434: if (buffer_len(&sockets[i].output) > 0 &&
435: FD_ISSET(sockets[i].fd, writeset))
436: {
437: len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
438: buffer_len(&sockets[i].output));
439: if (len <= 0)
440: {
1.8 deraadt 441: shutdown(sockets[i].fd, SHUT_RDWR);
1.1 deraadt 442: close(sockets[i].fd);
443: sockets[i].type = AUTH_UNUSED;
444: break;
445: }
446: buffer_consume(&sockets[i].output, len);
447: }
448: if (FD_ISSET(sockets[i].fd, readset))
449: {
450: len = read(sockets[i].fd, buf, sizeof(buf));
451: if (len <= 0)
452: {
1.8 deraadt 453: shutdown(sockets[i].fd, SHUT_RDWR);
1.1 deraadt 454: close(sockets[i].fd);
455: sockets[i].type = AUTH_UNUSED;
456: break;
457: }
458: buffer_append(&sockets[i].input, buf, len);
459: process_message(&sockets[i]);
460: }
461: break;
462: default:
463: fatal("Unknown type %d", sockets[i].type);
464: }
465: }
466:
1.6 deraadt 467: void
1.2 provos 468: check_parent_exists(int sig)
1.1 deraadt 469: {
470: if (kill(parent_pid, 0) < 0)
471: {
472: /* printf("Parent has died - Authentication agent exiting.\n"); */
473: exit(1);
474: }
475: signal(SIGALRM, check_parent_exists);
476: alarm(10);
477: }
478:
1.10 markus 479: void cleanup_socket(void) {
480: remove(socket_name);
481: rmdir(socket_dir);
482: }
483:
1.2 provos 484: int
485: main(int ac, char **av)
1.1 deraadt 486: {
487: fd_set readset, writeset;
488: int sock;
489: struct sockaddr_un sunaddr;
490:
1.3 deraadt 491: /* check if RSA support exists */
492: if (rsa_alive() == 0) {
493: extern char *__progname;
494: fprintf(stderr,
495: "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
496: __progname);
497: exit(1);
498: }
1.1 deraadt 499:
500: if (ac < 2)
501: {
502: fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
503: fprintf(stderr, "Usage: %s command\n", av[0]);
504: exit(1);
505: }
506:
1.9 markus 507: parent_pid = getpid();
1.10 markus 508:
509: /* Create private directory for agent socket */
510: strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
511: if (mkdtemp(socket_dir) == NULL) {
512: perror("mkdtemp: private socket dir");
513: exit(1);
514: }
515: snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, parent_pid);
1.9 markus 516:
517: /* Fork, and have the parent execute the command. The child continues as
518: the authentication agent. */
519: if (fork() != 0)
520: { /* Parent - execute the given command. */
1.12 ! markus 521: setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
1.9 markus 522: execvp(av[1], av + 1);
523: perror(av[1]);
524: exit(1);
525: }
1.10 markus 526:
527: if (atexit(cleanup_socket) < 0) {
528: perror("atexit");
529: cleanup_socket();
530: exit(1);
531: }
532:
1.9 markus 533: sock = socket(AF_UNIX, SOCK_STREAM, 0);
534: if (sock < 0)
1.1 deraadt 535: {
1.9 markus 536: perror("socket");
537: exit(1);
538: }
539: memset(&sunaddr, 0, sizeof(sunaddr));
540: sunaddr.sun_family = AF_UNIX;
541: strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
542: if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
543: {
544: perror("bind");
545: exit(1);
546: }
547: if (listen(sock, 5) < 0)
548: {
549: perror("listen");
550: exit(1);
1.1 deraadt 551: }
1.9 markus 552: new_socket(AUTH_SOCKET, sock);
553: signal(SIGALRM, check_parent_exists);
554: alarm(10);
1.1 deraadt 555:
556: signal(SIGINT, SIG_IGN);
557: while (1)
558: {
559: FD_ZERO(&readset);
560: FD_ZERO(&writeset);
561: prepare_select(&readset, &writeset);
562: if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
563: {
564: if (errno == EINTR)
565: continue;
566: perror("select");
567: exit(1);
568: }
569: after_select(&readset, &writeset);
570: }
571: /*NOTREACHED*/
572: }