Removed threading
[middleman.git] / src / forward.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 <stdio.h>
21 #include <string.h>
22 #include "proto.h"
23
24 FORWARD_LIST *forward_load(FORWARD_LIST * forward_list, XML_LIST * xml_list)
25 {
26         FORWARD_LIST *tmp_list = forward_list;
27         struct FORWARD_LIST_LIST *forward = NULL;
28
29         if (tmp_list == NULL) {
30                 tmp_list = xmalloc(sizeof(FORWARD_LIST));
31                 tmp_list->forward_list = NULL;
32                 tmp_list->id = 0;
33                 tmp_list->enabled = TRUE;
34
35                 forward_list = tmp_list;
36
37                 pthread_rwlock_init(&tmp_list->lock, NULL);
38         } else
39                 forward = tmp_list->forward_list;
40
41         while ((xml_list = xml_section(xml_list, "<forward>"))) {
42                 XML_LIST_LOOP(xml_list, "<forward>") {
43                         XML_LIST_CMP(xml_list, "<item>") {
44                                 forward = forward_list_new(forward);
45                                 forward->id = tmp_list->id++;
46
47                                 if (tmp_list->forward_list == NULL)
48                                         tmp_list->forward_list = forward;
49
50                                 XML_LIST_LOOP(xml_list, "<item>") {
51                                         XML_LIST_CMP(xml_list, "<enabled>") {
52                                                 xml_list = xml_list->next;
53                                                 if (xml_list->type == XML_VALUE) {
54                                                         if (!strcasecmp(xml_list->item, "false"))
55                                                                 forward->enabled = FALSE;
56                                                         else
57                                                                 forward->enabled = TRUE;
58                                                 }
59                                         }
60                                         XML_LIST_CMP(xml_list, "<comment>") {
61                                                 xml_list = xml_list->next;
62                                                 if (xml_list->type == XML_VALUE)
63                                                         forward_list_insert(forward, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
64                                         }
65                                         XML_LIST_CMP(xml_list, "<host>") {
66                                                 xml_list = xml_list->next;
67                                                 if (xml_list->type == XML_VALUE)
68                                                         forward_list_insert(forward, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
69                                         }
70                                         XML_LIST_CMP(xml_list, "<file>") {
71                                                 xml_list = xml_list->next;
72                                                 if (xml_list->type == XML_VALUE)
73                                                         forward_list_insert(forward, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
74                                         }
75                                         XML_LIST_CMP(xml_list, "<proxy>") {
76                                                 xml_list = xml_list->next;
77                                                 if (xml_list->type == XML_VALUE)
78                                                         forward_list_insert(forward, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL);
79                                         }
80                                         XML_LIST_CMP(xml_list, "<port>") {
81                                                 xml_list = xml_list->next;
82                                                 if (xml_list->type == XML_VALUE)
83                                                         forward_list_insert(forward, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL);
84                                         }
85                                         XML_LIST_CMP(xml_list, "<type>") {
86                                                 xml_list = xml_list->next;
87                                                 if (xml_list->type == XML_VALUE)
88                                                         forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL);
89                                         }
90                                         XML_LIST_CMP(xml_list, "<which>") {
91                                                 xml_list = xml_list->next;
92                                                 if (xml_list->type == XML_VALUE)
93                                                         forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL);
94                                         }
95                                         XML_LIST_CMP(xml_list, "<username>") {
96                                                 xml_list = xml_list->next;
97                                                 if (xml_list->type == XML_VALUE)
98                                                         forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL);
99                                         }
100                                         XML_LIST_CMP(xml_list, "<password>") {
101                                                 xml_list = xml_list->next;
102                                                 if (xml_list->type == XML_VALUE)
103                                                         forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL);
104                                         }
105                                         XML_LIST_CMP(xml_list, "<domain>") {
106                                                 xml_list = xml_list->next;
107                                                 if (xml_list->type == XML_VALUE)
108                                                         forward_list_insert(forward, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item);
109                                         }
110                                 }
111                                 XML_LIST_CMP(xml_list, "<enabled>") {
112                                         xml_list = xml_list->next;
113                                         if (xml_list->type == XML_VALUE) {
114                                                 if (!strcasecmp(xml_list->item, "false"))
115                                                         tmp_list->enabled = FALSE;
116                                                 else
117                                                         tmp_list->enabled = TRUE;
118                                         }
119                                 }
120                         }
121                 }
122         }
123
124         return tmp_list;
125 }
126
127 XML_LIST *forward_xml(FORWARD_LIST * forward_list, XML_LIST * xml_list)
128 {
129         char *ptr, buf[128];
130         struct FORWARD_LIST_LIST *fl;
131
132         pthread_rwlock_rdlock(&forward_list->lock);
133
134         xml_list = xml_list_add(xml_list, "<forward>", XML_TAG);
135
136         xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
137         xml_list = xml_list_add(xml_list, (forward_list->enabled == TRUE) ? "true" : "false", XML_VALUE);
138         xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
139
140         for (fl = forward_list->forward_list; fl; fl = fl->next) {
141                 xml_list = xml_list_add(xml_list, "<item>", XML_TAG);
142
143                 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
144                 xml_list = xml_list_add(xml_list, (fl->enabled == TRUE) ? "true" : "false", XML_VALUE);
145                 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
146
147                 if (fl->comment != NULL) {
148                         xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
149                         ptr = string_to_xml(fl->comment);
150                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
151                         xfree(ptr);
152                         xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
153                 }
154                 if (fl->host != NULL) {
155                         xml_list = xml_list_add(xml_list, "<host>", XML_TAG);
156                         ptr = string_to_xml(fl->host);
157                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
158                         xfree(ptr);
159                         xml_list = xml_list_add(xml_list, "</host>", XML_TAG);
160                 }
161                 if (fl->file != NULL) {
162                         xml_list = xml_list_add(xml_list, "<file>", XML_TAG);
163                         ptr = string_to_xml(fl->file);
164                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
165                         xfree(ptr);
166                         xml_list = xml_list_add(xml_list, "</file>", XML_TAG);
167                 }
168                 if (fl->proxy != NULL) {
169                         xml_list = xml_list_add(xml_list, "<proxy>", XML_TAG);
170                         ptr = string_to_xml(fl->proxy);
171                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
172                         xfree(ptr);
173                         xml_list = xml_list_add(xml_list, "</proxy>", XML_TAG);
174                 }
175
176                 if (fl->port != -1) {
177                         xml_list_add(xml_list, "<port>", XML_TAG);
178                         snprintf(buf, sizeof(buf), "%d", fl->port);
179                         xml_list = xml_list_add(xml_list, buf, XML_VALUE);
180                         xml_list_add(xml_list, "</port>", XML_TAG);
181                 }
182                 if (fl->username != NULL) {
183                         xml_list = xml_list_add(xml_list, "<username>", XML_TAG);
184                         ptr = string_to_xml(fl->username);
185                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
186                         xfree(ptr);
187                         xml_list = xml_list_add(xml_list, "</username>", XML_TAG);
188                 }
189                 if (fl->password != NULL) {
190                         xml_list = xml_list_add(xml_list, "<password>", XML_TAG);
191                         ptr = string_to_xml(fl->password);
192                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
193                         xfree(ptr);
194                         xml_list = xml_list_add(xml_list, "</password>", XML_TAG);
195                 }
196                 if (fl->domain != NULL) {
197                         xml_list = xml_list_add(xml_list, "<domain>", XML_TAG);
198                         ptr = string_to_xml(fl->domain);
199                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
200                         xfree(ptr);
201                         xml_list = xml_list_add(xml_list, "</domain>", XML_TAG);
202                 }
203
204
205                 xml_list = xml_list_add(xml_list, "<type>", XML_TAG);
206                 xml_list = xml_list_add(xml_list, (fl->type == PROXY_NORMAL) ? "HTTP" : "SOCKS4", XML_VALUE);
207                 xml_list = xml_list_add(xml_list, "</type>", XML_TAG);
208
209                 xml_list = xml_list_add(xml_list, "<which>", XML_TAG);
210                 snprintf(buf, sizeof(buf), "%s,%s", (fl->which & FORWARD_HTTP) ? "HTTP" : "", (fl->which & FORWARD_CONNECT) ? "CONNECT" : "");
211                 xml_list = xml_list_add(xml_list, buf, XML_VALUE);
212                 xml_list = xml_list_add(xml_list, "</which>", XML_TAG);
213
214                 xml_list = xml_list_add(xml_list, "</item>", XML_TAG);
215         }
216
217         xml_list = xml_list_add(xml_list, "</forward>", XML_TAG);
218
219         pthread_rwlock_unlock(&forward_list->lock);
220
221         return xml_list;
222 }
223
224 struct FORWARD_LIST_LIST *forward_list_new(struct FORWARD_LIST_LIST *x)
225 {
226         if (x == NULL) {
227                 x = xmalloc(sizeof(struct FORWARD_LIST_LIST));
228                 x->prev = NULL;
229         } else {
230                 while (x->next != NULL)
231                         x = x->next;
232                 x->next = xmalloc(sizeof(struct FORWARD_LIST_LIST));
233                 x->next->prev = x;
234                 x = x->next;
235         }
236
237         x->enabled = TRUE;
238         x->comment = NULL;
239         x->host = NULL;
240         x->file = NULL;
241         x->port = -1;
242         x->type = PROXY_NORMAL;
243         x->which = 0;
244         x->proxy = NULL;
245         x->username = NULL;
246         x->password = NULL;
247         x->domain = NULL;
248         x->he = NULL;
249         x->fe = NULL;
250         x->next = NULL;
251
252         return x;
253 }
254
255 void forward_list_insert(struct FORWARD_LIST_LIST *x, char *a, char *b, char *c, char *d, char *e, char *f, char *g, char *h, char *i, char *j)
256 {
257         int z;
258         char **args;
259
260         if (a != NULL) {
261                 FREE_AND_NULL(x->comment);
262
263                 if (strcmp(a, ""))
264                         x->comment = xstrdup(a);
265         }
266         if (b != NULL) {
267                 if (x->he != NULL)
268                         reg_free(x->he);
269                 FREE_AND_NULL(x->host);
270
271                 if (strcmp(b, "")) {
272                         x->he = reg_compile(b, REGFLAGS);
273                         x->host = xstrdup(b);
274                 } else
275                         x->he = NULL;
276         }
277         if (c != NULL) {
278                 if (x->fe != NULL)
279                         reg_free(x->fe);
280                 FREE_AND_NULL(x->file);
281
282                 if (strcmp(c, "")) {
283                         x->fe = reg_compile(c, REGFLAGS);
284                         x->file = xstrdup(c);
285                 } else
286                         x->fe = NULL;
287         }
288         if (d != NULL) {
289                 FREE_AND_NULL(x->proxy);
290
291                 if (strcmp(d, ""))
292                         x->proxy = xstrdup(d);
293         }
294         if (e != NULL) {
295                 x->port = -1;
296
297                 if (strcmp(e, ""))
298                         x->port = atoi(e);
299         }
300         if (f != NULL) {
301                 x->type = PROXY_NORMAL;
302
303                 if (strcmp(f, "")) {
304                         if (!strcasecmp(f, "HTTP"))
305                                 x->type = PROXY_NORMAL;
306                         else if (!strcasecmp(f, "SOCKS4"))
307                                 x->type = PROXY_SOCKS4;
308                 }
309         }
310         if (g != NULL) {
311                 x->which = 0;
312
313                 if (strcmp(g, "")) {
314                         args = string_break(g, ',');
315                         for (z = 0; args[z]; z++) {
316                                 if (!strcasecmp(args[z], "HTTP"))
317                                         x->which |= FORWARD_HTTP;
318                                 else if (!strcasecmp(args[z], "CONNECT"))
319                                         x->which |= FORWARD_CONNECT;
320
321                                 xfree(args[z]);
322                         }
323                         xfree(args);
324                 }
325         }
326         if (h != NULL) {
327                 FREE_AND_NULL(x->username);
328
329                 if (strcmp(h, ""))
330                         x->username = xstrdup(h);
331         }
332
333         if (i != NULL) {
334                 FREE_AND_NULL(x->password);
335
336                 if (strcmp(i, ""))
337                         x->password = xstrdup(i);
338         }
339
340         if (j != NULL) {
341                 FREE_AND_NULL(x->domain);
342
343                 if (strcmp(j, ""))
344                         x->domain = xstrdup(j);
345         }
346 }
347
348 struct FORWARD_LIST_LIST *forward_list_delete(struct FORWARD_LIST_LIST *x)
349 {
350         struct FORWARD_LIST_LIST *start = x;
351
352         while (start->prev != NULL)
353                 start = start->prev;
354
355         if (x->next != NULL)
356                 x->next->prev = x->prev;
357         if (x->prev != NULL)
358                 x->prev->next = x->next;
359         else
360                 start = start->next;
361
362         if (x->he != NULL)
363                 reg_free(x->he);
364         if (x->fe != NULL)
365                 reg_free(x->fe);
366         FREE_AND_NULL(x->comment);
367         FREE_AND_NULL(x->host);
368         FREE_AND_NULL(x->file);
369         FREE_AND_NULL(x->proxy);
370         FREE_AND_NULL(x->username);
371         FREE_AND_NULL(x->password);
372         FREE_AND_NULL(x->domain);
373
374         return start;
375 }
376
377 void forward_list_free(struct FORWARD_LIST_LIST *fl)
378 {
379         struct FORWARD_LIST_LIST *tmp;
380
381         while (fl != NULL) {
382                 tmp = fl->next;
383
384                 if (fl->he != NULL)
385                         reg_free(fl->he);
386                 if (fl->fe != NULL)
387                         reg_free(fl->fe);
388                 FREE_AND_NULL(fl->comment);
389                 FREE_AND_NULL(fl->host);
390                 FREE_AND_NULL(fl->file);
391                 FREE_AND_NULL(fl->proxy);
392                 FREE_AND_NULL(fl->username);
393                 FREE_AND_NULL(fl->password);
394                 FREE_AND_NULL(fl->domain);
395
396                 xfree(fl);
397
398                 fl = tmp;
399         }
400 }
401
402 void forward_free(FORWARD_LIST * forward_list)
403 {
404         if (forward_list == NULL)
405                 return;
406
407         forward_list_free(forward_list->forward_list);
408
409         xfree(forward_list);
410 }
411
412 int forward_do(FORWARD_LIST * forward_list, CONNECTION * connection)
413 {
414         int ret;
415         struct FORWARD_LIST_LIST *forward;
416
417         if (!forward_list || connection->bypass & FEATURE_FORWARD)
418                 return FALSE;
419
420         pthread_rwlock_rdlock(&forward_list->lock);
421
422         if (forward_list->enabled == FALSE) {
423                 pthread_rwlock_unlock(&forward_list->lock);
424
425                 return FALSE;
426         }
427
428         for (forward = forward_list->forward_list; forward; forward = forward->next) {
429                 if (forward->enabled == FALSE)
430                         continue;
431
432                 if (((connection->header->type == HTTP_PROXY || connection->header->type == HTTP_REQUEST) && !(forward->which & FORWARD_HTTP)) || ((connection->header->type == HTTP_CONNECT) && !(forward->which & FORWARD_CONNECT)))
433                         continue;
434
435                 if (forward->he != NULL) {
436                         ret = reg_exec(forward->he, connection->header->host);
437                         if (ret)
438                                 continue;
439                 }
440
441                 if (forward->fe != NULL) {
442                         ret = reg_exec(forward->fe, connection->header->file);
443                         if (ret)
444                                 continue;
445                 }
446
447                 /* allow entries with no proxy host to match, but don't do anything */
448                 if (forward->proxy == NULL)
449                         break;
450
451                 connection->proxy_type = forward->type;
452                 connection->proxy_host = xstrdup(forward->proxy);
453                 if (forward->username != NULL) connection->proxy_username = xstrdup(forward->username);
454                 if (forward->password != NULL) connection->proxy_password = xstrdup(forward->password);
455                 if (forward->domain != NULL) connection->proxy_domain = xstrdup(forward->domain);
456                 connection->proxy_port = (forward->port != -1) ? forward->port : (forward->type == PROXY_SOCKS4) ? 443 : 3128;
457
458                 pthread_rwlock_unlock(&forward_list->lock);
459
460                 return TRUE;
461         }
462
463         pthread_rwlock_unlock(&forward_list->lock);
464
465         return FALSE;
466 }