fixed/improved logging
[rxpd] / src / rxpd_connection.c
1 /*
2     rxpd_connection.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 struct rxpd_connection*
25 rxpd_connection_new (struct rxpd_socket* socket, int fd)
26 {
27   struct rxpd_connection* self;
28   self = rxpd_malloc (sizeof (struct rxpd_connection));
29
30   llist_init (&self->node);
31   self->fd = fd;
32   self->socket = socket;
33   self->file = NULL;
34   self->tmp_str = NULL;
35   llist_init (&self->tmp_list);
36
37   rxpd_buffer_init (&self->in, fd);
38   rxpd_buffer_init (&self->out, fd);
39
40   self->connecter = NULL;
41   llist_insert_tail (&socket->connections, &self->node);
42
43   return self;
44 }
45
46 void
47 rxpd_connection_delete (struct rxpd_connection* self)
48 {
49   if (self)
50     {
51       if (self->fd != -1)
52         close (self->fd);
53       free (self->tmp_str);
54       LLIST_WHILE_HEAD (&self->tmp_list, n)
55         {
56           struct rxpd_rule* node = (struct rxpd_rule*)n;
57           rxpd_rule_delete (node);
58         }
59     }
60   free (self);
61 }
62
63 static void
64 rxpd_connection_cleanup (void* ptr)
65 {
66   struct rxpd_connection* self = ptr;
67   llist_unlink (&self->node);
68   close (self->fd);
69   self->fd = -1;
70
71   char buf[512];
72   *buf = '\0';
73   if (self->socket->rxpd_socket_addr (self, buf, "", 511))
74     {
75       rxpd_log (NULL, LOG_DEBUG, "connection %s terminated\n", buf);
76     }
77
78   rxpd_connection_delete (self);
79 }
80
81
82 struct rxpd_connection*
83 rxpd_connection_spawn (struct rxpd_connection* self)
84 {
85   if (self)
86     {
87       if (self->connecter)
88         rxpd_die ("connection thread already spawned\n");
89
90       pth_attr_t attr = pth_attr_new ();
91
92       pth_attr_set (attr, PTH_ATTR_JOINABLE, FALSE);
93
94       self->connecter = pth_spawn (attr, rxpd_connection_parse_cmd, self);
95
96       if (!self->connecter)
97         rxpd_die ("failed spawning thread\n");
98     }
99   return self;
100 }
101
102 int
103 rxpd_connection_check_policy (struct rxpd_connection* self, char* line)
104 {
105   struct rxpd_base* base = self->socket->base;
106   if (base->policy)
107     {
108       char buf[256];
109       buf[0] = '\0';
110
111       if (!self->socket->rxpd_socket_addr (self, buf, line, 256))
112         {
113           rxpd_log (base, LOG_ERR, "policy line too long\n");
114           return 0;
115         }
116
117       char* match = NULL;
118       LLIST_FOREACH (&base->policy->rules, n)
119       {
120         struct rxpd_rule* rule = (struct rxpd_rule*)n;
121         if (rule->string[0] != '#')
122           {
123             if (regexec (&rule->rx, buf, 0, NULL, 0) == 0)
124               {
125                 match = rule->string;
126                 break;
127               }
128           }
129       }
130
131       if (!match || !RXPD_PREFIXCMP (match, "ACCEPT:"))
132         {
133           rxpd_log (base, LOG_WARNING, "policy check: access denied '%s'\n", buf);
134           return 0;
135         }
136       rxpd_log (base, LOG_NOTICE, "policy check: permitted '%s'\n", buf);
137     }
138   return 1;
139 }
140
141 struct rxpd_connection*
142 rxpd_connection_cancel (struct rxpd_connection* self)
143 {
144   llist_unlink (&self->node);
145   pth_cancel (self->connecter);
146   return self;
147 }
148
149 void*
150 rxpd_connection_parse_cmd (void* ptr)
151 {
152   struct rxpd_connection* self = (struct rxpd_connection*) ptr;
153   struct rxpd_base* base = self->socket->base;
154
155   pth_cleanup_push (rxpd_connection_cleanup, ptr);
156
157   char* line;
158   line = rxpd_buffer_readline (&self->in);
159
160   if (!line)
161     {
162       rxpd_log (base, LOG_ERR, "no data\n");
163       rxpd_buffer_printf (&self->out, "#ERROR: no data\n");
164       goto end;
165     }
166
167   rxpd_log (base, LOG_DEBUG, "parse command '%s'\n", line);
168
169   static const struct cmd_table
170   {
171     enum rxpd_cmd_e nr;
172     const char* cmd;
173     size_t sz;
174   } cmds[] =
175     {
176 #define RXPD_CMD(cmd, _) {RXPD_CMD_##cmd, #cmd":", sizeof (#cmd)},
177       RXPD_COMMANDS
178 #undef RXPD_CMD
179       {0, NULL, 0}
180     };
181
182   const struct cmd_table* i;
183   for (i = cmds; i->cmd; ++i)
184     if (strncmp (line, i->cmd, i->sz) == 0)
185       break;
186
187   if (!i->cmd)
188     {
189       rxpd_log (base, LOG_ERR, "no command\n");
190       rxpd_buffer_printf (&self->out, "#ERROR: no command\n");
191       goto end;
192     }
193
194   if (!rxpd_connection_check_policy (self, line))
195     {
196       rxpd_buffer_printf (&self->out, "#ERROR: access denied\n");
197       goto end;
198     }
199
200   if (line[i->sz])
201     {
202       // rulename provided
203       self->file = (struct rxpd_file*) psplay_find (&base->files, &line[i->sz]);
204
205       if (!self->file)
206         {
207           self->file = rxpd_file_new (base, &line[i->sz]);
208           if (!self->file)
209             {
210               rxpd_buffer_printf (&self->out, "#ERROR: illegal filename\n");
211               goto end;
212             }
213         }
214     }
215
216   // dispatch
217   switch (i->nr)
218     {
219 #define RXPD_CMD(cmd, _)                        \
220 case RXPD_CMD_##cmd:                            \
221    rxpd_connection_cmd_##cmd (self); break;
222
223       RXPD_COMMANDS
224 #undef RXPD_CMD
225     }
226
227  end:
228   pth_cleanup_pop (TRUE);
229   return NULL;
230 }
231