1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-02-01 16:33:02 +01:00

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>
This commit is contained in:
Werner Koch 2014-12-01 10:45:06 +01:00
parent eede0e59bf
commit 2f90b7c21b
2 changed files with 69 additions and 27 deletions

View File

@ -1525,8 +1525,8 @@ create_socket_name (char *standard_name, int with_homedir)
/* Create a Unix domain socket with NAME. Returns the file descriptor /* Create a Unix domain socket with NAME. Returns the file descriptor
or terminates the process in case of an error. Note that this or terminates the process in case of an error. Note that this
function needs to be used for the regular socket first (indicated function needs to be used for the regular socket first (indicated
by PRIMARY) and only then for the extra and the ssh sockets. if by PRIMARY) and only then for the extra and the ssh sockets. If
the soecket has been redirected the name of the real socket is the socket has been redirected the name of the real socket is
stored as a malloced string at R_REDIR_NAME. */ stored as a malloced string at R_REDIR_NAME. */
static gnupg_fd_t static gnupg_fd_t
create_server_socket (char *name, int primary, create_server_socket (char *name, int primary,

View File

@ -55,6 +55,9 @@
#include "asshelp.h" #include "asshelp.h"
#include "../common/init.h" #include "../common/init.h"
#ifndef ENAMETOOLONG
# define ENAMETOOLONG EINVAL
#endif
enum cmd_and_opt_values enum cmd_and_opt_values
{ aNull = 0, { aNull = 0,
@ -194,6 +197,8 @@ static int pipe_server;
/* Name of the communication socket */ /* Name of the communication socket */
static char *socket_name; 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 /* We need to keep track of the server's nonces (these are dummies for
POSIX systems). */ POSIX systems). */
@ -207,6 +212,7 @@ static int ticker_disabled;
static char *create_socket_name (char *standard_name); static char *create_socket_name (char *standard_name);
static gnupg_fd_t create_server_socket (const char *name, static gnupg_fd_t create_server_socket (const char *name,
char **r_redir_name,
assuan_sock_nonce_t *nonce); assuan_sock_nonce_t *nonce);
static void *start_connection_thread (void *arg); static void *start_connection_thread (void *arg);
@ -357,14 +363,17 @@ cleanup (void)
{ {
if (socket_name && *socket_name) if (socket_name && *socket_name)
{ {
char *name;
char *p; char *p;
remove (socket_name); name = redir_socket_name? redir_socket_name : socket_name;
p = strrchr (socket_name, '/');
gnupg_remove (name);
p = strrchr (name, '/');
if (p) if (p)
{ {
*p = 0; *p = 0;
rmdir (socket_name); rmdir (name);
*p = '/'; *p = '/';
} }
*socket_name = 0; *socket_name = 0;
@ -736,7 +745,8 @@ main (int argc, char **argv )
if (multi_server) if (multi_server)
{ {
socket_name = create_socket_name (SCDAEMON_SOCK_NAME); 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); res = npth_attr_init (&tattr);
@ -788,7 +798,8 @@ main (int argc, char **argv )
/* Create the socket. */ /* Create the socket. */
socket_name = create_socket_name (SCDAEMON_SOCK_NAME); 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); 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); log_error (("'%s' are not allowed in the socket name\n"), PATHSEP_S);
scd_exit (2); 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; return name;
} }
/* Create a Unix domain socket with NAME. Returns the file descriptor /* 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 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; socklen_t len;
gnupg_fd_t fd; gnupg_fd_t fd;
int rc; int rc;
xfree (*r_redir_name);
*r_redir_name = NULL;
fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0); fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
if (fd == GNUPG_INVALID_FD) if (fd == GNUPG_INVALID_FD)
{ {
@ -1052,26 +1065,55 @@ create_server_socket (const char *name, assuan_sock_nonce_t *nonce)
scd_exit (2); scd_exit (2);
} }
serv_addr = xmalloc (sizeof (*serv_addr)); unaddr = xmalloc (sizeof (*unaddr));
memset (serv_addr, 0, sizeof *serv_addr); addr = (struct sockaddr*)unaddr;
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);
rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len); #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, addr, len);
if (rc == -1 && errno == EADDRINUSE) if (rc == -1 && errno == EADDRINUSE)
{ {
remove (name); gnupg_remove (unaddr->sun_path);
rc = assuan_sock_bind (fd, (struct sockaddr*) serv_addr, len); rc = assuan_sock_bind (fd, addr, len);
} }
if (rc != -1 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")); log_error (_("error getting nonce for the socket\n"));
if (rc == -1) if (rc == -1)
{ {
log_error (_("error binding socket to '%s': %s\n"), log_error (_("error binding socket to '%s': %s\n"),
serv_addr->sun_path, unaddr->sun_path,
gpg_strerror (gpg_error_from_syserror ())); gpg_strerror (gpg_error_from_syserror ()));
assuan_sock_close (fd); assuan_sock_close (fd);
scd_exit (2); scd_exit (2);
@ -1086,7 +1128,7 @@ create_server_socket (const char *name, assuan_sock_nonce_t *nonce)
} }
if (opt.verbose) 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; return fd;
} }