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