LRN: Fix automake deps to allow -j* builds again
[oweals/gnunet.git] / src / util / service.c
index 46a01a098fe49df3e7bf8cc0bacae8b0c2861b76..ac5ce8d8003095e5d49f0e171a875717b0409afa 100644 (file)
@@ -32,6 +32,7 @@
 #include "gnunet_getopt_lib.h"
 #include "gnunet_os_lib.h"
 #include "gnunet_protocols.h"
+#include "gnunet_resolver_service.h"
 #include "gnunet_server_lib.h"
 #include "gnunet_service_lib.h"
 
@@ -429,11 +430,6 @@ struct GNUNET_SERVICE_Context
    */
   struct GNUNET_SERVER_Handle *server;
 
-  /**
-   * Scheduler for the server.
-   */
-  struct GNUNET_SCHEDULER_Handle *sched;
-
   /**
    * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
    * listen sockets.
@@ -498,11 +494,6 @@ struct GNUNET_SERVICE_Context
    */
   struct GNUNET_TIME_Relative timeout;
 
-  /**
-   * Maximum buffer size for the server.
-   */
-  size_t maxbuf;
-
   /**
    * Overall success/failure of the service start.
    */
@@ -521,6 +512,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.
    */
@@ -589,9 +592,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;
@@ -618,10 +630,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);
@@ -738,11 +767,12 @@ add_unixpath (struct sockaddr **saddrs,
          unixpath,
          slen);
   un->sun_path[slen] = '\0';
+  slen = sizeof (struct sockaddr_un);
 #if LINUX
   un->sun_path[0] = '\0';
-  slen = sizeof (struct sockaddr_un);
-#else
-  slen += sizeof (sa_family_t);
+#endif
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  un->sun_len = (u_char) slen;
 #endif
   *saddrs = (struct sockaddr*) un;
   *saddrlens = slen;
@@ -866,22 +896,35 @@ 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;
+       }
+
       desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
       if (NULL == desc)
         {
-          if ((errno == ENOBUFS) ||
-              (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES))
+          if ( (errno == ENOBUFS) ||
+              (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES))
             {
               GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
              GNUNET_free_non_null (hostname);
@@ -901,10 +944,6 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
           desc = NULL;
        }
     }
-  else
-    unixpath = NULL;
-#else
-  unixpath = NULL;
 #endif
 
   if ( (port == 0) &&
@@ -922,6 +961,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);
       *addrs = saddrs;
       *addr_lens = saddrlens;
       return 1;
@@ -945,7 +985,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;
@@ -964,7 +1004,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;
@@ -984,6 +1024,10 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
          next = pos->ai_next;
          if ( (disablev6) && (pos->ai_family == AF_INET6))
            continue;
+         if ( (pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0) )
+           continue; /* not TCP */
+         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",
@@ -1012,6 +1056,7 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
        }
       GNUNET_free (hostname);
       freeaddrinfo (res);
+      resi = i;
     }
   else
     {
@@ -1077,14 +1122,13 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
 
 
 /**
- * Setup addr, addrlen, maxbuf, idle_timeout
+ * Setup addr, addrlen, idle_timeout
  * based on configuration!
  *
  * Configuration may specify:
  * - PORT (where to bind to for TCP)
  * - UNIXPATH (where to bind to for UNIX domain sockets)
  * - TIMEOUT (after how many ms does an inactive service timeout);
- * - MAXBUF (maximum incoming message size supported)
  * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
  * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
  * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
@@ -1097,14 +1141,15 @@ GNUNET_SERVICE_get_server_addresses (const char *serviceName,
 static int
 setup_service (struct GNUNET_SERVICE_Context *sctx)
 {
-  unsigned long long maxbuf;
   struct GNUNET_TIME_Relative idleout;
   int tolerant;
+#ifndef MINGW
   const char *lpid;
   unsigned int pid;
   const char *nfds;
   unsigned int cnt;
   int flags;
+#endif
 
   if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
                                        sctx->serviceName, "TIMEOUT"))
@@ -1124,23 +1169,6 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
     }
   else
     sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-  if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
-                                       sctx->serviceName, "MAXBUF"))
-    {
-      if (GNUNET_OK !=
-          GNUNET_CONFIGURATION_get_value_number (sctx->cfg,
-                                                 sctx->serviceName,
-                                                 "MAXBUF", &maxbuf))
-       {
-         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                     _("Specified value for `%s' of service `%s' is invalid\n"),
-                     "MAXBUF",
-                     sctx->serviceName);
-         return GNUNET_SYSERR;
-       }
-    }
-  else
-    maxbuf = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
 
   if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
                                        sctx->serviceName, "TOLERANT"))
@@ -1167,7 +1195,9 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
        (getpid () == (pid_t) pid) &&
        (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
        (1 == sscanf (nfds, "%u", &cnt)) &&
-       (cnt > 0) )
+       (cnt > 0) &&
+       (cnt < FD_SETSIZE) &&
+       (cnt + 4 < FD_SETSIZE) )
     {
       sctx->lsocks = GNUNET_malloc (sizeof(struct GNUNET_NETWORK_Handle*) * (cnt+1));
       while (0 < cnt--)
@@ -1201,16 +1231,12 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
                                             &sctx->addrlens)) )
     return GNUNET_SYSERR;
   sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
-  sctx->maxbuf = (size_t) maxbuf;
-  if (sctx->maxbuf != maxbuf)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _
-                  ("Value in configuration for `%s' and service `%s' too large!\n"),
-                  "MAXBUF", sctx->serviceName);
-      return GNUNET_SYSERR;
-    }
-
+  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");
@@ -1318,21 +1344,17 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct GNUNET_SERVICE_Context *sctx = cls;
   unsigned int i;
 
-  sctx->sched = tc->sched;
+  GNUNET_RESOLVER_connect (sctx->cfg);
   if (sctx->lsocks != NULL)
-    sctx->server = GNUNET_SERVER_create_with_sockets (tc->sched,
-                                                     &check_access,
+    sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
                                                      sctx,
                                                      sctx->lsocks,
-                                                     sctx->maxbuf,
                                                      sctx->timeout, sctx->require_found);
   else
-    sctx->server = GNUNET_SERVER_create (tc->sched,
-                                        &check_access,
+    sctx->server = GNUNET_SERVER_create (&check_access,
                                         sctx,
                                         sctx->addrs,
                                         sctx->addrlens,
-                                        sctx->maxbuf,
                                         sctx->timeout, sctx->require_found);
   if (sctx->server == NULL)
     {
@@ -1355,8 +1377,7 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     {
       /* install a task that will kill the server
          process if the scheduler ever gets a shutdown signal */
-      GNUNET_SCHEDULER_add_delayed (tc->sched,
-                                    GNUNET_TIME_UNIT_FOREVER_REL,
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
                                     &shutdown_task, sctx->server);
     }
   sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
@@ -1384,7 +1405,7 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
          i++;
        }
     }
-  sctx->task (sctx->task_cls, tc->sched, sctx->server, sctx->cfg);
+  sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
 }
 
 
@@ -1448,10 +1469,12 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
     return GNUNET_SYSERR;
   /* set stdin/stdout to /dev/null */
   if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
-    {
+    {      
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");
+      (void) CLOSE (nullfd);
       return GNUNET_SYSERR;
     }
+  (void) CLOSE (nullfd);
   /* Detach from controlling terminal */
   pid = setsid ();
   if (pid == -1)
@@ -1554,6 +1577,9 @@ GNUNET_SERVICE_run (int argc,
   char *logfile;
   int do_daemonize;
   unsigned int i;
+  unsigned long long skew_offset;
+  unsigned long long skew_variance;
+  long long clock_offset;
   struct GNUNET_SERVICE_Context sctx;
   struct GNUNET_CONFIGURATION_Handle *cfg;
   struct GNUNET_GETOPT_CommandLineOption service_options[] = {
@@ -1577,8 +1603,8 @@ GNUNET_SERVICE_run (int argc,
   sctx.ready_confirm_fd = -1;
   sctx.ret = GNUNET_OK;
   sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-  sctx.maxbuf = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
   sctx.task = task;
+  sctx.task_cls = task_cls;
   sctx.serviceName = serviceName;
   sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
   /* setup subsystems */
@@ -1600,6 +1626,15 @@ GNUNET_SERVICE_run (int argc,
               "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) &&
+      (GNUNET_OK == 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);
+#endif
+    }
   /* actually run service */
   GNUNET_SCHEDULER_run (&service_task, &sctx);
 
@@ -1640,13 +1675,11 @@ shutdown:
  * initialized system.
  *
  * @param serviceName our service name
- * @param sched scheduler to use
  * @param cfg configuration to use
  * @return NULL on error, service handle
  */
 struct GNUNET_SERVICE_Context *
 GNUNET_SERVICE_start (const char *serviceName,
-                      struct GNUNET_SCHEDULER_Handle *sched,
                       const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   int i;
@@ -1656,10 +1689,8 @@ GNUNET_SERVICE_start (const char *serviceName,
   sctx->ready_confirm_fd = -1;  /* no daemonizing */
   sctx->ret = GNUNET_OK;
   sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-  sctx->maxbuf = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
   sctx->serviceName = serviceName;
   sctx->cfg = cfg;
-  sctx->sched = sched;
 
   /* setup subsystems */
   if (GNUNET_OK != setup_service (sctx))
@@ -1668,19 +1699,15 @@ GNUNET_SERVICE_start (const char *serviceName,
       return NULL;
     }
   if (sctx->lsocks != NULL)
-    sctx->server = GNUNET_SERVER_create_with_sockets (sched,
-                                                     &check_access,
+    sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
                                                      sctx,
                                                      sctx->lsocks,
-                                                     sctx->maxbuf,
                                                      sctx->timeout, sctx->require_found);
   else
-    sctx->server = GNUNET_SERVER_create (sched,
-                                        &check_access,
+    sctx->server = GNUNET_SERVER_create (&check_access,
                                         sctx,
                                         sctx->addrs,
                                         sctx->addrlens,
-                                        sctx->maxbuf,
                                         sctx->timeout,
                                         sctx->require_found);