new daemonizing code which chdir's and switches user etc
authorChristian Thaeter <ct@pipapo.org>
Wed, 31 Oct 2007 04:13:33 +0000 (05:13 +0100)
committerChristian Thaeter <ct@pipapo.org>
Wed, 31 Oct 2007 04:13:33 +0000 (05:13 +0100)
src/main.c
src/rxpd.h
src/rxpd_base.c
src/rxpd_file.c
tests/10basics.tests

index 27aabf3..012ccfa 100644 (file)
@@ -63,8 +63,8 @@ usage (void)
     //" -r          resolve names\n"
     //" -l log      log hits to logfile\n"
     " -L locale   set locale, must be a utf-8 locale, only LC_CTYPE is used\n"
+    " -U user     if started as root, run as user [default: nobody]\n"
     " -h          this usage information\n"
-    //" -U user     switch to user\n"
     );
 }
 
@@ -84,7 +84,7 @@ main (int argc, char** argv)
   opterr = 0;
   int opt;
 
-  while ((opt = getopt (argc, argv, "vVdDb:qt:u:p:i46rl:L:h")) != -1)
+  while ((opt = getopt (argc, argv, "vVdDb:qt:u:p:i46rl:L:U:h")) != -1)
     switch (opt)
       {
       case 'v':
@@ -104,7 +104,7 @@ main (int argc, char** argv)
         break;
       case 'b':
         if (!rxpd->basedir)
-          rxpd_set_basedir (rxpd, optarg);
+          rxpd->basedir = rxpd_strdup (optarg);
         else
           rxpd_fail (rxpd, "basedir already set\n");
         break;
@@ -136,7 +136,7 @@ main (int argc, char** argv)
           rxpd_fail (rxpd, "policy already set\n");
         break;
       case 'i':
-        rxpd->regflags |= REG_ICASE; 
+        rxpd->regflags |= REG_ICASE;
         break;
       case 'L':
         if (!rxpd->locale)
@@ -154,6 +154,12 @@ main (int argc, char** argv)
       case 'l:':
         break;
 #endif
+      case 'U':
+        if (!rxpd->user)
+          rxpd->user = rxpd_strdup (optarg);
+        else
+          rxpd_fail (rxpd, "user already set\n");
+        break;
       case 'h':
         usage ();
         exit (0);
@@ -176,12 +182,16 @@ main (int argc, char** argv)
   if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0)
     rxpd_fail (rxpd, "Not a utf-8 locale '%s'\n", rxpd->locale);
 
+  rxpd_log (rxpd, LOG_NOTICE, PACKAGE_STRING" starting up\n");
+
+  rxpd_enter_personality (rxpd);
+
   if (rxpd->policy)
     {
       if (rxpd_file_load (rxpd->policy))
-        rxpd_log (rxpd, LOG_INFO, "Loaded policy '%s'\n", rxpd->policy->filename);
+        rxpd_log (rxpd, LOG_INFO, "Loaded policy '%s'\n", rxpd->policy->node.key);
       else
-        rxpd_fail (rxpd, "Failed loading policy '%s'\n", rxpd->policy->filename);
+        rxpd_fail (rxpd, "Failed loading policy '%s'\n", rxpd->policy->node.key);
     }
 
   for (int i = optind; i < argc; ++i)
@@ -190,15 +200,6 @@ main (int argc, char** argv)
         rxpd_fail (rxpd, "Failed loading file '%s'\n", argv[i]);
     }
 
-  if (rxpd->daemonize)
-    {
-      rxpd_log (rxpd, LOG_NOTICE, "Daemonizing ...\n");
-      if (daemon(1, 0))
-        rxpd_fail (rxpd, "Couldn't daemonize\n");
-    }
-
-  rxpd_log (rxpd, LOG_NOTICE, PACKAGE_STRING" starting up\n");
-
   LLIST_FOREACH (&rxpd->sockets, n)
     {
       struct rxpd_socket* socket = (struct rxpd_socket*)n;
index 69e2889..9fa53c6 100644 (file)
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/resource.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#include <event.h>
+#include <fcntl.h>
 #include <pth.h>
 #include <time.h>
 #include <netdb.h>
+#include <pwd.h>
+#include <grp.h>
 
 #define RXPD_COMMANDS                                           \
   RXPD_CMD(CHECK,       "data against regular expressions")     \
@@ -99,6 +102,7 @@ struct rxpd_base
   int regflags;
   int daemonize;
   const char* locale;
+  const char* user;
 
   struct rxpd_file* policy;
 
@@ -130,8 +134,8 @@ rxpd_malloc (size_t size);
 char*
 rxpd_strdup (const char* str);
 
-struct rxpd_base*
-rxpd_set_basedir (struct rxpd_base*, const char* basedir);
+void
+rxpd_enter_personality (struct rxpd_base* self);
 
 //
 struct rxpd_rule
@@ -163,7 +167,6 @@ rxpd_rule_delete (struct rxpd_rule* self);
 struct rxpd_file
 {
   psplay node;          // key points to basename part of filename
-  const char* filename; // full filename
   //TODO later     struct stat last_stat;
   struct rxpd_base* base;
   pth_rwlock_t lock;
@@ -198,7 +201,6 @@ struct rxpd_socket
 {
   llist node;
   int fd;
-  struct event ev;
   struct rxpd_base* base;
   pth_t accepter;
   int (*rxpd_socket_addr)(struct rxpd_connection* conn, char* dst, const char* pfx, size_t size);
index cc517d7..65886e6 100644 (file)
@@ -35,6 +35,7 @@ rxpd_init (void)
   global_base.daemonize = 0;
   global_base.regflags = 0;
   global_base.locale = NULL;
+  global_base.user = NULL;
   global_base.policy = NULL;
 
   psplay_init_root (&global_base.files, rxpd_file_cmp, (psplay_delete_t)rxpd_file_delete);
@@ -117,23 +118,57 @@ rxpd_strdup (const char* str)
   return r;
 }
 
-struct rxpd_base*
-rxpd_set_basedir (struct rxpd_base* self, const char* basedir)
+void
+rxpd_enter_personality (struct rxpd_base* self)
 {
-  if (self && !self->basedir)
+  umask (0022);
+
+  if (chdir (self->basedir))
+    rxpd_fail (self, "couldn't change to basedir '%s'\n", self->basedir);
+
+  if (getuid() == 0  ||  geteuid() == 0)
     {
-      size_t sz = strlen (basedir);
-      if (basedir [sz-1] == '/')
-        {
-          self->basedir = rxpd_malloc (sz + 1);
-          strcpy (self->basedir, basedir);
-        }
-      else
-        {
-          self->basedir = rxpd_malloc (sz + 2);
-          strcpy (self->basedir, basedir);
-          self->basedir [sz] = '/';
-        }
+      struct passwd *pw;
+
+      if (!self->user)
+        self->user = rxpd_strdup ("nobody");
+
+      pw = getpwnam (self->user);
+      if (!pw)
+        rxpd_fail (self, "couldn't find user '%s'\n", self->user);
+
+      if (setgid (pw->pw_gid))
+        rxpd_fail (self, "setgid failed\n");
+
+      if (setgroups (1, &pw->pw_gid))
+        rxpd_fail (self, "setgroups failed\n");
+
+      if (setuid (pw->pw_uid))
+        rxpd_fail (self, "setuid failed\n");
+    }
+
+  if (self->daemonize)
+    {
+      struct rlimit lim;
+
+      if (getrlimit (RLIMIT_NOFILE, &lim))
+        rxpd_die ("rlimit error\n");
+
+      for (rlim_t i = 0; i < lim.rlim_max; ++i)
+        close (i);
+
+      int n = open("/dev/null",O_RDWR);
+      if (n < 0)
+        rxpd_fail (self, "Couldn't open /dev/null\n");
+      dup(n);
+      dup(n);
+
+      pid_t pid = fork();
+      if (pid < 0)
+        rxpd_fail (self, "Couldn't daemonize\n");
+      if (pid > 0)
+        exit (0);
+
+      setsid();
     }
-  return self;
 }
index ca6155f..3610730 100644 (file)
 struct rxpd_file*
 rxpd_file_new (struct rxpd_base* base, const char* filename)
 {
-  char buf[4096];
   struct rxpd_file* self = NULL;
 
   while (*filename == '/')
     ++filename;
 
   if (!filename ||
-      strcspn(filename, RXPD_FILE_ILG_CHARS) != strlen (filename) ||
+      strcspn (filename, RXPD_FILE_ILG_CHARS) != strlen (filename) ||
       strstr (filename, "../") ||
       strstr (filename, "/./") ||
+      filename[strlen (filename) - 1] == '/' ||
       strlen (filename) + strlen (base->basedir) > 4095)
     {
       rxpd_log (base, LOG_ERR, "illegal filename: '%s'\n", filename?filename:"");
       return NULL;
     }
 
-  strcpy (buf, base->basedir);
-  strcat (buf, filename);
-  filename = rxpd_strdup (buf);
-
   self = rxpd_malloc (sizeof (struct rxpd_file));
-  self->filename = filename;
   self->base = base;
   pth_rwlock_init (&self->lock);
 
-  psplay_init (&self->node, filename + strlen (base->basedir));
+  psplay_init (&self->node, rxpd_strdup (filename));
   llist_init (&self->rules);
 
   psplay_insert (&base->files, &self->node);
@@ -65,7 +60,7 @@ rxpd_file_delete (struct rxpd_file* self)
     {
       rxpd_file_rules_delete (self);
       psplay_remove (&self->base->files, &self->node);
-      free ((void*)self->filename);
+      free ((void*)self->node.key);
       free (self);
     }
 }
@@ -89,7 +84,7 @@ rxpd_file_rules_delete (struct rxpd_file* self)
 int
 rxpd_file_load (struct rxpd_file* self)
 {
-  FILE* f = fopen (self->filename, "r");
+  FILE* f = fopen (self->node.key, "r");
   if (f)
     {
       pth_rwlock_acquire (&self->lock, PTH_RWLOCK_RW, FALSE, NULL);
@@ -104,7 +99,7 @@ rxpd_file_load (struct rxpd_file* self)
       // TODO test excess line length = error
       char buf[4096];
 
-      rxpd_log (self->base, LOG_NOTICE, "loading '%s'\n", self->filename);
+      rxpd_log (self->base, LOG_NOTICE, "loading '%s'\n", self->node.key);
 
       while (fgets (buf, 4096, f))
         {
@@ -125,7 +120,7 @@ rxpd_file_load (struct rxpd_file* self)
     }
   else
     {
-      rxpd_log (self->base, LOG_ERR, "failed loading '%s'\n", self->filename);
+      rxpd_log (self->base, LOG_ERR, "failed loading '%s'\n", self->node.key);
       return 0;
     }
 }
@@ -134,14 +129,14 @@ rxpd_file_load (struct rxpd_file* self)
 int
 rxpd_file_save (struct rxpd_file* self)
 {
-  char* filename = strdupa (self->filename);
+  char* filename = strdupa (self->node.key);
 
   char* slash = filename;
 
   while ((slash = strchr (slash+1, '/')))
     {
       *slash = '\0';
-      mkdir(filename, 0777);
+      mkdir (filename, 0777);
       *slash = '/';
     }
 
index 80e8f44..79de3e7 100644 (file)
@@ -26,6 +26,7 @@ out:  -q          be quiet
 out:  -t port     listen on tcp port
 out:  -p policy   define a list for access policies
 out:  -L locale   set locale, must be a utf-8 locale, only LC_CTYPE is used
+out:  -U user     if started as root, run as user [default: nobody]
 out:  -h          this usage information
 return: 0
 END