this is version 0.1alpha
[rxpd] / src / rxpd.c
index 907a05d..7688c8b 100644 (file)
@@ -44,6 +44,7 @@ rxpd_init (struct event_base* 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;
 }
 
@@ -70,7 +71,7 @@ rxpd_log (struct rxpd_base* self, int level, const char* fmt, ...)
   va_start (ap, fmt);
   if (level <= (self?self->verbosity:LOG_DEBUG))
     {
-      if (self->daemonize)
+      if (!self || self->daemonize)
         vsyslog (level, fmt, ap);
       vfprintf (stderr, fmt, ap);
     }
@@ -163,9 +164,8 @@ rxpd_rule_delete (struct rxpd_rule* rule)
     }
 }
 
-//
-
 
+//
 struct rxpd_file*
 rxpd_file_new (struct rxpd_base* base, const char* filename)
 {
@@ -175,7 +175,10 @@ rxpd_file_new (struct rxpd_base* base, const char* filename)
   if (!filename ||
       strcspn(filename, RXPD_FILE_ILG_CHARS) != strlen (filename) ||
       strlen (filename) + strlen (base->basedir) > 4095)
-    return NULL;
+    {
+      rxpd_log (base, LOG_ERR, "illegal filename: '%s'\n", filename?filename:"");
+      return NULL;
+    }
 
   strcpy (buf, base->basedir);
   strcat (buf, filename);
@@ -193,6 +196,8 @@ rxpd_file_new (struct rxpd_base* base, const char* filename)
   llist_init (&self->rules);
 
   psplay_insert (&base->files, &self->node);
+
+  rxpd_log (base, LOG_INFO, "new file: '%s'\n", filename);
   return self;
 }
 
@@ -289,7 +294,6 @@ 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)
 {
@@ -300,6 +304,7 @@ rxpd_socket_new_tcp4 (struct rxpd_base* base, const char* addr, unsigned short p
 
   llist_init (&self->node);
 
+  // TODO all abort() shall become rxpd_die
   self->fd = socket (PF_INET, SOCK_STREAM, 0);
   if (self->fd == -1)
     abort ();
@@ -328,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)
@@ -373,7 +401,7 @@ rxpd_socket_accept (int fd, short event, void* ptr)
   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);
@@ -406,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;
@@ -462,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);
 
@@ -483,25 +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;
   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 ();
-
-  // TODO
-  rxpd_log (base, LOG_INFO, "incoming connection\n");
-
-
-  self->base = base;
+  self->socket = socket;
   self->file = NULL;
   self->tmp_str = NULL;
   llist_init (&self->tmp_list);
@@ -510,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;
 }
 
@@ -540,25 +559,65 @@ 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)
 {
   (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 (self->base, LOG_ERR, "no data\n");
+      rxpd_log (base, LOG_ERR, "no data\n");
       rxpd_buffer_printf (&self->out, "#ERROR: no data\n");
       close (fd);
       return;
     }
 
-  rxpd_log (self->base, LOG_DEBUG, "parse command '%s'\n", line);
+  rxpd_log (base, LOG_DEBUG, "parse command '%s'\n", line);
 
   static const struct cmd_table
   {
@@ -579,24 +638,30 @@ rxpd_connection_parse_cmd (int fd, short event, void* ptr)
       break;
   if (!i->cmd)
     {
-      rxpd_log (self->base, LOG_ERR, "no command\n");
+      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 (self->base, LOG_ERR, "illeagal filename\n");
+              rxpd_log (base, LOG_ERR, "illeagal filename\n");
               rxpd_buffer_printf (&self->out, "#ERROR: illegal filename\n");
               rxpd_connection_delete (self);
               return;
@@ -957,11 +1022,12 @@ 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);
 }
@@ -972,8 +1038,9 @@ 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);