]> andersk Git - openssh.git/blame - ssh-agent.c
- Add recommendation to use GNU make to INSTALL document
[openssh.git] / ssh-agent.c
CommitLineData
9d6b7add 1/* $OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $ */
dae3fa13 2
8efc0c15 3/*
4
5ssh-agent.c
6
7Author: Tatu Ylonen <ylo@cs.hut.fi>
8
9Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
10 All rights reserved
11
12Created: Wed Mar 29 03:46:59 1995 ylo
13
14The authentication agent program.
15
16*/
17
18#include "includes.h"
9d6b7add 19RCSID("$OpenBSD: ssh-agent.c,v 1.20 1999/11/19 10:20:51 markus Exp $");
8efc0c15 20
21#include "ssh.h"
22#include "rsa.h"
23#include "authfd.h"
24#include "buffer.h"
25#include "bufaux.h"
26#include "xmalloc.h"
27#include "packet.h"
28#include "getput.h"
29#include "mpaux.h"
30
5881cd60 31#ifdef HAVE_OPENSSL
8efc0c15 32#include <openssl/md5.h>
5881cd60 33#endif
34#ifdef HAVE_SSL
35#include <ssl/md5.h>
36#endif
8efc0c15 37
f601d847 38#ifdef HAVE___PROGNAME
39extern char *__progname;
40#else /* HAVE___PROGNAME */
41const char *__progname = "ssh-agent";
42#endif /* HAVE___PROGNAME */
43
8efc0c15 44typedef struct
45{
46 int fd;
47 enum { AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION } type;
48 Buffer input;
49 Buffer output;
50} SocketEntry;
51
52unsigned int sockets_alloc = 0;
53SocketEntry *sockets = NULL;
54
55typedef struct
56{
57 RSA *key;
58 char *comment;
59} Identity;
60
61unsigned int num_identities = 0;
62Identity *identities = NULL;
63
64int max_fd = 0;
65
66/* pid of shell == parent of agent */
67int parent_pid = -1;
68
69/* pathname and directory for AUTH_SOCKET */
70char socket_name[1024];
71char socket_dir[1024];
72
73void
74process_request_identity(SocketEntry *e)
75{
76 Buffer msg;
77 int i;
78
79 buffer_init(&msg);
80 buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
81 buffer_put_int(&msg, num_identities);
82 for (i = 0; i < num_identities; i++)
83 {
84 buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
85 buffer_put_bignum(&msg, identities[i].key->e);
86 buffer_put_bignum(&msg, identities[i].key->n);
87 buffer_put_string(&msg, identities[i].comment,
88 strlen(identities[i].comment));
89 }
90 buffer_put_int(&e->output, buffer_len(&msg));
91 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
92 buffer_free(&msg);
93}
94
95void
96process_authentication_challenge(SocketEntry *e)
97{
98 int i, pub_bits, len;
99 BIGNUM *pub_e, *pub_n, *challenge;
100 Buffer msg;
101 MD5_CTX md;
102 unsigned char buf[32], mdbuf[16], session_id[16];
103 unsigned int response_type;
104
105 buffer_init(&msg);
106 pub_e = BN_new();
107 pub_n = BN_new();
108 challenge = BN_new();
109 pub_bits = buffer_get_int(&e->input);
110 buffer_get_bignum(&e->input, pub_e);
111 buffer_get_bignum(&e->input, pub_n);
112 buffer_get_bignum(&e->input, challenge);
113 if (buffer_len(&e->input) == 0)
114 {
115 /* Compatibility code for old servers. */
116 memset(session_id, 0, 16);
117 response_type = 0;
118 }
119 else
120 {
121 /* New code. */
122 buffer_get(&e->input, (char *)session_id, 16);
123 response_type = buffer_get_int(&e->input);
124 }
125 for (i = 0; i < num_identities; i++)
126 if (pub_bits == BN_num_bits(identities[i].key->n) &&
127 BN_cmp(pub_e, identities[i].key->e) == 0 &&
128 BN_cmp(pub_n, identities[i].key->n) == 0)
129 {
130 /* Decrypt the challenge using the private key. */
131 rsa_private_decrypt(challenge, challenge, identities[i].key);
132
133 /* Compute the desired response. */
134 switch (response_type)
135 {
136 case 0: /* As of protocol 1.0 */
137 /* This response type is no longer supported. */
138 log("Compatibility with ssh protocol 1.0 no longer supported.");
139 buffer_put_char(&msg, SSH_AGENT_FAILURE);
140 goto send;
141
142 case 1: /* As of protocol 1.1 */
143 /* The response is MD5 of decrypted challenge plus session id. */
144 len = BN_num_bytes(challenge);
5bae4ab8 145
146 if (len <= 0 || len > 32) {
147 fatal("process_authentication_challenge: "
148 "bad challenge length %d", len);
149 }
150
8efc0c15 151 memset(buf, 0, 32);
152 BN_bn2bin(challenge, buf + 32 - len);
153 MD5_Init(&md);
154 MD5_Update(&md, buf, 32);
155 MD5_Update(&md, session_id, 16);
156 MD5_Final(mdbuf, &md);
157 break;
158
159 default:
160 fatal("process_authentication_challenge: bad response_type %d",
161 response_type);
162 break;
163 }
164
165 /* Send the response. */
166 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
167 for (i = 0; i < 16; i++)
168 buffer_put_char(&msg, mdbuf[i]);
169
170 goto send;
171 }
172 /* Unknown identity. Send failure. */
173 buffer_put_char(&msg, SSH_AGENT_FAILURE);
174 send:
175 buffer_put_int(&e->output, buffer_len(&msg));
176 buffer_append(&e->output, buffer_ptr(&msg),
177 buffer_len(&msg));
178 buffer_free(&msg);
179 BN_clear_free(pub_e);
180 BN_clear_free(pub_n);
181 BN_clear_free(challenge);
182}
183
184void
185process_remove_identity(SocketEntry *e)
186{
187 unsigned int bits;
188 unsigned int i;
189 BIGNUM *dummy, *n;
190
191 dummy = BN_new();
192 n = BN_new();
193
194 /* Get the key from the packet. */
195 bits = buffer_get_int(&e->input);
196 buffer_get_bignum(&e->input, dummy);
197 buffer_get_bignum(&e->input, n);
4d195447 198
199 if (bits != BN_num_bits(n))
2ad77510 200 error("Warning: keysize mismatch: actual %d, announced %d",
4d195447 201 BN_num_bits(n), bits);
8efc0c15 202
203 /* Check if we have the key. */
204 for (i = 0; i < num_identities; i++)
205 if (BN_cmp(identities[i].key->n, n) == 0)
206 {
207 /* We have this key. Free the old key. Since we don\'t want to leave
208 empty slots in the middle of the array, we actually free the
209 key there and copy data from the last entry. */
210 RSA_free(identities[i].key);
211 xfree(identities[i].comment);
212 if (i < num_identities - 1)
213 identities[i] = identities[num_identities - 1];
214 num_identities--;
215 BN_clear_free(dummy);
216 BN_clear_free(n);
217
218 /* Send success. */
219 buffer_put_int(&e->output, 1);
220 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
221 return;
222 }
223 /* We did not have the key. */
224 BN_clear(dummy);
225 BN_clear(n);
226
227 /* Send failure. */
228 buffer_put_int(&e->output, 1);
229 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
230}
231
232/* Removes all identities from the agent. */
233
234void
235process_remove_all_identities(SocketEntry *e)
236{
237 unsigned int i;
238
239 /* Loop over all identities and clear the keys. */
240 for (i = 0; i < num_identities; i++)
241 {
242 RSA_free(identities[i].key);
243 xfree(identities[i].comment);
244 }
245
246 /* Mark that there are no identities. */
247 num_identities = 0;
248
249 /* Send success. */
250 buffer_put_int(&e->output, 1);
251 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
252 return;
253}
254
255/* Adds an identity to the agent. */
256
257void
258process_add_identity(SocketEntry *e)
259{
260 RSA *k;
261 int i;
262 BIGNUM *aux;
263 BN_CTX *ctx;
264
265 if (num_identities == 0)
266 identities = xmalloc(sizeof(Identity));
267 else
268 identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
269
270 identities[num_identities].key = RSA_new();
271 k = identities[num_identities].key;
272 buffer_get_int(&e->input); /* bits */
273 k->n = BN_new();
274 buffer_get_bignum(&e->input, k->n);
275 k->e = BN_new();
276 buffer_get_bignum(&e->input, k->e);
277 k->d = BN_new();
278 buffer_get_bignum(&e->input, k->d);
279 k->iqmp = BN_new();
280 buffer_get_bignum(&e->input, k->iqmp);
281 /* SSH and SSL have p and q swapped */
282 k->q = BN_new();
283 buffer_get_bignum(&e->input, k->q); /* p */
284 k->p = BN_new();
285 buffer_get_bignum(&e->input, k->p); /* q */
286
287 /* Generate additional parameters */
288 aux = BN_new();
289 ctx = BN_CTX_new();
290
291 BN_sub(aux, k->q, BN_value_one());
292 k->dmq1 = BN_new();
293 BN_mod(k->dmq1, k->d, aux, ctx);
294
295 BN_sub(aux, k->p, BN_value_one());
296 k->dmp1 = BN_new();
297 BN_mod(k->dmp1, k->d, aux, ctx);
298
299 BN_clear_free(aux);
300 BN_CTX_free(ctx);
301
302 identities[num_identities].comment = buffer_get_string(&e->input, NULL);
303
304 /* Check if we already have the key. */
305 for (i = 0; i < num_identities; i++)
306 if (BN_cmp(identities[i].key->n, k->n) == 0)
307 {
308 /* We already have this key. Clear and free the new data and
309 return success. */
310 RSA_free(k);
311 xfree(identities[num_identities].comment);
312
313 /* Send success. */
314 buffer_put_int(&e->output, 1);
315 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
316 return;
317 }
318
319 /* Increment the number of identities. */
320 num_identities++;
321
322 /* Send a success message. */
323 buffer_put_int(&e->output, 1);
324 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
325}
326
327void
328process_message(SocketEntry *e)
329{
330 unsigned int msg_len;
331 unsigned int type;
332 unsigned char *cp;
333 if (buffer_len(&e->input) < 5)
334 return; /* Incomplete message. */
335 cp = (unsigned char *)buffer_ptr(&e->input);
336 msg_len = GET_32BIT(cp);
337 if (msg_len > 256 * 1024)
338 {
339 shutdown(e->fd, SHUT_RDWR);
340 close(e->fd);
341 e->type = AUTH_UNUSED;
342 return;
343 }
344 if (buffer_len(&e->input) < msg_len + 4)
345 return;
346 buffer_consume(&e->input, 4);
347 type = buffer_get_char(&e->input);
348
349 switch (type)
350 {
351 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
352 process_request_identity(e);
353 break;
354 case SSH_AGENTC_RSA_CHALLENGE:
355 process_authentication_challenge(e);
356 break;
357 case SSH_AGENTC_ADD_RSA_IDENTITY:
358 process_add_identity(e);
359 break;
360 case SSH_AGENTC_REMOVE_RSA_IDENTITY:
361 process_remove_identity(e);
362 break;
363 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
364 process_remove_all_identities(e);
365 break;
366 default:
367 /* Unknown message. Respond with failure. */
368 error("Unknown message %d", type);
369 buffer_clear(&e->input);
370 buffer_put_int(&e->output, 1);
371 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
372 break;
373 }
374}
375
376void
377new_socket(int type, int fd)
378{
379 unsigned int i, old_alloc;
380 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
381 error("fcntl O_NONBLOCK: %s", strerror(errno));
382
383 if (fd > max_fd)
384 max_fd = fd;
385
386 for (i = 0; i < sockets_alloc; i++)
387 if (sockets[i].type == AUTH_UNUSED)
388 {
389 sockets[i].fd = fd;
390 sockets[i].type = type;
391 buffer_init(&sockets[i].input);
392 buffer_init(&sockets[i].output);
393 return;
394 }
395 old_alloc = sockets_alloc;
396 sockets_alloc += 10;
397 if (sockets)
398 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
399 else
400 sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
401 for (i = old_alloc; i < sockets_alloc; i++)
402 sockets[i].type = AUTH_UNUSED;
403 sockets[old_alloc].type = type;
404 sockets[old_alloc].fd = fd;
405 buffer_init(&sockets[old_alloc].input);
406 buffer_init(&sockets[old_alloc].output);
407}
408
409void
410prepare_select(fd_set *readset, fd_set *writeset)
411{
412 unsigned int i;
413 for (i = 0; i < sockets_alloc; i++)
414 switch (sockets[i].type)
415 {
416 case AUTH_SOCKET:
417 case AUTH_CONNECTION:
418 FD_SET(sockets[i].fd, readset);
419 if (buffer_len(&sockets[i].output) > 0)
420 FD_SET(sockets[i].fd, writeset);
421 break;
422 case AUTH_UNUSED:
423 break;
424 default:
425 fatal("Unknown socket type %d", sockets[i].type);
426 break;
427 }
428}
429
430void after_select(fd_set *readset, fd_set *writeset)
431{
432 unsigned int i;
433 int len, sock;
434 char buf[1024];
435 struct sockaddr_un sunaddr;
436
437 for (i = 0; i < sockets_alloc; i++)
438 switch (sockets[i].type)
439 {
440 case AUTH_UNUSED:
441 break;
442 case AUTH_SOCKET:
443 if (FD_ISSET(sockets[i].fd, readset))
444 {
445 len = sizeof(sunaddr);
446 sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len);
447 if (sock < 0)
448 {
449 perror("accept from AUTH_SOCKET");
450 break;
451 }
452 new_socket(AUTH_CONNECTION, sock);
453 }
454 break;
455 case AUTH_CONNECTION:
456 if (buffer_len(&sockets[i].output) > 0 &&
457 FD_ISSET(sockets[i].fd, writeset))
458 {
459 len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
460 buffer_len(&sockets[i].output));
461 if (len <= 0)
462 {
463 shutdown(sockets[i].fd, SHUT_RDWR);
464 close(sockets[i].fd);
465 sockets[i].type = AUTH_UNUSED;
466 break;
467 }
468 buffer_consume(&sockets[i].output, len);
469 }
470 if (FD_ISSET(sockets[i].fd, readset))
471 {
472 len = read(sockets[i].fd, buf, sizeof(buf));
473 if (len <= 0)
474 {
475 shutdown(sockets[i].fd, SHUT_RDWR);
476 close(sockets[i].fd);
477 sockets[i].type = AUTH_UNUSED;
478 break;
479 }
480 buffer_append(&sockets[i].input, buf, len);
481 process_message(&sockets[i]);
482 }
483 break;
484 default:
485 fatal("Unknown type %d", sockets[i].type);
486 }
487}
488
489void
490check_parent_exists(int sig)
491{
492 if (kill(parent_pid, 0) < 0)
493 {
494 /* printf("Parent has died - Authentication agent exiting.\n"); */
495 exit(1);
496 }
497 signal(SIGALRM, check_parent_exists);
498 alarm(10);
499}
500
dae3fa13 501void
502cleanup_socket(void)
503{
8efc0c15 504 remove(socket_name);
505 rmdir(socket_dir);
506}
507
dae3fa13 508void
509cleanup_exit(int i)
510{
511 cleanup_socket();
512 exit(i);
513}
514
515void
516usage()
517{
dae3fa13 518 fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
519 fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
520 __progname);
521 exit(1);
522}
523
8efc0c15 524int
525main(int ac, char **av)
526{
527 fd_set readset, writeset;
dae3fa13 528 int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
8efc0c15 529 struct sockaddr_un sunaddr;
dae3fa13 530 pid_t pid;
531 char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
8efc0c15 532
533 /* check if RSA support exists */
534 if (rsa_alive() == 0) {
8efc0c15 535 fprintf(stderr,
536 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
537 __progname);
538 exit(1);
539 }
540
f370266e 541#if defined(__GNU_LIBRARY__)
542 while ((ch = getopt(ac, av, "+cks")) != -1)
543#else
dae3fa13 544 while ((ch = getopt(ac, av, "cks")) != -1)
f370266e 545#endif /* defined(__GNU_LIBRARY__) */
8efc0c15 546 {
dae3fa13 547 switch (ch)
548 {
549 case 'c':
550 if (s_flag)
551 usage();
552 c_flag++;
553 break;
554 case 'k':
555 k_flag++;
556 break;
557 case 's':
558 if (c_flag)
559 usage();
560 s_flag++;
561 break;
562 default:
563 usage();
564 }
565 }
566 ac -= optind;
567 av += optind;
568
569 if (ac > 0 && (c_flag || k_flag || s_flag))
570 usage();
571
572 if (ac == 0 && !c_flag && !k_flag && !s_flag)
573 {
574 shell = getenv("SHELL");
575 if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
576 c_flag = 1;
577 }
578
579 if (k_flag)
580 {
581 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
582 if (pidstr == NULL)
583 {
584 fprintf(stderr, "%s not set, cannot kill agent\n",
585 SSH_AGENTPID_ENV_NAME);
586 exit(1);
587 }
588 pid = atoi(pidstr);
589 if (pid < 1) /* XXX PID_MAX check too */
590 {
591 fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
592 SSH_AGENTPID_ENV_NAME, pidstr);
593 exit(1);
594 }
595 if (kill(pid, SIGTERM) == -1)
596 {
597 perror("kill");
598 exit(1);
599 }
600 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
601 printf(format, SSH_AUTHSOCKET_ENV_NAME);
602 printf(format, SSH_AGENTPID_ENV_NAME);
603 printf("echo Agent pid %d killed;\n", pid);
604 exit(0);
8efc0c15 605 }
606
607 parent_pid = getpid();
608
609 /* Create private directory for agent socket */
610 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
611 if (mkdtemp(socket_dir) == NULL) {
612 perror("mkdtemp: private socket dir");
613 exit(1);
614 }
dae3fa13 615 snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
616 parent_pid);
5068f573 617
dae3fa13 618 /* Create socket early so it will exist before command gets run from
619 the parent. */
8efc0c15 620 sock = socket(AF_UNIX, SOCK_STREAM, 0);
621 if (sock < 0)
622 {
623 perror("socket");
dae3fa13 624 cleanup_exit(1);
8efc0c15 625 }
626 memset(&sunaddr, 0, sizeof(sunaddr));
627 sunaddr.sun_family = AF_UNIX;
628 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
629 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
630 {
631 perror("bind");
dae3fa13 632 cleanup_exit(1);
8efc0c15 633 }
634 if (listen(sock, 5) < 0)
635 {
636 perror("listen");
dae3fa13 637 cleanup_exit(1);
638 }
639
640 /* Fork, and have the parent execute the command, if any, or present the
641 socket data. The child continues as the authentication agent. */
642 pid = fork();
643 if (pid == -1)
644 {
645 perror("fork");
8efc0c15 646 exit(1);
647 }
dae3fa13 648 if (pid != 0)
649 { /* Parent - execute the given command. */
650 close(sock);
651 snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
652 if (ac == 0)
653 {
654 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
655 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
656 SSH_AUTHSOCKET_ENV_NAME);
657 printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
658 SSH_AGENTPID_ENV_NAME);
659 printf("echo Agent pid %d;\n", pid);
660 exit(0);
661 }
662
663 setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
664 setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1);
665 execvp(av[0], av);
666 perror(av[0]);
667 exit(1);
668 }
669
670 close(0);
671 close(1);
672 close(2);
673
69256d9d 674 if (setsid() == -1)
675 {
676 perror("setsid");
677 cleanup_exit(1);
678 }
dae3fa13 679
680 if (atexit(cleanup_socket) < 0)
69256d9d 681 {
682 perror("atexit");
683 cleanup_exit(1);
684 }
dae3fa13 685
8efc0c15 686 new_socket(AUTH_SOCKET, sock);
dae3fa13 687 if (ac > 0)
688 {
689 signal(SIGALRM, check_parent_exists);
690 alarm(10);
691 }
8efc0c15 692
693 signal(SIGINT, SIG_IGN);
dae3fa13 694 signal(SIGPIPE, SIG_IGN);
8efc0c15 695 while (1)
696 {
697 FD_ZERO(&readset);
698 FD_ZERO(&writeset);
699 prepare_select(&readset, &writeset);
700 if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
701 {
702 if (errno == EINTR)
703 continue;
8efc0c15 704 exit(1);
705 }
706 after_select(&readset, &writeset);
707 }
708 /*NOTREACHED*/
709}
This page took 0.160458 seconds and 5 git commands to generate.