-fixes
[oweals/gnunet.git] / src / util / service.c
index cf1002ca9e40df2253f2814bf27598aec13cc5b2..7583dccb6d78b6cd59d413f13eca09b46d01eb90 100644 (file)
@@ -106,7 +106,7 @@ parse_ipv4_specification (const char *routeList)
   while (i < count)
   {
     cnt =
-        sscanf (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0],
+        SSCANF (&routeList[pos], "%u.%u.%u.%u/%u.%u.%u.%u;", &temps[0],
                 &temps[1], &temps[2], &temps[3], &temps[4], &temps[5],
                 &temps[6], &temps[7]);
     if (cnt == 8)
@@ -133,7 +133,7 @@ parse_ipv4_specification (const char *routeList)
     }
     /* try second notation */
     cnt =
-        sscanf (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1],
+        SSCANF (&routeList[pos], "%u.%u.%u.%u/%u;", &temps[0], &temps[1],
                 &temps[2], &temps[3], &slash);
     if (cnt == 5)
     {
@@ -176,7 +176,7 @@ parse_ipv4_specification (const char *routeList)
     /* try third notation */
     slash = 32;
     cnt =
-        sscanf (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1],
+        SSCANF (&routeList[pos], "%u.%u.%u.%u;", &temps[0], &temps[1],
                 &temps[2], &temps[3]);
     if (cnt == 4)
     {
@@ -501,14 +501,18 @@ struct GNUNET_SERVICE_Context
   int require_found;
 
   /**
-   * Do we require a matching UID for UNIX domain socket
-   * connections?
+   * Do we require a matching UID for UNIX domain socket connections?
+   * GNUNET_NO means that the UID does not have to match (however,
+   * "match_gid" may still impose other access control checks).
    */
   int match_uid;
 
   /**
-   * Do we require a matching GID for UNIX domain socket
-   * connections?
+   * Do we require a matching GID for UNIX domain socket connections?
+   * Ignored if "match_uid" is GNUNET_YES.  Note that this is about
+   * checking that the client's UID is in our group OR that the
+   * client's GID is our GID.  If both "match_gid" and "match_uid" are
+   * "GNUNET_NO", all users on the local system have access.
    */
   int match_gid;
 
@@ -617,15 +621,50 @@ check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
 #ifndef WINDOWS
   case AF_UNIX:
     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
+    if (sctx->match_uid == GNUNET_YES) 
+    {
+      /* UID match required */
+      ret = (uc != NULL) && (uc->uid == geteuid ());
+    }
+    else if (sctx->match_gid == GNUNET_YES) 
+    {
+      /* group match required */
+      if (uc == NULL) 
+      {
+       /* no credentials, group match not possible */
+       ret = GNUNET_NO;
+      }
+      else
+      {
+       struct group *grp;
+       unsigned int i;
+
+       if (uc->gid != getegid())
+       {
+         /* default group did not match, but maybe the user is in our group, let's check */
+         grp = getgrgid (getegid ());
+         if (NULL == grp)
+         {
+           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "getgrgid");
+           return GNUNET_NO;
+         }
+         ret = GNUNET_NO;
+         for (i=0; NULL != grp->gr_mem[i]; i++)
+         {
+           struct passwd *nam = getpwnam (grp->gr_mem[i]);
+           if (NULL == nam)
+             continue; /* name in group that is not in user DB !? */
+           if (nam->pw_uid == uc->uid)
+           {
+             /* yes, uid is in our group, allow! */
+             ret = GNUNET_YES;
+             break;
+           }
+         }
+       }
+      }
+    }
+    if (GNUNET_NO == ret)
       LOG (GNUNET_ERROR_TYPE_WARNING, _("Access denied to UID %d / GID %d\n"),
            (uc == NULL) ? -1 : uc->uid, (uc == NULL) ? -1 : uc->gid);
     break;
@@ -1079,6 +1118,89 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
 }
 
 
+#ifdef MINGW
+/**
+ * @return GNUNET_YES if ok, GNUNET_NO if not ok (must bind yourself),
+ * and GNUNET_SYSERR on error.
+ */
+static int
+receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
+{
+  const char *env_buf;
+  int fail;
+  uint64_t count, i;
+  HANDLE lsocks_pipe;
+
+  env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
+  if ((env_buf == NULL) || (strlen (env_buf) <= 0))
+  {
+    return GNUNET_NO;
+  }
+  /* Using W32 API directly here, because this pipe will
+   * never be used outside of this function, and it's just too much of a bother
+   * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
+   */
+  lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
+  if (lsocks_pipe == 0 || lsocks_pipe == INVALID_HANDLE_VALUE)
+    return GNUNET_NO;
+
+  fail = 1;
+  do
+  {
+    int ret;
+    int fail2;
+    DWORD rd;
+
+    ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
+    if (ret == 0 || rd != sizeof (count) || count == 0)
+      break;
+    sctx->lsocks =
+        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
+
+    fail2 = 1;
+    for (i = 0; i < count; i++)
+    {
+      WSAPROTOCOL_INFOA pi;
+      uint64_t size;
+      SOCKET s;
+      ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
+      if (ret == 0 || rd != sizeof (size) || size != sizeof (pi))
+        break;
+      ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
+      if (ret == 0 || rd != sizeof (pi))
+        break;
+      s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
+      sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
+      if (sctx->lsocks[i] == NULL)
+        break;
+      else if (i == count - 1)
+        fail2 = 0;
+    }
+    if (fail2)
+      break;
+    sctx->lsocks[count] = NULL;
+    fail = 0;
+  }
+  while (fail);
+
+  CloseHandle (lsocks_pipe);
+
+  if (fail)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Could not access a pre-bound socket, will try to bind myself\n"));
+    for (i = 0; i < count && sctx->lsocks[i] != NULL; i++)
+      GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
+    GNUNET_free_non_null (sctx->lsocks);
+    sctx->lsocks = NULL;
+    return GNUNET_NO;
+  }
+
+  return GNUNET_YES;
+}
+#endif
+
+
 /**
  * Setup addr, addrlen, idle_timeout
  * based on configuration!
@@ -1146,9 +1268,9 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
 #ifndef MINGW
   errno = 0;
   if ((NULL != (lpid = getenv ("LISTEN_PID"))) &&
-      (1 == sscanf (lpid, "%u", &pid)) && (getpid () == (pid_t) pid) &&
+      (1 == SSCANF (lpid, "%u", &pid)) && (getpid () == (pid_t) pid) &&
       (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
-      (1 == sscanf (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
+      (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
       (cnt + 4 < FD_SETSIZE))
   {
     sctx->lsocks =
@@ -1175,6 +1297,12 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
     unsetenv ("LISTEN_PID");
     unsetenv ("LISTEN_FDS");
   }
+#else
+  if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
+  {
+    receive_sockets_from_parent (sctx);
+    putenv ("GNUNET_OS_READ_LSOCKS=");
+  }
 #endif
 
   if ((sctx->lsocks == NULL) &&
@@ -1262,7 +1390,7 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
   }
   if (0 > FPRINTF (pidfd, "%u", pid))
     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
-  GNUNET_break (0 == fclose (pidfd));
+  GNUNET_break (0 == FCLOSE (pidfd));
   if ((user != NULL) && (0 < strlen (user)))
     GNUNET_DISK_file_change_owner (pif, user);
   GNUNET_free_non_null (user);
@@ -1566,17 +1694,17 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Service `%s' runs with configuration from `%s'\n", serviceName, cfg_fn);
 #endif
-  if (GNUNET_OK ==
-      GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "testing", "skew_offset",
-                                             &skew_offset) &&
+  if ((GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+                                              "SKEW_OFFSET", &skew_offset)) &&
       (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "testing",
-                                              "skew_variance", &skew_variance)))
+       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+                                              "SKEW_VARIANCE", &skew_variance)))
   {
     clock_offset = skew_offset - skew_variance;
     GNUNET_TIME_set_offset (clock_offset);
 #if DEBUG_SERVICE
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll\n", clock_offset);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
 #endif
   }
   /* actually run service */