+Missing <time.h> include
[middleman.git] / src / cookies.c
1 /*
2     MiddleMan filtering proxy server
3     Copyright (C) 2002  Jason McLaughlin
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #include <string.h>
21 #include "proto.h"
22
23 /*
24 read the <cookies> section from xml_list and load into another linked list
25 */
26 COOKIE_LIST *cookie_load(COOKIE_LIST * cookie_list, XML_LIST * xml_list)
27 {
28         COOKIE_LIST *tmp_list = cookie_list;
29         struct COOKIE_LIST_LIST *allow = NULL, *deny = NULL;
30
31         if (tmp_list == NULL) {
32                 tmp_list = xmalloc(sizeof(COOKIE_LIST));
33                 cookie_list = tmp_list;
34                 tmp_list->allow = NULL;
35                 tmp_list->deny = NULL;
36                 tmp_list->policy = POLICY_ALLOW;
37                 tmp_list->id = 0;
38                 tmp_list->enabled = TRUE;
39
40                 pthread_rwlock_init(&tmp_list->lock, NULL);
41         } else {
42                 allow = tmp_list->allow;
43                 deny = tmp_list->deny;
44         }
45
46         while ((xml_list = xml_section(xml_list, "<cookies>"))) {
47                 XML_LIST_LOOP(xml_list, "<cookies>") {
48                         XML_LIST_CMP(xml_list, "<allow>") {
49                                 allow = cookie_ll_new(allow);
50                                 allow->id = cookie_list->id++;
51
52                                 if (tmp_list->allow == NULL)
53                                         tmp_list->allow = allow;
54                                 XML_LIST_LOOP(xml_list, "<allow>") {
55                                         XML_LIST_CMP(xml_list, "<enabled>") {
56                                                 xml_list = xml_list->next;
57                                                 if (xml_list->type == XML_VALUE) {
58                                                         if (!strcasecmp(xml_list->item, "false"))
59                                                                 allow->enabled = FALSE;
60                                                         else
61                                                                 allow->enabled = TRUE;
62                                                 }
63                                         }
64                                         XML_LIST_CMP(xml_list, "<comment>") {
65                                                 xml_list = xml_list->next;
66                                                 if (xml_list->type == XML_VALUE)
67                                                         cookie_ll_insert(allow, xml_list->item, NULL, NULL);
68                                         }
69                                         XML_LIST_CMP(xml_list, "<direction>") {
70                                                 xml_list = xml_list->next;
71                                                 if (xml_list->type == XML_VALUE)
72                                                         cookie_ll_insert(allow, NULL, xml_list->item, NULL);
73                                         }
74                                         XML_LIST_CMP(xml_list, "<host>") {
75                                                 xml_list = xml_list->next;
76                                                 if (xml_list->type == XML_VALUE)
77                                                         cookie_ll_insert(allow, NULL, NULL, xml_list->item);
78                                         }
79                                 }
80                         }
81
82                         XML_LIST_CMP(xml_list, "<deny>") {
83                                 deny = cookie_ll_new(deny);
84                                 deny->id = cookie_list->id++;
85
86                                 if (tmp_list->deny == NULL)
87                                         tmp_list->deny = deny;
88                                 XML_LIST_LOOP(xml_list, "<deny>") {
89                                         XML_LIST_CMP(xml_list, "<enabled>") {
90                                                 xml_list = xml_list->next;
91                                                 if (xml_list->type == XML_VALUE) {
92                                                         if (!strcasecmp(xml_list->item, "false"))
93                                                                 deny->enabled = FALSE;
94                                                         else
95                                                                 deny->enabled = TRUE;
96                                                 }
97                                         }
98                                         XML_LIST_CMP(xml_list, "<comment>") {
99                                                 xml_list = xml_list->next;
100                                                 if (xml_list->type == XML_VALUE)
101                                                         cookie_ll_insert(deny, xml_list->item, NULL, NULL);
102                                         }
103                                         XML_LIST_CMP(xml_list, "<direction>") {
104                                                 xml_list = xml_list->next;
105                                                 if (xml_list->type == XML_VALUE)
106                                                         cookie_ll_insert(deny, NULL, xml_list->item, NULL);
107                                         }
108                                         XML_LIST_CMP(xml_list, "<host>") {
109                                                 xml_list = xml_list->next;
110                                                 if (xml_list->type == XML_VALUE)
111                                                         cookie_ll_insert(deny, NULL, NULL, xml_list->item);
112                                         }
113                                 }
114                         }
115                         XML_LIST_CMP(xml_list, "<policy>") {
116                                 xml_list = xml_list->next;
117                                 if (xml_list->type == XML_VALUE) {
118                                         if (!strcasecmp(xml_list->item, "allow"))
119                                                 tmp_list->policy = POLICY_ALLOW;
120                                         else if (!strcasecmp(xml_list->item, "deny"))
121                                                 tmp_list->policy = POLICY_DENY;
122                                 }
123                         }
124                         XML_LIST_CMP(xml_list, "<enabled>") {
125                                 xml_list = xml_list->next;
126                                 if (xml_list->type == XML_VALUE) {
127                                         if (!strcasecmp(xml_list->item, "false"))
128                                                 tmp_list->enabled = FALSE;
129                                         else
130                                                 tmp_list->enabled = TRUE;
131                                 }
132                         }
133                 }
134         }
135
136         return cookie_list;
137 }
138
139 XML_LIST *cookie_xml(COOKIE_LIST * cookie_list, XML_LIST * xml_list)
140 {
141         int i;
142         char *ptr;
143         struct COOKIE_LIST_LIST *cl = NULL;
144
145         if (cookie_list == NULL)
146                 return xml_list;
147
148         pthread_rwlock_rdlock(&cookie_list->lock);
149
150         xml_list = xml_list_add(xml_list, "<cookies>", XML_TAG);
151
152         xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
153         xml_list = xml_list_add(xml_list, (cookie_list->enabled == TRUE) ? "true" : "false", XML_VALUE);
154         xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
155
156         xml_list = xml_list_add(xml_list, "<policy>", XML_TAG);
157         xml_list = xml_list_add(xml_list, (cookie_list->policy == POLICY_ALLOW) ? "allow" : "deny", XML_VALUE);
158         xml_list = xml_list_add(xml_list, "</policy>", XML_TAG);
159
160         for (i = 0; i < 2; i++) {
161                 switch (i) {
162                 case 0:
163                         cl = cookie_list->allow;
164                         break;
165                 case 1:
166                         cl = cookie_list->deny;
167                         break;
168                 }
169
170                 for (; cl; cl = cl->next) {
171                         xml_list = xml_list_add(xml_list, (i == 0) ? "<allow>" : "<deny>", XML_TAG);
172
173                         xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
174                         xml_list = xml_list_add(xml_list, (cl->enabled == TRUE) ? "true" : "false", XML_VALUE);
175                         xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
176
177                         if (cl->comment != NULL) {
178                                 xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
179                                 ptr = string_to_xml(cl->comment);
180                                 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
181                                 xfree(ptr);
182                                 xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
183                         }
184
185                         xml_list = xml_list_add(xml_list, "<direction>", XML_TAG);
186                         xml_list = xml_list_add(xml_list, (cl->direction == COOKIE_BOTH) ? "both" : (cl->direction == COOKIE_IN) ? "in" : "out", XML_VALUE);
187                         xml_list = xml_list_add(xml_list, "</direction>", XML_TAG);
188
189                         if (cl->host != NULL) {
190                                 xml_list = xml_list_add(xml_list, "<host>", XML_TAG);
191                                 ptr = string_to_xml(cl->host);
192                                 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
193                                 xfree(ptr);
194                                 xml_list = xml_list_add(xml_list, "</host>", XML_TAG);
195                         }
196
197                         xml_list = xml_list_add(xml_list, (i == 0) ? "</allow>" : "</deny>", XML_TAG);
198                 }
199         }
200
201         xml_list = xml_list_add(xml_list, "</cookies>", XML_TAG);
202
203         pthread_rwlock_unlock(&cookie_list->lock);
204
205         return xml_list;
206 }
207
208 void cookie_ll_insert(struct COOKIE_LIST_LIST *x, char *a, char *b, char *c)
209 {
210         if (a != NULL) {
211                 FREE_AND_NULL(x->comment);
212
213                 if (strcmp(a, ""))
214                         x->comment = xstrdup(a);
215         }
216         if (b != NULL) {
217                 if (!strcasecmp(b, "in"))
218                         x->direction = COOKIE_IN;
219                 else if (!strcasecmp(b, "out"))
220                         x->direction = COOKIE_OUT;
221                 else if (!strcasecmp(b, "both"))
222                         x->direction = COOKIE_BOTH;
223         }
224         if (c != NULL) {
225                 if (x->he != NULL)
226                         reg_free(x->he);
227                 FREE_AND_NULL(x->host);
228
229                 if (strcmp(c, "")) {
230                         x->host = xstrdup(c);
231                         x->he = reg_compile(c, REGFLAGS);
232                 } else
233                         x->he = NULL;
234         }
235 }
236
237 struct COOKIE_LIST_LIST *cookie_ll_new(struct COOKIE_LIST_LIST *x)
238 {
239         if (x == NULL) {
240                 x = xmalloc(sizeof(struct COOKIE_LIST_LIST));
241                 x->prev = NULL;
242         } else {
243                 while (x->next != NULL)
244                         x = x->next;
245                 x->next = xmalloc(sizeof(struct COOKIE_LIST_LIST));
246                 x->next->prev = x;
247                 x = x->next;
248         }
249
250         x->enabled = TRUE;
251         x->comment = NULL;
252         x->he = NULL;
253         x->host = NULL;
254         x->direction = COOKIE_BOTH;
255         x->next = NULL;
256
257         return x;
258 }
259
260 struct COOKIE_LIST_LIST *cookie_ll_delete(struct COOKIE_LIST_LIST *x)
261 {
262         struct COOKIE_LIST_LIST *start = x;
263
264         while (start->prev != NULL)
265                 start = start->prev;
266
267         if (x->next != NULL)
268                 x->next->prev = x->prev;
269         if (x->prev != NULL)
270                 x->prev->next = x->next;
271         else
272                 start = start->next;
273
274         if (x->he != NULL)
275                 reg_free(x->he);
276         FREE_AND_NULL(x->comment);
277         FREE_AND_NULL(x->host);
278
279         xfree(x);
280
281         return start;
282 }
283
284 /*
285 free memory used by COOKIE_LIST type structure
286 */
287 void cookie_free(COOKIE_LIST * cookie_list)
288 {
289         if (!cookie_list)
290                 return;
291
292         cookie_ll_free(cookie_list->allow);
293         cookie_ll_free(cookie_list->deny);
294
295         xfree(cookie_list);
296
297 }
298
299 void cookie_ll_free(struct COOKIE_LIST_LIST *cl)
300 {
301         struct COOKIE_LIST_LIST *tmp;
302
303         while (cl != NULL) {
304                 tmp = cl->next;
305
306                 if (cl->he != NULL)
307                         reg_free(cl->he);
308                 FREE_AND_NULL(cl->comment);
309                 FREE_AND_NULL(cl->host);
310
311                 xfree(cl);
312                 cl = tmp;
313         }
314 }
315
316 /*
317 check if a cookie is allowed to pass in a given direction for a host
318 */
319 int cookie_check(COOKIE_LIST * cookie_list, int direction, CONNECTION * connection)
320 {
321         int action = FALSE, result = TRUE, ret, i;
322         struct COOKIE_LIST_LIST *current;
323
324         if (connection->bypass & FEATURE_COOKIES)
325                 return TRUE;
326
327         pthread_rwlock_rdlock(&cookie_list->lock);
328
329         if (cookie_list->enabled == FALSE) {
330                 pthread_rwlock_unlock(&cookie_list->lock);
331
332                 return TRUE;
333         }
334
335         for (i = 0; i < 2; i++) {
336                 if (i == 0) {
337                         if (cookie_list->policy == POLICY_ALLOW) {
338                                 current = cookie_list->deny;
339                                 action = FALSE;
340                                 result = TRUE;
341                         } else {
342                                 current = cookie_list->allow;
343                                 action = TRUE;
344                                 result = FALSE;
345                         }
346                 } else if (action == result) {
347                         if (cookie_list->policy == POLICY_ALLOW) {
348                                 current = cookie_list->allow;
349                                 action = TRUE;
350                         } else {
351                                 current = cookie_list->deny;
352                                 action = FALSE;
353                         }
354                 } else
355                         break;
356
357                 for (; current != NULL; current = current->next) {
358                         if (current->enabled == FALSE)
359                                 continue;
360
361                         if (current->he != NULL && (current->direction == direction || current->direction == COOKIE_BOTH)) {
362                                 ret = reg_exec(current->he, connection->header->host);
363                                 if (ret)
364                                         continue;
365                         }
366
367                         result = action;
368                         break;
369                 }
370         }
371
372         pthread_rwlock_unlock(&cookie_list->lock);
373
374         return result;
375 }