2 rxpd.c - regex policy daemon
5 2007, Christian Thaeter <ct@pipapo.org>
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.
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.
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.
24 static struct rxpd_base global_base;
27 rxpd_init (char* rulesdir)
29 if (global_base.rulesdir)
32 global_base.rulesdir = strdup (rulesdir);
33 if (!global_base.rulesdir) abort();
35 psplay_init_root (&global_base.files, rxpd_file_cmp, rxpd_file_delete);
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);
48 if (global_base.rulesdir)
50 free (global_base.rulesdir);
51 psplay_destroy_root (&global_base.files);
52 LLIST_WHILE_HEAD (&global_base.sockets_pending, n)
54 struct rxpd_socket* socket = (struct rxpd_socket*)n;
55 rxpd_socket_delete (socket);
57 LLIST_WHILE_HEAD (&global_base.sockets_active, n)
59 struct rxpd_socket* socket = (struct rxpd_socket*)n;
60 rxpd_socket_delete (socket);
62 LLIST_WHILE_HEAD (&global_base.connections_pending, n)
64 struct rxpd_connection* connection = (struct rxpd_connection*)n;
65 rxpd_connection_delete (connection);
67 LLIST_WHILE_HEAD (&global_base.connections_active, n)
69 struct rxpd_connection* connection = (struct rxpd_connection*)n;
70 rxpd_connection_delete (connection);
78 rxpd_rule_new (const char* buf)
80 struct rxpd_rule* self = malloc (sizeof (struct rxpd_rule));
83 llist_init (&self->node);
88 char* rxstart = strchr (buf, ':') + 1;
90 err = regcomp (&self->rx, rxstart, REG_EXTENDED|REG_ICASE|REG_NOSUB);
94 self->string = strdup (buf);
95 if (!self->string) abort();
101 size_t len = regerror (err, NULL, ebuf, 256);
102 self->string = malloc(len + strlen(buf) + 14);
103 if (!self->string) abort();
104 strcpy (self->string, "#ERROR ");
105 strcat (self->string, ebuf);
106 strcat (self->string, " in '");
107 strcat (self->string, buf);
108 strcat (self->string, "'");
113 self->string = strdup (buf);
114 if (!self->string) abort();
121 rxpd_rule_delete (struct rxpd_rule* rule)
125 llist_unlink (&rule->node);
126 if (rule->string[0] != '#')
137 rxpd_file_new (struct rxpd_base* base, const char* filename)
140 struct rxpd_file* self = NULL;
142 // TODO better filenname validation / error handling
144 strchr (filename, '/') ||
145 strlen (filename) + strlen (base->rulesdir) > 4097)
148 strcpy (buf, base->rulesdir);
149 strcat (buf, filename);
150 filename = strdup (buf);
153 self = malloc (sizeof (struct rxpd_file));
156 self->filename = filename;
157 const char* basename = strrchr (filename, '/');
162 psplay_init (&self->node, basename);
163 llist_init (&self->rules);
165 psplay_insert (&base->files, &self->node);
172 rxpd_file_delete (PSplay f)
176 struct rxpd_file* file = (struct rxpd_file*)f;
177 LLIST_WHILE_HEAD (&file->rules, n)
179 struct rxpd_rule* node = (struct rxpd_rule*)n;
180 rxpd_rule_delete (node);
182 free ((void*)file->filename);
188 rxpd_file_load (struct rxpd_file* self)
190 FILE* f = fopen (self->filename, "r");
191 // TODO error handling
194 // TODO test excess line length = error
197 while (fgets (buf, 4096, f))
199 size_t last = strlen(buf);
200 if (buf[last-1] == '\n')
203 struct rxpd_rule* rule;
204 rule = rxpd_rule_new (buf);
208 printf("%s\n", rule->string);
210 llist_insert_tail (&self->rules, &rule->node);
221 rxpd_file_cmp (const void* A, const void* B)
223 return strcmp (A, B);
230 rxpd_socket_new_tcp4 (struct rxpd_base* base, const char* addr, unsigned short port)
232 struct rxpd_socket* self = malloc (sizeof (struct rxpd_socket));
238 llist_init (&self->node);
240 self->fd = socket (PF_INET, SOCK_STREAM, 0);
244 struct sockaddr_in listen_addr;
245 memset (&listen_addr, 0, sizeof (listen_addr));
247 listen_addr.sin_family = AF_INET;
250 if (inet_aton (addr, &listen_addr.sin_addr) == 0)
254 listen_addr.sin_addr.s_addr = INADDR_ANY;
256 listen_addr.sin_port = htons(port);
258 if (bind (self->fd, (struct sockaddr*)&listen_addr, sizeof (listen_addr)) == -1)
262 if (setsockopt (self->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
265 if (listen (self->fd, 20) == -1)
268 event_set (&self->ev, self->fd, EV_READ, rxpd_socket_accept, self);
269 llist_insert_tail (&base->sockets_pending, &self->node);
275 rxpd_socket_delete (struct rxpd_socket* self)
279 event_del (&self->ev);
280 llist_unlink (&self->node);
287 rxpd_socket_schedule (struct rxpd_socket* self)
291 llist_insert_head (&self->base->sockets_active, &self->node);
292 event_add (&self->ev, NULL);
298 rxpd_socket_suspend (struct rxpd_socket* self)
302 event_del (&self->ev);
303 llist_insert_tail (&self->base->sockets_pending, &self->node);
309 rxpd_socket_accept (int fd, short event, void* ptr)
311 printf ("incoming connection\n");
313 struct rxpd_socket* self = ptr;
315 struct rxpd_connection* conn =
316 rxpd_connection_new (self->base, fd);
318 rxpd_connection_schedule (conn);
319 rxpd_socket_schedule (self);
325 rxpd_buffer_init (struct rxpd_buffer* self, struct rxpd_connection* conn)
328 self->state = RXPD_OK;
329 self->eol = self->eob = self->buffer;
330 self->buffer [4095] = '\0';
336 rxpd_buffer_readline (struct rxpd_buffer* self, int again)
338 int fd = self->conn->fd;
340 if (self->eol < self->eob)
342 //there was a line pending, shift buffer left
343 memmove (self->buffer, self->eol+1, self->eob - self->eol - 1);
344 self->eob = (char*)(self->eob - (self->eol - self->buffer + 1));
345 self->eol = self->buffer;
350 if (!again && self->state == RXPD_OK) // we only read when again is 0, first iteration
355 r = read(fd, self->eob, 4095 - (self->eob - self->buffer));
357 while (r == -1 && errno == EINTR);
364 shutdown (fd, SHUT_RD);
365 self->state = RXPD_EOF;
371 self->state = RXPD_ERROR;
374 // find next newline, terminate string there
375 for (char* i = self->buffer; i < self->eob; ++i)
385 // TODO handle buffer overfulls
387 return (self->eob == self->buffer) ? NULL : self->buffer;
392 rxpd_buffer_write(int fd, short event, void* ptr)
394 struct rxpd_buffer* self = (struct rxpd_buffer*) ptr;
396 ssize_t n = write(int fd, const void *buf, size_t count);
402 rxpd_buffer_printf (struct rxpd_buffer* self, const char* fmt, ...)
404 // for now we do a blocking write, needs to be fixed some day
405 // add string to buffer
408 //int sz = self->buffer+4096 - self->eob;
409 int n = vsnprintf (self->buffer, 4096, fmt, ap);
412 write (self->conn->fd, self->buffer, n);
425 struct rxpd_connection*
426 rxpd_connection_new (struct rxpd_base* base, int fd)
428 struct rxpd_connection* self = malloc (sizeof (struct rxpd_connection));
432 llist_init (&self->node);
434 socklen_t addr_sz = sizeof (self->peer_addr);
435 self->fd = accept (fd, (struct sockaddr*)&self->peer_addr, &addr_sz);
440 if (setsockopt (self->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
446 rxpd_buffer_init (&self->in, self);
447 rxpd_buffer_init (&self->out, self);
449 event_set (&self->ev, self->fd, EV_READ, rxpd_connection_parse_cmd, self);
451 llist_insert_tail (&base->connections_pending, &self->node);
457 rxpd_connection_delete (struct rxpd_connection* self)
461 event_del (&self->ev);
462 llist_unlink (&self->node);
468 struct rxpd_connection*
469 rxpd_connection_schedule (struct rxpd_connection* self)
473 llist_insert_tail (&self->base->connections_active, &self->node);
474 event_add (&self->ev, NULL);
479 struct rxpd_connection*
480 rxpd_connection_suspend (struct rxpd_connection* self)
484 event_del (&self->ev);
485 llist_insert_tail (&self->base->connections_pending, &self->node);
491 rxpd_connection_parse_cmd (int fd, short event, void* ptr)
493 printf ("parse cmd\n");
494 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
497 line = rxpd_buffer_readline (&self->in, 0);
501 rxpd_buffer_printf (&self->out, "#ERROR: no data\n");
506 static const struct cmd_table
513 #define RXPD_CMD(cmd) {RXPD_CMD_##cmd, #cmd":", sizeof (#cmd)},
519 const struct cmd_table* i;
520 for (i = cmds; i->cmd; ++i)
521 if (strncmp (line, i->cmd, i->sz) == 0)
525 rxpd_buffer_printf (&self->out, "#ERROR: no command\n");
526 rxpd_connection_delete (self);
529 // TODO policy check here
534 self->file = (struct rxpd_file*) psplay_find (&self->base->files, &line[i->sz]);
537 self->file = rxpd_file_new (self->base, &line[i->sz]);
540 rxpd_buffer_printf (&self->out, "#ERROR: illegal rule\n");
541 rxpd_connection_delete (self);
550 #define RXPD_CMD(cmd) \
551 case RXPD_CMD_##cmd: \
552 event_set (&self->ev, self->fd, EV_READ, rxpd_connection_cmd_##cmd, self); \
557 rxpd_connection_schedule (self);
563 rxpd_connection_cmd_CHECK (int fd, short event, void* ptr)
565 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
569 while (line = rxpd_buffer_readline (&self->in, ++again))
574 rxpd_buffer_printf (&self->out, "#OK:\n");
579 LLIST_FOREACH (&self->file->rules, n)
581 struct rxpd_rule* rule = (struct rxpd_rule*)n;
582 if (rule->string[0] != '#')
584 if (regexec (&rule->rx, line, 0, NULL, 0) == 0)
586 rxpd_buffer_printf (&self->out, "%s\n", rule->string);
594 if (rxpd_buffer_state (&self->in) == RXPD_OK)
595 rxpd_connection_schedule (self);
598 if (rxpd_buffer_state (&self->in) == RXPD_ERROR)
599 rxpd_buffer_printf (&self->out, "#ERROR:\n");
605 rxpd_connection_cmd_APPEND (int fd, short event, void* ptr)
607 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
608 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
612 rxpd_connection_cmd_PREPEND (int fd, short event, void* ptr)
614 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
615 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
619 rxpd_connection_cmd_REMOVE (int fd, short event, void* ptr)
621 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
622 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
626 rxpd_connection_cmd_REPLACE (int fd, short event, void* ptr)
628 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
629 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
633 rxpd_connection_cmd_LOAD (int fd, short event, void* ptr)
635 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
636 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
640 rxpd_connection_cmd_SAVE (int fd, short event, void* ptr)
642 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
643 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
647 rxpd_connection_cmd_DUMP (int fd, short event, void* ptr)
649 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
650 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
654 rxpd_connection_cmd_LIST (int fd, short event, void* ptr)
656 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
657 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);
661 rxpd_connection_cmd_SHUTDOWN (int fd, short event, void* ptr)
663 struct rxpd_connection* self = (struct rxpd_connection*) ptr;
664 rxpd_buffer_printf (&self->out, "#ERROR: unimplemented command %s\n", &__func__[20]);