From 8a6d5d56ba09ddd8a8848bae490b84ef3ea2923d Mon Sep 17 00:00:00 2001 From: Sree Harsha Totakura Date: Sun, 9 Feb 2014 21:54:56 +0000 Subject: Create UNIX domain sockets as abstract sockets when running in LINUX and the option USE_ABSTRACT_SOCKETS is present in configuration. --- src/transport/plugin_transport_unix.c | 22 ++++++++++++++++++--- src/util/client.c | 17 ++++++++++++++-- src/util/connection.c | 10 ++++++++++ src/util/network.c | 29 ++++++++++++++++++--------- src/util/service.c | 37 ++++++++++++++++++++++++++--------- src/util/util.conf | 5 +++++ 6 files changed, 97 insertions(+), 23 deletions(-) diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c index 56e1de426..6c0a02e2c 100644 --- a/src/transport/plugin_transport_unix.c +++ b/src/transport/plugin_transport_unix.c @@ -384,7 +384,8 @@ unix_address_to_string (void *cls, const void *addr, size_t addrlen) static struct sockaddr_un * -unix_address_to_sockaddr (const char *unixpath, +unix_address_to_sockaddr (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *unixpath, socklen_t *sock_len) { struct sockaddr_un *un; @@ -398,6 +399,17 @@ unix_address_to_sockaddr (const char *unixpath, slen = sizeof (un->sun_path) - 1; memcpy (un->sun_path, unixpath, slen); un->sun_path[slen] = '\0'; +#ifdef LINUX + { + int abstract; + + abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, + "TESTING", + "USE_ABSTRACT_SOCKETS"); + if (GNUNET_YES == abstract) + un->sun_path[0] = '\0'; + } +#endif slen = sizeof (struct sockaddr_un); #if HAVE_SOCKADDR_IN_SIN_LEN un->sun_len = (u_char) slen; @@ -633,7 +645,9 @@ unix_real_send (void *cls, /* Prepare address */ unixpath = (const char *) &addr[1]; - if (NULL == (un = unix_address_to_sockaddr (unixpath, &un_len))) + if (NULL == (un = unix_address_to_sockaddr (plugin->env->cfg, + unixpath, + &un_len))) { GNUNET_break (0); return -1; @@ -1252,7 +1266,9 @@ unix_transport_server_start (void *cls) struct sockaddr_un *un; socklen_t un_len; - un = unix_address_to_sockaddr (plugin->unix_socket_path, &un_len); + un = unix_address_to_sockaddr (plugin->env->cfg, + plugin->unix_socket_path, + &un_len); plugin->ats_network = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) un, un_len); plugin->unix_sock.desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0); diff --git a/src/util/client.c b/src/util/client.c index ea3cc45f4..02bec5a8f 100644 --- a/src/util/client.c +++ b/src/util/client.c @@ -842,6 +842,7 @@ GNUNET_CLIENT_service_test (const char *service, /* probe UNIX support */ struct sockaddr_un s_un; char *unixpath; + int abstract; unixpath = NULL; if ((GNUNET_OK == @@ -862,17 +863,29 @@ GNUNET_CLIENT_service_test (const char *service, _("Using `%s' instead\n"), unixpath); } } - if (NULL != unixpath) +#ifdef LINUX + abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, + "TESTING", + "USE_ABSTRACT_SOCKETS"); +#else + abstract = GNUNET_NO; +#endif + if ((NULL != unixpath) && (GNUNET_YES != abstract)) { if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (unixpath)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, - "mkdir", unixpath); + "mkdir", unixpath); + } + if (NULL != unixpath) + { sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); if (NULL != sock) { memset (&s_un, 0, sizeof (s_un)); s_un.sun_family = AF_UNIX; strncpy (s_un.sun_path, unixpath, sizeof (s_un.sun_path) - 1); + if (GNUNET_YES == abstract) + s_un.sun_path[0] = '\0'; #if HAVE_SOCKADDR_IN_SIN_LEN s_un.sun_len = (u_char) sizeof (struct sockaddr_un); #endif diff --git a/src/util/connection.c b/src/util/connection.c index 39dad12c3..fb20617fd 100644 --- a/src/util/connection.c +++ b/src/util/connection.c @@ -832,6 +832,16 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct un = GNUNET_new (struct sockaddr_un); un->sun_family = AF_UNIX; strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1); +#ifdef LINUX + { + int abstract; + + abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING", + "USE_ABSTRACT_SOCKETS"); + if (GNUNET_YES == abstract) + un->sun_path[0] = '\0'; + } +#endif #if HAVE_SOCKADDR_IN_SIN_LEN un->sun_len = (u_char) sizeof (struct sockaddr_un); #endif diff --git a/src/util/network.c b/src/util/network.c index 2ee1a73a0..d321a7009 100644 --- a/src/util/network.c +++ b/src/util/network.c @@ -420,17 +420,23 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc, #endif #ifndef WINDOWS { - /* set permissions of newly created UNIX domain socket to "user-only"; applications - can choose to relax this later */ + /* set permissions of newly created non-abstract UNIX domain socket to + "user-only"; applications can choose to relax this later */ mode_t old_mask = 0; /* assigned to make compiler happy */ - - if (AF_UNIX == address->sa_family) + const struct sockaddr_un *un; + int not_abstract = 0; + + if ((AF_UNIX == address->sa_family) + && (NULL != (un = (const struct sockaddr_un *) address)->sun_path) + && ('\0' != un->sun_path[0]) ) /* Not an abstract socket */ + not_abstract = 1; + if (not_abstract) old_mask = umask (S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH | S_IXOTH); #endif ret = bind (desc->fd, address, address_len); #ifndef WINDOWS - if (AF_UNIX == address->sa_family) + if (not_abstract) (void) umask (old_mask); } #endif @@ -460,7 +466,7 @@ GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc) { int ret; -#ifdef MINGW +#ifdef WINDOWS DWORD error = 0; SetLastError (0); @@ -473,10 +479,15 @@ GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc) #else ret = close (desc->fd); #endif -#ifndef MINGW - if ((desc->af == AF_UNIX) && (NULL != desc->addr)) +#ifndef WINDOWS + const struct sockaddr_un *un; + + /* Cleanup the UNIX domain socket and its parent directories in case of non + abstract sockets */ + if ((AF_UNIX == desc->af) && (NULL != desc->addr) + && (NULL != (un = (const struct sockaddr_un *) desc->addr)->sun_path) + && ('\0' != un->sun_path[0])) { - const struct sockaddr_un *un = (const struct sockaddr_un *) desc->addr; char *dirname = GNUNET_strndup (un->sun_path, sizeof (un->sun_path)); diff --git a/src/util/service.c b/src/util/service.c index c03247a6d..deb0be46b 100644 --- a/src/util/service.c +++ b/src/util/service.c @@ -475,10 +475,13 @@ process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, struct GNUNET_SERVI * @param saddrs array to update * @param saddrlens where to store the address length * @param unixpath path to add + * @param abstract GNUNET_YES to add an abstract UNIX domain socket. This + * parameter is ignore on systems other than LINUX */ static void add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens, - const char *unixpath) + const char *unixpath, + int abstract) { #ifdef AF_UNIX struct sockaddr_un *un; @@ -486,6 +489,10 @@ add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens, un = GNUNET_new (struct sockaddr_un); un->sun_family = AF_UNIX; strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1); +#ifdef LINUX + if (GNUNET_YES == abstract) + un->sun_path[0] = '\0'; +#endif #if HAVE_SOCKADDR_IN_SIN_LEN un->sun_len = (u_char) sizeof (struct sockaddr_un); #endif @@ -536,6 +543,7 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, unsigned int i; int resi; int ret; + int abstract; struct sockaddr **saddrs; socklen_t *saddrlens; char *hostname; @@ -608,6 +616,7 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, hostname = NULL; unixpath = NULL; + abstract = GNUNET_NO; #ifdef AF_UNIX if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && @@ -628,8 +637,16 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, LOG (GNUNET_ERROR_TYPE_INFO, _("Using `%s' instead\n"), unixpath); } - if (GNUNET_OK != - GNUNET_DISK_directory_create_for_file (unixpath)) +#ifdef LINUX + abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, + "TESTING", + "USE_ABSTRACT_SOCKETS"); + if (GNUNET_SYSERR == abstract) + abstract = GNUNET_NO; +#endif + if ((GNUNET_YES != abstract) + && (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (unixpath))) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath); @@ -673,7 +690,7 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, { saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); - add_unixpath (saddrs, saddrlens, unixpath); + add_unixpath (saddrs, saddrlens, unixpath, abstract); GNUNET_free_non_null (unixpath); GNUNET_free_non_null (hostname); *addrs = saddrs; @@ -725,7 +742,7 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, i = 0; if (NULL != unixpath) { - add_unixpath (saddrs, saddrlens, unixpath); + add_unixpath (saddrs, saddrlens, unixpath, abstract); i++; } next = res; @@ -777,7 +794,7 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); if (NULL != unixpath) { - add_unixpath (saddrs, saddrlens, unixpath); + add_unixpath (saddrs, saddrlens, unixpath, abstract); i++; } saddrlens[i] = sizeof (struct sockaddr_in); @@ -799,7 +816,7 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, i = 0; if (NULL != unixpath) { - add_unixpath (saddrs, saddrlens, unixpath); + add_unixpath (saddrs, saddrlens, unixpath, abstract); i++; } saddrlens[i] = sizeof (struct sockaddr_in6); @@ -1168,7 +1185,8 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) #ifndef WINDOWS if (NULL != sctx->addrs) for (i = 0; NULL != sctx->addrs[i]; i++) - if (AF_UNIX == sctx->addrs[i]->sa_family) + if ((AF_UNIX == sctx->addrs[i]->sa_family) + && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0])) GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path, sctx->match_uid, sctx->match_gid); @@ -1589,7 +1607,8 @@ GNUNET_SERVICE_start (const char *service_name, #ifndef WINDOWS if (NULL != sctx->addrs) for (i = 0; NULL != sctx->addrs[i]; i++) - if (AF_UNIX == sctx->addrs[i]->sa_family) + if ((AF_UNIX == sctx->addrs[i]->sa_family) + && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0])) GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path, sctx->match_uid, sctx->match_gid); diff --git a/src/util/util.conf b/src/util/util.conf index 3df538f5d..1627b068a 100644 --- a/src/util/util.conf +++ b/src/util/util.conf @@ -49,3 +49,8 @@ PRIVATE_KEY = $GNUNET_DATA_HOME/private_key.ecc [TESTING] SPEEDUP_INTERVAL = 0 ms SPEEDUP_DELTA = 0 ms +# This following option is applicable to LINUX. Enabling this option causes all +# UNIX domain sockets to be opened as abstract sockets. Note that the +# filesystem level restrictions no longer apply for abstract sockets. An +# end-user should not modify this option. +USE_ABSTRACT_SOCKETS = NO -- cgit v1.2.3