this is version 0.1alpha
[rxpd] / src / rxpd.c
index d22ae03..7688c8b 100644 (file)
 static struct rxpd_base global_base;
 
 struct rxpd_base*
-rxpd_init (char* rulesdir)
+rxpd_init (struct event_base* eventbase)
 {
-  if (global_base.rulesdir)
+  if (global_base.basedir)
     return NULL;
 
-  global_base.rulesdir = strdup (rulesdir);
-  if (!global_base.rulesdir) abort();
+  global_base.basedir = NULL;
 
-  psplay_init_root (&global_base.files, rxpd_file_cmp, rxpd_file_delete);
+  global_base.verbosity = LOG_WARNING;
+  global_base.daemonize = 0;
+  global_base.regflags = 0;
+  global_base.policy = NULL;
+
+  if (!eventbase)
+    rxpd_die ("no eventbase provided");
 
+  global_base.eventbase = eventbase;
+
+  psplay_init_root (&global_base.files, rxpd_file_cmp, rxpd_file_delete);
   llist_init (&global_base.sockets);
 
+  rxpd_log (&global_base, LOG_DEBUG, PACKAGE_NAME" initialized\n");
   return &global_base;
 }
 
+
 void
 rxpd_destroy (void)
 {
-  if (global_base.rulesdir)
+  if (global_base.basedir)
     {
-      free (global_base.rulesdir);
+      free (global_base.basedir);
       psplay_destroy_root (&global_base.files);
       LLIST_WHILE_HEAD (&global_base.sockets, n)
         {
@@ -54,53 +64,90 @@ rxpd_destroy (void)
     }
 }
 
+void
+rxpd_log (struct rxpd_base* self, int level, const char* fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  if (level <= (self?self->verbosity:LOG_DEBUG))
+    {
+      if (!self || self->daemonize)
+        vsyslog (level, fmt, ap);
+      vfprintf (stderr, fmt, ap);
+    }
+  va_end (ap);
+}
+
+void
+rxpd_die (const char* fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  vsyslog (LOG_EMERG, fmt, ap);
+  vfprintf (stderr, fmt, ap);
+  va_end (ap);
+  abort ();
+}
+
+void*
+rxpd_malloc (size_t size)
+{
+  void* r;
+  r = malloc (size);
+  if (!r)
+    rxpd_die ("Out of Memeory\n");
+  return r;
+}
+
+char*
+rxpd_strdup (const char* str)
+{
+  char* r;
+  r = strdup (str);
+  if (!r)
+    rxpd_die ("Out of Memeory\n");
+  return r;
+}
 
 //
 struct rxpd_rule*
 rxpd_rule_new (const char* buf)
 {
-  struct rxpd_rule* self = malloc (sizeof (struct rxpd_rule));
-  if (self)
+  struct rxpd_rule* self = rxpd_malloc (sizeof (struct rxpd_rule));
+
+  llist_init (&self->node);
+
+  if (*buf != '#')
     {
-      llist_init (&self->node);
+      int err;
+      char* rxstart = strchr (buf, ':');
 
-      if (*buf != '#')
+      if (!rxstart)
+        self->string = rxpd_strdup ("#ERROR: Syntax error, line was neither a comment nor a rule");
+      else
         {
-          int err;
-          char* rxstart = strchr (buf, ':');
+          // TODO regflags from base
+          err = regcomp (&self->rx, rxstart+1, REG_EXTENDED|REG_ICASE|REG_NOSUB);
 
-          if (!rxstart)
-            self->string = strdup ("#ERROR: Syntax error, line was neither a comment nor a rule");
+          if (!err)
+            self->string = rxpd_strdup (buf);
           else
             {
-              err = regcomp (&self->rx, rxstart+1, REG_EXTENDED|REG_ICASE|REG_NOSUB);
-
-              if (!err)
-                {
-                  self->string = strdup (buf);
-                  if (!self->string) abort();
-                }
-              else
-                {
-                  regfree (&self->rx);
-                  char ebuf[256];
-                  size_t len = regerror (err, NULL, ebuf, 256);
-                  self->string = malloc(len + strlen(buf) + 14);
-                  if (!self->string) abort();
-                  strcpy (self->string, "#ERROR: ");
-                  strcat (self->string, ebuf);
-                  strcat (self->string, " in '");
-                  strcat (self->string, buf);
-                  strcat (self->string, "'");
-                }
+              regfree (&self->rx);
+              char ebuf[256];
+              size_t len = regerror (err, NULL, ebuf, 256);
+              self->string = rxpd_malloc (len + strlen(buf) + 14);
+              strcpy (self->string, "#ERROR: ");
+              strcat (self->string, ebuf);
+              strcat (self->string, " in '");
+              strcat (self->string, buf);
+              strcat (self->string, "'");
             }
         }
-      else
-        {
-          self->string = strdup (buf);
-          if (!self->string) abort();
-        }
     }
+  else
+    self->string = rxpd_strdup (buf);
+
   return self;
 }
 
@@ -117,9 +164,8 @@ rxpd_rule_delete (struct rxpd_rule* rule)
     }
 }
 
-//
-
 
+//
 struct rxpd_file*
 rxpd_file_new (struct rxpd_base* base, const char* filename)
 {
@@ -128,29 +174,30 @@ rxpd_file_new (struct rxpd_base* base, const char* filename)
 
   if (!filename ||
       strcspn(filename, RXPD_FILE_ILG_CHARS) != strlen (filename) ||
-      strlen (filename) + strlen (base->rulesdir) > 4095)
-    return NULL;
+      strlen (filename) + strlen (base->basedir) > 4095)
+    {
+      rxpd_log (base, LOG_ERR, "illegal filename: '%s'\n", filename?filename:"");
+      return NULL;
+    }
 
-  strcpy (buf, base->rulesdir);
+  strcpy (buf, base->basedir);
   strcat (buf, filename);
-  filename = strdup (buf);
-  if (filename)
-    {
-      self = malloc (sizeof (struct rxpd_file));
-      if (self)
-        {
-          self->filename = filename;
-          const char* basename = strrchr (filename, '/');
-          if (basename)
-            ++basename;
-          else
-            basename = filename;
-          psplay_init (&self->node, basename);
-          llist_init (&self->rules);
+  filename = rxpd_strdup (buf);
 
-          psplay_insert (&base->files, &self->node);
-        }
-    }
+  self = rxpd_malloc (sizeof (struct rxpd_file));
+  self->filename = filename;
+  self->base = base;
+  const char* basename = strrchr (filename, '/');
+  if (basename)
+    ++basename;
+  else
+    basename = filename;
+  psplay_init (&self->node, basename);
+  llist_init (&self->rules);
+
+  psplay_insert (&base->files, &self->node);
+
+  rxpd_log (base, LOG_INFO, "new file: '%s'\n", filename);
   return self;
 }
 
@@ -187,6 +234,8 @@ 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);
+
       while (fgets (buf, 4096, f))
         {
           size_t last = strlen(buf);
@@ -198,7 +247,7 @@ rxpd_file_load (struct rxpd_file* self)
           if (!rule)
             abort();
 
-          printf("loaded rule '%s'\n", rule->string);
+          rxpd_log (self->base, LOG_DEBUG, "new rule '%s'\n", rule->string);
 
           llist_insert_tail (&self->rules, &rule->node);
         }
@@ -207,7 +256,10 @@ rxpd_file_load (struct rxpd_file* self)
       return 1;
     }
   else
-    return 0;
+    {
+      rxpd_log (self->base, LOG_ERR, "failed loading '%s'\n", self->filename);
+      return 0;
+    }
 }
 
 int
@@ -224,10 +276,14 @@ rxpd_file_save (struct rxpd_file* self)
         }
 
       fclose (f);
+      rxpd_log (self->base, LOG_NOTICE, "saved '%s'\n", self->filename);
       return 1;
     }
   else
-    return 0;
+    {
+      rxpd_log (self->base, LOG_ERR, "failed saving '%s'\n", self->filename);
+      return 0;
+    }
 }
 
 int
@@ -238,18 +294,17 @@ rxpd_file_cmp (const void* A, const void* B)
 
 
 //
-
 struct rxpd_socket*
 rxpd_socket_new_tcp4 (struct rxpd_base* base, const char* addr, unsigned short port)
 {
-  struct rxpd_socket* self = malloc (sizeof (struct rxpd_socket));
-  if (!self)
-    abort();
+  struct rxpd_socket* self;
+  self = rxpd_malloc (sizeof (struct rxpd_socket));
 
   self->base = base;
 
   llist_init (&self->node);
 
+  // TODO all abort() shall become rxpd_die
   self->fd = socket (PF_INET, SOCK_STREAM, 0);
   if (self->fd == -1)
     abort ();
@@ -278,11 +333,34 @@ rxpd_socket_new_tcp4 (struct rxpd_base* base, const char* addr, unsigned short p
   if (listen (self->fd, 20) == -1)
     abort ();
 
+  self->rxpd_socket_addr = rxpd_socket_tcp4addr;
+
   event_set (&self->ev, self->fd, EV_READ, rxpd_socket_accept, self);
   llist_insert_tail (&base->sockets, &self->node);
+
+  rxpd_log (base, LOG_INFO, "Listening on tcp4:%d\n", port);
   return self;
 }
 
+int
+rxpd_socket_tcp4addr (struct rxpd_connection* conn, char* dst, const char* pfx, size_t size)
+{
+  struct sockaddr_in peer;
+  socklen_t len = sizeof (peer);
+  getpeername (conn->fd, (struct sockaddr*)&peer, &len);
+
+  char* addr;
+  addr = inet_ntoa (peer.sin_addr);
+  if (sizeof (":tcp4:") + strlen (pfx) + strlen (addr) > size)
+    return 0;
+
+  strcat (dst, pfx);
+  strcat (dst, ":tcp4:");
+  strcat (dst, addr);
+  return 1;
+}
+
+
 
 void
 rxpd_socket_delete (struct rxpd_socket* self)
@@ -319,12 +397,11 @@ rxpd_socket_suspend (struct rxpd_socket* self)
 void
 rxpd_socket_accept (int fd, short event, void* ptr)
 {
-  printf ("incoming connection\n");
-
+  (void) event;
   struct rxpd_socket* self = ptr;
 
   struct rxpd_connection* conn =
-    rxpd_connection_new (self->base, fd);
+    rxpd_connection_new (self, fd);
 
   rxpd_connection_schedule (conn);
   rxpd_socket_schedule (self);
@@ -357,7 +434,6 @@ rxpd_buffer_readline (struct rxpd_buffer* self, int again)
       // TODO handle \r's
     }
 
-
   if (!again && self->state == RXPD_OK)   // we only read when again is 0, first iteration
     {
       ssize_t r = 0;
@@ -413,10 +489,8 @@ int
 rxpd_buffer_printf (struct rxpd_buffer* self, const char* fmt, ...)
 {
   // for now we do a blocking write, needs to be fixed some day
-  // add string to buffer
   va_list ap;
   va_start(ap, fmt);
-  //int sz = self->buffer+4096 - self->eob;
   int n = vsnprintf (self->buffer, 4096, fmt, ap);
   va_end(ap);
 
@@ -434,22 +508,16 @@ rxpd_buffer_printf (struct rxpd_buffer* self, const char* fmt, ...)
 ///
 
 struct rxpd_connection*
-rxpd_connection_new (struct rxpd_base* base, int fd)
+rxpd_connection_new (struct rxpd_socket* socket, int fd)
 {
-  struct rxpd_connection* self = malloc (sizeof (struct rxpd_connection));
-  if (!self)
-    abort();
+  struct rxpd_connection* self;
+  self = rxpd_malloc (sizeof (struct rxpd_connection));
 
-  socklen_t addr_sz = sizeof (self->peer_addr); 
-  self->fd = accept (fd, (struct sockaddr*)&self->peer_addr, &addr_sz);
+  self->fd = accept (fd, NULL, 0);
   if (self->fd == -1)
     abort ();
 
-  static int yes = 1;
-  if (setsockopt (self->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
-    abort ();
-
-  self->base = base;
+  self->socket = socket;
   self->file = NULL;
   self->tmp_str = NULL;
   llist_init (&self->tmp_list);
@@ -458,6 +526,9 @@ rxpd_connection_new (struct rxpd_base* base, int fd)
   rxpd_buffer_init (&self->out, self);
   
   event_set (&self->ev, self->fd, EV_READ, rxpd_connection_parse_cmd, self);
+
+  // TODO more info
+  rxpd_log (socket->base, LOG_INFO, "incoming connection\n");
   return self;
 }
 
@@ -488,22 +559,66 @@ rxpd_connection_schedule (struct rxpd_connection* self)
   return self;
 }
 
+int
+rxpd_connection_check_policy (struct rxpd_connection* self, char* line)
+{
+  struct rxpd_base* base = self->socket->base;
+  if (base->policy)
+    {
+      char buf[256];
+      buf[0] = '\0';
+
+      if (!self->socket->rxpd_socket_addr (self, buf, line, 256))
+        {
+          rxpd_log (base, LOG_ERR, "policy line too long\n");
+          return 0;
+        }
+
+      rxpd_log (base, LOG_DEBUG, "policy check '%s'\n", buf);
+
+      char* match = NULL;
+      LLIST_FOREACH (&base->policy->rules, n)
+      {
+        struct rxpd_rule* rule = (struct rxpd_rule*)n;
+        if (rule->string[0] != '#')
+          {
+            if (regexec (&rule->rx, buf, 0, NULL, 0) == 0)
+              {
+                match = rule->string;
+                break;
+              }
+          }
+      }
+
+      if (!match || strncmp("ACCEPT:", match, sizeof("ACCEPT:")-1) != 0)
+        {
+          rxpd_log (base, LOG_WARNING, "access denied '%s'\n", buf);
+          return 0;
+        }
+    }
+  return 1;
+}
 void
 rxpd_connection_parse_cmd (int fd, short event, void* ptr)
 {
-  printf ("parse cmd\n");
+  (void) event;
+
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
+  struct rxpd_base* base = self->socket->base;
 
   char* line;
   line = rxpd_buffer_readline (&self->in, 0);
 
   if (!line)
     {
+      rxpd_log (base, LOG_ERR, "no data\n");
       rxpd_buffer_printf (&self->out, "#ERROR: no data\n");
       close (fd);
       return;
     }
 
+  rxpd_log (base, LOG_DEBUG, "parse command '%s'\n", line);
+
   static const struct cmd_table
   {
     enum rxpd_cmd_e nr;
@@ -523,22 +638,30 @@ rxpd_connection_parse_cmd (int fd, short event, void* ptr)
       break;
   if (!i->cmd)
     {
+      rxpd_log (base, LOG_ERR, "no command\n");
       rxpd_buffer_printf (&self->out, "#ERROR: no command\n");
       rxpd_connection_delete (self);
       return;
     }
-  // TODO policy check here
+
+  if (!rxpd_connection_check_policy (self, line))
+    {
+      rxpd_buffer_printf (&self->out, "#ERROR: access denied\n");
+      rxpd_connection_delete (self);
+      return;
+    }
 
   if (line[i->sz])
     {
       // rulename provided
-      self->file = (struct rxpd_file*) psplay_find (&self->base->files, &line[i->sz]);
+      self->file = (struct rxpd_file*) psplay_find (&base->files, &line[i->sz]);
 
       if (!self->file)
         {
-          self->file = rxpd_file_new (self->base, &line[i->sz]);
+          self->file = rxpd_file_new (base, &line[i->sz]);
           if (!self->file)
             {
+              rxpd_log (base, LOG_ERR, "illeagal filename\n");
               rxpd_buffer_printf (&self->out, "#ERROR: illegal filename\n");
               rxpd_connection_delete (self);
               return;
@@ -564,13 +687,14 @@ case RXPD_CMD_##cmd:
 void
 rxpd_connection_cmd_CHECK (int fd, short event, void* ptr)
 {
+  (void) fd;
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
 
   if (event == EV_READ)
     {
       int again = -1;
       char* line;
-      while (line = rxpd_buffer_readline (&self->in, ++again))
+      while ((line = rxpd_buffer_readline (&self->in, ++again)))
         {
           if (*line == '\0')
             {
@@ -613,7 +737,7 @@ rxpd_connection_cmd_CHECK (int fd, short event, void* ptr)
 
 
 static void
-rxpd_connection_APPEND_PREPEND_helper (int fd, short event, void* ptr, int do_append)
+rxpd_connection_APPEND_PREPEND_helper (short event, void* ptr, int do_append)
 {
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
 
@@ -622,7 +746,7 @@ rxpd_connection_APPEND_PREPEND_helper (int fd, short event, void* ptr, int do_ap
       int again = -1;
       char* line;
 
-      while (line = rxpd_buffer_readline (&self->in, ++again))
+      while ((line = rxpd_buffer_readline (&self->in, ++again)))
         {
           if (*line)
             {
@@ -667,26 +791,29 @@ rxpd_connection_APPEND_PREPEND_helper (int fd, short event, void* ptr, int do_ap
 void
 rxpd_connection_cmd_APPEND (int fd, short event, void* ptr)
 {
-  rxpd_connection_APPEND_PREPEND_helper (fd, event, ptr, 1);
+  (void) fd;
+  rxpd_connection_APPEND_PREPEND_helper (event, ptr, 1);
 }
 
 void
 rxpd_connection_cmd_PREPEND (int fd, short event, void* ptr)
 {
-  rxpd_connection_APPEND_PREPEND_helper (fd, event, ptr, 0);
+  (void) fd;
+  rxpd_connection_APPEND_PREPEND_helper (event, ptr, 0);
 }
 
 
 void
 rxpd_connection_cmd_REMOVE (int fd, short event, void* ptr)
 {
+  (void) fd;
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
 
   if (event == EV_READ)
     {
       int again = -1;
       char* line;
-      while (line = rxpd_buffer_readline (&self->in, ++again))
+      while ((line = rxpd_buffer_readline (&self->in, ++again)))
         {
           LLIST_FOREACH (&self->file->rules, n)
             {
@@ -746,13 +873,14 @@ rxpd_connection_do_REPLACE (struct rxpd_connection* self)
 void
 rxpd_connection_cmd_REPLACE (int fd, short event, void* ptr)
 {
+  (void) fd;
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
 
   if (event == EV_READ)
     {
       int again = -1;
       char* line;
-      while (line = rxpd_buffer_readline (&self->in, ++again))
+      while ((line = rxpd_buffer_readline (&self->in, ++again)))
         {
           if (self->tmp_str)
             {
@@ -768,10 +896,7 @@ rxpd_connection_cmd_REPLACE (int fd, short event, void* ptr)
               /* TODO handle empty lines? */
             }
           else
-            {
-              self->tmp_str = strdup (line);
-              if (!self->tmp_str) abort();
-            }
+            self->tmp_str = rxpd_strdup (line);
         }
     }
   else if (!self->file)
@@ -802,6 +927,7 @@ rxpd_connection_cmd_REPLACE (int fd, short event, void* ptr)
 void
 rxpd_connection_cmd_LOAD (int fd, short event, void* ptr)
 {
+  (void) fd;
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
 
   if (!event)
@@ -826,6 +952,7 @@ rxpd_connection_cmd_LOAD (int fd, short event, void* ptr)
 void
 rxpd_connection_cmd_SAVE (int fd, short event, void* ptr)
 {
+  (void) fd;
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
 
   if (!event)
@@ -850,6 +977,7 @@ rxpd_connection_cmd_SAVE (int fd, short event, void* ptr)
 void
 rxpd_connection_cmd_DUMP (int fd, short event, void* ptr)
 {
+  (void) fd;
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
 
   if (!event && !self->file)
@@ -891,12 +1019,15 @@ walk_LIST (PSplay node, const enum psplay_order_e which, int level, void* data)
 void
 rxpd_connection_cmd_LIST (int fd, short event, void* ptr)
 {
+  (void) fd;
+  (void) event;
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
+  struct rxpd_base* base = self->socket->base;
 
-  if (psplay_isempty_root (&self->base->files))
+  if (psplay_isempty_root (&base->files))
     rxpd_buffer_printf (&self->out, "#OK:\n");
   else
-    psplay_walk (&self->base->files, NULL, walk_LIST, 0, ptr);
+    psplay_walk (&base->files, NULL, walk_LIST, 0, ptr);
 
   rxpd_connection_delete (self);
 }
@@ -904,9 +1035,12 @@ rxpd_connection_cmd_LIST (int fd, short event, void* ptr)
 void
 rxpd_connection_cmd_SHUTDOWN (int fd, short event, void* ptr)
 {
+  (void) fd;
+  (void) event;
   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
+  struct rxpd_base* base = self->socket->base;
   // destroy all sockets
-  LLIST_WHILE_HEAD (&self->base->sockets, n)
+  LLIST_WHILE_HEAD (&base->sockets, n)
     {
       struct rxpd_socket* socket = (struct rxpd_socket*)n;
       rxpd_socket_delete (socket);