summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2007-10-01 16:48:39 +0200
committerWerner Koch <wk@gnupg.org>2007-10-01 16:48:39 +0200
commit31c19d1d685b75377d9ff6dfbc9138ecbd5600b4 (patch)
treef6630bee0deef3ff050b3ca7dbb55e4951e34372 /agent
parentSupport the SETQUALITYBAR command of recent pinentries. (diff)
downloadgnupg2-31c19d1d685b75377d9ff6dfbc9138ecbd5600b4.tar.xz
gnupg2-31c19d1d685b75377d9ff6dfbc9138ecbd5600b4.zip
Use Assuan socket wrapper calls.
Made socket servers secure under Windows.
Diffstat (limited to 'agent')
-rw-r--r--agent/ChangeLog14
-rw-r--r--agent/agent.h11
-rw-r--r--agent/command-ssh.c7
-rw-r--r--agent/command.c7
-rw-r--r--agent/gpg-agent.c175
5 files changed, 121 insertions, 93 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index 2aa2c1375..7b46155fe 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,3 +1,17 @@
+2007-10-01 Werner Koch <wk@g10code.com>
+
+ * agent.h (struct server_control_s): Remove unused CONNECTION_FD.
+
+ * gpg-agent.c: Remove w32-afunix.h. Include mkdtemp.h.
+ (socket_nonce, socket_nonce_ssh): New.
+ (create_server_socket): Use assuan socket wrappers. Remove W32
+ specific stuff. Save the server nonce.
+ (check_nonce): New.
+ (start_connection_thread, start_connection_thread_ssh): Call it.
+ (handle_connections): Change args to gnupg_fd_t.
+ * command.c (start_command_handler): Change LISTEN_FD to gnupg_fd_t.
+ * command-ssh.c (start_command_handler_ssh): Ditto.
+
2007-09-18 Werner Koch <wk@g10code.com>
* agent.h (struct pin_entry_info_s): Add element WITH_QUALITYBAR.
diff --git a/agent/agent.h b/agent/agent.h
index 41b44c322..9648ac40a 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -32,7 +32,8 @@
#include <gcrypt.h>
#include "../common/util.h"
#include "../common/errors.h"
-#include "membuf.h"
+#include "../common/membuf.h"
+#include "../common/sysutils.h" /* (gnupg_fd_t) */
/* To convey some special hash algorithms we use algorithm numbers
reserved for application use. */
@@ -131,7 +132,7 @@ struct server_control_s
/* Private data used to fire up the connection thread. We use this
structure do avoid an extra allocation for just a few bytes. */
struct {
- int fd;
+ gnupg_fd_t fd;
} thread_startup;
/* Private data of the server (command.c). */
@@ -140,8 +141,6 @@ struct server_control_s
/* Private data of the SCdaemon (call-scd.c). */
struct scd_local_s *scd_local;
- int connection_fd; /* -1 or an identifier for the current connection. */
-
char *display;
char *ttyname;
char *ttytype;
@@ -209,10 +208,10 @@ void agent_sighup_action (void);
gpg_error_t agent_write_status (ctrl_t ctrl, const char *keyword, ...);
void bump_key_eventcounter (void);
void bump_card_eventcounter (void);
-void start_command_handler (ctrl_t, int, int);
+void start_command_handler (ctrl_t, gnupg_fd_t, gnupg_fd_t);
/*-- command-ssh.c --*/
-void start_command_handler_ssh (ctrl_t, int);
+void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
/*-- findkey.c --*/
int agent_write_private_key (const unsigned char *grip,
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 4fc9d4df5..6b5087830 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -2818,15 +2818,12 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock)
/* Start serving client on SOCK_CLIENT. */
void
-start_command_handler_ssh (ctrl_t ctrl, int sock_client)
+start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
{
estream_t stream_sock;
gpg_error_t err;
int ret;
- /* Setup control structure. */
- ctrl->connection_fd = sock_client;
-
/* Because the ssh protocol does not send us information about the
the current TTY setting, we resort here to use those from startup
or those explictly set. */
@@ -2843,7 +2840,7 @@ start_command_handler_ssh (ctrl_t ctrl, int sock_client)
/* Create stream from socket. */
- stream_sock = es_fdopen (sock_client, "r+");
+ stream_sock = es_fdopen (FD2INT(sock_client), "r+");
if (!stream_sock)
{
err = gpg_error_from_syserror ();
diff --git a/agent/command.c b/agent/command.c
index 431639b1c..b816fac3e 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1544,12 +1544,12 @@ register_commands (assuan_context_t ctx)
control structure for this connection; it has only the basic
intialization. */
void
-start_command_handler (ctrl_t ctrl, int listen_fd, int fd)
+start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
{
int rc;
assuan_context_t ctx;
- if (listen_fd == -1 && fd == -1)
+ if (listen_fd == GNUPG_INVALID_FD && fd == GNUPG_INVALID_FD)
{
int filedes[2];
@@ -1557,14 +1557,13 @@ start_command_handler (ctrl_t ctrl, int listen_fd, int fd)
filedes[1] = 1;
rc = assuan_init_pipe_server (&ctx, filedes);
}
- else if (listen_fd != -1)
+ else if (listen_fd != GNUPG_INVALID_FD)
{
rc = assuan_init_socket_server_ext (&ctx, listen_fd, 0);
}
else
{
rc = assuan_init_socket_server_ext (&ctx, fd, 2);
- ctrl->connection_fd = fd;
}
if (rc)
{
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 64424d975..ba98b38aa 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -40,13 +40,11 @@
#define JNLIB_NEED_LOG_LOGV
#include "agent.h"
-#include <assuan.h> /* Malloc hooks */
+#include <assuan.h> /* Malloc hooks and socket wrappers. */
#include "i18n.h"
+#include "mkdtemp.h" /* Gnulib replacement. */
#include "sysutils.h"
-#ifdef HAVE_W32_SYSTEM
-# include "../jnlib/w32-afunix.h"
-#endif
#include "setenv.h"
#include "gc-opt-flags.h"
@@ -207,6 +205,12 @@ static char *socket_name;
/* Name of the communication socket used for ssh-agent-emulation. */
static char *socket_name_ssh;
+/* We need to keep track of the server's nonces (these are dummies for
+ POSIX systems). */
+static assuan_sock_nonce_t socket_nonce;
+static assuan_sock_nonce_t socket_nonce_ssh;
+
+
/* Default values for options passed to the pinentry. */
static char *default_display;
static char *default_ttyname;
@@ -236,13 +240,15 @@ static pid_t parent_pid = (pid_t)(-1);
static char *create_socket_name (int use_standard_socket,
char *standard_name, char *template);
-static int create_server_socket (int is_standard_name, char *name);
+static gnupg_fd_t create_server_socket (int is_standard_name, char *name,
+ assuan_sock_nonce_t *nonce);
static void create_directories (void);
static void agent_init_default_ctrl (ctrl_t ctrl);
static void agent_deinit_default_ctrl (ctrl_t ctrl);
-static void handle_connections (int listen_fd, int listen_fd_ssh);
+static void handle_connections (gnupg_fd_t listen_fd,
+ gnupg_fd_t listen_fd_ssh);
static int check_for_running_agent (int silent, int mode);
/* Pth wrapper function definitions. */
@@ -845,7 +851,7 @@ main (int argc, char **argv )
agent_exit (1);
}
agent_init_default_ctrl (ctrl);
- start_command_handler (ctrl, -1, -1);
+ start_command_handler (ctrl, GNUPG_INVALID_FD, GNUPG_INVALID_FD);
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
}
@@ -853,8 +859,8 @@ main (int argc, char **argv )
; /* NOTREACHED */
else
{ /* Regular server mode */
- int fd;
- int fd_ssh;
+ gnupg_fd_t fd;
+ gnupg_fd_t fd_ssh;
pid_t pid;
/* Remove the DISPLAY variable so that a pinentry does not
@@ -878,11 +884,13 @@ main (int argc, char **argv )
"S.gpg-agent.ssh",
"/tmp/gpg-XXXXXX/S.gpg-agent.ssh");
- fd = create_server_socket (standard_socket, socket_name);
+ fd = create_server_socket (standard_socket, socket_name,
+ &socket_nonce);
if (opt.ssh_support)
- fd_ssh = create_server_socket (standard_socket, socket_name_ssh);
+ fd_ssh = create_server_socket (standard_socket, socket_name_ssh,
+ &socket_nonce_ssh);
else
- fd_ssh = -1;
+ fd_ssh = GNUPG_INVALID_FD;
/* If we are going to exec a program in the parent, we record
the PID, so that the child may check whether the program is
@@ -1079,8 +1087,8 @@ main (int argc, char **argv )
}
#endif /*!HAVE_W32_SYSTEM*/
- handle_connections (fd, opt.ssh_support ? fd_ssh : -1);
- close (fd);
+ handle_connections (fd, opt.ssh_support ? fd_ssh : GNUPG_INVALID_FD);
+ assuan_sock_close (fd);
}
return 0;
@@ -1109,8 +1117,6 @@ agent_exit (int rc)
static void
agent_init_default_ctrl (ctrl_t ctrl)
{
- ctrl->connection_fd = -1;
-
/* Note we ignore malloc errors because we can't do much about it
and the request will fail anyway shortly after this
initialization. */
@@ -1269,20 +1275,17 @@ create_socket_name (int use_standard_socket,
/* Create a Unix domain socket with NAME. IS_STANDARD_NAME indicates
whether a non-random socket is used. Returns the file descriptor or
terminates the process in case of an error. */
-static int
-create_server_socket (int is_standard_name, char *name)
+static gnupg_fd_t
+create_server_socket (int is_standard_name, char *name,
+ assuan_sock_nonce_t *nonce)
{
struct sockaddr_un *serv_addr;
socklen_t len;
- int fd;
+ gnupg_fd_t fd;
int rc;
-#ifdef HAVE_W32_SYSTEM
- fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
-#else
- fd = socket (AF_UNIX, SOCK_STREAM, 0);
-#endif
- if (fd == -1)
+ fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
+ if (fd == ASSUAN_INVALID_FD)
{
log_error (_("can't create socket: %s\n"), strerror (errno));
agent_exit (2);
@@ -1291,43 +1294,32 @@ create_server_socket (int is_standard_name, char *name)
serv_addr = xmalloc (sizeof (*serv_addr));
memset (serv_addr, 0, sizeof *serv_addr);
serv_addr->sun_family = AF_UNIX;
- assert (strlen (name) + 1 < sizeof (serv_addr->sun_path));
+ if (strlen (name) + 1 >= sizeof (serv_addr->sun_path))
+ {
+ log_error (_("socket name `%s' is too long\n"), name);
+ agent_exit (2);
+ }
strcpy (serv_addr->sun_path, name);
len = (offsetof (struct sockaddr_un, sun_path)
+ strlen (serv_addr->sun_path) + 1);
-#ifdef HAVE_W32_SYSTEM
- rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
- if (is_standard_name && rc == -1 && errno == WSAEADDRINUSE)
- {
- if (!check_for_running_agent (1, 1))
- {
- log_error (_("a gpg-agent is already running - "
- "not starting a new one\n"));
- *name = 0; /* Inhibit removal of the socket by cleanup(). */
- close (fd);
- agent_exit (2);
- }
-
- remove (name);
- rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
- }
-#else
- rc = bind (fd, (struct sockaddr*) serv_addr, len);
+ rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
if (is_standard_name && rc == -1 && errno == EADDRINUSE)
{
if (!check_for_running_agent (1, 1))
{
log_error (_("a gpg-agent is already running - "
- "not starting a new one\n"));
+ "not starting a new one\n"));
*name = 0; /* Inhibit removal of the socket by cleanup(). */
- close (fd);
+ assuan_sock_close (fd);
agent_exit (2);
}
remove (name);
- rc = bind (fd, (struct sockaddr*) serv_addr, len);
+ rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len);
}
-#endif
+ if (rc != -1
+ && (rc=assuan_sock_get_nonce ((struct sockaddr*)serv_addr, len, nonce)))
+ log_error (_("error getting nonce for the socket\n"));
if (rc == -1)
{
/* We use gpg_strerror here because it allows us to get strings
@@ -1336,16 +1328,16 @@ create_server_socket (int is_standard_name, char *name)
serv_addr->sun_path,
gpg_strerror (gpg_error_from_errno (errno)));
- close (fd);
+ assuan_sock_close (fd);
if (is_standard_name)
*name = 0; /* Inhibit removal of the socket by cleanup(). */
agent_exit (2);
}
- if (listen (fd, 5 ) == -1)
+ if (listen (FD2INT(fd), 5 ) == -1)
{
log_error (_("listen() failed: %s\n"), strerror (errno));
- close (fd);
+ assuan_sock_close (fd);
agent_exit (2);
}
@@ -1538,21 +1530,42 @@ handle_signal (int signo)
}
+/* Check the nonce on a new connection. This is a NOP unless we we
+ are using our Unix domain socket emulation under Windows. */
+static int
+check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
+{
+ if (assuan_sock_check_nonce (ctrl->thread_startup.fd, nonce))
+ {
+ log_info (_("error reading nonce on fd %d: %s\n"),
+ FD2INT(ctrl->thread_startup.fd), strerror (errno));
+ assuan_sock_close (ctrl->thread_startup.fd);
+ xfree (ctrl);
+ return -1;
+ }
+ else
+ return 0;
+}
+
+
/* This is the standard connection thread's main function. */
static void *
start_connection_thread (void *arg)
{
ctrl_t ctrl = arg;
+ if (check_nonce (ctrl, &socket_nonce))
+ return NULL;
+
agent_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("handler 0x%lx for fd %d started\n"),
- (long)pth_self (), ctrl->thread_startup.fd);
+ (long)pth_self (), FD2INT(ctrl->thread_startup.fd));
- start_command_handler (ctrl, -1, ctrl->thread_startup.fd);
+ start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
if (opt.verbose)
log_info (_("handler 0x%lx for fd %d terminated\n"),
- (long)pth_self (), ctrl->thread_startup.fd);
+ (long)pth_self (), FD2INT(ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
@@ -1566,15 +1579,18 @@ start_connection_thread_ssh (void *arg)
{
ctrl_t ctrl = arg;
+ if (check_nonce (ctrl, &socket_nonce_ssh))
+ return NULL;
+
agent_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d started\n"),
- (long)pth_self (), ctrl->thread_startup.fd);
+ (long)pth_self (), FD2INT(ctrl->thread_startup.fd));
start_command_handler_ssh (ctrl, ctrl->thread_startup.fd);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
- (long)pth_self (), ctrl->thread_startup.fd);
+ (long)pth_self (), FD2INT(ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
@@ -1585,7 +1601,7 @@ start_connection_thread_ssh (void *arg)
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. */
static void
-handle_connections (int listen_fd, int listen_fd_ssh)
+handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
{
pth_attr_t tattr;
pth_event_t ev, time_ev;
@@ -1595,7 +1611,7 @@ handle_connections (int listen_fd, int listen_fd_ssh)
socklen_t plen;
fd_set fdset, read_fdset;
int ret;
- int fd;
+ gnupg_fd_t fd;
int nfd;
tattr = pth_attr_new();
@@ -1620,13 +1636,13 @@ handle_connections (int listen_fd, int listen_fd_ssh)
time_ev = NULL;
FD_ZERO (&fdset);
- FD_SET (listen_fd, &fdset);
- nfd = listen_fd;
- if (listen_fd_ssh != -1)
+ FD_SET (FD2INT (listen_fd), &fdset);
+ nfd = FD2INT (listen_fd);
+ if (listen_fd_ssh != GNUPG_INVALID_FD)
{
- FD_SET (listen_fd_ssh, &fdset);
- if (listen_fd_ssh > nfd)
- nfd = listen_fd_ssh;
+ FD_SET ( FD2INT(listen_fd_ssh), &fdset);
+ if (FD2INT (listen_fd_ssh) > nfd)
+ nfd = FD2INT (listen_fd_ssh);
}
for (;;)
@@ -1701,13 +1717,14 @@ handle_connections (int listen_fd, int listen_fd_ssh)
new thread. Thus we need to block those signals. */
pth_sigmask (SIG_BLOCK, &sigs, &oldsigs);
- if (FD_ISSET (listen_fd, &read_fdset))
+ if (FD_ISSET (FD2INT (listen_fd), &read_fdset))
{
ctrl_t ctrl;
plen = sizeof paddr;
- fd = pth_accept (listen_fd, (struct sockaddr *)&paddr, &plen);
- if (fd == -1)
+ fd = INT2FD (pth_accept (FD2INT(listen_fd),
+ (struct sockaddr *)&paddr, &plen));
+ if (fd == GNUPG_INVALID_FD)
{
log_error ("accept failed: %s\n", strerror (errno));
}
@@ -1715,14 +1732,14 @@ handle_connections (int listen_fd, int listen_fd_ssh)
{
log_error ("error allocating connection control data: %s\n",
strerror (errno) );
- close (fd);
+ assuan_sock_close (fd);
}
else
{
char threadname[50];
snprintf (threadname, sizeof threadname-1,
- "conn fd=%d (gpg)", fd);
+ "conn fd=%d (gpg)", FD2INT(fd));
threadname[sizeof threadname -1] = 0;
pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
ctrl->thread_startup.fd = fd;
@@ -1730,20 +1747,22 @@ handle_connections (int listen_fd, int listen_fd_ssh)
{
log_error ("error spawning connection handler: %s\n",
strerror (errno) );
- close (fd);
+ assuan_sock_close (fd);
xfree (ctrl);
}
}
- fd = -1;
+ fd = GNUPG_INVALID_FD;
}
- if (listen_fd_ssh != -1 && FD_ISSET (listen_fd_ssh, &read_fdset))
+ if (listen_fd_ssh != GNUPG_INVALID_FD
+ && FD_ISSET ( FD2INT (listen_fd_ssh), &read_fdset))
{
ctrl_t ctrl;
plen = sizeof paddr;
- fd = pth_accept (listen_fd_ssh, (struct sockaddr *)&paddr, &plen);
- if (fd == -1)
+ fd = INT2FD(pth_accept (FD2INT(listen_fd_ssh),
+ (struct sockaddr *)&paddr, &plen));
+ if (fd == GNUPG_INVALID_FD)
{
log_error ("accept failed for ssh: %s\n", strerror (errno));
}
@@ -1751,7 +1770,7 @@ handle_connections (int listen_fd, int listen_fd_ssh)
{
log_error ("error allocating connection control data: %s\n",
strerror (errno) );
- close (fd);
+ assuan_sock_close (fd);
}
else
{
@@ -1759,7 +1778,7 @@ handle_connections (int listen_fd, int listen_fd_ssh)
agent_init_default_ctrl (ctrl);
snprintf (threadname, sizeof threadname-1,
- "conn fd=%d (ssh)", fd);
+ "conn fd=%d (ssh)", FD2INT(fd));
threadname[sizeof threadname -1] = 0;
pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
ctrl->thread_startup.fd = fd;
@@ -1767,11 +1786,11 @@ handle_connections (int listen_fd, int listen_fd_ssh)
{
log_error ("error spawning ssh connection handler: %s\n",
strerror (errno) );
- close (fd);
+ assuan_sock_close (fd);
xfree (ctrl);
}
}
- fd = -1;
+ fd = GNUPG_INVALID_FD;
}
/* Restore the signal mask. */