Annotation of src/usr.bin/ssh/ssh-agent.c, Revision 1.9
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.9 ! markus 17: RCSID("$Id: ssh-agent.c,v 1.8 1999/10/03 19:22:38 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: {
1.8 deraadt 311: shutdown(e->fd, SHUT_RDWR);
1.1 deraadt 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. */
1.8 deraadt 468: shutdown(sockets[i].fd, SHUT_RDWR);
1.1 deraadt 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: {
1.8 deraadt 484: shutdown(sockets[i].fd, SHUT_RDWR);
1.1 deraadt 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: {
1.8 deraadt 496: shutdown(sockets[i].fd, SHUT_RDWR);
1.1 deraadt 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:
1.9 ! markus 555: /* The agent uses SSH_AUTHENTICATION_SOCKET. */
! 556:
! 557: parent_pid = getpid();
! 558:
! 559: snprintf(socket_name, sizeof socket_name, SSH_AGENT_SOCKET, parent_pid);
! 560:
! 561: /* Fork, and have the parent execute the command. The child continues as
! 562: the authentication agent. */
! 563: if (fork() != 0)
! 564: { /* Parent - execute the given command. */
! 565: snprintf(buf, sizeof buf, "SSH_AUTHENTICATION_SOCKET=%s", socket_name);
! 566: putenv(buf);
! 567: execvp(av[1], av + 1);
! 568: perror(av[1]);
! 569: exit(1);
! 570: }
! 571:
! 572: sock = socket(AF_UNIX, SOCK_STREAM, 0);
! 573: if (sock < 0)
1.1 deraadt 574: {
1.9 ! markus 575: perror("socket");
! 576: exit(1);
! 577: }
! 578: memset(&sunaddr, 0, sizeof(sunaddr));
! 579: sunaddr.sun_family = AF_UNIX;
! 580: strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
! 581: if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
! 582: {
! 583: perror("bind");
! 584: exit(1);
! 585: }
! 586: if (chmod(socket_name, 0700) < 0)
! 587: {
! 588: perror("chmod");
! 589: exit(1);
! 590: }
! 591: if (listen(sock, 5) < 0)
! 592: {
! 593: perror("listen");
! 594: exit(1);
1.1 deraadt 595: }
1.9 ! markus 596: new_socket(AUTH_SOCKET, sock);
! 597: signal(SIGALRM, check_parent_exists);
! 598: alarm(10);
1.1 deraadt 599:
600: signal(SIGINT, SIG_IGN);
601: while (1)
602: {
603: FD_ZERO(&readset);
604: FD_ZERO(&writeset);
605: prepare_select(&readset, &writeset);
606: if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
607: {
608: if (errno == EINTR)
609: continue;
610: perror("select");
611: exit(1);
612: }
613: after_select(&readset, &writeset);
614: }
615: /*NOTREACHED*/
616: }