diff -uprk.orig openssh-3.6.1p1.orig/ssh-agent.1 openssh-3.6.1p1/ssh-agent.1 --- openssh-3.6.1p1.orig/ssh-agent.1 2003-04-01 15:42:14 +0400 +++ openssh-3.6.1p1/ssh-agent.1 2003-04-11 19:09:40 +0400 @@ -45,6 +45,7 @@ .Op Fl a Ar bind_address .Op Fl c Li | Fl s .Op Fl t Ar life +.Op Fl u .Op Fl d .Op Ar command Op Ar args ... .Nm ssh-agent @@ -95,6 +96,8 @@ A lifetime specified for an identity wit .Xr ssh-add 1 overrides this value. Without this option the default maximum lifetime is forever. +.It Fl u +Run the agent in unique mode. .It Fl d Debug mode. When this option is specified @@ -174,6 +177,7 @@ Contains the protocol version 2 DSA auth .It Pa $HOME/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of the user. .It Pa /tmp/ssh-XXXXXXXX/agent. +.It Pa ~/.ssh/agent Unix-domain sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. diff -uprk.orig openssh-3.6.1p1.orig/ssh-agent.c openssh-3.6.1p1/ssh-agent.c --- openssh-3.6.1p1.orig/ssh-agent.c 2003-04-11 18:58:18 +0400 +++ openssh-3.6.1p1/ssh-agent.c 2003-04-11 19:19:53 +0400 @@ -971,6 +971,30 @@ check_parent_exists(int sig) errno = save_errno; } +static int +check_auth_socket(const char *authsocket) +{ + int sock, len, ret; + struct sockaddr_un sunaddr; + + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); +#ifdef HAVE_SUN_LEN_IN_SOCKADDR_UN + sunaddr.sun_len = len = SUN_LEN(&sunaddr)+1; +#else /* HAVE_SUN_LEN_IN_SOCKADDR_UN */ + len = SUN_LEN(&sunaddr)+1; +#endif /* HAVE_SUN_LEN_IN_SOCKADDR_UN */ + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + ret = connect(sock, (struct sockaddr *) & sunaddr, len); + close(sock); + + return ret; +} + static void usage(void) { @@ -980,6 +1004,7 @@ usage(void) fprintf(stderr, " -c Generate C-shell commands on stdout.\n"); fprintf(stderr, " -s Generate Bourne shell commands on stdout.\n"); fprintf(stderr, " -k Kill the current agent.\n"); + fprintf(stderr, " -u Unique mode.\n"); fprintf(stderr, " -d Debug mode.\n"); fprintf(stderr, " -a socket Bind agent socket to given name.\n"); fprintf(stderr, " -t life Default identity lifetime (seconds).\n"); @@ -989,7 +1014,7 @@ usage(void) int main(int ac, char **av) { - int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0; + int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, u_flag = 0, already_running = 0; int sock, fd, ch, nalloc; char *shell, *format, *pidstr, *agentsocket = NULL; fd_set *readsetp = NULL, *writesetp = NULL; @@ -997,13 +1022,10 @@ main(int ac, char **av) #ifdef HAVE_SETRLIMIT struct rlimit rlim; #endif -#ifdef HAVE_CYGWIN int prev_mask; -#endif extern int optind; extern char *optarg; pid_t pid; - char pidstrbuf[1 + 3 * sizeof pid]; /* drop */ setegid(getgid()); @@ -1027,7 +1049,7 @@ main(int ac, char **av) init_rng(); seed_rng(); - while ((ch = getopt(ac, av, "cdksa:t:")) != -1) { + while ((ch = getopt(ac, av, "cdksua:t:")) != -1) { switch (ch) { case 'c': if (s_flag) @@ -1042,6 +1064,9 @@ main(int ac, char **av) usage(); s_flag++; break; + case 'u': + u_flag++; + break; case 'd': if (d_flag) usage(); @@ -1063,7 +1088,10 @@ main(int ac, char **av) ac -= optind; av += optind; - if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) + if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || u_flag)) + usage(); + + if (u_flag && (k_flag || agentsocket)) usage(); if (ac == 0 && !c_flag && !s_flag) { @@ -1074,19 +1102,16 @@ main(int ac, char **av) 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); + fatal("%s: %s not set, cannot kill agent", + __progname, SSH_AGENTPID_ENV_NAME); } pid = atoi(pidstr); if (pid < 1) { - fprintf(stderr, "%s=\"%s\", which is not a good PID\n", - SSH_AGENTPID_ENV_NAME, pidstr); - exit(1); + fatal("%s: %s=\"%s\", which is not a good PID", + __progname, SSH_AGENTPID_ENV_NAME, pidstr); } if (kill(pid, SIGTERM) == -1) { - perror("kill"); - exit(1); + fatal("%s: kill: %s", __progname, strerror(errno)); } format = c_flag ? "unsetenv %s;\n" : "unset %s;\n"; printf(format, SSH_AUTHSOCKET_ENV_NAME); @@ -1096,12 +1121,17 @@ main(int ac, char **av) } parent_pid = getpid(); - if (agentsocket == NULL) { + if (u_flag) { + struct passwd *pw = getpwuid(geteuid()); + if (!pw) + fatal("%s: getpwuid: %s", __progname, strerror(errno)); + snprintf(socket_name, sizeof socket_name, "%s/.ssh/agent", pw->pw_dir); + } + else if (agentsocket == NULL) { /* Create private directory for agent socket */ strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir); if (mkdtemp(socket_dir) == NULL) { - perror("mkdtemp: private socket dir"); - exit(1); + fatal("%s: mkdtemp: private socket dir: %s", __progname, strerror(errno)); } snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir, (long)parent_pid); @@ -1117,27 +1147,51 @@ main(int ac, char **av) */ sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { - perror("socket"); + error("%s: socket: %s", __progname, strerror(errno)); cleanup_exit(1); } memset(&sunaddr, 0, sizeof(sunaddr)); sunaddr.sun_family = AF_UNIX; strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path)); -#ifdef HAVE_CYGWIN prev_mask = umask(0177); -#endif if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) { - perror("bind"); -#ifdef HAVE_CYGWIN - umask(prev_mask); -#endif - cleanup_exit(1); + if (u_flag && (EADDRINUSE == errno)) { + if (check_auth_socket(socket_name) >= 0) + already_running = 1; + else { + unlink(socket_name); + if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) { + error("%s: bind: %s: %s", __progname, socket_name, strerror(errno)); + cleanup_exit(1); + } + } + } + else { + error("%s: bind: %s: %s", __progname, socket_name, strerror(errno)); + cleanup_exit(1); + } } -#ifdef HAVE_CYGWIN umask(prev_mask); -#endif + + if (already_running) { + close(sock); + 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); + exit(0); + } + if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) < 0) { + error("%s: setenv: %s", __progname, strerror(errno)); + exit(1); + } + execvp(av[0], av); + perror(av[0]); + exit(1); + } + if (listen(sock, 128) < 0) { - perror("listen"); + error("%s: listen: %s", __progname, strerror(errno)); cleanup_exit(1); } @@ -1155,10 +1209,11 @@ main(int ac, char **av) } pid = fork(); if (pid == -1) { - perror("fork"); + error("%s: fork: %s", __progname, strerror(errno)); cleanup_exit(1); } if (pid != 0) { /* Parent - execute the given command. */ + char pidstrbuf[1 + 3 * sizeof pid]; close(sock); snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid); if (ac == 0) { @@ -1172,8 +1227,7 @@ main(int ac, char **av) } if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 || setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) { - perror("setenv"); - exit(1); + fatal("%s: setenv: %s", __progname, strerror(errno)); } log_done(); execvp(av[0], av); @@ -1210,7 +1264,7 @@ main(int ac, char **av) skip: fatal_add_cleanup(cleanup_socket, NULL); new_socket(AUTH_SOCKET, sock); - if (ac > 0) { + if (!u_flag && ac > 0) { signal(SIGALRM, check_parent_exists); alarm(10); }