first simple rxpd access check
authorChristian Thaeter <ct@pipapo.org>
Wed, 23 Jan 2008 13:22:07 +0000 (14:22 +0100)
committerChristian Thaeter <ct@pipapo.org>
Wed, 23 Jan 2008 13:22:07 +0000 (14:22 +0100)
this checks the tuple
 HOST=%s:USER-AGENT=%s:ACTION=%s:REPO=%s:HEAD=%s
against the list 'webgit/access' on the configured rxpd

An example rxpd webgit/access list looks like following:
# format: HOST=%s:USER-AGENT=%s:ACTION=%s:REPO=%s:HEAD=%s
:allow:^HOST=10\.20\.[^:]*:
:allow:^HOST=127\.0\.0\.1:
:deny::ACTION=config:
:allow:

Makefile.am
src/options.c
src/query.c
src/rxpd_client.c [new file with mode: 0644]
src/rxpd_client.h [new file with mode: 0644]
src/webgit.c
src/webgit.h

index dec8a54..6b7e63b 100644 (file)
@@ -52,7 +52,8 @@ webgit_SOURCES =                              \
        $(webgit_srcdir)/object_tag.c           \
        $(webgit_srcdir)/branch.c               \
        $(webgit_srcdir)/tag.c                  \
-       $(webgit_srcdir)/log.c
+       $(webgit_srcdir)/log.c                  \
+       $(webgit_srcdir)/rxpd_client.c
 
 noinst_HEADERS =                               \
        $(webgit_srcdir)/webgit.h               \
@@ -65,7 +66,8 @@ noinst_HEADERS =                              \
        $(webgit_srcdir)/object.h               \
        $(webgit_srcdir)/branch.h               \
        $(webgit_srcdir)/tag.h                  \
-       $(webgit_srcdir)/log.h
+       $(webgit_srcdir)/log.h                  \
+       $(webgit_srcdir)/rxpd_client.h
 
 webgit_DEPENDENCIES = $(abs_top_builddir)/git/libgit.a $(abs_top_builddir)/git/xdiff/lib.a
 
index 8b3d64c..e1d4c70 100644 (file)
@@ -68,22 +68,8 @@ conf_rxpd_opt (struct webgit_query* query, char* arg)
 {
   char* delim = strchr (arg, ':');
 
-  if (delim)
-    {
-      query->rxpd_name = cwa_strndup (arg, delim-arg-1);
-      query->rxpd_port = atoi (delim+1);
-    }
-  else if (strchr (arg, '/'))
-    {
-      query->rxpd_name = cwa_strndup (arg, SIZE_MAX);
-      query->rxpd_port = 0;
-      return -1; /* rxpd doesnt yet support unix domain sockets */
-    }
-  else
-    {
-      return -1;
-    }
-
+  free (query->rxpd);
+  query->rxpd = cwa_strndup (arg, SIZE_MAX);
   return 0;
 }
 
index 4662b8d..95578b6 100644 (file)
@@ -38,8 +38,7 @@ webgit_query_init (struct webgit_query* q)
   q->content_type = cwa_strndup ("text/html", SIZE_MAX);
 
   q->count_def = 100;
-  q->rxpd_name = NULL;
-  q->rxpd_port = 0;
+  q->rxpd = NULL;
   q->skindir = cwa_strndup (WEBGIT_SKINDIR_DEFAULT, SIZE_MAX);
   q->webskindir = cwa_strndup (WEBGIT_WEBSKINDIR_DEFAULT, SIZE_MAX);
 
@@ -62,7 +61,7 @@ webgit_query_destroy (struct webgit_query* q)
   cgi_free (q->request);
 
   free (q->content_type);
-  free (q->rxpd_name);
+  free (q->rxpd);
   free (q->skindir);
   free (q->webskindir);
 
diff --git a/src/rxpd_client.c b/src/rxpd_client.c
new file mode 100644 (file)
index 0000000..ba882d8
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+    rxpd_client.c - regex policy daemon, client library
+
+  Copyright (C)
+    2007, 2008,         Christian Thaeter <ct@pipapo.org>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <poll.h>
+
+struct rxpd_client
+{
+  char* address;
+  char* port;
+  struct addrinfo* ai;
+
+  char* prefix;
+  FILE* handle;
+  char buf[4096];
+};
+typedef struct rxpd_client* RxpdClient;
+
+/*
+  initialize a RxpdClient handle 'self'
+  'address' is the address of the rxpd to connect to,
+  either "host:port" for TCP or "path/to/socket" notation for unix domain sockets
+  'prefix' is the leading part for any list queried
+ */
+RxpdClient
+rxpd_client_init (RxpdClient self, const char* address, const char* prefix)
+{
+  if (!self || !address)
+    return NULL;
+
+  self->handle = NULL;
+
+  self->address = strdup (address);
+  self->prefix = strdup (prefix);
+  if (!self->prefix || !self->address)
+    return NULL;
+
+  char* delim = strchr (self->address, ':');
+  if (delim)
+    {
+      /* TCP socket */
+      *delim = '\0';
+      self->port = delim+1;
+    }
+  else if (strchr (self->address, '/'))
+    {
+      /* unix domain socket */
+      self->port = NULL;
+      return NULL; /* TODO: rxpd doesnt yet support unix domain sockets */
+    }
+  else
+    {
+      /* syntax error */
+      return NULL;
+    }
+
+  /* resolve peer */
+  self->ai = NULL;
+  if (getaddrinfo (self->address, self->port, NULL, &self->ai))
+    return NULL;
+
+  return self;
+}
+
+
+/*
+  Destruct a rxpd_client structure
+ */
+RxpdClient
+rxpd_client_destroy (RxpdClient self)
+{
+  if (self)
+    {
+      free (self->prefix);
+      free (self->address);
+      if (self->ai)
+        freeaddrinfo (self->ai);
+      if (self->handle)
+        fclose (self->handle);
+    }
+  return self;
+}
+
+
+/*
+  destruct and free a rxpd_client structure
+*/
+void
+rxpd_client_free (RxpdClient self)
+{
+  free (rxpd_client_destroy (self));
+}
+
+
+/*
+  allocate and initialize a rxpd_client structure
+*/
+RxpdClient
+rxpd_client_new (const char* address, const char* prefix)
+{
+  RxpdClient self = malloc (sizeof (struct rxpd_client));
+  if (!rxpd_client_init (self, address, prefix))
+    {
+      rxpd_client_free (self);
+      return NULL;
+    }
+  return self;
+}
+
+
+/*
+  open connection to rxpd if not already open
+ */
+int
+rxpd_client_open (RxpdClient self)
+{
+  if (self && !self->handle)
+    {
+      int fd;
+      fd = socket (self->ai->ai_family, self->ai->ai_socktype, self->ai->ai_protocol);
+      if (fd == -1)
+        return 0;
+
+      if (connect (fd, self->ai->ai_addr, self->ai->ai_addrlen))
+        {
+          close (fd);
+          return 0;
+        }
+
+      self->handle = fdopen (fd, "rb+");
+      if (!self->handle)
+        {
+          close (fd);
+          return 0;
+        }
+
+      /* Local sockets not yet supported */
+    }
+  return 1;
+}
+
+
+/*
+  close connection when open
+ */
+void
+rxpd_client_close (RxpdClient self)
+{
+  if (self->handle)
+    {
+      fclose (self->handle);
+      self->handle = NULL;
+    }
+}
+
+
+/*
+  send a command to the rxpd
+ */
+int
+rxpd_client_cmd (RxpdClient self, const char* command, const char* list)
+{
+  if (!self || !rxpd_client_open (self))
+    return 0;
+
+  if (fprintf (self->handle, "%s:%s%s\n", command, self->prefix?self->prefix:"", list?list:"") < 0)
+    return 0;
+
+  fflush (self->handle);
+  return 1;
+}
+
+
+/*
+  send data to the rxpd
+*/
+int
+rxpd_client_query (RxpdClient self, const char* fmt, ...)
+{
+  if (!self || !rxpd_client_open (self))
+    return 0;
+
+  va_list args;
+  int r;
+  va_start (args, fmt);
+  r = vfprintf (self->handle, fmt, args);
+  va_end (args);
+  if (r < 0)
+    return 0;
+
+  fflush (self->handle);
+  return 1;
+}
+
+
+/*
+  test if data is available for read from rxpd
+*/
+int
+rxpd_client_pending (RxpdClient self, int timeout)
+{
+  if (!self || !self->handle)
+    return -1;
+
+  struct pollfd pollme;
+
+  pollme.fd = fileno (self->handle);
+  pollme.events = POLLIN;
+
+  return poll (&pollme, 1, timeout);
+}
+
+
+/*
+  read a response from rxpd
+
+  this call is blocking
+*/
+const char*
+rxpd_client_recieve (RxpdClient self)
+{
+  if (!self->handle)
+    return NULL;
+  return fgets (self->buf, 4096, self->handle);
+}
+
+
+#ifdef RXPD_CLIENT_EXAMPLE
+int
+main ()
+{
+  /* how to use */
+  RxpdClient query = rxpd_client_new ("galaxy:2345", "ct@pipapo.org/irc_experimental/");
+
+  if (rxpd_client_cmd (query, "CHECK", "xchat"))
+    {
+      const char* response;
+
+      rxpd_client_query (query, "TEST\n\n");
+
+      while (rxpd_client_pending (query, 1000))
+        {
+          response = rxpd_client_recieve (query);
+          printf ("> %s", response);
+        }
+    }
+  rxpd_client_free (query);
+
+  return 0;
+}
+#endif
diff --git a/src/rxpd_client.h b/src/rxpd_client.h
new file mode 100644 (file)
index 0000000..52007a4
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+    rxpd_client.h - regex policy daemon, client library
+
+  Copyright (C)
+    2007, 2008,         Christian Thaeter <ct@pipapo.org>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+struct rxpd_client
+{
+  char* address;
+  char* port;
+  struct addrinfo* ai;
+
+  char* prefix;
+  FILE* handle;
+  char buf[4096];
+};
+typedef struct rxpd_client* RxpdClient;
+
+RxpdClient
+rxpd_client_init (RxpdClient self, const char* address, const char* prefix);
+
+RxpdClient
+rxpd_client_destroy (RxpdClient self);
+
+void
+rxpd_client_free (RxpdClient self);
+
+RxpdClient
+rxpd_client_new (const char* address, const char* prefix);
+
+int
+rxpd_client_open (RxpdClient self);
+
+void
+rxpd_client_close (RxpdClient self);
+
+int
+rxpd_client_cmd (RxpdClient self, const char* command, const char* list);
+
+int
+rxpd_client_query (RxpdClient self, const char* fmt, ...);
+
+int
+rxpd_client_pending (RxpdClient self, int timeout);
+
+const char*
+rxpd_client_recieve (RxpdClient self);
index 9a18ab3..aaf1d52 100644 (file)
@@ -31,6 +31,7 @@
 #include "actions.h"
 #include "query.h"
 #include "options.h"
+#include "rxpd_client.h"
 
 #include "git/git-compat-util.h"
 
@@ -221,6 +222,37 @@ main (int argc, char**argv)
   if (!query.action)
     query.action = cwa_strndup ("main", SIZE_MAX);
 
+  if (query.rxpd)
+    {
+      RxpdClient rxpd = rxpd_client_new (query.rxpd, "webgit/");  /*TODO config rxpd prefix*/
+      rxpd_client_cmd (rxpd, "CHECK", "access");
+
+      if (query.request->user_agent && strchr (query.request->user_agent, '\n'))
+        webgit_err ("I dont like you");
+
+      rxpd_client_query (rxpd,
+                         "HOST=%s:USER-AGENT=%s:ACTION=%s:REPO=%s:HEAD=%s\n\n",
+                         query.request->user_addr?query.request->user_addr:"",
+                         query.request->user_agent?query.request->user_agent:"",
+                         query.action,
+                         query.repo?query.repo:"",
+                         query.head?query.head:""
+                         );
+
+      if (rxpd_client_pending (rxpd, 1000) < 1)
+        webgit_err ("rxpd check failed");
+
+      if (!!strncmp (rxpd_client_recieve (rxpd), "allow:", 6))
+        webgit_err ("access denied HOST=%s:USER-AGENT=%s:ACTION=%s:REPO=%s:HEAD=%s\n\n",
+                    query.request->user_addr?query.request->user_addr:"",
+                    query.request->user_agent?query.request->user_agent:"",
+                    query.action,
+                    query.repo?query.repo:"",
+                    query.head?query.head:""
+                    );
+
+      rxpd_client_free (rxpd);
+    }
 
   // query to cache-line
 
index 625f2c0..d64ec73 100644 (file)
@@ -51,8 +51,7 @@ struct webgit_query
   /* confiuration parameters */
   char* stylesheet;
   int count_def;
-  char* rxpd_name;
-  unsigned rxpd_port;
+  char* rxpd;
   char* skindir;
   char* webskindir;
   //int cache_read;