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