1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

2004-07-19 Moritz Schulte <moritz@g10code.com>

* Makefile.am (gpg_agent_SOURCES): Adding: gpg-stream.c,
	gpg-stream.h, buffer.c, buffer.h, command-ssh.c.

	* pksign.c (agent_pksign_do): New function, based on code ripped
	out from agent_pksign.
	(agent_pksign): Use agent_pksign_do.

	* query.c (start_pinentry): Accept CTRL being NULL.

	* agent.h (start_command_handler_ssh): Declare function.
	(agent_pksign_do): Declare function.
	(opt): New member: ssh_support.

	* gpg-agent.c: Include <sys/select.h>.
	New configuration option: ssh-support.
	(socket_name_ssh): New variabel.
	(handle_connections): Additional argument: listen_fd_ssh.  Accept
	connections on both sockets, call start_connection_thread_ssh for
	connections on listen_fd_ssh.
	(start_connection_thread_ssh): New function.
	(cleanup_do): New functions, basically old cleanup function.
	(cleanup): Call cleanup_do for socket_name and socket_name_ssh.
	(server_socket_create): New function ...
	(main): ... use it.
	(main): Generate environment entries for ssh.

	* command-ssh.c: New file, implementing the ssh-agent protocol.
	* gpg-stream.c, gpg-stream.h, buffer.c, buffer.h: Merged
	Libgpg-stream.
This commit is contained in:
Moritz Schulte 2004-07-19 15:54:11 +00:00
parent 6decea8316
commit 15664a8598
11 changed files with 3643 additions and 141 deletions

View file

@ -30,6 +30,7 @@
#include <time.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
@ -84,8 +85,8 @@ enum cmd_and_opt_values
oAllowMarkTrusted,
oKeepTTY,
oKeepDISPLAY,
aTest };
aTest,
oSSHSupport };
@ -131,6 +132,8 @@ static ARGPARSE_OPTS opts[] = {
N_("do not use the PIN cache when signing")},
{ oAllowMarkTrusted, "allow-mark-trusted", 0,
N_("allow clients to mark keys as \"trusted\"")},
{ oSSHSupport, "ssh-support", 0, "Enable SSH-Agent emulation" },
{0}
};
@ -149,6 +152,9 @@ static int maybe_setuid = 1;
/* Name of the communication socket */
static char socket_name[128];
/* Name of the communication socket used for ssh-agent-emulation. */
static char socket_name_ssh[128];
/* Default values for options passed to the pinentry. */
static char *default_display;
static char *default_ttyname;
@ -169,7 +175,7 @@ static char *current_logfile;
/* Local prototypes. */
static void create_directories (void);
#ifdef USE_GNU_PTH
static void handle_connections (int listen_fd);
static void handle_connections (int listen_fd, int listen_fd_ssh);
/* Pth wrapper function definitions. */
GCRY_THREAD_OPTION_PTH_IMPL;
@ -280,25 +286,30 @@ set_debug (void)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
}
static void
cleanup_do (char *name)
{
char *p = NULL;
remove (name);
p = strrchr (name, '/');
if (p)
{
*p = 0;
rmdir (name);
*p = '/';
}
*name = 0;
}
static void
cleanup (void)
{
if (*socket_name)
{
char *p;
remove (socket_name);
p = strrchr (socket_name, '/');
if (p)
{
*p = 0;
rmdir (socket_name);
*p = '/';
}
*socket_name = 0;
}
cleanup_do (socket_name);
if (*socket_name_ssh)
cleanup_do (socket_name_ssh);
}
@ -383,6 +394,76 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
return 1; /* handled */
}
static void
server_socket_create (int *sock,
const char *identifier, char *name, int name_size)
{
struct sockaddr_un serv_addr;
char *p = NULL;
int fd = -1;
socklen_t len;
*name = 0;
snprintf (name, name_size - 1,
"/tmp/gpg-XXXXXX/S.gpg-agent%s",
identifier ? identifier : "");
name[name_size - 1] = 0;
if (strchr (name, ':'))
{
log_error ("colons are not allowed in the socket name\n");
exit (1);
}
p = strrchr (name, '/');
if (! p)
BUG ();
*p = 0;;
if (! mkdtemp (name))
{
log_error ("can't create directory `%s': %s\n",
name, strerror (errno));
exit (1);
}
*p = '/';
if (strlen (name) + 1 >= sizeof (serv_addr.sun_path))
{
log_error ("name of socket too long\n");
exit (1);
}
fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
{
log_error ("can't create socket: %s\n", strerror (errno));
exit (1);
}
memset (&serv_addr, 0, sizeof serv_addr);
serv_addr.sun_family = AF_UNIX;
strcpy (serv_addr.sun_path, name);
len = (offsetof (struct sockaddr_un, sun_path)
+ strlen (serv_addr.sun_path) + 1);
if (bind (fd, (struct sockaddr*) &serv_addr, len) == -1)
{
log_error ("error binding socket to `%s': %s\n",
serv_addr.sun_path, strerror (errno));
close (fd);
exit (1);
}
if (listen (fd, 5) == -1)
{
log_error ("listen() failed: %s\n", strerror (errno));
close (fd);
exit (1);
}
*sock = fd;
}
int
main (int argc, char **argv )
@ -568,6 +649,12 @@ main (int argc, char **argv )
case oKeepTTY: opt.keep_tty = 1; break;
case oKeepDISPLAY: opt.keep_display = 1; break;
case oSSHSupport:
opt.ssh_support = 1;
opt.keep_tty = 1;
opt.keep_display = 1;
break;
default : pargs.err = configfp? 1:2; break;
}
}
@ -702,12 +789,10 @@ main (int argc, char **argv )
else if (!is_daemon)
;
else
{ /* regular server mode */
int fd;
{ /* regular server mode */
int fd = -1, fd_ssh = -1;
pid_t pid;
int len;
struct sockaddr_un serv_addr;
char *p;
//char *p;
/* Remove the DISPLAY variable so that a pinentry does not
default to a specific display. There is still a default
@ -716,65 +801,18 @@ main (int argc, char **argv )
if (!opt.keep_display)
unsetenv ("DISPLAY");
*socket_name = 0;
snprintf (socket_name, DIM(socket_name)-1,
"/tmp/gpg-XXXXXX/S.gpg-agent");
socket_name[DIM(socket_name)-1] = 0;
p = strrchr (socket_name, '/');
if (!p)
BUG ();
*p = 0;;
if (!mkdtemp(socket_name))
{
log_error ("can't create directory `%s': %s\n",
socket_name, strerror(errno) );
exit (1);
}
*p = '/';
server_socket_create (&fd, "", socket_name, sizeof (socket_name));
if (opt.ssh_support)
server_socket_create (&fd_ssh, "-ssh",
socket_name_ssh, sizeof (socket_name_ssh));
if (strchr (socket_name, ':') )
{
log_error ("colons are not allowed in the socket name\n");
exit (1);
}
if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
{
log_error ("name of socket too long\n");
exit (1);
}
fd = socket (AF_UNIX, SOCK_STREAM, 0);
if (fd == -1)
{
log_error ("can't create socket: %s\n", strerror(errno) );
exit (1);
}
memset (&serv_addr, 0, sizeof serv_addr);
serv_addr.sun_family = AF_UNIX;
strcpy (serv_addr.sun_path, socket_name);
len = (offsetof (struct sockaddr_un, sun_path)
+ strlen(serv_addr.sun_path) + 1);
if (bind (fd, (struct sockaddr*)&serv_addr, len) == -1)
{
log_error ("error binding socket to `%s': %s\n",
serv_addr.sun_path, strerror (errno) );
close (fd);
exit (1);
}
if (listen (fd, 5 ) == -1)
{
log_error ("listen() failed: %s\n", strerror (errno));
close (fd);
exit (1);
}
if (opt.verbose)
log_info ("listening on socket `%s'\n", socket_name );
{
log_info ("listening on socket `%s'\n", socket_name);
if (opt.ssh_support)
log_info ("listening on socket `%s'\n", socket_name_ssh);
}
fflush (NULL);
pid = fork ();
@ -785,9 +823,11 @@ main (int argc, char **argv )
}
else if (pid)
{ /* We are the parent */
char *infostr;
char *infostr, *infostr_ssh_sock, *infostr_ssh_pid;
close (fd);
if (opt.ssh_support)
close (fd_ssh);
/* create the info string: <name>:<pid>:<protocol_version> */
if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1",
@ -797,8 +837,28 @@ main (int argc, char **argv )
kill (pid, SIGTERM);
exit (1);
}
if (opt.ssh_support)
{
if (asprintf (&infostr_ssh_sock, "SSH_AUTH_SOCK=%s",
socket_name_ssh) < 0)
{
log_error ("out of core\n");
kill (pid, SIGTERM);
exit (1);
}
if (asprintf (&infostr_ssh_pid, "SSH_AGENT_PID=%u",
pid) < 0)
{
log_error ("out of core\n");
kill (pid, SIGTERM);
exit (1);
}
}
*socket_name = 0; /* don't let cleanup() remove the socket -
the child should do this from now on */
*socket_name_ssh = 0;
if (argc)
{ /* run the program given on the commandline */
if (putenv (infostr))
@ -808,6 +868,20 @@ main (int argc, char **argv )
kill (pid, SIGTERM );
exit (1);
}
if (putenv (infostr_ssh_sock))
{
log_error ("failed to set environment: %s\n",
strerror (errno) );
kill (pid, SIGTERM );
exit (1);
}
if (putenv (infostr_ssh_pid))
{
log_error ("failed to set environment: %s\n",
strerror (errno) );
kill (pid, SIGTERM );
exit (1);
}
execvp (argv[0], argv);
log_error ("failed to run the command: %s\n", strerror (errno));
kill (pid, SIGTERM);
@ -821,12 +895,29 @@ main (int argc, char **argv )
{
*strchr (infostr, '=') = ' ';
printf ( "setenv %s\n", infostr);
if (opt.ssh_support)
{
*strchr (infostr_ssh_sock, '=') = ' ';
printf ( "setenv %s\n", infostr_ssh_sock);
*strchr (infostr_ssh_pid, '=') = ' ';
printf ( "setenv %s\n", infostr_ssh_pid);
}
}
else
{
printf ( "%s; export GPG_AGENT_INFO;\n", infostr);
if (opt.ssh_support)
{
printf ( "%s; export SSH_AUTH_SOCK;\n", infostr_ssh_sock);
printf ( "%s; export SSH_AGENT_PID;\n", infostr_ssh_pid);
}
}
free (infostr);
if (opt.ssh_support)
{
free (infostr_ssh_sock);
free (infostr_ssh_pid);
}
exit (0);
}
/*NEVER REACHED*/
@ -877,7 +968,7 @@ main (int argc, char **argv )
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
sigaction (SIGPIPE, &sa, NULL);
handle_connections (fd);
handle_connections (fd, opt.ssh_support ? fd_ssh : -1);
}
else
#endif /*!USE_GNU_PTH*/
@ -903,7 +994,7 @@ main (int argc, char **argv )
}
close (fd);
}
return 0;
}
@ -1144,24 +1235,40 @@ start_connection_thread (void *arg)
return NULL;
}
static void *
start_connection_thread_ssh (void *arg)
{
int fd = (int)arg;
if (opt.verbose)
log_info ("ssh handler for fd %d started\n", fd);
/* FIXME: Move this housekeeping into a ticker function. Calling it
for each connection should work but won't work anymore if our
cleints start to keep connections. */
agent_trustlist_housekeeping ();
start_command_handler_ssh (fd);
if (opt.verbose)
log_info ("ssh handler for fd %d terminated\n", fd);
return NULL;
}
static void
handle_connections (int listen_fd)
handle_connections (int listen_fd, int listen_fd_ssh)
{
pth_attr_t tattr;
pth_event_t ev;
sigset_t sigs;
int signo;
struct sockaddr_un paddr;
socklen_t plen = sizeof( paddr );
pth_attr_t tattr;
fd_set fdset, read_fdset;
int ret = -1;
int fd;
tattr = pth_attr_new();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
sigemptyset (&sigs );
sigemptyset (&sigs);
sigaddset (&sigs, SIGHUP);
sigaddset (&sigs, SIGUSR1);
sigaddset (&sigs, SIGUSR2);
@ -1169,6 +1276,16 @@ handle_connections (int listen_fd)
sigaddset (&sigs, SIGTERM);
ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
tattr = pth_attr_new();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
FD_ZERO (&fdset);
FD_SET (listen_fd, &fdset);
if (listen_fd_ssh != -1)
FD_SET (listen_fd_ssh, &fdset);
for (;;)
{
if (shutdown_pending)
@ -1185,28 +1302,67 @@ handle_connections (int listen_fd)
continue;
}
fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
if (fd == -1)
{
#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */
if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
#else
if (pth_event_occurred (ev))
#endif
{
handle_signal (signo);
continue;
}
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
pth_sleep(1);
continue;
read_fdset = fdset;
ret = pth_select (FD_SETSIZE, &read_fdset, NULL, NULL, NULL);
if (ret == -1)
{
log_error ("pth_select failed: %s - waiting 1s\n",
strerror (errno));
pth_sleep (1);
continue;
}
if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
{
log_error ("error spawning connection handler: %s\n",
strerror (errno) );
close (fd);
if (FD_ISSET (listen_fd, &read_fdset))
{
fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
if (fd == -1)
{
#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */
if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
#else
if (pth_event_occurred (ev))
#endif
{
handle_signal (signo);
continue;
}
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
pth_sleep(1);
continue;
}
if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
{
log_error ("error spawning connection handler: %s\n",
strerror (errno) );
close (fd);
}
}
else if ((listen_fd_ssh != -1) && FD_ISSET (listen_fd_ssh, &read_fdset))
{
fd = pth_accept_ev (listen_fd_ssh, (struct sockaddr *)&paddr, &plen, ev);
if (fd == -1)
{
#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */
if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
#else
if (pth_event_occurred (ev))
#endif
{
handle_signal (signo);
continue;
}
log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
pth_sleep(1);
continue;
}
if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd))
{
log_error ("error spawning connection handler: %s\n",
strerror (errno) );
close (fd);
}
}
}