Annotation of src/usr.bin/ssh/ssh-agent.c, Revision 1.2
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"
17: RCSID("$Id: ssh-agent.c,v 1.3 1999/05/04 11:59:14 bg Exp $");
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 defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN)
351: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
352: error("fcntl O_NONBLOCK: %s", strerror(errno));
353: #else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
354: if (fcntl(fd, F_SETFL, O_NDELAY) < 0)
355: error("fcntl O_NDELAY: %s", strerror(errno));
356: #endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */
357:
358: if (fd > max_fd)
359: max_fd = fd;
360:
361: for (i = 0; i < sockets_alloc; i++)
362: if (sockets[i].type == AUTH_UNUSED)
363: {
364: sockets[i].fd = fd;
365: sockets[i].type = type;
366: buffer_init(&sockets[i].input);
367: buffer_init(&sockets[i].output);
368: return;
369: }
370: old_alloc = sockets_alloc;
371: sockets_alloc += 10;
372: if (sockets)
373: sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
374: else
375: sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
376: for (i = old_alloc; i < sockets_alloc; i++)
377: sockets[i].type = AUTH_UNUSED;
378: sockets[old_alloc].type = type;
379: sockets[old_alloc].fd = fd;
380: buffer_init(&sockets[old_alloc].input);
381: buffer_init(&sockets[old_alloc].output);
382: }
383:
1.2 ! provos 384: void
! 385: prepare_select(fd_set *readset, fd_set *writeset)
1.1 deraadt 386: {
387: unsigned int i;
388: for (i = 0; i < sockets_alloc; i++)
389: switch (sockets[i].type)
390: {
391: case AUTH_FD:
392: case AUTH_CONNECTION:
393: case AUTH_SOCKET:
394: case AUTH_SOCKET_FD:
395: FD_SET(sockets[i].fd, readset);
396: if (buffer_len(&sockets[i].output) > 0)
397: FD_SET(sockets[i].fd, writeset);
398: break;
399: case AUTH_UNUSED:
400: break;
401: default:
402: fatal("Unknown socket type %d", sockets[i].type);
403: break;
404: }
405: }
406:
407: void after_select(fd_set *readset, fd_set *writeset)
408: {
409: unsigned int i;
410: int len, sock, port;
411: char buf[1024];
412: struct sockaddr_in sin;
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_FD:
421: if (FD_ISSET(sockets[i].fd, readset))
422: {
423: len = recv(sockets[i].fd, buf, sizeof(buf), 0);
424: if (len <= 0)
425: { /* All instances of the other side have been closed. */
426: log("Authentication agent exiting.");
427: exit(0);
428: }
429: process_auth_fd_input:
430: if (len != 3 || (unsigned char)buf[0] != SSH_AUTHFD_CONNECT)
431: break; /* Incorrect message; ignore it. */
432: /* It is a connection request message. */
433: port = (unsigned char)buf[1] * 256 + (unsigned char)buf[2];
434: memset(&sin, 0, sizeof(sin));
435: sin.sin_family = AF_INET;
436: sin.sin_addr.s_addr = htonl(0x7f000001); /* localhost */
437: sin.sin_port = htons(port);
438: sock = socket(AF_INET, SOCK_STREAM, 0);
439: if (sock < 0)
440: {
441: perror("socket");
442: break;
443: }
444: if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
445: {
446: perror("connecting to port requested in authfd message");
447: close(sock);
448: break;
449: }
450: new_socket(AUTH_CONNECTION, sock);
451: }
452: break;
453: case AUTH_SOCKET:
454: if (FD_ISSET(sockets[i].fd, readset))
455: {
456: len = sizeof(sunaddr);
457: sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len);
458: if (sock < 0)
459: {
460: perror("accept from AUTH_SOCKET");
461: break;
462: }
463: new_socket(AUTH_SOCKET_FD, sock);
464: }
465: break;
466: case AUTH_SOCKET_FD:
467: if (FD_ISSET(sockets[i].fd, readset))
468: {
469: len = recv(sockets[i].fd, buf, sizeof(buf), 0);
470: if (len <= 0)
471: { /* The other side has closed the socket. */
472: shutdown(sockets[i].fd, 2);
473: close(sockets[i].fd);
474: sockets[i].type = AUTH_UNUSED;
475: break;
476: }
477: goto process_auth_fd_input;
478: }
479: break;
480: case AUTH_CONNECTION:
481: if (buffer_len(&sockets[i].output) > 0 &&
482: FD_ISSET(sockets[i].fd, writeset))
483: {
484: len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
485: buffer_len(&sockets[i].output));
486: if (len <= 0)
487: {
488: shutdown(sockets[i].fd, 2);
489: close(sockets[i].fd);
490: sockets[i].type = AUTH_UNUSED;
491: break;
492: }
493: buffer_consume(&sockets[i].output, len);
494: }
495: if (FD_ISSET(sockets[i].fd, readset))
496: {
497: len = read(sockets[i].fd, buf, sizeof(buf));
498: if (len <= 0)
499: {
500: shutdown(sockets[i].fd, 2);
501: close(sockets[i].fd);
502: sockets[i].type = AUTH_UNUSED;
503: break;
504: }
505: buffer_append(&sockets[i].input, buf, len);
506: process_message(&sockets[i]);
507: }
508: break;
509: default:
510: fatal("Unknown type %d", sockets[i].type);
511: }
512: }
513:
514: int parent_pid = -1;
515: char socket_name[1024];
516:
1.2 ! provos 517: RETSIGTYPE
! 518: check_parent_exists(int sig)
1.1 deraadt 519: {
520: if (kill(parent_pid, 0) < 0)
521: {
522: remove(socket_name);
523: /* printf("Parent has died - Authentication agent exiting.\n"); */
524: exit(1);
525: }
526: signal(SIGALRM, check_parent_exists);
527: alarm(10);
528: }
529:
1.2 ! provos 530: int
! 531: main(int ac, char **av)
1.1 deraadt 532: {
533: fd_set readset, writeset;
534: char buf[1024];
535: int pfd;
536: int sock;
537: struct sockaddr_un sunaddr;
538:
539: int sockets[2], i;
540: int *dups;
541:
542: if (ac < 2)
543: {
544: fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
545: fprintf(stderr, "Usage: %s command\n", av[0]);
546: exit(1);
547: }
548:
549: pfd = get_permanent_fd(NULL);
550: if (pfd < 0)
551: {
552: /* The agent uses SSH_AUTHENTICATION_SOCKET. */
553:
554: parent_pid = getpid();
555:
556: sprintf(socket_name, SSH_AGENT_SOCKET, parent_pid);
557:
558: /* Fork, and have the parent execute the command. The child continues as
559: the authentication agent. */
560: if (fork() != 0)
561: { /* Parent - execute the given command. */
562: sprintf(buf, "SSH_AUTHENTICATION_SOCKET=%s", socket_name);
563: putenv(buf);
564: execvp(av[1], av + 1);
565: perror(av[1]);
566: exit(1);
567: }
568:
569: sock = socket(AF_UNIX, SOCK_STREAM, 0);
570: if (sock < 0)
571: {
572: perror("socket");
573: exit(1);
574: }
575: memset(&sunaddr, 0, sizeof(sunaddr));
576: sunaddr.sun_family = AF_UNIX;
577: strncpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
578: if (bind(sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)) < 0)
579: {
580: perror("bind");
581: exit(1);
582: }
583: if (chmod(socket_name, 0700) < 0)
584: {
585: perror("chmod");
586: exit(1);
587: }
588: if (listen(sock, 5) < 0)
589: {
590: perror("listen");
591: exit(1);
592: }
593: new_socket(AUTH_SOCKET, sock);
594: signal(SIGALRM, check_parent_exists);
595: alarm(10);
596: }
597: else
598: {
599: /* The agent uses SSH_AUTHENTICATION_FD. */
600: int cnt, newfd;
601:
602: dups = xmalloc(sizeof (int) * (1 + pfd));
603:
604: if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0)
605: {
606: perror("socketpair");
607: exit(1);
608: }
609:
610: /* Dup some descriptors to get the authentication fd to pfd,
611: because some shells arbitrarily close descriptors below that.
612: Don't use dup2 because maybe some systems don't have it?? */
613: for (cnt = 0;; cnt++) {
614: if ((dups[cnt] = dup(0)) < 0)
615: fatal("auth_input_request_forwarding: dup failed");
616: if (dups[cnt] == pfd)
617: break;
618: }
619: close(dups[cnt]);
620:
621: /* Move the file descriptor we pass to children up high where
622: the shell won't close it. */
623: newfd = dup(sockets[1]);
624: if (newfd != pfd)
625: fatal("auth_input_request_forwarding: dup didn't return %d.", pfd);
626: close(sockets[1]);
627: sockets[1] = newfd;
628: /* Close duped descriptors. */
629: for (i = 0; i < cnt; i++)
630: close(dups[i]);
631: free(dups);
632:
633: if (fork() != 0)
634: { /* Parent - execute the given command. */
635: close(sockets[0]);
636: sprintf(buf, "SSH_AUTHENTICATION_FD=%d", sockets[1]);
637: putenv(buf);
638: execvp(av[1], av + 1);
639: perror(av[1]);
640: exit(1);
641: }
642: close(sockets[1]);
643: new_socket(AUTH_FD, sockets[0]);
644: }
645:
646: signal(SIGINT, SIG_IGN);
647: while (1)
648: {
649: FD_ZERO(&readset);
650: FD_ZERO(&writeset);
651: prepare_select(&readset, &writeset);
652: if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
653: {
654: if (errno == EINTR)
655: continue;
656: perror("select");
657: exit(1);
658: }
659: after_select(&readset, &writeset);
660: }
661: /*NOTREACHED*/
662: }