diff options
author | Werner Koch <wk@gnupg.org> | 2014-12-01 10:45:06 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2014-12-01 10:45:06 +0100 |
commit | 2f90b7c21b2f84ca2bf5f4555da9233e84606b4e (patch) | |
tree | 13b6df2c24b8c46f1377e6cd65dcaad3c2478986 /scd | |
parent | dirmngr: Implement socket redirection. (diff) | |
download | gnupg2-2f90b7c21b2f84ca2bf5f4555da9233e84606b4e.tar.xz gnupg2-2f90b7c21b2f84ca2bf5f4555da9233e84606b4e.zip |
scd: Implement socket redirection.
* scd/scdaemon.c (ENAMETOOLONG): New.
(redir_socket_name): New.
(cleanup): Take care of a redirected socket.
(main): Pass redir_socket_name to create_server_socket.
(create_socket_name): Remove superfluous length check.
(create_server_socket): Add arg r_redir_name and implement
redirection. Replace assert for older Assuan by an error message.
Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'scd')
-rw-r--r-- | scd/scdaemon.c | 92 |
1 files changed, 67 insertions, 25 deletions
diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 77b6283e9..763ce2d90 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -55,6 +55,9 @@ #include "asshelp.h" #include "../common/init.h" +#ifndef ENAMETOOLONG +# define ENAMETOOLONG EINVAL +#endif enum cmd_and_opt_values { aNull = 0, @@ -194,6 +197,8 @@ static int pipe_server; /* Name of the communication socket */ static char *socket_name; +/* Name of the redirected socket or NULL. */ +static char *redir_socket_name; /* We need to keep track of the server's nonces (these are dummies for POSIX systems). */ @@ -207,6 +212,7 @@ static int ticker_disabled; static char *create_socket_name (char *standard_name); static gnupg_fd_t create_server_socket (const char *name, + char **r_redir_name, assuan_sock_nonce_t *nonce); static void *start_connection_thread (void *arg); @@ -357,14 +363,17 @@ cleanup (void) { if (socket_name && *socket_name) { + char *name; char *p; - remove (socket_name); - p = strrchr (socket_name, '/'); + name = redir_socket_name? redir_socket_name : socket_name; + + gnupg_remove (name); + p = strrchr (name, '/'); if (p) { *p = 0; - rmdir (socket_name); + rmdir (name); *p = '/'; } *socket_name = 0; @@ -736,7 +745,8 @@ main (int argc, char **argv ) if (multi_server) { socket_name = create_socket_name (SCDAEMON_SOCK_NAME); - fd = FD2INT(create_server_socket (socket_name, &socket_nonce)); + fd = FD2INT(create_server_socket (socket_name, + &redir_socket_name, &socket_nonce)); } res = npth_attr_init (&tattr); @@ -788,7 +798,8 @@ main (int argc, char **argv ) /* Create the socket. */ socket_name = create_socket_name (SCDAEMON_SOCK_NAME); - fd = FD2INT (create_server_socket (socket_name, &socket_nonce)); + fd = FD2INT (create_server_socket (socket_name, + &redir_socket_name, &socket_nonce)); fflush (NULL); @@ -1025,26 +1036,28 @@ create_socket_name (char *standard_name) log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S); scd_exit (2); } - if (strlen (name) + 1 >= DIMof (struct sockaddr_un, sun_path) ) - { - log_error (_("name of socket too long\n")); - scd_exit (2); - } return name; } /* Create a Unix domain socket with NAME. Returns the file descriptor - or terminates the process in case of an error. */ + or terminates the process in case of an error. If the socket has + been redirected the name of the real socket is stored as a malloced + string at R_REDIR_NAME. */ static gnupg_fd_t -create_server_socket (const char *name, assuan_sock_nonce_t *nonce) +create_server_socket (const char *name, char **r_redir_name, + assuan_sock_nonce_t *nonce) { - struct sockaddr_un *serv_addr; + struct sockaddr *addr; + struct sockaddr_un *unaddr; socklen_t len; gnupg_fd_t fd; int rc; + xfree (*r_redir_name); + *r_redir_name = NULL; + fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0); if (fd == GNUPG_INVALID_FD) { @@ -1052,26 +1065,55 @@ create_server_socket (const char *name, assuan_sock_nonce_t *nonce) scd_exit (2); } - 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)); - strcpy (serv_addr->sun_path, name); - len = SUN_LEN (serv_addr); + unaddr = xmalloc (sizeof (*unaddr)); + addr = (struct sockaddr*)unaddr; + +#if ASSUAN_VERSION_NUMBER >= 0x020104 /* >= 2.1.4 */ + { + int redirected; + + if (assuan_sock_set_sockaddr_un (name, addr, &redirected)) + { + if (errno == ENAMETOOLONG) + log_error (_("socket name '%s' is too long\n"), name); + else + log_error ("error preparing socket '%s': %s\n", + name, gpg_strerror (gpg_error_from_syserror ())); + scd_exit (2); + } + if (redirected) + { + *r_redir_name = xstrdup (unaddr->sun_path); + if (opt.verbose) + log_info ("redirecting socket '%s' to '%s'\n", name, *r_redir_name); + } + } +#else /* Assuan < 2.1.4 */ + memset (unaddr, 0, sizeof *unaddr); + unaddr->sun_family = AF_UNIX; + if (strlen (name) + 1 >= sizeof (unaddr->sun_path)) + { + log_error (_("socket name '%s' is too long\n"), name); + scd_exit (2); + } + strcpy (unaddr->sun_path, name); +#endif /* Assuan < 2.1.4 */ + + len = SUN_LEN (unaddr); - rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len); + rc = assuan_sock_bind (fd, addr, len); if (rc == -1 && errno == EADDRINUSE) { - remove (name); - rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len); + gnupg_remove (unaddr->sun_path); + rc = assuan_sock_bind (fd, addr, len); } if (rc != -1 - && (rc=assuan_sock_get_nonce ((struct sockaddr*)serv_addr, len, nonce))) + && (rc=assuan_sock_get_nonce (addr, len, nonce))) log_error (_("error getting nonce for the socket\n")); if (rc == -1) { log_error (_("error binding socket to '%s': %s\n"), - serv_addr->sun_path, + unaddr->sun_path, gpg_strerror (gpg_error_from_syserror ())); assuan_sock_close (fd); scd_exit (2); @@ -1086,7 +1128,7 @@ create_server_socket (const char *name, assuan_sock_nonce_t *nonce) } if (opt.verbose) - log_info (_("listening on socket '%s'\n"), serv_addr->sun_path); + log_info (_("listening on socket '%s'\n"), unaddr->sun_path); return fd; } |