2fe7b7715d8989fca5f49845c8965f41749e1fda
[rxpd] / rxpd.c
1 /*
2     rxpd.c - regex policy daemon
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rxpd.h"
23
24 static struct rxpd_base global_base;
25
26 struct rxpd_base*
27 rxpd_init (char* rulesdir)
28 {
29   if (global_base.rulesdir)
30     return NULL;
31
32   global_base.rulesdir = strdup (rulesdir);
33   if (!global_base.rulesdir) abort();
34
35   psplay_init_root (&global_base.files, rxpd_file_cmp, rxpd_file_delete);
36
37   llist_init (&global_base.sockets_pending);
38   llist_init (&global_base.sockets_active);
39   llist_init (&global_base.connections_pending);
40   llist_init (&global_base.connections_active);
41
42   return &global_base;
43 }
44
45 void
46 rxpd_destroy (void)
47 {
48   if (global_base.rulesdir)
49     {
50       free (global_base.rulesdir);
51       psplay_destroy_root (&global_base.files);
52       LLIST_WHILE_HEAD (&global_base.sockets_pending, n)
53         {
54           struct rxpd_socket* socket = (struct rxpd_socket*)n;
55           rxpd_socket_delete (socket);
56         }
57       LLIST_WHILE_HEAD (&global_base.sockets_active, n)
58         {
59           struct rxpd_socket* socket = (struct rxpd_socket*)n;
60           rxpd_socket_delete (socket);
61         }
62       LLIST_WHILE_HEAD (&global_base.connections_pending, n)
63         {
64           struct rxpd_connection* connection = (struct rxpd_connection*)n;
65           rxpd_connection_delete (connection);
66         }
67       LLIST_WHILE_HEAD (&global_base.connections_active, n)
68         {
69           struct rxpd_connection* connection = (struct rxpd_connection*)n;
70           rxpd_connection_delete (connection);
71         }
72     }
73 }
74
75
76 //
77 struct rxpd_rule*
78 rxpd_rule_new (const char* buf)
79 {
80   struct rxpd_rule* self = malloc (sizeof (struct rxpd_rule));
81   if (self)
82     {
83       llist_init (&self->node);
84
85       if (*buf != '#')
86         {
87           int err;
88           char* rxstart = strchr (buf, ':');
89
90           if (!rxstart)
91             self->string = strdup ("#ERROR: Syntax error, line was neither a comment nor a rule");
92           else
93             {
94               err = regcomp (&self->rx, rxstart+1, REG_EXTENDED|REG_ICASE|REG_NOSUB);
95
96               if (!err)
97                 {
98                   self->string = strdup (buf);
99                   if (!self->string) abort();
100                 }
101               else
102                 {
103                   regfree (&self->rx);
104                   char ebuf[256];
105                   size_t len = regerror (err, NULL, ebuf, 256);
106                   self->string = malloc(len + strlen(buf) + 14);
107                   if (!self->string) abort();
108                   strcpy (self->string, "#ERROR: ");
109                   strcat (self->string, ebuf);
110                   strcat (self->string, " in '");
111                   strcat (self->string, buf);
112                   strcat (self->string, "'");
113                 }
114             }
115         }
116       else
117         {
118           self->string = strdup (buf);
119           if (!self->string) abort();
120         }
121     }
122   return self;
123 }
124
125 void
126 rxpd_rule_delete (struct rxpd_rule* rule)
127 {
128   if (rule)
129     {
130       llist_unlink (&rule->node);
131       if (rule->string[0] != '#')
132         regfree (&rule->rx);
133       free (rule->string);
134       free(rule);
135     }
136 }
137
138 //
139
140
141 struct rxpd_file*
142 rxpd_file_new (struct rxpd_base* base, const char* filename)
143 {
144   char buf[4096];
145   struct rxpd_file* self = NULL;
146
147   // TODO better filenname validation / error handling
148   if (!filename ||
149       strchr (filename, '/') ||
150       strlen (filename) + strlen (base->rulesdir) > 4097)
151     return NULL;
152
153   strcpy (buf, base->rulesdir);
154   strcat (buf, filename);
155   filename = strdup (buf);
156   if (filename)
157     {
158       self = malloc (sizeof (struct rxpd_file));
159       if (self)
160         {
161           self->filename = filename;
162           const char* basename = strrchr (filename, '/');
163           if (basename)
164             ++basename;
165           else
166             basename = filename;
167           psplay_init (&self->node, basename);
168           llist_init (&self->rules);
169
170           psplay_insert (&base->files, &self->node);
171         }
172     }
173   return self;
174 }
175
176 void
177 rxpd_file_delete (PSplay f)
178 {
179   if (f)
180     {
181       struct rxpd_file* file = (struct rxpd_file*)f;
182       LLIST_WHILE_HEAD (&file->rules, n)
183         {
184           struct rxpd_rule* node = (struct rxpd_rule*)n;
185           rxpd_rule_delete (node);
186         }
187       free ((void*)file->filename);
188       free (f);
189     }
190 }
191
192 int
193 rxpd_file_load (struct rxpd_file* self)
194 {
195   FILE* f = fopen (self->filename, "r");
196   // TODO error handling
197   if (f)
198     {
199       // TODO test excess line length = error
200       char buf[4096];
201
202       while (fgets (buf, 4096, f))
203         {
204           size_t last = strlen(buf);
205           if (buf[last-1] == '\n')
206             buf[last-1] = '\0';
207
208           struct rxpd_rule* rule;
209           rule = rxpd_rule_new (buf);
210           if (!rule)
211             abort();
212
213           printf("loaded rule '%s'\n", rule->string);
214
215           llist_insert_tail (&self->rules, &rule->node);
216         }
217
218       fclose (f);
219       return 1;
220     }
221   else
222     return 0;
223 }
224
225 int
226 rxpd_file_cmp (const void* A, const void* B)
227 {
228   return strcmp (A, B);
229 }
230
231
232 //
233
234 struct rxpd_socket*
235 rxpd_socket_new_tcp4 (struct rxpd_base* base, const char* addr, unsigned short port)
236 {
237   struct rxpd_socket* self = malloc (sizeof (struct rxpd_socket));
238   if (!self)
239     abort();
240
241   self->base = base;
242
243   llist_init (&self->node);
244
245   self->fd = socket (PF_INET, SOCK_STREAM, 0);
246   if (self->fd == -1)
247     abort ();
248
249   struct sockaddr_in listen_addr;
250   memset (&listen_addr, 0, sizeof (listen_addr));
251
252   listen_addr.sin_family = AF_INET;
253   if (addr)
254     {
255       if (inet_aton (addr, &listen_addr.sin_addr) == 0)
256         abort();
257     }
258   else
259     listen_addr.sin_addr.s_addr = INADDR_ANY;
260
261   listen_addr.sin_port = htons(port);
262
263   if (bind (self->fd, (struct sockaddr*)&listen_addr, sizeof (listen_addr)) == -1)
264     abort();
265
266   static int yes = 1;
267   if (setsockopt (self->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
268     abort ();
269
270   if (listen (self->fd, 20) == -1)
271     abort ();
272
273   event_set (&self->ev, self->fd, EV_READ, rxpd_socket_accept, self);
274   llist_insert_tail (&base->sockets_pending, &self->node);
275   return self;
276 }
277
278
279 void
280 rxpd_socket_delete (struct rxpd_socket* self)
281 {
282   if (self)
283     {
284       event_del (&self->ev);
285       llist_unlink (&self->node);
286       close (self->fd);
287     }
288   free (self);
289 }
290
291 struct rxpd_socket*
292 rxpd_socket_schedule (struct rxpd_socket* self)
293 {
294   if (self)
295     {
296       llist_insert_head (&self->base->sockets_active, &self->node);
297       event_add (&self->ev, NULL);
298     }
299   return self;
300 }
301
302 struct rxpd_socket*
303 rxpd_socket_suspend (struct rxpd_socket* self)
304 {
305   if (self)
306     {
307       event_del (&self->ev);
308       llist_insert_tail (&self->base->sockets_pending, &self->node);
309     }
310   return self;
311 }
312
313 void
314 rxpd_socket_accept (int fd, short event, void* ptr)
315 {
316   printf ("incoming connection\n");
317
318   struct rxpd_socket* self = ptr;
319
320   struct rxpd_connection* conn =
321     rxpd_connection_new (self->base, fd);
322
323   rxpd_connection_schedule (conn);
324   rxpd_socket_schedule (self);
325 }
326
327 ///
328
329 struct rxpd_buffer*
330 rxpd_buffer_init (struct rxpd_buffer* self, struct rxpd_connection* conn)
331 {
332   self->conn = conn;
333   self->state = RXPD_OK;
334   self->eol = self->eob = self->buffer;
335   self->buffer [4095] = '\0';
336   return self;
337 }
338
339
340 char*
341 rxpd_buffer_readline (struct rxpd_buffer* self, int again)
342 {
343   int fd = self->conn->fd;
344
345   if (self->eol < self->eob)
346     {
347       //there was a line pending, shift buffer left
348       memmove (self->buffer, self->eol+1, self->eob - self->eol - 1);
349       self->eob = (char*)(self->eob - (self->eol - self->buffer + 1));
350       self->eol = self->buffer;
351       // TODO handle \r's
352     }
353
354
355   if (!again && self->state == RXPD_OK)   // we only read when again is 0, first iteration
356     {
357       ssize_t r = 0;
358       do
359         {
360           r = read(fd, self->eob, 4095 - (self->eob - self->buffer));
361         }
362       while (r == -1 && errno == EINTR);
363
364       if (r != -1)
365         {
366
367           if (r == 0)
368             {
369               shutdown (fd, SHUT_RD);
370               self->state = RXPD_EOF;
371             }
372
373           self->eob += r;
374         }
375       else
376         self->state = RXPD_ERROR;
377     }
378
379   // find next newline, terminate string there
380   for (char* i = self->buffer; i < self->eob; ++i)
381     {
382       if (*i == '\n')
383         {
384           *i = '\0';
385           self->eol = i;
386           break;
387         }
388     }
389
390   // TODO handle buffer overfulls
391
392   return (self->eob == self->buffer) ? NULL : self->buffer;
393 }
394
395 /*
396 void
397 rxpd_buffer_write(int fd, short event, void* ptr)
398 {
399   struct rxpd_buffer* self = (struct rxpd_buffer*) ptr;
400
401   ssize_t n = write(int fd, const void *buf, size_t count);
402
403 }
404 */
405
406 int
407 rxpd_buffer_printf (struct rxpd_buffer* self, const char* fmt, ...)
408 {
409   // for now we do a blocking write, needs to be fixed some day
410   // add string to buffer
411   va_list ap;
412   va_start(ap, fmt);
413   //int sz = self->buffer+4096 - self->eob;
414   int n = vsnprintf (self->buffer, 4096, fmt, ap);
415   va_end(ap);
416
417   write (self->conn->fd, self->buffer, n);
418
419   if (n>4095)
420     return 0;
421
422   return 1;
423 }
424
425
426
427
428 ///
429
430 struct rxpd_connection*
431 rxpd_connection_new (struct rxpd_base* base, int fd)
432 {
433   struct rxpd_connection* self = malloc (sizeof (struct rxpd_connection));
434   if (!self)
435     abort();
436
437   llist_init (&self->node);
438
439   socklen_t addr_sz = sizeof (self->peer_addr); 
440   self->fd = accept (fd, (struct sockaddr*)&self->peer_addr, &addr_sz);
441   if (self->fd == -1)
442     abort ();
443
444   static int yes = 1;
445   if (setsockopt (self->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
446     abort ();
447
448   self->base = base;
449   self->file = NULL;
450
451   rxpd_buffer_init (&self->in, self);
452   rxpd_buffer_init (&self->out, self);
453   
454   event_set (&self->ev, self->fd, EV_READ, rxpd_connection_parse_cmd, self);
455
456   llist_insert_tail (&base->connections_pending, &self->node);
457
458   return self;
459 }
460
461 void
462 rxpd_connection_delete (struct rxpd_connection* self)
463 {
464   if (self)
465     {
466       event_del (&self->ev);
467       llist_unlink (&self->node);
468       close (self->fd);
469     }
470   free (self);
471 }
472
473 struct rxpd_connection*
474 rxpd_connection_schedule (struct rxpd_connection* self)
475 {
476   if (self)
477     {
478       llist_insert_tail (&self->base->connections_active, &self->node);
479       event_add (&self->ev, NULL);
480     }
481   return self;
482 }
483
484 struct rxpd_connection*
485 rxpd_connection_suspend (struct rxpd_connection* self)
486 {
487   if (self)
488     {
489       event_del (&self->ev);
490       llist_insert_tail (&self->base->connections_pending, &self->node);
491     }
492   return self;
493 }
494
495 void
496 rxpd_connection_parse_cmd (int fd, short event, void* ptr)
497 {
498   printf ("parse cmd\n");
499   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
500
501   char* line;
502   line = rxpd_buffer_readline (&self->in, 0);
503
504   if (!line)
505     {
506       rxpd_buffer_printf (&self->out, "#ERROR: no data\n");
507       close (fd);
508       return;
509     }
510
511   static const struct cmd_table
512   {
513     enum rxpd_cmd_e nr;
514     const char* cmd;
515     size_t sz;
516   } cmds[] =
517     {
518 #define RXPD_CMD(cmd) {RXPD_CMD_##cmd, #cmd":", sizeof (#cmd)},
519       RXPD_COMMANDS
520 #undef RXPD_CMD
521       {0, NULL, 0}
522     };
523
524   const struct cmd_table* i;
525   for (i = cmds; i->cmd; ++i)
526     if (strncmp (line, i->cmd, i->sz) == 0)
527       break;
528   if (!i->cmd)
529     {
530       rxpd_buffer_printf (&self->out, "#ERROR: no command\n");
531       rxpd_connection_delete (self);
532       return;
533     }
534   // TODO policy check here
535
536   if (line[i->sz])
537     {
538       // rulename provided
539       self->file = (struct rxpd_file*) psplay_find (&self->base->files, &line[i->sz]);
540
541       if (!self->file)
542         {
543           // todo create policy?
544           self->file = rxpd_file_new (self->base, &line[i->sz]);
545           if (!self->file)
546             {
547               rxpd_buffer_printf (&self->out, "#ERROR: illegal rule\n");
548               rxpd_connection_delete (self);
549               return;
550             }
551         }
552     }
553
554   // dispatch
555   switch (i->nr)
556     {
557 #define RXPD_CMD(cmd)                                                           \
558 case RXPD_CMD_##cmd:                                                            \
559   event_set (&self->ev, self->fd, EV_READ, rxpd_connection_cmd_##cmd, self);    \
560   rxpd_connection_cmd_##cmd (fd, 0, ptr);                                       \
561   break;
562       RXPD_COMMANDS
563 #undef RXPD_CMD
564     }
565 }
566
567
568
569 void
570 rxpd_connection_cmd_CHECK (int fd, short event, void* ptr)
571 {
572   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
573
574   if (event == EV_READ)
575     {
576       int again = -1;
577       char* line;
578       while (line = rxpd_buffer_readline (&self->in, ++again))
579         {
580           if (*line == '\0')
581             {
582               rxpd_buffer_printf (&self->out, "#OK:\n");
583             }
584           else
585             {
586               LLIST_FOREACH (&self->file->rules, n)
587                 {
588                   struct rxpd_rule* rule = (struct rxpd_rule*)n;
589                   if (rule->string[0] != '#')
590                     {
591                       if (regexec (&rule->rx, line, 0, NULL, 0) == 0)
592                         {
593                           rxpd_buffer_printf (&self->out, "%s\n", rule->string);
594                           break;
595                         }
596                     }
597                 }
598             }
599         }
600     }
601
602   if (rxpd_buffer_state (&self->in) == RXPD_OK)
603     rxpd_connection_schedule (self);
604   else
605     {
606       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
607         rxpd_buffer_printf (&self->out, "#ERROR:\n");
608       close (fd);
609     }
610 }
611
612
613
614 static void
615 rxpd_connection_APPEND_PREPEND_helper (int fd, short event, void* ptr, int do_append)
616 {
617   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
618
619   if (!event)
620     llist_init (&self->tmp_list);
621
622   if (event == EV_READ)
623     {
624       int again = -1;
625       char* line;
626
627       while (line = rxpd_buffer_readline (&self->in, ++again))
628         {
629           if (*line)
630             {
631               struct rxpd_rule* rule;
632               rule = rxpd_rule_new (line);
633               if (!rule)
634                 abort();
635
636               llist_insert_tail (&self->tmp_list, &rule->node);
637             }
638           else goto finish;
639         }
640     }
641
642   if (rxpd_buffer_state (&self->in) == RXPD_OK)
643     rxpd_connection_schedule (self);
644   else
645     {
646       // TODO should also print error when any rule compilation failed
647       if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
648         rxpd_buffer_printf (&self->out, "#ERROR:\n");
649       else
650         {
651         finish:
652           rxpd_buffer_printf (&self->out, "#OK:\n");
653         }
654
655       if (do_append)
656         llist_insertlist_prev (&self->file->rules, &self->tmp_list);
657       else
658         llist_insertlist_next (&self->file->rules, &self->tmp_list);
659       close (fd);
660     }
661 }
662
663 void
664 rxpd_connection_cmd_APPEND (int fd, short event, void* ptr)
665 {
666   rxpd_connection_APPEND_PREPEND_helper (fd, event, ptr, 1);
667 }
668
669 void
670 rxpd_connection_cmd_PREPEND (int fd, short event, void* ptr)
671 {
672   rxpd_connection_APPEND_PREPEND_helper (fd, event, ptr, 0);
673 }
674
675 void
676 rxpd_connection_cmd_REMOVE (int fd, short event, void* ptr)
677 {
678   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
679   rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
680 }
681
682 void
683 rxpd_connection_cmd_REPLACE (int fd, short event, void* ptr)
684 {
685   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
686   rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
687 }
688
689 void
690 rxpd_connection_cmd_LOAD (int fd, short event, void* ptr)
691 {
692   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
693   rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
694 }
695
696 void
697 rxpd_connection_cmd_SAVE (int fd, short event, void* ptr)
698 {
699   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
700   rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
701 }
702
703 void
704 rxpd_connection_cmd_DUMP (int fd, short event, void* ptr)
705 {
706   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
707
708   if (llist_is_empty (&self->file->rules))
709     rxpd_buffer_printf (&self->out, "#OK:\n");
710   else
711     {
712       LLIST_FOREACH (&self->file->rules, n)
713         {
714           struct rxpd_rule* rule = (struct rxpd_rule*)n;
715           rxpd_buffer_printf (&self->out, "%s\n", rule->string);
716         }
717     }
718
719   close (fd);
720 }
721
722
723 static psplay_delete_t
724 walk_LIST (PSplay node, const enum psplay_order_e which, int level, void* data)
725 {
726   (void) level;
727   struct rxpd_file* file = (struct rxpd_file*) node;
728   struct rxpd_connection* conn = (struct rxpd_connection*) data;
729
730   if (which == PSPLAY_INORDER)
731     rxpd_buffer_printf (&conn->out, "%s\n", file->node.key);
732
733   return PSPLAY_CONT;
734 }
735
736
737 void
738 rxpd_connection_cmd_LIST (int fd, short event, void* ptr)
739 {
740   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
741
742   if (psplay_isempty_root (&self->base->files))
743     rxpd_buffer_printf (&self->out, "#OK:\n");
744   else
745     psplay_walk (&self->base->files, NULL, walk_LIST, 0, ptr);
746
747   close (fd);
748 }
749
750 void
751 rxpd_connection_cmd_SHUTDOWN (int fd, short event, void* ptr)
752 {
753   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
754   // destroy all sockets
755   LLIST_WHILE_HEAD (&self->base->sockets_pending, n)
756     {
757       struct rxpd_socket* socket = (struct rxpd_socket*)n;
758       rxpd_socket_delete (socket);
759     }
760   LLIST_WHILE_HEAD (&self->base->sockets_active, n)
761     {
762       struct rxpd_socket* socket = (struct rxpd_socket*)n;
763       rxpd_socket_delete (socket);
764     }
765
766   rxpd_buffer_printf (&self->out, "#OK:\n");
767   close (fd);
768 }