From: Christian Grothoff Date: Mon, 24 Jan 2011 12:03:32 +0000 (+0000) Subject: UNIX domain socket authentication support added X-Git-Tag: initial-import-from-subversion-38251~19278 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=48718834d4fb6c411ff5b00b86662a3dee3ac6cc;p=oweals%2Fgnunet.git UNIX domain socket authentication support added --- diff --git a/TODO b/TODO index afd45f091..6b3a2230b 100644 --- a/TODO +++ b/TODO @@ -7,13 +7,13 @@ + implement UDP, HTTP/HTTPS * Transport: - UDP fragmentation -* UTIL / FS: - - gnunet-publish tires to connect to service even if - run with 'simulation' option (-s) * DHT: [Nate] - track paths content travels (PUT, reply-to-get) in messages, pass to client (client API & protocol already support this!) * FS: [CG] + - gnunet-publish tires to connect to service even if + run with 'simulation' option (-s) + - gnunet-download does not *always* use inline full data (?) - implement multi-peer FS performance tests + insert + download @@ -65,8 +65,6 @@ - Remove KBlocks in gnunet-unindex (see discussion with Kenneth Almquist on gnunet-devs in 9/2009) - use different queue prioritization for probe-downloads vs. normal downloads - re-implement gnunet-auto-share -* UTIL: [CG] - - allow limiting UNIX socket access by UID/GID * GNUNET-GTK: [CG] - add tool bar - do meaningful update to status line (starting up, peer running, #connections, shutdown, ...) diff --git a/configure.ac b/configure.ac index a57030a5c..7938ff1d8 100644 --- a/configure.ac +++ b/configure.ac @@ -293,7 +293,7 @@ AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h math.h errno.h ctype.h limits.h stdio.h stdlib.h string.h unistd.h stdarg.h signal.h locale.h sys/stat.h sys/types.h],,AC_MSG_ERROR([Compiling GNUnet requires standard UNIX headers files])) # Checks for headers that are only required on some systems or opional (and where we do NOT abort if they are not there) -AC_CHECK_HEADERS([langinfo.h sys/param.h sys/mount.h sys/statvfs.h sys/select.h sockLib.h sys/mman.h sys/msg.h sys/vfs.h arpa/inet.h fcntl.h libintl.h netdb.h netinet/in.h netinet/in_systm.h sys/ioctl.h sys/socket.h sys/time.h unistd.h kstat.h sys/sysinfo.h kvm.h sys/file.h sys/resource.h ifaddrs.h mach/mach.h stddef.h sys/timeb.h terminos.h argz.h]) +AC_CHECK_HEADERS([langinfo.h sys/param.h sys/mount.h sys/statvfs.h sys/select.h sockLib.h sys/mman.h sys/msg.h sys/vfs.h arpa/inet.h fcntl.h libintl.h netdb.h netinet/in.h netinet/in_systm.h sys/ioctl.h sys/socket.h sys/time.h unistd.h kstat.h sys/sysinfo.h kvm.h sys/file.h sys/resource.h ifaddrs.h mach/mach.h stddef.h sys/timeb.h terminos.h argz.h ucred.h]) SAVE_LDFLAGS=$LDFLAGS SAVE_CPPFLAGS=$CPPFLAGS @@ -664,7 +664,7 @@ AC_FUNC_VPRINTF AC_HEADER_SYS_WAIT AC_TYPE_OFF_T AC_TYPE_UID_T -AC_CHECK_FUNCS([floor gethostname memmove rmdir strncasecmp strrchr strtol atoll dup2 fdatasync ftruncate gettimeofday memset mkdir mkfifo select socket strcasecmp strchr strdup strerror strstr clock_gettime getrusage rand uname setlocale getcwd mktime gmtime_r gmtime strlcpy strlcat ftruncate stat64 sbrk mmap mremap setrlimit sysconf gethostbyaddr initgroups getifaddrs freeifaddrs getnameinfo getaddrinfo inet_ntoa localtime_r nl_langinfo putenv realpath strndup gethostbyname2 gethostbyname]) +AC_CHECK_FUNCS([floor gethostname memmove rmdir strncasecmp strrchr strtol atoll dup2 fdatasync ftruncate gettimeofday memset mkdir mkfifo select socket strcasecmp strchr strdup strerror strstr clock_gettime getrusage rand uname setlocale getcwd mktime gmtime_r gmtime strlcpy strlcat ftruncate stat64 sbrk mmap mremap setrlimit sysconf gethostbyaddr initgroups getifaddrs freeifaddrs getnameinfo getaddrinfo inet_ntoa localtime_r nl_langinfo putenv realpath strndup gethostbyname2 gethostbyname getpeerucred getpeereid]) # restore LIBS LIBS=$SAVE_LIBS diff --git a/contrib/defaults.conf b/contrib/defaults.conf index 621230c73..5c54b362b 100644 --- a/contrib/defaults.conf +++ b/contrib/defaults.conf @@ -82,6 +82,8 @@ ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; DEFAULTSERVICES = topology hostlist UNIXPATH = /tmp/gnunet-service-arm.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES # GLOBAL_POSTFIX = -l $SERVICEHOME/{}-logs # GLOBAL_PREFIX = # USERNAME = @@ -103,6 +105,8 @@ BINARY = gnunet-service-statistics ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-statistics.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = @@ -123,6 +127,8 @@ BINARY = gnunet-service-resolver ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-resolver.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = NO # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = @@ -143,6 +149,8 @@ BINARY = gnunet-service-peerinfo ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; UNIXPATH = /tmp/gnunet-service-peerinfo.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = @@ -168,6 +176,8 @@ ACCEPT_FROM6 = ::1; PLUGINS = tcp UNIXPATH = /tmp/gnunet-service-transport.sock BLACKLIST_FILE = $SERVICEHOME/blacklist +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # USERNAME = # MAXBUF = @@ -191,6 +201,8 @@ ACCEPT_FROM6 = ::1; TOTAL_QUOTA_IN = 65536 TOTAL_QUOTA_OUT = 65536 UNIXPATH = /tmp/gnunet-service-core.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # DEBUG = YES # USERNAME = @@ -229,6 +241,8 @@ HTTP-PROXY = [datastore] AUTOSTART = YES UNIXPATH = /tmp/gnunet-service-datastore.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES PORT = 2093 HOSTNAME = localhost HOME = $SERVICEHOME @@ -283,6 +297,8 @@ CONTENT_CACHING = YES CONTENT_PUSHING = YES UNIXPATH = /tmp/gnunet-service-fs.sock +UNIX_MATCH_UID = NO +UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # DEBUG = YES MAX_PENDING_REQUESTS = 65536 @@ -303,6 +319,8 @@ ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; BUCKET_SIZE = 4 UNIXPATH = /tmp/gnunet-service-dht.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES # DISABLE_SOCKET_FORWARDING = NO # DEBUG = YES # USERNAME = diff --git a/src/include/gnunet_connection_lib.h b/src/include/gnunet_connection_lib.h index 33afb0386..8d2dbb611 100644 --- a/src/include/gnunet_connection_lib.h +++ b/src/include/gnunet_connection_lib.h @@ -52,16 +52,35 @@ extern "C" struct GNUNET_CONNECTION_Handle; +/** + * Credentials for UNIX domain sockets. + */ +struct GNUNET_CONNECTION_Credentials +{ + /** + * UID of the other end of the connection. + */ + uid_t uid; + + /** + * GID of the other end of the connection. + */ + gid_t gid; +}; + + /** * Function to call for access control checks. * * @param cls closure + * @param ucred credentials, if available, otherwise NULL * @param addr address * @param addrlen length of address * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR * for unknown address family (will be denied). */ typedef int (*GNUNET_CONNECTION_AccessCheck) (void *cls, + const struct GNUNET_CONNECTION_Credentials *ucred, const struct sockaddr * addr, socklen_t addrlen); diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h index 73303689a..34cb7bc32 100644 --- a/src/include/gnunet_network_lib.h +++ b/src/include/gnunet_network_lib.h @@ -309,6 +309,7 @@ void GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst, void GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, const struct GNUNET_NETWORK_FDSet *from); + /** * Return file descriptor for this network handle * diff --git a/src/include/platform.h b/src/include/platform.h index cc2aa03ae..230031307 100644 --- a/src/include/platform.h +++ b/src/include/platform.h @@ -156,6 +156,9 @@ #include #include #endif +#if HAVE_UCRED_H +#include +#endif #ifdef CYGWIN #include #include diff --git a/src/util/connection.c b/src/util/connection.c index aa5db91bf..12969b3ba 100644 --- a/src/util/connection.c +++ b/src/util/connection.c @@ -346,6 +346,12 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, struct sockaddr_in6 *v6; struct sockaddr *sa; void *uaddr; + struct GNUNET_CONNECTION_Credentials *gcp; + struct GNUNET_CONNECTION_Credentials gc; +#ifdef SO_PEERCRED + struct ucred uc; + socklen_t olen; +#endif addrlen = sizeof (addr); sock = @@ -384,9 +390,50 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, uaddr = GNUNET_malloc (addrlen); memcpy (uaddr, addr, addrlen); } + gcp = NULL; + gc.uid = 0; + gc.gid = 0; + if (sa->sa_family == AF_UNIX) + { +#if HAVE_GETPEEREID + /* most BSDs */ + if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), + &gc.uid, + &gc.gid)) + gcp = &gc; +#else +#ifdef SO_PEERCRED + /* largely traditional GNU/Linux */ + olen = sizeof (uc); + if ( (0 == + getsockopt (GNUNET_NETWORK_get_fd (sock), + SOL_SOCKET, SO_PEERCRED, &uc, &olen)) && + (olen == sizeof (uc)) ) + { + gc.uid = uc.uid; + gc.gid = uc.gid; + gcp = &gc; + } +#else +#if HAVE_GETPEERUCRED + /* this is for Solaris 10 */ + ucred_t *uc; + + uc = NULL; + if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc)) + { + gc.uid = ucred_geteuid (uc); + gc.gid = ucred_getegid (uc); + gcp = &gc; + } + ucred_free (uc); +#endif +#endif +#endif + } if ((access != NULL) && - (GNUNET_YES != (aret = access (access_cls, uaddr, addrlen)))) + (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen)))) { if (aret == GNUNET_NO) GNUNET_log (GNUNET_ERROR_TYPE_INFO, diff --git a/src/util/network.c b/src/util/network.c index 9e85a3be9..f7c1e53c1 100644 --- a/src/util/network.c +++ b/src/util/network.c @@ -451,6 +451,7 @@ GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle return GNUNET_NO; } + /** * Read data from a connected socket (always non-blocking). * @param desc socket @@ -774,12 +775,20 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to, #endif } + +/** + * Return file descriptor for this network handle + * + * @param desc wrapper to process + * @return POSIX file descriptor + */ int GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc) { return desc->fd; } + /** * Copy a native fd set * diff --git a/src/util/service.c b/src/util/service.c index ac90eb93b..0594149d9 100644 --- a/src/util/service.c +++ b/src/util/service.c @@ -511,6 +511,18 @@ struct GNUNET_SERVICE_Context */ int require_found; + /** + * Do we require a matching UID for UNIX domain socket + * connections? + */ + int match_uid; + + /** + * Do we require a matching GID for UNIX domain socket + * connections? + */ + int match_gid; + /** * Our options. */ @@ -579,9 +591,18 @@ static const struct GNUNET_SERVER_MessageHandler defhandlers[] = { /** * Check if access to the service is allowed from the given address. + * + * @param cls closure + * @param uc credentials, if available, otherwise NULL + * @param addr address + * @param addrlen length of address + * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR + * for unknown address family (will be denied). */ static int -check_access (void *cls, const struct sockaddr *addr, socklen_t addrlen) +check_access (void *cls, + const struct GNUNET_CONNECTION_Credentials *uc, + const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_SERVICE_Context *sctx = cls; const struct sockaddr_in *i4; @@ -609,8 +630,23 @@ check_access (void *cls, const struct sockaddr *addr, socklen_t addrlen) (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr))); break; case AF_UNIX: - /* FIXME: support checking UID/GID in the future... */ ret = GNUNET_OK; /* always OK for now */ + if ( (sctx->match_uid == GNUNET_YES) || + (sctx->match_gid == GNUNET_YES) ) + ret = GNUNET_NO; + if ( (uc != NULL) && + ( (sctx->match_uid != GNUNET_YES) || + (uc->uid == geteuid()) || + (uc->uid == getuid()) ) && + ( (sctx->match_gid != GNUNET_YES) || + (uc->gid == getegid()) || + (uc->gid == getgid())) ) + ret = GNUNET_YES; + else + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Access denied to UID %d / GID %d\n"), + (uc == NULL) ? -1 : uc->uid, + (uc == NULL) ? -1 : uc->gid); break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -1187,7 +1223,12 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) &sctx->addrlens)) ) return GNUNET_SYSERR; sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; - + sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, + sctx->serviceName, + "UNIX_MATCH_UID"); + sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, + sctx->serviceName, + "UNIX_MATCH_GID"); process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");