version 1.14, 1999/10/27 23:34:53 |
version 1.15, 1999/10/28 08:43:10 |
|
|
|
/* $OpenBSD$ */ |
|
|
/* |
/* |
|
|
ssh-agent.c |
ssh-agent.c |
|
|
*/ |
*/ |
|
|
#include "includes.h" |
#include "includes.h" |
RCSID("$Id$"); |
RCSID("$OpenBSD$"); |
|
|
#include "ssh.h" |
#include "ssh.h" |
#include "rsa.h" |
#include "rsa.h" |
|
|
alarm(10); |
alarm(10); |
} |
} |
|
|
void cleanup_socket(void) { |
void |
|
cleanup_socket(void) |
|
{ |
remove(socket_name); |
remove(socket_name); |
rmdir(socket_dir); |
rmdir(socket_dir); |
} |
} |
|
|
|
void |
|
cleanup_exit(int i) |
|
{ |
|
cleanup_socket(); |
|
exit(i); |
|
} |
|
|
|
void |
|
usage() |
|
{ |
|
extern char *__progname; |
|
|
|
fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); |
|
fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n", |
|
__progname); |
|
exit(1); |
|
} |
|
|
int |
int |
main(int ac, char **av) |
main(int ac, char **av) |
{ |
{ |
fd_set readset, writeset; |
fd_set readset, writeset; |
int sock; |
int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch; |
struct sockaddr_un sunaddr; |
struct sockaddr_un sunaddr; |
|
pid_t pid; |
|
char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid]; |
|
|
/* check if RSA support exists */ |
/* check if RSA support exists */ |
if (rsa_alive() == 0) { |
if (rsa_alive() == 0) { |
|
|
exit(1); |
exit(1); |
} |
} |
|
|
if (ac < 2) |
while ((ch = getopt(ac, av, "cks")) != -1) |
{ |
{ |
fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); |
switch (ch) |
fprintf(stderr, "Usage: %s command\n", av[0]); |
{ |
exit(1); |
case 'c': |
|
if (s_flag) |
|
usage(); |
|
c_flag++; |
|
break; |
|
case 'k': |
|
k_flag++; |
|
break; |
|
case 's': |
|
if (c_flag) |
|
usage(); |
|
s_flag++; |
|
break; |
|
default: |
|
usage(); |
|
} |
} |
} |
|
ac -= optind; |
|
av += optind; |
|
|
|
if (ac > 0 && (c_flag || k_flag || s_flag)) |
|
usage(); |
|
|
|
if (ac == 0 && !c_flag && !k_flag && !s_flag) |
|
{ |
|
shell = getenv("SHELL"); |
|
if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) |
|
c_flag = 1; |
|
} |
|
|
|
if (k_flag) |
|
{ |
|
pidstr = getenv(SSH_AGENTPID_ENV_NAME); |
|
if (pidstr == NULL) |
|
{ |
|
fprintf(stderr, "%s not set, cannot kill agent\n", |
|
SSH_AGENTPID_ENV_NAME); |
|
exit(1); |
|
} |
|
pid = atoi(pidstr); |
|
if (pid < 1) /* XXX PID_MAX check too */ |
|
{ |
|
fprintf(stderr, "%s=\"%s\", which is not a good PID\n", |
|
SSH_AGENTPID_ENV_NAME, pidstr); |
|
exit(1); |
|
} |
|
if (kill(pid, SIGTERM) == -1) |
|
{ |
|
perror("kill"); |
|
exit(1); |
|
} |
|
format = c_flag ? "unsetenv %s;\n" : "unset %s;\n"; |
|
printf(format, SSH_AUTHSOCKET_ENV_NAME); |
|
printf(format, SSH_AGENTPID_ENV_NAME); |
|
printf("echo Agent pid %d killed;\n", pid); |
|
exit(0); |
|
} |
|
|
parent_pid = getpid(); |
parent_pid = getpid(); |
|
|
/* Create private directory for agent socket */ |
/* Create private directory for agent socket */ |
|
|
perror("mkdtemp: private socket dir"); |
perror("mkdtemp: private socket dir"); |
exit(1); |
exit(1); |
} |
} |
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, parent_pid); |
snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, |
|
parent_pid); |
/* Fork, and have the parent execute the command. The child continues as |
|
the authentication agent. */ |
|
if (fork() != 0) |
|
{ /* Parent - execute the given command. */ |
|
setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1); |
|
execvp(av[1], av + 1); |
|
perror(av[1]); |
|
exit(1); |
|
} |
|
|
|
if (atexit(cleanup_socket) < 0) { |
/* Create socket early so it will exist before command gets run from |
perror("atexit"); |
the parent. */ |
cleanup_socket(); |
|
exit(1); |
|
} |
|
|
|
/* Create a new session and process group */ |
|
if (setsid() < 0) { |
|
perror("setsid failed"); |
|
exit(1); |
|
} |
|
|
|
/* Ignore if a client dies while we are sending a reply */ |
|
signal(SIGPIPE, SIG_IGN); |
|
|
|
sock = socket(AF_UNIX, SOCK_STREAM, 0); |
sock = socket(AF_UNIX, SOCK_STREAM, 0); |
if (sock < 0) |
if (sock < 0) |
{ |
{ |
perror("socket"); |
perror("socket"); |
exit(1); |
cleanup_exit(1); |
} |
} |
memset(&sunaddr, 0, sizeof(sunaddr)); |
memset(&sunaddr, 0, sizeof(sunaddr)); |
sunaddr.sun_family = AF_UNIX; |
sunaddr.sun_family = AF_UNIX; |
|
|
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) |
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) |
{ |
{ |
perror("bind"); |
perror("bind"); |
exit(1); |
cleanup_exit(1); |
} |
} |
if (listen(sock, 5) < 0) |
if (listen(sock, 5) < 0) |
{ |
{ |
perror("listen"); |
perror("listen"); |
|
cleanup_exit(1); |
|
} |
|
|
|
/* Fork, and have the parent execute the command, if any, or present the |
|
socket data. The child continues as the authentication agent. */ |
|
pid = fork(); |
|
if (pid == -1) |
|
{ |
|
perror("fork"); |
exit(1); |
exit(1); |
} |
} |
|
if (pid != 0) |
|
{ /* Parent - execute the given command. */ |
|
close(sock); |
|
snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid); |
|
if (ac == 0) |
|
{ |
|
format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; |
|
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, |
|
SSH_AUTHSOCKET_ENV_NAME); |
|
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, |
|
SSH_AGENTPID_ENV_NAME); |
|
printf("echo Agent pid %d;\n", pid); |
|
exit(0); |
|
} |
|
|
|
setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1); |
|
setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1); |
|
execvp(av[0], av); |
|
perror(av[0]); |
|
exit(1); |
|
} |
|
|
|
close(0); |
|
close(1); |
|
close(2); |
|
|
|
if (ac == 0 && setsid() == -1) |
|
cleanup_exit(1); |
|
|
|
if (atexit(cleanup_socket) < 0) |
|
cleanup_exit(1); |
|
|
new_socket(AUTH_SOCKET, sock); |
new_socket(AUTH_SOCKET, sock); |
signal(SIGALRM, check_parent_exists); |
if (ac > 0) |
alarm(10); |
{ |
|
signal(SIGALRM, check_parent_exists); |
|
alarm(10); |
|
} |
|
|
signal(SIGINT, SIG_IGN); |
signal(SIGINT, SIG_IGN); |
|
signal(SIGPIPE, SIG_IGN); |
while (1) |
while (1) |
{ |
{ |
FD_ZERO(&readset); |
FD_ZERO(&readset); |
|
|
{ |
{ |
if (errno == EINTR) |
if (errno == EINTR) |
continue; |
continue; |
perror("select"); |
|
exit(1); |
exit(1); |
} |
} |
after_select(&readset, &writeset); |
after_select(&readset, &writeset); |