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