WiP
[oweals/gnunet.git] / src / util / service.c
index 25a9b08dc3ef3032341491c1bd01346d4878684f..2338e795dc0c2710b774616ddf34623181982234 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;
@@ -608,10 +629,27 @@ check_access (void *cls, const struct sockaddr *addr, socklen_t addrlen)
         && ((sctx->v6_denied == NULL) ||
             (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
       break;
+#ifndef WINDOWS
     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;
+#endif
     default:
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                   _("Unknown address family %d\n"), addr->sa_family);
@@ -856,26 +894,26 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
   else
     hostname = NULL;
 
+  unixpath = NULL;
 #ifdef AF_UNIX
-  if (GNUNET_CONFIGURATION_have_value (cfg,
-                                       serviceName, "UNIXPATH"))
-    {
-      GNUNET_break (GNUNET_OK ==
-                    GNUNET_CONFIGURATION_get_value_string (cfg,
+  if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
+                                                     serviceName, "UNIXPATH")) &&
+      (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
                                                            serviceName,
                                                            "UNIXPATH",
-                                                           &unixpath));
-
+                                                           &unixpath)) &&
+      (0 < strlen(unixpath)))
+    {
       /* probe UNIX support */
       struct sockaddr_un s_un;
       if (strlen(unixpath) >= sizeof(s_un.sun_path))
-      {
-         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("UNIXPATH `%s' too long, maximum length is %llu\n"),unixpath, sizeof(s_un.sun_path));
-             GNUNET_free_non_null (hostname);
-             GNUNET_free (unixpath);
-         return GNUNET_SYSERR;
-      }
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                     _("UNIXPATH `%s' too long, maximum length is %llu\n"),unixpath, sizeof(s_un.sun_path));
+         GNUNET_free_non_null (hostname);
+         GNUNET_free (unixpath);
+         return GNUNET_SYSERR;
+       }
 
       desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
       if (NULL == desc)
@@ -901,10 +939,6 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
           desc = NULL;
        }
     }
-  else
-    unixpath = NULL;
-#else
-  unixpath = NULL;
 #endif
 
   if ( (port == 0) &&
@@ -922,7 +956,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
       saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
       add_unixpath (saddrs, saddrlens, unixpath);
       GNUNET_free_non_null (unixpath);
-      GNUNET_free_non_null(hostname);
+      GNUNET_free_non_null (hostname);
       *addrs = saddrs;
       *addr_lens = saddrlens;
       return 1;
@@ -946,7 +980,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
                       _("Failed to resolve `%s': %s\n"),
                       hostname, gai_strerror (ret));
           GNUNET_free (hostname);
-         GNUNET_free (unixpath);
+         GNUNET_free_non_null (unixpath);
           return GNUNET_SYSERR;
         }
       next = res;
@@ -965,7 +999,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
                       disablev6 ? "IPv4 " : "", hostname);
           freeaddrinfo (res);
           GNUNET_free (hostname);
-         GNUNET_free (unixpath);
+         GNUNET_free_non_null (unixpath);
           return GNUNET_SYSERR;
         }
       resi = i;
@@ -1187,7 +1221,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");