diff options
author | Werner Koch <wk@gnupg.org> | 2007-10-01 16:48:39 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2007-10-01 16:48:39 +0200 |
commit | 31c19d1d685b75377d9ff6dfbc9138ecbd5600b4 (patch) | |
tree | f6630bee0deef3ff050b3ca7dbb55e4951e34372 /agent | |
parent | Support the SETQUALITYBAR command of recent pinentries. (diff) | |
download | gnupg2-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/ChangeLog | 14 | ||||
-rw-r--r-- | agent/agent.h | 11 | ||||
-rw-r--r-- | agent/command-ssh.c | 7 | ||||
-rw-r--r-- | agent/command.c | 7 | ||||
-rw-r--r-- | agent/gpg-agent.c | 175 |
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. */ |