diff options
Diffstat (limited to 'ssh-agent.c')
-rw-r--r-- | ssh-agent.c | 177 |
1 files changed, 139 insertions, 38 deletions
diff --git a/ssh-agent.c b/ssh-agent.c index 56618aded..a9d2a1426 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -1,3 +1,5 @@ | |||
1 | /* $OpenBSD: ssh-agent.c,v 1.15 1999/10/28 08:43:10 markus Exp $ */ | ||
2 | |||
1 | /* | 3 | /* |
2 | 4 | ||
3 | ssh-agent.c | 5 | ssh-agent.c |
@@ -15,7 +17,7 @@ The authentication agent program. | |||
15 | 17 | ||
16 | #include "config.h" | 18 | #include "config.h" |
17 | #include "includes.h" | 19 | #include "includes.h" |
18 | RCSID("$Id: ssh-agent.c,v 1.3 1999/10/28 05:23:30 damien Exp $"); | 20 | RCSID("$OpenBSD: ssh-agent.c,v 1.15 1999/10/28 08:43:10 markus Exp $"); |
19 | 21 | ||
20 | #include "ssh.h" | 22 | #include "ssh.h" |
21 | #include "rsa.h" | 23 | #include "rsa.h" |
@@ -482,17 +484,39 @@ check_parent_exists(int sig) | |||
482 | alarm(10); | 484 | alarm(10); |
483 | } | 485 | } |
484 | 486 | ||
485 | void cleanup_socket(void) { | 487 | void |
488 | cleanup_socket(void) | ||
489 | { | ||
486 | remove(socket_name); | 490 | remove(socket_name); |
487 | rmdir(socket_dir); | 491 | rmdir(socket_dir); |
488 | } | 492 | } |
489 | 493 | ||
494 | void | ||
495 | cleanup_exit(int i) | ||
496 | { | ||
497 | cleanup_socket(); | ||
498 | exit(i); | ||
499 | } | ||
500 | |||
501 | void | ||
502 | usage() | ||
503 | { | ||
504 | extern char *__progname; | ||
505 | |||
506 | fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); | ||
507 | fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n", | ||
508 | __progname); | ||
509 | exit(1); | ||
510 | } | ||
511 | |||
490 | int | 512 | int |
491 | main(int ac, char **av) | 513 | main(int ac, char **av) |
492 | { | 514 | { |
493 | fd_set readset, writeset; | 515 | fd_set readset, writeset; |
494 | int sock; | 516 | int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; |
495 | struct sockaddr_un sunaddr; | 517 | struct sockaddr_un sunaddr; |
518 | pid_t pid; | ||
519 | char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; | ||
496 | 520 | ||
497 | /* check if RSA support exists */ | 521 | /* check if RSA support exists */ |
498 | if (rsa_alive() == 0) { | 522 | if (rsa_alive() == 0) { |
@@ -503,11 +527,66 @@ main(int ac, char **av) | |||
503 | exit(1); | 527 | exit(1); |
504 | } | 528 | } |
505 | 529 | ||
506 | if (ac < 2) | 530 | while ((ch = getopt(ac, av, "cks")) != -1) |
507 | { | 531 | { |
508 | fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); | 532 | switch (ch) |
509 | fprintf(stderr, "Usage: %s command\n", av[0]); | 533 | { |
510 | exit(1); | 534 | case 'c': |
535 | if (s_flag) | ||
536 | usage(); | ||
537 | c_flag++; | ||
538 | break; | ||
539 | case 'k': | ||
540 | k_flag++; | ||
541 | break; | ||
542 | case 's': | ||
543 | if (c_flag) | ||
544 | usage(); | ||
545 | s_flag++; | ||
546 | break; | ||
547 | default: | ||
548 | usage(); | ||
549 | } | ||
550 | } | ||
551 | ac -= optind; | ||
552 | av += optind; | ||
553 | |||
554 | if (ac > 0 && (c_flag || k_flag || s_flag)) | ||
555 | usage(); | ||
556 | |||
557 | if (ac == 0 && !c_flag && !k_flag && !s_flag) | ||
558 | { | ||
559 | shell = getenv("SHELL"); | ||
560 | if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) | ||
561 | c_flag = 1; | ||
562 | } | ||
563 | |||
564 | if (k_flag) | ||
565 | { | ||
566 | pidstr = getenv(SSH_AGENTPID_ENV_NAME); | ||
567 | if (pidstr == NULL) | ||
568 | { | ||
569 | fprintf(stderr, "%s not set, cannot kill agent\n", | ||
570 | SSH_AGENTPID_ENV_NAME); | ||
571 | exit(1); | ||
572 | } | ||
573 | pid = atoi(pidstr); | ||
574 | if (pid < 1) /* XXX PID_MAX check too */ | ||
575 | { | ||
576 | fprintf(stderr, "%s=\"%s\", which is not a good PID\n", | ||
577 | SSH_AGENTPID_ENV_NAME, pidstr); | ||
578 | exit(1); | ||
579 | } | ||
580 | if (kill(pid, SIGTERM) == -1) | ||
581 | { | ||
582 | perror("kill"); | ||
583 | exit(1); | ||
584 | } | ||
585 | format = c_flag ? "unsetenv %s;\n" : "unset %s;\n"; | ||
586 | printf(format, SSH_AUTHSOCKET_ENV_NAME); | ||
587 | printf(format, SSH_AGENTPID_ENV_NAME); | ||
588 | printf("echo Agent pid %d killed;\n", pid); | ||
589 | exit(0); | ||
511 | } | 590 | } |
512 | 591 | ||
513 | parent_pid = getpid(); | 592 | parent_pid = getpid(); |
@@ -518,38 +597,16 @@ main(int ac, char **av) | |||
518 | perror("mkdtemp: private socket dir"); | 597 | perror("mkdtemp: private socket dir"); |
519 | exit(1); | 598 | exit(1); |
520 | } | 599 | } |
521 | snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, parent_pid); | 600 | snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, |
522 | 601 | parent_pid); | |
523 | /* Fork, and have the parent execute the command. The child continues as | ||
524 | the authentication agent. */ | ||
525 | if (fork() != 0) | ||
526 | { /* Parent - execute the given command. */ | ||
527 | setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1); | ||
528 | execvp(av[1], av + 1); | ||
529 | perror(av[1]); | ||
530 | exit(1); | ||
531 | } | ||
532 | |||
533 | if (atexit(cleanup_socket) < 0) { | ||
534 | perror("atexit"); | ||
535 | cleanup_socket(); | ||
536 | exit(1); | ||
537 | } | ||
538 | |||
539 | /* Create a new session and process group */ | ||
540 | if (setsid() < 0) { | ||
541 | perror("setsid failed"); | ||
542 | exit(1); | ||
543 | } | ||
544 | |||
545 | /* Ignore if a client dies while we are sending a reply */ | ||
546 | signal(SIGPIPE, SIG_IGN); | ||
547 | 602 | ||
603 | /* Create socket early so it will exist before command gets run from | ||
604 | the parent. */ | ||
548 | sock = socket(AF_UNIX, SOCK_STREAM, 0); | 605 | sock = socket(AF_UNIX, SOCK_STREAM, 0); |
549 | if (sock < 0) | 606 | if (sock < 0) |
550 | { | 607 | { |
551 | perror("socket"); | 608 | perror("socket"); |
552 | exit(1); | 609 | cleanup_exit(1); |
553 | } | 610 | } |
554 | memset(&sunaddr, 0, sizeof(sunaddr)); | 611 | memset(&sunaddr, 0, sizeof(sunaddr)); |
555 | sunaddr.sun_family = AF_UNIX; | 612 | sunaddr.sun_family = AF_UNIX; |
@@ -557,18 +614,63 @@ main(int ac, char **av) | |||
557 | if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) | 614 | if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) |
558 | { | 615 | { |
559 | perror("bind"); | 616 | perror("bind"); |
560 | exit(1); | 617 | cleanup_exit(1); |
561 | } | 618 | } |
562 | if (listen(sock, 5) < 0) | 619 | if (listen(sock, 5) < 0) |
563 | { | 620 | { |
564 | perror("listen"); | 621 | perror("listen"); |
622 | cleanup_exit(1); | ||
623 | } | ||
624 | |||
625 | /* Fork, and have the parent execute the command, if any, or present the | ||
626 | socket data. The child continues as the authentication agent. */ | ||
627 | pid = fork(); | ||
628 | if (pid == -1) | ||
629 | { | ||
630 | perror("fork"); | ||
565 | exit(1); | 631 | exit(1); |
566 | } | 632 | } |
633 | if (pid != 0) | ||
634 | { /* Parent - execute the given command. */ | ||
635 | close(sock); | ||
636 | snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid); | ||
637 | if (ac == 0) | ||
638 | { | ||
639 | format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; | ||
640 | printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, | ||
641 | SSH_AUTHSOCKET_ENV_NAME); | ||
642 | printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, | ||
643 | SSH_AGENTPID_ENV_NAME); | ||
644 | printf("echo Agent pid %d;\n", pid); | ||
645 | exit(0); | ||
646 | } | ||
647 | |||
648 | setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1); | ||
649 | setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1); | ||
650 | execvp(av[0], av); | ||
651 | perror(av[0]); | ||
652 | exit(1); | ||
653 | } | ||
654 | |||
655 | close(0); | ||
656 | close(1); | ||
657 | close(2); | ||
658 | |||
659 | if (ac == 0 && setsid() == -1) | ||
660 | cleanup_exit(1); | ||
661 | |||
662 | if (atexit(cleanup_socket) < 0) | ||
663 | cleanup_exit(1); | ||
664 | |||
567 | new_socket(AUTH_SOCKET, sock); | 665 | new_socket(AUTH_SOCKET, sock); |
568 | signal(SIGALRM, check_parent_exists); | 666 | if (ac > 0) |
569 | alarm(10); | 667 | { |
668 | signal(SIGALRM, check_parent_exists); | ||
669 | alarm(10); | ||
670 | } | ||
570 | 671 | ||
571 | signal(SIGINT, SIG_IGN); | 672 | signal(SIGINT, SIG_IGN); |
673 | signal(SIGPIPE, SIG_IGN); | ||
572 | while (1) | 674 | while (1) |
573 | { | 675 | { |
574 | FD_ZERO(&readset); | 676 | FD_ZERO(&readset); |
@@ -578,7 +680,6 @@ main(int ac, char **av) | |||
578 | { | 680 | { |
579 | if (errno == EINTR) | 681 | if (errno == EINTR) |
580 | continue; | 682 | continue; |
581 | perror("select"); | ||
582 | exit(1); | 683 | exit(1); |
583 | } | 684 | } |
584 | after_select(&readset, &writeset); | 685 | after_select(&readset, &writeset); |