-fixes
[oweals/gnunet.git] / src / util / service.c
index 9b60dc56b31b061f11b56dbd3331af1a8cd0a162..7583dccb6d78b6cd59d413f13eca09b46d01eb90 100644 (file)
 #include "gnunet_server_lib.h"
 #include "gnunet_service_lib.h"
 
-#define DEBUG_SERVICE GNUNET_NO
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
+#define DEBUG_SERVICE GNUNET_EXTRA_LOGGING
 
 /* ******************* access control ******************** */
 
@@ -100,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)
@@ -108,8 +114,8 @@ parse_ipv4_specification (const char *routeList)
       for (j = 0; j < 8; j++)
         if (temps[j] > 0xFF)
         {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      _("Invalid format for IP: `%s'\n"), &routeList[pos]);
+          LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
+               &routeList[pos]);
           GNUNET_free (result);
           return NULL;
         }
@@ -127,15 +133,15 @@ 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)
     {
       for (j = 0; j < 4; j++)
         if (temps[j] > 0xFF)
         {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      _("Invalid format for IP: `%s'\n"), &routeList[pos]);
+          LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
+               &routeList[pos]);
           GNUNET_free (result);
           return NULL;
         }
@@ -160,10 +166,9 @@ parse_ipv4_specification (const char *routeList)
       }
       else
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    _
-                    ("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
-                    slash);
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
+             slash);
         GNUNET_free (result);
         return NULL;            /* error */
       }
@@ -171,15 +176,15 @@ 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)
     {
       for (j = 0; j < 4; j++)
         if (temps[j] > 0xFF)
         {
-          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                      _("Invalid format for IP: `%s'\n"), &routeList[pos]);
+          LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
+               &routeList[pos]);
           GNUNET_free (result);
           return NULL;
         }
@@ -199,15 +204,15 @@ parse_ipv4_specification (const char *routeList)
       i++;
       continue;
     }
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
-                &routeList[pos]);
+    LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
+         &routeList[pos]);
     GNUNET_free (result);
     return NULL;                /* error */
   }
   if (pos < strlen (routeList))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
-                &routeList[pos]);
+    LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid format for IP: `%s'\n"),
+         &routeList[pos]);
     GNUNET_free (result);
     return NULL;                /* oops */
   }
@@ -254,9 +259,9 @@ parse_ipv6_specification (const char *routeListX)
       count++;
   if (routeList[len - 1] != ';')
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Invalid network notation (does not end with ';': `%s')\n"),
-                routeList);
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Invalid network notation (does not end with ';': `%s')\n"),
+         routeList);
     GNUNET_free (routeList);
     return NULL;
   }
@@ -288,13 +293,12 @@ parse_ipv6_specification (const char *routeListX)
         if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits >= 128))
         {
           if (ret == 0)
-            GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                        _("Wrong format `%s' for netmask\n"),
-                        &routeList[slash + 1]);
+            LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for netmask\n"),
+                 &routeList[slash + 1]);
           else
           {
             errno = save;
-            GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
+            LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
           }
           GNUNET_free (result);
           GNUNET_free (routeList);
@@ -319,11 +323,10 @@ parse_ipv6_specification (const char *routeListX)
     if (ret <= 0)
     {
       if (ret == 0)
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    _("Wrong format `%s' for network\n"),
-                    &routeList[slash + 1]);
+        LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong format `%s' for network\n"),
+             &routeList[slash + 1]);
       else
-        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "inet_pton");
       GNUNET_free (result);
       GNUNET_free (routeList);
       return NULL;
@@ -498,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;
 
@@ -614,30 +621,65 @@ 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
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Access denied to UID %d / GID %d\n"),
-                  (uc == NULL) ? -1 : uc->uid, (uc == NULL) ? -1 : uc->gid);
+    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;
 #endif
   default:
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
-                addr->sa_family);
+    LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
+         addr->sa_family);
     return GNUNET_SYSERR;
   }
   if (ret != GNUNET_OK)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                _("Access from `%s' denied to service `%s'\n"),
-                GNUNET_a2s (addr, addrlen), sctx->serviceName);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Access from `%s' denied to service `%s'\n"), GNUNET_a2s (addr,
+                                                                     addrlen),
+         sctx->serviceName);
   }
   return ret;
 }
@@ -678,10 +720,9 @@ process_acl4 (struct IPv4NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx,
                                                        option, &opt));
   if (NULL == (*ret = parse_ipv4_specification (opt)))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                _
-                ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
-                opt, sctx->serviceName, option);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
+         opt, sctx->serviceName, option);
     GNUNET_free (opt);
     return GNUNET_SYSERR;
   }
@@ -707,10 +748,9 @@ process_acl6 (struct IPv6NetworkSet **ret, struct GNUNET_SERVICE_Context *sctx,
                                                        option, &opt));
   if (NULL == (*ret = parse_ipv6_specification (opt)))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                _
-                ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
-                opt, sctx->serviceName, option);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
+         opt, sctx->serviceName, option);
     GNUNET_free (opt);
     return GNUNET_SYSERR;
   }
@@ -751,7 +791,7 @@ add_unixpath (struct sockaddr **saddrs, socklen_t * saddrlens,
   *saddrs = (struct sockaddr *) un;
   *saddrlens = slen;
 #else
-  /* this function should never be called 
+  /* this function should never be called
    * unless AF_UNIX is defined! */
   GNUNET_assert (0);
 #endif
@@ -821,13 +861,13 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
       if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
           (errno == EACCES))
       {
-        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
         return GNUNET_SYSERR;
       }
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _
-                  ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
-                  serviceName, STRERROR (errno));
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _
+           ("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
+           serviceName, STRERROR (errno));
       disablev6 = GNUNET_YES;
     }
     else
@@ -845,10 +885,9 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
                                                          "PORT", &port));
     if (port > 65535)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _
-                  ("Require valid port number for service `%s' in configuration!\n"),
-                  serviceName);
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Require valid port number for service `%s' in configuration!\n"),
+           serviceName);
       return GNUNET_SYSERR;
     }
   }
@@ -876,9 +915,9 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
 
     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));
+      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;
@@ -890,15 +929,15 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
       if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
           (errno == EACCES))
       {
-        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
         GNUNET_free_non_null (hostname);
         GNUNET_free (unixpath);
         return GNUNET_SYSERR;
       }
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _
-                  ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
-                  serviceName, STRERROR (errno));
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _
+           ("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
+           serviceName, STRERROR (errno));
       GNUNET_free (unixpath);
       unixpath = NULL;
     }
@@ -912,10 +951,10 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
 
   if ((port == 0) && (unixpath == NULL))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _
-                ("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
-                serviceName);
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _
+         ("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
+         serviceName);
     GNUNET_free_non_null (hostname);
     return GNUNET_SYSERR;
   }
@@ -934,9 +973,9 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
   if (hostname != NULL)
   {
 #if DEBUG_SERVICE
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Resolving `%s' since that is where `%s' will bind to.\n",
-                hostname, serviceName);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Resolving `%s' since that is where `%s' will bind to.\n", hostname,
+         serviceName);
 #endif
     memset (&hints, 0, sizeof (struct addrinfo));
     if (disablev6)
@@ -944,8 +983,8 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
     if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
         (res == NULL))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"),
-                  hostname, gai_strerror (ret));
+      LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), hostname,
+           gai_strerror (ret));
       GNUNET_free (hostname);
       GNUNET_free_non_null (unixpath);
       return GNUNET_SYSERR;
@@ -961,9 +1000,8 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
     }
     if (0 == i)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Failed to find %saddress for `%s'.\n"),
-                  disablev6 ? "IPv4 " : "", hostname);
+      LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to find %saddress for `%s'.\n"),
+           disablev6 ? "IPv4 " : "", hostname);
       freeaddrinfo (res);
       GNUNET_free (hostname);
       GNUNET_free_non_null (unixpath);
@@ -991,8 +1029,8 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
       if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0))
         continue;               /* huh? */
 #if DEBUG_SERVICE
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
-                  serviceName, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
+           serviceName, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
 #endif
       if (pos->ai_family == AF_INET)
       {
@@ -1080,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!
@@ -1117,9 +1238,9 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
         GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->serviceName,
                                              "TIMEOUT", &idleout))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Specified value for `%s' of service `%s' is invalid\n"),
-                  "TIMEOUT", sctx->serviceName);
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Specified value for `%s' of service `%s' is invalid\n"),
+           "TIMEOUT", sctx->serviceName);
       return GNUNET_SYSERR;
     }
     sctx->timeout = idleout;
@@ -1135,9 +1256,9 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
          GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->serviceName,
                                                "TOLERANT")))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Specified value for `%s' of service `%s' is invalid\n"),
-                  "TOLERANT", sctx->serviceName);
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Specified value for `%s' of service `%s' is invalid\n"),
+           "TOLERANT", sctx->serviceName);
       return GNUNET_SYSERR;
     }
   }
@@ -1147,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 =
@@ -1161,10 +1282,10 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
           (NULL ==
            (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                    _
-                    ("Could not access pre-bound socket %u, will try to bind myself\n"),
-                    (unsigned int) 3 + cnt);
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _
+             ("Could not access pre-bound socket %u, will try to bind myself\n"),
+             (unsigned int) 3 + cnt);
         cnt++;
         while (sctx->lsocks[cnt] != NULL)
           GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
@@ -1176,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) &&
@@ -1246,7 +1373,7 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
   }
   if (0 != ACCESS (rdir, W_OK | X_OK))
   {
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
     GNUNET_free (rdir);
     GNUNET_free_non_null (user);
     GNUNET_free (pif);
@@ -1256,14 +1383,14 @@ write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
   pidfd = FOPEN (pif, "w");
   if (pidfd == NULL)
   {
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
     GNUNET_free (pif);
     GNUNET_free_non_null (user);
     return GNUNET_SYSERR;
   }
   if (0 > FPRINTF (pidfd, "%u", pid))
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
-  GNUNET_break (0 == fclose (pidfd));
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
+  GNUNET_break (0 == FCLOSE (pidfd));
   if ((user != NULL) && (0 < strlen (user)))
     GNUNET_DISK_file_change_owner (pif, user);
   GNUNET_free_non_null (user);
@@ -1312,9 +1439,8 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
       i = 0;
       while (sctx->addrs[i] != NULL)
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to start `%s' at `%s'\n"),
-                    sctx->serviceName, GNUNET_a2s (sctx->addrs[i],
-                                                   sctx->addrlens[i]));
+        LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to start `%s' at `%s'\n"),
+             sctx->serviceName, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
         i++;
       }
     }
@@ -1346,9 +1472,8 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     i = 0;
     while (sctx->addrs[i] != NULL)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
-                  sctx->serviceName, GNUNET_a2s (sctx->addrs[i],
-                                                 sctx->addrlens[i]));
+      LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
+           sctx->serviceName, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
       i++;
     }
   }
@@ -1369,13 +1494,13 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
 
   if (0 != PIPE (filedes))
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
     return GNUNET_SYSERR;
   }
   pid = fork ();
   if (pid < 0)
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
     return GNUNET_SYSERR;
   }
   if (pid != 0)
@@ -1386,23 +1511,22 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
     GNUNET_break (0 == CLOSE (filedes[1]));
     c = 'X';
     if (1 != READ (filedes[0], &c, sizeof (char)))
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "read");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
     fflush (stdout);
     switch (c)
     {
     case '.':
       exit (0);
     case 'I':
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Service process failed to initialize\n"));
+      LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n"));
       break;
     case 'S':
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Service process could not initialize server function\n"));
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Service process could not initialize server function\n"));
       break;
     case 'X':
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Service process failed to report status\n"));
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Service process failed to report status\n"));
       break;
     }
     exit (1);                   /* child reported error */
@@ -1416,7 +1540,7 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
   /* set stdin/stdout to /dev/null */
   if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
     (void) CLOSE (nullfd);
     return GNUNET_SYSERR;
   }
@@ -1424,7 +1548,7 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
   /* Detach from controlling terminal */
   pid = setsid ();
   if (pid == -1)
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsid");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
   sctx->ready_confirm_fd = filedes[1];
 #else
   /* FIXME: we probably need to do something else
@@ -1452,9 +1576,9 @@ set_user_id (struct GNUNET_SERVICE_Context *sctx)
   pws = getpwnam (user);
   if (pws == NULL)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _("Cannot obtain information about user `%s': %s\n"), user,
-                errno == 0 ? _("No such user") : STRERROR (errno));
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Cannot obtain information about user `%s': %s\n"), user,
+         errno == 0 ? _("No such user") : STRERROR (errno));
     GNUNET_free (user);
     return GNUNET_SYSERR;
   }
@@ -1467,9 +1591,8 @@ set_user_id (struct GNUNET_SERVICE_Context *sctx)
     if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
         (0 != setreuid (pws->pw_uid, pws->pw_uid)))
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Cannot change user/group to `%s': %s\n"), user,
-                  STRERROR (errno));
+      LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
+           user, STRERROR (errno));
       GNUNET_free (user);
       return GNUNET_SYSERR;
     }
@@ -1491,7 +1614,7 @@ pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
   if (pif == NULL)
     return;                     /* no PID file */
   if (0 != UNLINK (pif))
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
   GNUNET_free (pif);
 }
 
@@ -1514,7 +1637,7 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
                     enum GNUNET_SERVICE_Options opt, GNUNET_SERVICE_Main task,
                     void *task_cls)
 {
-#define HANDLE_ERROR do { err = 1; GNUNET_break (0); goto shutdown; } while (0)
+#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
 
   int err;
   char *cfg_fn;
@@ -1539,10 +1662,10 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
     GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION),
     GNUNET_GETOPT_OPTION_END
   };
-  err = 0;
+  err = 1;
   do_daemonize = 0;
   logfile = NULL;
-  loglev = GNUNET_strdup ("WARNING");
+  loglev = NULL;
   cfg_fn = GNUNET_strdup (GNUNET_DEFAULT_USER_CONFIG_FILE);
   memset (&sctx, 0, sizeof (sctx));
   sctx.options = opt;
@@ -1568,25 +1691,24 @@ GNUNET_SERVICE_run (int argc, char *const *argv, const char *serviceName,
   if (GNUNET_OK != set_user_id (&sctx))
     goto shutdown;
 #if DEBUG_SERVICE
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Service `%s' runs with configuration from `%s'\n", serviceName,
-              cfg_fn);
+  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
-    GNUNET_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 */
+  err = 0;
   GNUNET_SCHEDULER_run (&service_task, &sctx);
 
   /* shutdown */
@@ -1598,7 +1720,7 @@ shutdown:
   if (sctx.ready_confirm_fd != -1)
   {
     if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
     GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
   }
 
@@ -1610,7 +1732,7 @@ shutdown:
   GNUNET_free_non_null (sctx.addrs);
   GNUNET_free_non_null (sctx.addrlens);
   GNUNET_free_non_null (logfile);
-  GNUNET_free (loglev);
+  GNUNET_free_non_null (loglev);
   GNUNET_free (cfg_fn);
   GNUNET_free_non_null (sctx.v4_denied);
   GNUNET_free_non_null (sctx.v6_denied);