summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/ssh/ssh-agent.161
-rw-r--r--usr.bin/ssh/ssh-agent.c177
-rw-r--r--usr.bin/ssh/ssh.h6
3 files changed, 194 insertions, 50 deletions
diff --git a/usr.bin/ssh/ssh-agent.1 b/usr.bin/ssh/ssh-agent.1
index 286c9d94d61..8b9504fa5f5 100644
--- a/usr.bin/ssh/ssh-agent.1
+++ b/usr.bin/ssh/ssh-agent.1
@@ -1,16 +1,16 @@
+.\" $OpenBSD: ssh-agent.1,v 1.7 1999/10/28 08:43:10 markus Exp $
+.\"
.\" -*- nroff -*-
.\"
.\" ssh-agent.1
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
-.\"
+pp.\"
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
.\" All rights reserved
.\"
.\" Created: Sat Apr 23 20:10:43 1995 ylo
.\"
-.\" $Id: ssh-agent.1,v 1.6 1999/10/17 00:31:06 deraadt Exp $
-.\"
.Dd September 25, 1999
.Dt SSH-AGENT 1
.Os
@@ -19,22 +19,47 @@
.Nd authentication agent
.Sh SYNOPSIS
.Nm ssh-agent
+.Op Fl c Li | Fl s
+.Op Fl k
+.Oo
.Ar command
+.Op Ar args ...
+.Oc
.Sh DESCRIPTION
.Nm
is a program to hold authentication private keys. The
idea is that
.Nm
is started in the beginning of an X-session or a login session, and
-all other windows or programs are started as children of the ssh-agent
-program (the
-.Ar command
-normally starts X or is the user shell). Programs started under
-the agent inherit a connection to the agent, and the agent is
-automatically used for RSA authentication when logging to other
+all other windows or programs are started as clients to the ssh-agent
+program. Through use of environment variables the agent can be located
+and automatically used for RSA authentication when logging in to other
machines using
.Xr ssh 1 .
.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c
+Generate C-shell commands on
+.Dv stdout .
+This is the default if
+.Ev SHELL
+looks like it's a csh style of shell.
+.It Fl s
+Generate Bourne shell commands on
+.Dv stdout .
+This is the default if
+.Ev SHELL
+does not look like it's a csh style of shell.
+.It Fl k
+Kill the current agent (given by the
+.Ev SSH_AGENT_PID
+environment variable).
+.El
+.Pp
+If a commandline is given, this is executed as a subprocess of the agent.
+When the command dies, so does the agent.
+.Pp
The agent initially does not have any private keys. Keys are added
using
.Xr ssh-add 1 .
@@ -58,9 +83,19 @@ However, the connection to the agent is forwarded over SSH
remote logins, and the user can thus use the privileges given by the
identities anywhere in the network in a secure way.
.Pp
-A connection to the agent is inherited by child programs:
+There are two main ways to get an agent setup: Either you let the agent
+start a new subcommand into which some environment variables are exported, or
+you let the agent print the needed shell commands (either
+.Xr sh 1
+or
+.Xr csh 1
+syntax can be generated) which can be evalled in the calling shell.
+Later
+.Xr ssh 1
+look at these variables and use them to establish a connection to the agent.
+.Pp
A unix-domain socket is created
-.Pq Pa /tmp/ssh-XXXX/agent.<pid> ,
+.Pq Pa /tmp/ssh-XXXXXXXX/agent.<pid> ,
and the name of this socket is stored in the
.Ev SSH_AUTH_SOCK
environment
@@ -68,6 +103,10 @@ variable. The socket is made accessible only to the current user.
This method is easily abused by root or another instance of the same
user.
.Pp
+The
+.Ev SSH_AGENT_PID
+environment variable holds the agent's PID.
+.Pp
The agent exits automatically when the command given on the command
line terminates.
.Sh FILES
diff --git a/usr.bin/ssh/ssh-agent.c b/usr.bin/ssh/ssh-agent.c
index fbf02e3e875..d6f48740ca7 100644
--- a/usr.bin/ssh/ssh-agent.c
+++ b/usr.bin/ssh/ssh-agent.c
@@ -1,3 +1,5 @@
+/* $OpenBSD: ssh-agent.c,v 1.15 1999/10/28 08:43:10 markus Exp $ */
+
/*
ssh-agent.c
@@ -14,7 +16,7 @@ The authentication agent program.
*/
#include "includes.h"
-RCSID("$Id: ssh-agent.c,v 1.14 1999/10/27 23:34:53 markus Exp $");
+RCSID("$OpenBSD: ssh-agent.c,v 1.15 1999/10/28 08:43:10 markus Exp $");
#include "ssh.h"
#include "rsa.h"
@@ -476,17 +478,39 @@ check_parent_exists(int sig)
alarm(10);
}
-void cleanup_socket(void) {
+void
+cleanup_socket(void)
+{
remove(socket_name);
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
main(int ac, char **av)
{
fd_set readset, writeset;
- int sock;
+ int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
struct sockaddr_un sunaddr;
+ pid_t pid;
+ char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
/* check if RSA support exists */
if (rsa_alive() == 0) {
@@ -497,11 +521,66 @@ main(int ac, char **av)
exit(1);
}
- if (ac < 2)
+ while ((ch = getopt(ac, av, "cks")) != -1)
{
- fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
- fprintf(stderr, "Usage: %s command\n", av[0]);
- exit(1);
+ switch (ch)
+ {
+ 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();
@@ -512,38 +591,16 @@ main(int ac, char **av)
perror("mkdtemp: private socket dir");
exit(1);
}
- 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) {
- perror("atexit");
- 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);
+ snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
+ parent_pid);
+ /* Create socket early so it will exist before command gets run from
+ the parent. */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0)
{
perror("socket");
- exit(1);
+ cleanup_exit(1);
}
memset(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_UNIX;
@@ -551,18 +608,63 @@ main(int ac, char **av)
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
{
perror("bind");
- exit(1);
+ cleanup_exit(1);
}
if (listen(sock, 5) < 0)
{
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);
}
+ 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);
- signal(SIGALRM, check_parent_exists);
- alarm(10);
+ if (ac > 0)
+ {
+ signal(SIGALRM, check_parent_exists);
+ alarm(10);
+ }
signal(SIGINT, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
while (1)
{
FD_ZERO(&readset);
@@ -572,7 +674,6 @@ main(int ac, char **av)
{
if (errno == EINTR)
continue;
- perror("select");
exit(1);
}
after_select(&readset, &writeset);
diff --git a/usr.bin/ssh/ssh.h b/usr.bin/ssh/ssh.h
index 099ad20db79..e30f74d2fc6 100644
--- a/usr.bin/ssh/ssh.h
+++ b/usr.bin/ssh/ssh.h
@@ -13,7 +13,7 @@ Generic header file for ssh.
*/
-/* RCSID("$Id: ssh.h,v 1.14 1999/10/25 20:41:55 markus Exp $"); */
+/* RCSID("$Id: ssh.h,v 1.15 1999/10/28 08:43:10 markus Exp $"); */
#ifndef SSH_H
#define SSH_H
@@ -120,6 +120,10 @@ only by root, whereas ssh_config should be world-readable. */
authentication socket. */
#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK"
+/* Name of the environment variable containing the pathname of the
+ authentication socket. */
+#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID"
+
/* Force host key length and server key length to differ by at least this
many bits. This is to make double encryption with rsaref work. */
#define SSH_KEY_BITS_RESERVED 128