]> mj.ucw.cz Git - moe.git/commitdiff
Added general command code.
authorMartin Mares <mj@ucw.cz>
Mon, 4 Jun 2007 07:44:51 +0000 (09:44 +0200)
committerMartin Mares <mj@ucw.cz>
Mon, 4 Jun 2007 07:44:51 +0000 (09:44 +0200)
submit/Makefile
submit/commands.c [new file with mode: 0644]
submit/connect.c
submit/submitd.c
submit/submitd.h [new file with mode: 0644]

index 847f15e007212a93e4a068d6099dd279b26b600b..b5a7c1d02db86c495865b6578fa482ce191c45d9 100644 (file)
@@ -9,8 +9,9 @@ CFLAGS+=-Wno-pointer-sign -Wdisabled-optimization -Wno-missing-field-initializer
 
 all: submitd connect
 
-submitd: submitd.o lib/libucw.a lib/libsh.a
-submitd.o: submitd.c
+submitd: submitd.o commands.o lib/libsh.a lib/libucw.a
+submitd.o: submitd.c submitd.h
+commands.o: commands.c submitd.h
 connect: connect.o lib/libucw.a
 connect.o: connect.c
 
diff --git a/submit/commands.c b/submit/commands.c
new file mode 100644 (file)
index 0000000..dc71e30
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *  The Submit Daemon: Processing of Commands
+ *
+ *  (c) 2007 Martin Mares <mj@ucw.cz>
+ */
+
+#include "lib/lib.h"
+#include "lib/mempool.h"
+#include "lib/stkstring.h"
+#include "sherlock/object.h"
+#include "sherlock/objread.h"
+
+#include <sys/stat.h>
+
+#include "submitd.h"
+
+static void NONRET
+read_error_cb(struct obj_read_state *st UNUSED, byte *msg)
+{
+  client_error("Request parse error: %s", msg);
+}
+
+static int
+read_request(struct conn *c)
+{
+  if (c->pool)
+    mp_flush(c->pool);
+  else
+    c->pool = mp_new(1024);
+  c->request = obj_new(c->pool);
+  c->reply = obj_new(c->pool);
+
+  struct obj_read_state st;
+  obj_read_start(&st, c->request);
+  st.error_callback = read_error_cb;
+  byte line[1024];
+  uns size = 0;
+  for (;;)
+    {
+      int l = bgets_nodie(&c->rx_fb, line, sizeof(line));
+      if (l < 0)
+       client_error("Request line too long");
+      if (!l)
+       {
+         if (!size)
+           return 0;
+         else
+           client_error("Truncated request");
+       }
+      if (l == 1)
+       break;
+      size += l;
+      if (size >= max_request_size)
+       client_error("Request too long");
+      obj_read_attr(&st, line[0], line+1);
+    }
+  obj_read_end(&st);
+  return 1;
+}
+
+static void
+write_reply(struct conn *c)
+{
+  if (trace_commands)
+    {
+      byte *msg;
+      if (msg = obj_find_aval(c->reply, '-'))
+       log(L_DEBUG, ">> -%s", msg);
+      else if (msg = obj_find_aval(c->reply, '+'))
+       log(L_DEBUG, ">> +%s", msg);
+      else
+       log(L_DEBUG, ">> ???");
+    }
+  put_attr_set_type(BUCKET_TYPE_PLAIN);
+  bput_object(&c->tx_fb, c->reply);
+  bputc(&c->tx_fb, '\n');
+  bflush(&c->tx_fb);
+}
+
+static void
+execute_command(struct conn *c)
+{
+  byte *cmd = obj_find_aval(c->request, '!');
+  if (!cmd)
+    {
+      obj_set_attr(c->reply, '-', "Missing command");
+      return;
+    }
+  if (trace_commands)
+    log(L_DEBUG, "<< %s", cmd);
+  obj_set_attr(c->reply, '-', "Unknown command");
+}
+
+int
+process_command(struct conn *c)
+{
+  if (!read_request(c))
+    return 0;
+  execute_command(c);
+  write_reply(c);
+  return 1;
+}
+
+static int
+user_exists_p(byte *user)
+{
+  byte *fn = stk_printf("solutions/%s/status", user);
+  struct stat st;
+  return !stat(fn, &st) && S_ISREG(st.st_mode);
+}
+
+static void
+execute_init(struct conn *c)
+{
+  byte *user = obj_find_aval(c->request, 'U');
+  if (!user)
+    {
+      obj_set_attr(c->reply, '-', "Missing user");
+      return;
+    }
+  if (!c->cert_name ||
+      !strcmp(user, c->cert_name) ||
+      c->rule->allow_admin && !strcmp(c->cert_name, "admin"))
+    {
+      if (!user_exists_p(user))
+       {
+         obj_set_attr(c->reply, '-', "Unknown user");
+         return;
+       }
+      log(L_INFO, "Logged in %s", user);
+    }
+  else
+    {
+      obj_set_attr(c->reply, '-', "Permission denied");
+      log(L_ERROR, "Unauthorized attempt to log in as %s", user);
+      return;
+    }
+  obj_set_attr(c->reply, '+', "OK");
+}
+
+int
+process_init(struct conn *c)
+{
+  if (!read_request(c))
+    return 0;
+  execute_init(c);
+  write_reply(c);
+  return !!obj_find_attr(c->reply, '+');
+}
index d0c83ffe47dac808d3a1a2c17d6e10c1223acd7c..7f60f6df4a2ffff93f5055fc8d9f324fd869208e 100644 (file)
@@ -156,20 +156,36 @@ int main(int argc UNUSED, char **argv UNUSED)
   for (;;)
     {
       byte buf[1024];
-      if (!fgets(buf, sizeof(buf), stdin))
-       break;
-      int len = strlen(buf);
-      err = gnutls_record_send(s, buf, len); TLS_CHECK(gnutls_record_send);
-      err = gnutls_record_recv(s, buf, len); TLS_CHECK(gnutls_record_recv);
-      if (!err)
+      do
        {
-         log(L_INFO, "Connection closed");
-         break;
+         if (!fgets(buf, sizeof(buf), stdin))
+           goto done;
+         int len = strlen(buf);
+         err = gnutls_record_send(s, buf, len); TLS_CHECK(gnutls_record_send);
        }
-      fwrite(buf, 1, err, stdout);
+      while (buf[0] != '\n');
+      int last = 0;
+      for (;;)
+       {
+         err = gnutls_record_recv(s, buf, sizeof(buf)); TLS_CHECK(gnutls_record_recv);
+         if (!err)
+           {
+             log(L_INFO, "Connection closed");
+             break;
+           }
+         fwrite(buf, 1, err, stdout);
+         for (int i=0; i<err; i++)
+           {
+             if (buf[i] == '\n' && last == '\n')
+               goto next;
+             last = buf[i];
+           }
+       }
+next:
       fflush(stdout);
     }
 
+done:
   gnutls_bye(s, GNUTLS_SHUT_RDWR);
   close(sk);
   gnutls_deinit(s);
index a58ae69255bb4ff914c5bab27a5853ca4f3f7bed..22be143b6aad69f635c0dec767fc7306fa5493d1 100644 (file)
@@ -14,8 +14,6 @@
 #include "lib/lib.h"
 #include "lib/conf.h"
 #include "lib/getopt.h"
-#include "lib/ipaccess.h"
-#include "lib/fastbuf.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -27,8 +25,8 @@
 #include <sys/wait.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
+
+#include "submitd.h"
 
 /*** CONFIGURATION ***/
 
@@ -40,14 +38,10 @@ static byte *ca_cert_name = "?";
 static byte *server_cert_name = "?";
 static byte *server_key_name = "?";
 static clist access_rules;
-
-struct access_rule {
-  cnode n;
-  struct ip_addrmask addrmask;
-  uns allow_admin;
-  uns plain_text;
-  uns max_conn;
-};
+static uns trace_tls;
+uns max_request_size;
+uns max_attachment_size;
+uns trace_commands;
 
 static struct cf_section access_conf = {
   CF_TYPE(struct access_rule),
@@ -74,27 +68,20 @@ static struct cf_section submitd_conf = {
     CF_UNS("DHBits", &dh_bits),
     CF_UNS("MaxConn", &max_conn),
     CF_UNS("SessionTimeout", &session_timeout),
+    CF_UNS("MaxRequestSize", &max_request_size),
+    CF_UNS("MaxAttachSize", &max_attachment_size),
     CF_STRING("CACert", &ca_cert_name),
     CF_STRING("ServerCert", &server_cert_name),
     CF_STRING("ServerKey", &server_key_name),
     CF_LIST("Access", &access_rules, &access_conf),
+    CF_UNS("TraceTLS", &trace_tls),
+    CF_UNS("TraceCommands", &trace_commands),
     CF_END
   }
 };
 
 /*** CONNECTIONS ***/
 
-struct conn {
-  cnode n;
-  u32 ip;                              // Used by the main loop connection logic
-  pid_t pid;
-  uns id;
-  struct access_rule *rule;            // Rule matched by this connection
-  int sk;                              // Client socket
-  gnutls_session_t tls;                        // TLS session
-  struct fastbuf rx_fb, tx_fb;         // Fastbufs for communication with the client
-};
-
 static clist connections;
 static uns last_conn_id;
 static uns num_conn;
@@ -108,7 +95,7 @@ conn_init(void)
 static struct conn *
 conn_new(void)
 {
-  struct conn *c = xmalloc(sizeof(*c));
+  struct conn *c = xmalloc_zero(sizeof(*c));
   c->id = ++last_conn_id;
   clist_add_tail(&connections, &c->n);
   num_conn++;
@@ -187,8 +174,9 @@ tls_new_session(int sk)
 }
 
 static const char *
-tls_verify_cert(gnutls_session_t s)
+tls_verify_cert(struct conn *c)
 {
+  gnutls_session_t s = c->tls;
   uns status, num_certs;
   int err;
   gnutls_x509_crt_t cert;
@@ -223,7 +211,9 @@ tls_verify_cert(gnutls_session_t s)
   err = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn, &dn_len);
   if (err < 0)
     return "Cannot retrieve common name";
-  log(L_INFO, "Cert CN: %s", dn);
+  if (trace_tls)
+    log(L_INFO, "Cert CN: %s", dn);
+  c->cert_name = xstrdup(dn);
 
   /* Check certificate purpose */
   byte purp[256];
@@ -244,8 +234,11 @@ tls_verify_cert(gnutls_session_t s)
 }
 
 static void
-tls_log_params(gnutls_session_t s)
+tls_log_params(struct conn *c)
 {
+  if (!trace_tls)
+    return;
+  gnutls_session_t s = c->tls;
   const char *proto = gnutls_protocol_get_name(gnutls_protocol_get_version(s));
   const char *kx = gnutls_kx_get_name(gnutls_kx_get(s));
   const char *cert = gnutls_certificate_type_get_name(gnutls_certificate_type_get(s));
@@ -258,7 +251,7 @@ tls_log_params(gnutls_session_t s)
 
 /*** SOCKET FASTBUFS ***/
 
-static void NONRET
+void NONRET
 client_error(char *msg, ...)
 {
   va_list args;
@@ -383,22 +376,23 @@ client_loop(struct conn *c)
       int err = gnutls_handshake(c->tls);
       if (err < 0)
        client_error("TLS handshake failed: %s", gnutls_strerror(err));
-      tls_log_params(c->tls);
-      const char *cert_err = tls_verify_cert(c->tls);
+      tls_log_params(c);
+      const char *cert_err = tls_verify_cert(c);
       if (cert_err)
        client_error("TLS certificate failure: %s", cert_err);
       init_tls_fastbufs(c);
     }
 
-  for (;;)
-    {
-      alarm(session_timeout);
-      byte buf[1024];
-      if (!bgets(&c->rx_fb, buf, sizeof(buf)))
-       break;
-      bputsn(&c->tx_fb, buf);
-      bflush(&c->tx_fb);
-    }
+  alarm(session_timeout);
+  if (!process_init(c))
+    log(L_ERROR, "Protocol handshake failed");
+  else
+    for (;;)
+      {
+       alarm(session_timeout);
+       if (!process_command(c))
+         break;
+      }
 
   if (c->tls)
     gnutls_bye(c->tls, GNUTLS_SHUT_WR);
diff --git a/submit/submitd.h b/submit/submitd.h
new file mode 100644 (file)
index 0000000..7e0d434
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  The Submit Daemon
+ *
+ *  (c) 2007 Martin Mares <mj@ucw.cz>
+ */
+
+#ifndef _SUBMITD_H
+#define _SUBMITD_H
+
+#include "lib/clists.h"
+#include "lib/ipaccess.h"
+#include "lib/fastbuf.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+struct access_rule {
+  cnode n;
+  struct ip_addrmask addrmask;
+  uns allow_admin;
+  uns plain_text;
+  uns max_conn;
+};
+
+struct conn {
+  // Set up by the master process
+  cnode n;
+  u32 ip;
+  pid_t pid;
+  uns id;
+  struct access_rule *rule;            // Rule matched by this connection
+  int sk;                              // Client socket
+  byte *cert_name;                     // Client name from the certificate (NULL if no TLS)
+
+  // Used by the child process
+  gnutls_session_t tls;                        // TLS session
+  struct fastbuf rx_fb, tx_fb;         // Fastbufs for communication with the client (either plain-text or TLS)
+  struct mempool *pool;
+  struct odes *request;
+  struct odes *reply;
+  byte *user;
+};
+
+extern uns max_request_size, max_attachment_size, trace_commands;
+
+/* submitd.c */
+
+void NONRET client_error(char *msg, ...);
+
+/* commands.c */
+
+int process_init(struct conn *c);
+int process_command(struct conn *c);
+
+#endif