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