UNIX domain socket authentication support added
authorChristian Grothoff <christian@grothoff.org>
Mon, 24 Jan 2011 12:03:32 +0000 (12:03 +0000)
committerChristian Grothoff <christian@grothoff.org>
Mon, 24 Jan 2011 12:03:32 +0000 (12:03 +0000)
TODO
configure.ac
contrib/defaults.conf
src/include/gnunet_connection_lib.h
src/include/gnunet_network_lib.h
src/include/platform.h
src/util/connection.c
src/util/network.c
src/util/service.c

diff --git a/TODO b/TODO
index afd45f0916854fd75baf71f1078a95a3f8c177ce..6b3a2230b2f7b95bc1e6fdde7a1985a860abe04d 100644 (file)
--- 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, ...)
index a57030a5c40eac4823ef6c4729342fc2c75478c8..7938ff1d87185a9c5a3032ff6a27faed26415daf 100644 (file)
@@ -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
index 621230c73b8aa0375f9a06ce355a432500ecb488..5c54b362bf7a1d5e8c17d7d79102eaebcbf97781 100644 (file)
@@ -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 = 
index 33afb0386c08d38a83b97b03d4355dfe96b9f351..8d2dbb6119f6b556c4248cfe70a5fb938d8f6c5f 100644 (file)
@@ -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);
 
index 73303689a168dd5a8c2184ad12c0107dce4d0d24..34cb7bc32374a37c67976d994555bbd3c718cbc1 100644 (file)
@@ -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
  *
index cc2aa03aee95ab62d9419a63cd458a4b1a31bc71..230031307ca5c48ec745ab52bd10ff26ae7e6436 100644 (file)
 #include <sys/loadavg.h>
 #include <semaphore.h>
 #endif
+#if HAVE_UCRED_H
+#include <ucred.h>
+#endif
 #ifdef CYGWIN
 #include <windows.h>
 #include <cygwin/if.h>
index aa5db91bf41e1a14976a4c1ce21f4584635ce5a5..12969b3ba23e9cbb9a93bf46edca14111a49a511 100644 (file)
@@ -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,
index 9e85a3be9dc6817b9b80b26b787eacde394be9a1..f7c1e53c1b3fca30e30569f3e8d0e7aaa30d31bd 100644 (file)
@@ -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
  *
index ac90eb93ba2459841bf9e6c5e5e938fe1c3f3d28..0594149d96e79798697daecf13daaabf57fece8f 100644 (file)
@@ -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");