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