gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r8194 - GNUnet/src/util/os


From: gnunet
Subject: [GNUnet-SVN] r8194 - GNUnet/src/util/os
Date: Thu, 5 Feb 2009 01:47:17 -0700 (MST)

Author: holindho
Date: 2009-02-05 01:47:16 -0700 (Thu, 05 Feb 2009)
New Revision: 8194

Modified:
   GNUnet/src/util/os/osconfig.c
   GNUnet/src/util/os/user.c
Log:
autostart and adduser for OS X


Modified: GNUnet/src/util/os/osconfig.c
===================================================================
--- GNUnet/src/util/os/osconfig.c       2009-02-04 23:55:38 UTC (rev 8193)
+++ GNUnet/src/util/os/osconfig.c       2009-02-05 08:47:16 UTC (rev 8194)
@@ -176,13 +176,18 @@
         return GNUNET_YES;
     }
   return GNUNET_NO;
-#else
-#ifdef WINDOWS
+#elif defined(OSX)
+  if (ACCESS ("/bin/launchctl", X_OK) == 0)
+    {
+      if (ACCESS ("/Library/LaunchDaemons/", W_OK) == 0)
+        return GNUNET_YES;
+    }
+  return GNUNET_NO;
+#elif defined(WINDOWS)
   return IsWinNT ()? GNUNET_YES : GNUNET_NO;
 #else
   return GNUNET_NO;
 #endif
-#endif
 }
 
 /**
@@ -330,6 +335,169 @@
     }
 
   return GNUNET_YES;
+#elif defined(OSX)
+/* TODO: has much in common with the linux code */
+  struct stat buf;
+  int ret;
+  int i;
+  char *initscript;
+
+  i = strlen (application) - 1;
+  if (i <= 0)
+    return GNUNET_SYSERR;
+  while ((i > 0) && (application[i] != DIR_SEPARATOR))
+    i--;
+  if (application[i] == DIR_SEPARATOR)
+    i++;
+  if (strlen (&application[i]) == 0)
+    return GNUNET_SYSERR;
+
+  initscript = GNUNET_malloc (23 + 11 + strlen (&application[i]) + 6 + 1);
+  strcpy (initscript, "/Library/LaunchDaemons/org.gnunet.");
+  strcat (initscript, &application[i]);
+  strcat (initscript, ".plist");
+
+  if (ACCESS ("/bin/launchctl", X_OK) != 0)
+    {
+      GNUNET_free (initscript);
+      return GNUNET_SYSERR;
+    }
+
+  if (doAutoStart)
+    {
+      if (ACCESS (application, X_OK) != 0)
+        {
+          GNUNET_GE_LOG_STRERROR_FILE (ectx,
+                                       GNUNET_GE_ERROR | GNUNET_GE_USER |
+                                       GNUNET_GE_ADMIN | GNUNET_GE_IMMEDIATE,
+                                       "access", application);
+        }
+
+      if (STAT (initscript, &buf) == -1)
+        {
+          /* create init file */
+          FILE *f = FOPEN (initscript, "w");
+          if (f == NULL)
+            {
+              GNUNET_GE_LOG_STRERROR_FILE (ectx,
+                                           GNUNET_GE_ERROR | GNUNET_GE_USER |
+                                           GNUNET_GE_ADMIN |
+                                           GNUNET_GE_IMMEDIATE, "fopen",
+                                           initscript);
+              GNUNET_free (initscript);
+              return 2;
+            }
+          fprintf (f,
+                   "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                   "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" 
\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\";>\n"
+                   "<plist version=\"1.0\">\n"
+                   "<dict>\n"
+                   "   <key>Disabled</key>\n"
+                   "   <false/>\n"
+                   "   <key>OnDemand</key>\n"
+                   "   <false/>\n"
+                   "   <key>Label</key>\n"
+                   "   <string>org.gnunet.%s</string>\n"
+                   "   <key>ServiceDescription</key>\n"
+                   "   <string>%s</string>\n"
+                   "   <key>ProgramArguments</key>\n"
+                   "   <array>\n"
+                   "           <string>%s</string>\n"
+                   "           <string>-n</string>\n"
+                   "   </array>\n"
+                   "   <key>RunAtLoad</key>\n"
+                   "   <true/>\n"
+                   "   <key>LowPriorityIO</key>\n"
+                   "   <true/>\n"
+                   "</dict>\n"
+                   "</plist>\n", &application[i], servicename, application);
+          fclose (f);
+          if (0 != CHMOD (initscript, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))
+            {
+              GNUNET_GE_LOG_STRERROR_FILE (ectx,
+                                           GNUNET_GE_WARNING | GNUNET_GE_USER
+                                           | GNUNET_GE_ADMIN |
+                                           GNUNET_GE_IMMEDIATE, "chmod",
+                                           initscript);
+              GNUNET_free (initscript);
+              return GNUNET_SYSERR;
+            }
+        }
+      if (STAT (initscript, &buf) != -1)
+        {
+          errno = 0;
+          if (ACCESS ("/bin/launchctl", W_OK) == 0)
+            {
+              char *cmd;
+              cmd = GNUNET_malloc (20 + strlen (initscript) + 1);
+              sprintf (cmd, "/bin/launchctl load %s", initscript);
+              ret = system (cmd);
+              if (ret != 0)
+                {
+                  if (errno != 0)
+                    {
+                      GNUNET_GE_LOG_STRERROR_FILE (ectx,
+                                                   GNUNET_GE_WARNING |
+                                                   GNUNET_GE_USER |
+                                                   GNUNET_GE_ADMIN |
+                                                   GNUNET_GE_IMMEDIATE,
+                                                   "system",
+                                                   "/bin/launchctl");
+                    }
+                  else
+                    {
+                      GNUNET_GE_LOG (ectx,
+                                     GNUNET_GE_WARNING | GNUNET_GE_USER |
+                                     GNUNET_GE_ADMIN | GNUNET_GE_IMMEDIATE,
+                                     _
+                                     ("Command `%s' failed with error code 
%u\n"),
+                                     cmd, WEXITSTATUS (ret));
+                    }
+                  GNUNET_free (cmd);
+                  GNUNET_free (initscript);
+                  return GNUNET_SYSERR;
+                }
+              GNUNET_free (cmd);
+            }
+        }
+      GNUNET_free (initscript);
+      return GNUNET_YES;
+    }
+  else
+    {
+      errno = 0;
+      if (ACCESS ("/bin/launchctl", W_OK) == 0)
+        {
+          char *cmd;
+          cmd = GNUNET_malloc (22 + strlen (initscript) + 1);
+          sprintf (cmd, "/bin/launchctl unload %s", initscript);
+          ret = system (cmd);
+          if (ret != 0)
+            {
+              GNUNET_GE_LOG_STRERROR_FILE (ectx,
+                                           GNUNET_GE_WARNING | GNUNET_GE_USER
+                                           | GNUNET_GE_ADMIN |
+                                           GNUNET_GE_IMMEDIATE, "system",
+                                           "/bin/launchctl");
+              GNUNET_free (cmd);
+              GNUNET_free (initscript);
+              return GNUNET_SYSERR;
+            }
+          GNUNET_free (cmd);
+        }
+      if ((UNLINK (initscript) == -1) && (errno != ENOENT))
+        {
+          GNUNET_GE_LOG_STRERROR_FILE (ectx,
+                                       GNUNET_GE_WARNING | GNUNET_GE_USER |
+                                       GNUNET_GE_ADMIN | GNUNET_GE_IMMEDIATE,
+                                       "unlink", initscript);
+          GNUNET_free (initscript);
+          return GNUNET_SYSERR;
+        }
+      GNUNET_free (initscript);
+      return GNUNET_YES;
+    }
+  GNUNET_free (initscript);
 #else
   struct stat buf;
   int ret;

Modified: GNUnet/src/util/os/user.c
===================================================================
--- GNUnet/src/util/os/user.c   2009-02-04 23:55:38 UTC (rev 8193)
+++ GNUnet/src/util/os/user.c   2009-02-05 08:47:16 UTC (rev 8194)
@@ -22,12 +22,178 @@
  * @file util/os/user.c
  * @brief wrappers for UID functions
  * @author Christian Grothoff
+ * @author Heikki Lindholm
  */
 
 #include "platform.h"
 #include "gnunet_util_os.h"
 #include "gnunet_util_string.h"
 
+#ifdef OSX
+static int
+parse_dscl_user_list_line (FILE * f, char *name, size_t name_len, int *id)
+{
+  int c;
+  int state;
+  int64_t tmp_id = 0LL;
+  int tmp_sign = 0;
+  int len = 0;
+  int retval;
+
+  retval = 2;
+  state = 1;
+  while ((retval == 2) && ((c = fgetc (f)) != EOF))
+    {
+      switch (state)
+        {
+        case 1:                /* skip leading ws */
+          tmp_id = 0;
+          tmp_sign = 1;
+          len = 0;
+          if (c != ' ' || c != '\t' || c != '\n')
+            {
+              if (len < name_len)
+                name[len++] = (char) c;
+              else
+                retval = -1;
+              state = 2;
+            }
+          break;
+        case 2:                /* user/group name */
+          if (c == ' ' || c == '\t')
+            {
+              name[len] = '\0';
+              state = 3;
+            }
+          else if (c == '\n')
+            state = 1;          /* error? */
+          else
+            {
+              if (len < name_len)
+                name[len++] = (char) c;
+              else
+                retval = -1;
+            }
+          break;
+        case 3:                /* skip ws */
+          if ((c >= '0' && c <= '9') || c == '-')
+            {
+              state = 4;
+              if (c == '-')
+                tmp_sign = -1;
+              else
+                tmp_id = c - '0';
+            }
+          else if (c == '\n')
+            state = 1;
+          else if (c != ' ' && c != '\t')
+            retval = -1;
+          break;
+        case 4:                /* user/group id */
+          if (c >= '0' && c <= '9')
+            {
+              state = 4;
+              tmp_id = (tmp_id * 10) + (c - '0');
+              if (tmp_id > INT32_MAX)
+                retval = -1;
+            }
+          else if (c == '\n')
+            {
+              *id = tmp_sign * (int) tmp_id;
+              state = 1;
+              retval = 0;
+            }
+          else
+            {
+              state = 1;
+              retval = -1;
+            }
+          break;
+        }
+    }
+  return retval;
+}
+
+static int
+run_dscl_command (const char *dir, const char *name, const char *attr_tmpl,
+                  const char *attr_val)
+{
+  char *cmd;
+  static const char *prefix = "/usr/bin/dscl .";
+  size_t len;
+  int ret = 0;
+
+  if ((!dir || !name) || (attr_tmpl && !attr_val))
+    return -1;
+
+  len = strlen (prefix) + 1 + 6 + 1 + strlen (dir) + 1 + (1 + strlen (name));
+  if (attr_tmpl != NULL)
+    len += 1 + strlen (attr_tmpl);      /* space + len */
+  else
+    len += 1 + strlen ("RecordName") + 1 + strlen (name);
+  if (attr_val != NULL)
+    len += 1 + strlen (attr_val);       /* space + len */
+  len++;                        /* terminating nil */
+  cmd = GNUNET_malloc (len);
+  if (attr_tmpl)
+    {
+      char *s;
+      snprintf (cmd, len, "%s %s %s/_%s %s", prefix, "create", dir, name,
+                attr_tmpl);
+      s = GNUNET_strdup (cmd);
+      snprintf (cmd, len, s, attr_val);
+      GNUNET_free (s);
+      ret = system (cmd);
+    }
+  else
+    {
+      snprintf (cmd, len, "%s %s %s/_%s", prefix, "create", dir, name);
+      ret = system (cmd);
+      if (ret == 0)
+        {
+          snprintf (cmd, len, "%s %s %s/_%s RecordName %s", prefix, "append",
+                    dir, name, name);
+          ret = system (cmd);
+        }
+    }
+
+  if (ret == -1)
+    GNUNET_GE_LOG_STRERROR (NULL,
+                            GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                            GNUNET_GE_ADMIN, "system");
+  else if (WEXITSTATUS (ret) != 0)
+    GNUNET_GE_LOG (NULL,
+                   GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_ADMIN,
+                   _("`%s' returned with error code %u"),
+                   cmd, WEXITSTATUS (ret));
+
+
+  GNUNET_free (cmd);
+  return ret;
+}
+
+static int
+check_name (const char *name)
+{
+  static const char *allowed_chars =
+    "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
+  int i, j;
+
+  for (i = 0; i < strlen (name); i++)
+    {
+      int found = 0;
+      for (j = 0; j < strlen (allowed_chars); j++)
+        {
+          if (name[i] == allowed_chars[j])
+            found = 1;
+        }
+      if (!found)
+        return -1;
+    }
+  return 0;
+}
+#endif /* OSX */
+
 int
 GNUNET_configure_user_account (int testCapability,
                                int doAdd, const char *group_name,
@@ -71,7 +237,14 @@
           return GNUNET_SYSERR;
         }
 #endif
+#ifdef OSX
+      if (geteuid () != 0)
+        return GNUNET_SYSERR;
+      if (ACCESS ("/usr/bin/dscl", X_OK) == 0)
+        return GNUNET_OK;
       return GNUNET_SYSERR;
+#endif
+      return GNUNET_SYSERR;
     }
   if ((user_name == NULL) || (0 == strlen (user_name)))
     return 0;
@@ -79,8 +252,209 @@
 #ifdef WINDOWS
   if (IsWinNT ())
     return CreateServiceAccount (user_name, "GNUnet service account");
-#elif OSX
-  return GNUNET_SYSERR;         /* TODO */
+#elif defined(OSX)
+  if (ACCESS ("/usr/bin/dscl", X_OK) == 0)
+    {
+      const char *real_user_name = "\"GNUnet daemon\"";
+      const char *real_group_name = "\"GNUnet administrators\"";
+      int id, uid, gid;
+      int user_found, group_found;
+      char *s;
+      FILE *f;
+      int ret;
+
+      haveGroup = group_name && strlen (group_name) > 0;
+
+      if (check_name (user_name) != 0)
+        return GNUNET_SYSERR;
+      if (haveGroup && check_name (group_name) != 0)
+        return GNUNET_SYSERR;
+
+      s = GNUNET_malloc (256);
+
+      if (!haveGroup)
+        group_name = "nogroup";
+
+      f = popen ("/usr/bin/dscl . -list /Groups PrimaryGroupID 2> /dev/null",
+                 "r");
+      if (f == NULL)
+        {
+          GNUNET_GE_LOG_STRERROR_FILE (NULL,
+                                       GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                                       GNUNET_GE_ADMIN, "popen", "dscl");
+          GNUNET_free (s);
+          return GNUNET_SYSERR;
+        }
+      gid = -100;
+      group_found = 0;
+      while (!feof (f))
+        {
+          ret = parse_dscl_user_list_line (f, s, 256, &id);
+          if (ret < 0)
+            {
+              GNUNET_GE_LOG (NULL,
+                             GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                             GNUNET_GE_ADMIN,
+                             _("Error while parsing dscl output.\n"));
+              pclose (f);
+              GNUNET_free (s);
+              return GNUNET_SYSERR;
+            }
+          if (ret == 2)
+            break;
+          if (!group_found && id > gid && id < 500)
+            gid = id;
+          if (strcmp (s, group_name) == 0 ||
+              (s[0] == '_' && strcmp (s + 1, group_name) == 0))
+            {
+              gid = id;
+              group_found = 1;
+            }
+        }
+      pclose (f);
+      if (!haveGroup && !group_found)
+        {
+          GNUNET_GE_LOG (NULL,
+                         GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_ADMIN,
+                         _
+                         ("Couldn't find a group (`%s') for the new user and 
none was specified.\n"),
+                         group_name);
+          GNUNET_free (s);
+          return GNUNET_SYSERR;
+        }
+
+      f = popen ("/usr/bin/dscl . -list /Users UniqueID 2> /dev/null", "r");
+      if (f == NULL)
+        {
+          GNUNET_GE_LOG_STRERROR_FILE (NULL,
+                                       GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                                       GNUNET_GE_ADMIN, "popen", "dscl");
+          GNUNET_free (s);
+          return GNUNET_SYSERR;
+        }
+      uid = -100;
+      user_found = 0;
+      while (!feof (f))
+        {
+          ret = parse_dscl_user_list_line (f, s, 256, &id);
+          if (ret < 0)
+            {
+              GNUNET_GE_LOG (NULL,
+                             GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                             GNUNET_GE_ADMIN,
+                             _("Error while parsing dscl output.\n"));
+              pclose (f);
+              GNUNET_free (s);
+              return GNUNET_SYSERR;
+            }
+          if (ret == 2)
+            break;
+          if (!user_found && id > uid && id < 500)
+            uid = id;
+          if (strcmp (s, user_name) == 0 ||
+              (s[0] == '_' && strcmp (s + 1, user_name) == 0))
+            {
+              uid = id;
+              user_found = 1;
+            }
+        }
+      pclose (f);
+
+      if (haveGroup && !group_found)
+        {
+          if (gid > 400)
+            gid++;
+          else
+            gid = 400;
+          if (gid >= 500)
+            {
+              GNUNET_GE_LOG (NULL,
+                             GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                             GNUNET_GE_ADMIN,
+                             _
+                             ("Failed to find a free system id for the new 
group.\n"));
+              GNUNET_free (s);
+              return GNUNET_SYSERR;
+            }
+        }
+      if (!user_found)
+        {
+          if (uid > 400)
+            uid++;
+          else
+            uid = 400;
+          if (uid >= 500)
+            {
+              GNUNET_GE_LOG (NULL,
+                             GNUNET_GE_ERROR | GNUNET_GE_BULK |
+                             GNUNET_GE_ADMIN,
+                             _
+                             ("Failed to find a free system id for the new 
user.\n"));
+              GNUNET_free (s);
+              return GNUNET_SYSERR;
+            }
+        }
+
+      ret = 0;
+      if (haveGroup && !group_found)
+        {
+          ret = run_dscl_command ("/Groups", group_name, NULL, NULL);
+
+          if (ret == 0)
+            ret =
+              run_dscl_command ("/Groups", group_name, "Password %s",
+                                "\"*\"");
+          if (ret == 0)
+            {
+              snprintf (s, 12, "%d", gid);
+              ret =
+                run_dscl_command ("/Groups", group_name, "PrimaryGroupID %s",
+                                  s);
+            }
+          if (ret == 0)
+            ret =
+              run_dscl_command ("/Groups", group_name, "RealName %s",
+                                real_group_name);
+        }
+
+      if (!user_found)
+        {
+          if (ret == 0)
+            ret = run_dscl_command ("/Users", user_name, NULL, NULL);
+          if (ret == 0)
+            ret =
+              run_dscl_command ("/Users", user_name, "UserShell %s",
+                                "/usr/bin/false");
+          if (ret == 0)
+            ret =
+              run_dscl_command ("/Users", user_name, "RealName %s",
+                                real_user_name);
+          if (ret == 0)
+            {
+              snprintf (s, 12, "%d", uid);
+              ret = run_dscl_command ("/Users", user_name, "UniqueID %s", s);
+            }
+          if (ret == 0)
+            {
+              snprintf (s, 12, "%d", gid);
+              ret =
+                run_dscl_command ("/Users", user_name, "PrimaryGroupID %s",
+                                  s);
+            }
+          if (ret == 0)
+            ret =
+              run_dscl_command ("/Users", user_name, "NFSHomeDirectory %s",
+                                "/var/empty");
+          if (ret == 0)
+            ret =
+              run_dscl_command ("/Users", user_name, "passwd %s", "\"*\"");
+        }
+
+      GNUNET_free (s);
+      return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
+    }
+  else
+    return GNUNET_SYSERR;
 #else
   if (ACCESS ("/usr/sbin/adduser", X_OK) == 0)
     {





reply via email to

[Prev in Thread] Current Thread [Next in Thread]