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