]> mj.ucw.cz Git - eval.git/blob - submit/submitd.c
4c1415b48d08d44aa31bdebbee9116a26d3c9d97
[eval.git] / submit / submitd.c
1 /*
2  *  The Submit Daemon
3  *
4  *  (c) 2007 Martin Mares <mj@ucw.cz>
5  */
6
7 #undef LOCAL_DEBUG
8
9 #include "lib/lib.h"
10 #include "lib/conf.h"
11 #include "lib/getopt.h"
12
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <signal.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/wait.h>
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
23
24 #include "submitd.h"
25
26 /*** CONFIGURATION ***/
27
28 static byte *log_name;
29 static uns port = 8888;
30 static uns dh_bits = 1024;
31 static uns max_conn = 10;
32 static uns session_timeout;
33 static byte *ca_cert_name = "?";
34 static byte *server_cert_name = "?";
35 static byte *server_key_name = "?";
36 static clist access_rules;
37 static uns trace_tls;
38 uns max_request_size;
39 uns max_attachment_size;
40 uns trace_commands;
41
42 static struct cf_section ip_node_conf = {
43   CF_TYPE(struct ip_node),
44   CF_ITEMS {
45     CF_USER("IP", PTR_TO(struct ip_node, addrmask), &ip_addrmask_type),
46     CF_END
47   }
48 };
49
50 static struct cf_section access_conf = {
51   CF_TYPE(struct access_rule),
52   CF_ITEMS {
53     CF_LIST("IP", PTR_TO(struct access_rule, ip_list), &ip_node_conf),
54     CF_UNS("Admin", PTR_TO(struct access_rule, allow_admin)),
55     CF_UNS("PlainText", PTR_TO(struct access_rule, plain_text)),
56     CF_UNS("MaxConn", PTR_TO(struct access_rule, max_conn)),
57     CF_END
58   }
59 };
60
61 static struct cf_section submitd_conf = {
62   CF_ITEMS {
63     CF_STRING("LogFile", &log_name),
64     CF_UNS("Port", &port),
65     CF_UNS("DHBits", &dh_bits),
66     CF_UNS("MaxConn", &max_conn),
67     CF_UNS("SessionTimeout", &session_timeout),
68     CF_UNS("MaxRequestSize", &max_request_size),
69     CF_UNS("MaxAttachSize", &max_attachment_size),
70     CF_STRING("CACert", &ca_cert_name),
71     CF_STRING("ServerCert", &server_cert_name),
72     CF_STRING("ServerKey", &server_key_name),
73     CF_LIST("Access", &access_rules, &access_conf),
74     CF_UNS("TraceTLS", &trace_tls),
75     CF_UNS("TraceCommands", &trace_commands),
76     CF_END
77   }
78 };
79
80 /*** CONNECTIONS ***/
81
82 static clist connections;
83 static uns last_conn_id;
84 static uns num_conn;
85
86 static void
87 conn_init(void)
88 {
89   clist_init(&connections);
90 }
91
92 static struct conn *
93 conn_new(void)
94 {
95   struct conn *c = xmalloc_zero(sizeof(*c));
96   c->id = ++last_conn_id;
97   clist_add_tail(&connections, &c->n);
98   num_conn++;
99   return c;
100 }
101
102 static void
103 conn_free(struct conn *c)
104 {
105   xfree(c->ip_string);
106   xfree(c->cert_name);
107   clist_remove(&c->n);
108   num_conn--;
109   xfree(c);
110 }
111
112 static struct access_rule *
113 lookup_rule(u32 ip)
114 {
115   CLIST_FOR_EACH(struct access_rule *, r, access_rules)
116     CLIST_FOR_EACH(struct ip_node *, n, r->ip_list)
117       if (ip_addrmask_match(&n->addrmask, ip))
118         return r;
119   return NULL;
120 }
121
122 static uns
123 conn_count(u32 ip)
124 {
125   uns cnt = 0;
126   CLIST_FOR_EACH(struct conn *, c, connections)
127     if (c->ip == ip)
128       cnt++;
129   return cnt;
130 }
131
132 /*** TLS ***/
133
134 static gnutls_certificate_credentials_t cert_cred;
135 static gnutls_dh_params_t dh_params;
136
137 #define TLS_CHECK(name) if (err < 0) die(#name " failed: %s", gnutls_strerror(err))
138
139 static void
140 tls_init(void)
141 {
142   int err;
143
144   gnutls_global_init();
145   err = gnutls_certificate_allocate_credentials(&cert_cred);
146   TLS_CHECK(gnutls_certificate_allocate_credentials);
147   err = gnutls_certificate_set_x509_trust_file(cert_cred, ca_cert_name, GNUTLS_X509_FMT_PEM);
148   if (!err)
149     die("No CA certificate found");
150   if (err < 0)
151     die("Unable to load X509 trust file: %s", gnutls_strerror(err));
152   err = gnutls_certificate_set_x509_key_file(cert_cred, server_cert_name, server_key_name, GNUTLS_X509_FMT_PEM);
153   if (err < 0)
154     die("Unable to load X509 key file: %s", gnutls_strerror(err));
155
156   err = gnutls_dh_params_init(&dh_params); TLS_CHECK(gnutls_dh_params_init);
157   err = gnutls_dh_params_generate2(dh_params, dh_bits); TLS_CHECK(gnutls_dh_params_generate2);
158   gnutls_certificate_set_dh_params(cert_cred, dh_params);
159 }
160
161 static gnutls_session_t
162 tls_new_session(int sk)
163 {
164   gnutls_session_t s;
165   int err;
166
167   err = gnutls_init(&s, GNUTLS_SERVER); TLS_CHECK(gnutls_init);
168   err = gnutls_set_default_priority(s); TLS_CHECK(gnutls_set_default_priority);                 // FIXME
169   gnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, cert_cred);
170   gnutls_certificate_server_set_request(s, GNUTLS_CERT_REQUEST);
171   gnutls_dh_set_prime_bits(s, dh_bits);
172   gnutls_transport_set_ptr(s, (gnutls_transport_ptr_t) sk);
173   return s;
174 }
175
176 static const char *
177 tls_verify_cert(struct conn *c)
178 {
179   gnutls_session_t s = c->tls;
180   uns status, num_certs;
181   int err;
182   gnutls_x509_crt_t cert;
183   const gnutls_datum_t *certs;
184
185   DBG("Verifying peer certificates");
186   err = gnutls_certificate_verify_peers2(s, &status);
187   if (err < 0)
188     return gnutls_strerror(err);
189   DBG("Verify status: %04x", status);
190   if (status & GNUTLS_CERT_INVALID)
191     return "Certificate is invalid";
192   /* XXX: We do not handle revokation. */
193   if (gnutls_certificate_type_get(s) != GNUTLS_CRT_X509)
194     return "Certificate is not X509";
195
196   err = gnutls_x509_crt_init(&cert);
197   if (err < 0)
198     return "gnutls_x509_crt_init() failed";
199   certs = gnutls_certificate_get_peers(s, &num_certs);
200   if (!certs)
201     return "No peer certificate found";
202   DBG("Got certificate list with %d peers", num_certs);
203
204   err = gnutls_x509_crt_import(cert, &certs[0], GNUTLS_X509_FMT_DER);
205   if (err < 0)
206     return "Cannot import certificate";
207   /* XXX: We do not check expiration and activation since the keys are generated for a single contest only anyway. */
208
209   byte dn[256];
210   size_t dn_len = sizeof(dn);
211   err = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn, &dn_len);
212   if (err < 0)
213     return "Cannot retrieve common name";
214   if (trace_tls)
215     msg(L_INFO, "Cert CN: %s", dn);
216   c->cert_name = xstrdup(dn);
217
218   /* Check certificate purpose */
219   byte purp[256];
220   int purpi = 0;
221   do
222     {
223       size_t purp_len = sizeof(purp);
224       uns crit;
225       err = gnutls_x509_crt_get_key_purpose_oid(cert, purpi++, purp, &purp_len, &crit);
226       if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
227         return "Not a client certificate";
228       TLS_CHECK(gnutls_x509_crt_get_key_purpose_oid);
229     }
230   while (strcmp(purp, GNUTLS_KP_TLS_WWW_CLIENT));
231
232   DBG("Verified OK");
233   return NULL;
234 }
235
236 static void
237 tls_log_params(struct conn *c)
238 {
239   if (!trace_tls)
240     return;
241   gnutls_session_t s = c->tls;
242   const char *proto = gnutls_protocol_get_name(gnutls_protocol_get_version(s));
243   const char *kx = gnutls_kx_get_name(gnutls_kx_get(s));
244   const char *cert = gnutls_certificate_type_get_name(gnutls_certificate_type_get(s));
245   const char *comp = gnutls_compression_get_name(gnutls_compression_get(s));
246   const char *cipher = gnutls_cipher_get_name(gnutls_cipher_get(s));
247   const char *mac = gnutls_mac_get_name(gnutls_mac_get(s));
248   msg(L_DEBUG, "TLS params: proto=%s kx=%s cert=%s comp=%s cipher=%s mac=%s",
249     proto, kx, cert, comp, cipher, mac);
250 }
251
252 /*** FASTBUFS OVER SOCKETS AND TLS ***/
253
254 void NONRET                             // Fatal protocol violation
255 client_error(char *msg, ...)
256 {
257   va_list args;
258   va_start(args, msg);
259   vmsg(L_ERROR_R, msg, args);
260   exit(0);
261 }
262
263 static int
264 sk_fb_refill(struct fastbuf *f)
265 {
266   struct conn *c = SKIP_BACK(struct conn, rx_fb, f);
267   int cnt = read(c->sk, f->buffer, f->bufend - f->buffer);
268   if (cnt < 0)
269     client_error("Read error: %m");
270   f->bptr = f->buffer;
271   f->bstop = f->buffer + cnt;
272   return cnt;
273 }
274
275 static void
276 sk_fb_spout(struct fastbuf *f)
277 {
278   struct conn *c = SKIP_BACK(struct conn, tx_fb, f);
279   int len = f->bptr - f->buffer;
280   if (!len)
281     return;
282   int cnt = careful_write(c->sk, f->buffer, len);
283   if (cnt <= 0)
284     client_error("Write error");
285   f->bptr = f->buffer;
286 }
287
288 static void
289 init_sk_fastbufs(struct conn *c)
290 {
291   struct fastbuf *rf = &c->rx_fb, *tf = &c->tx_fb;
292
293   rf->buffer = xmalloc(1024);
294   rf->bufend = rf->buffer + 1024;
295   rf->bptr = rf->bstop = rf->buffer;
296   rf->name = "socket";
297   rf->refill = sk_fb_refill;
298
299   tf->buffer = xmalloc(1024);
300   tf->bufend = tf->buffer + 1024;
301   tf->bptr = tf->bstop = tf->buffer;
302   tf->name = rf->name;
303   tf->spout = sk_fb_spout;
304 }
305
306 static int
307 tls_fb_refill(struct fastbuf *f)
308 {
309   struct conn *c = SKIP_BACK(struct conn, rx_fb, f);
310   DBG("TLS: Refill");
311   int cnt = gnutls_record_recv(c->tls, f->buffer, f->bufend - f->buffer);
312   DBG("TLS: Received %d bytes", cnt);
313   if (cnt < 0)
314     client_error("TLS read error: %s", gnutls_strerror(cnt));
315   f->bptr = f->buffer;
316   f->bstop = f->buffer + cnt;
317   return cnt;
318 }
319
320 static void
321 tls_fb_spout(struct fastbuf *f)
322 {
323   struct conn *c = SKIP_BACK(struct conn, tx_fb, f);
324   int len = f->bptr - f->buffer;
325   if (!len)
326     return;
327   int cnt = gnutls_record_send(c->tls, f->buffer, len);
328   DBG("TLS: Sent %d bytes", cnt);
329   if (cnt <= 0)
330     client_error("TLS write error: %s", gnutls_strerror(cnt));
331   f->bptr = f->buffer;
332 }
333
334 static void
335 init_tls_fastbufs(struct conn *c)
336 {
337   struct fastbuf *rf = &c->rx_fb, *tf = &c->tx_fb;
338
339   ASSERT(rf->buffer && tf->buffer);     // Already set up for the plaintext connection
340   rf->refill = tls_fb_refill;
341   tf->spout = tls_fb_spout;
342 }
343
344 /*** CLIENT LOOP (runs in a child process) ***/
345
346 static void
347 sigalrm_handler(int sig UNUSED)
348 {
349   // We do not try to do any gracious shutdown to avoid races
350   client_error("Timed out");
351 }
352
353 static void
354 client_loop(struct conn *c)
355 {
356   setproctitle("submitd: client %s", c->ip_string);
357   log_pid = c->id;
358   init_sk_fastbufs(c);
359
360   signal(SIGPIPE, SIG_IGN);
361   struct sigaction sa = {
362     .sa_handler = sigalrm_handler
363   };
364   if (sigaction(SIGALRM, &sa, NULL) < 0)
365     die("Cannot setup SIGALRM handler: %m");
366
367   if (c->rule->plain_text)
368     {
369       bputsn(&c->tx_fb, "+OK");
370       bflush(&c->tx_fb);
371     }
372   else
373     {
374       bputsn(&c->tx_fb, "+TLS");
375       bflush(&c->tx_fb);
376       c->tls = tls_new_session(c->sk);
377       int err = gnutls_handshake(c->tls);
378       if (err < 0)
379         client_error("TLS handshake failed: %s", gnutls_strerror(err));
380       tls_log_params(c);
381       const char *cert_err = tls_verify_cert(c);
382       if (cert_err)
383         client_error("TLS certificate failure: %s", cert_err);
384       init_tls_fastbufs(c);
385     }
386
387   alarm(session_timeout);
388   if (!process_init(c))
389     msg(L_ERROR, "Protocol handshake failed");
390   else
391     {
392       setproctitle("submitd: client %s (%s)", c->ip_string, c->user);
393       for (;;)
394         {
395           alarm(session_timeout);
396           if (!process_command(c))
397             break;
398         }
399     }
400
401   if (c->tls)
402     gnutls_bye(c->tls, GNUTLS_SHUT_WR);
403   close(c->sk);
404   if (c->tls)
405     gnutls_deinit(c->tls);
406 }
407
408 /*** MAIN LOOP ***/
409
410 static void
411 sigchld_handler(int sig UNUSED)
412 {
413   /* We do not need to do anything, just interrupt the accept syscall */
414 }
415
416 static void
417 reap_child(pid_t pid, int status)
418 {
419   byte buf[EXIT_STATUS_MSG_SIZE];
420   if (format_exit_status(buf, status))
421     msg(L_ERROR, "Child %d %s", (int)pid, buf);
422
423   CLIST_FOR_EACH(struct conn *, c, connections)
424     if (c->pid == pid)
425       {
426         msg(L_INFO, "Connection %d closed", c->id);
427         conn_free(c);
428         return;
429       }
430   msg(L_ERROR, "Cannot find connection for child process %d", (int)pid);
431 }
432
433 static int listen_sk;
434
435 static void
436 sk_init(void)
437 {
438   listen_sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
439   if (listen_sk < 0)
440     die("socket: %m");
441   int one = 1;
442   if (setsockopt(listen_sk, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
443     die("setsockopt(SO_REUSEADDR): %m");
444
445   struct sockaddr_in sa;
446   bzero(&sa, sizeof(sa));
447   sa.sin_family = AF_INET;
448   sa.sin_addr.s_addr = INADDR_ANY;
449   sa.sin_port = htons(port);
450   if (bind(listen_sk, (struct sockaddr *) &sa, sizeof(sa)) < 0)
451     die("Cannot bind to port %d: %m", port);
452   if (listen(listen_sk, 1024) < 0)
453     die("Cannot listen on port %d: %m", port);
454 }
455
456 static void
457 sk_accept(void)
458 {
459   struct sockaddr_in sa;
460   int salen = sizeof(sa);
461   int sk = accept(listen_sk, (struct sockaddr *) &sa, &salen);
462   if (sk < 0)
463     {
464       if (errno == EINTR)
465         return;
466       die("accept: %m");
467     }
468
469   byte ipbuf[INET_ADDRSTRLEN];
470   inet_ntop(AF_INET, &sa.sin_addr, ipbuf, sizeof(ipbuf));
471   u32 addr = ntohl(sa.sin_addr.s_addr);
472   uns port = ntohs(sa.sin_port);
473   char *err;
474
475   struct access_rule *rule = lookup_rule(addr);
476   if (!rule)
477     {
478       err = "Unauthorized";
479       goto reject;
480     }
481
482   if (num_conn >= max_conn)
483     {
484       err = "Too many connections";
485       goto reject;
486     }
487
488   if (conn_count(addr) >= rule->max_conn)
489     {
490       err = "Too many connections from this address";
491       goto reject;
492     }
493
494   struct conn *c = conn_new();
495   msg(L_INFO, "Connection from %s:%d (id %d, %s, %s)",
496         ipbuf, port, c->id,
497         (rule->plain_text ? "plain-text" : "TLS"),
498         (rule->allow_admin ? "admin" : "user"));
499   c->ip = addr;
500   c->ip_string = xstrdup(ipbuf);
501   c->sk = sk;
502   c->rule = rule;
503
504   c->pid = fork();
505   if (c->pid < 0)
506     {
507       conn_free(c);
508       err = "Server overloaded";
509       msg(L_ERROR, "Fork failed: %m");
510       goto reject2;
511     }
512   if (!c->pid)
513     {
514       close(listen_sk);
515       client_loop(c);
516       exit(0);
517     }
518   close(sk);
519   return;
520
521 reject:
522   msg(L_ERROR_R, "Connection from %s:%d rejected (%s)", ipbuf, port, err);
523 reject2: ;
524   // Write an error message to the socket, but do not allow it to slow us down
525   struct linger ling = { .l_onoff=0 };
526   if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) < 0)
527     msg(L_ERROR, "Cannot set SO_LINGER: %m");
528   write(sk, "-", 1);
529   write(sk, err, strlen(err));
530   write(sk, "\n", 1);
531   close(sk);
532 }
533
534 int main(int argc, char **argv)
535 {
536   setproctitle_init(argc, argv);
537   cf_def_file = "submit/config";
538   cf_declare_section("SubmitD", &submitd_conf, 0);
539   cf_declare_section("Tasks", &tasks_conf, 0);
540
541   int opt;
542   if ((opt = cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL)) >= 0)
543     die("This program has no options");
544
545   log_file(log_name);
546
547   msg(L_INFO, "Initializing TLS");
548   tls_init();
549
550   conn_init();
551   sk_init();
552   msg(L_INFO, "Listening on port %d", port);
553
554   struct sigaction sa = {
555     .sa_handler = sigchld_handler
556   };
557   if (sigaction(SIGCHLD, &sa, NULL) < 0)
558     die("Cannot setup SIGCHLD handler: %m");
559
560   for (;;)
561     {
562       setproctitle("submitd: %d connections", num_conn);
563       int status;
564       pid_t pid = waitpid(-1, &status, WNOHANG);
565       if (pid > 0)
566         reap_child(pid, status);
567       else
568         sk_accept();
569     }
570 }