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 /*
25 parse <access> section from XML file
26 */
access_load(ACCESS_LIST * access_list,XML_LIST * xml_list)27 ACCESS_LIST *access_load(ACCESS_LIST * access_list, XML_LIST * xml_list)
28 {
29 ACCESS_LIST *tmp_list = access_list;
30 struct ACCESS_LIST_LIST *allow = NULL, *deny = NULL;
31
32 if (tmp_list == NULL) {
33 tmp_list = xmalloc(sizeof(ACCESS_LIST));
34 tmp_list->allow = NULL;
35 tmp_list->deny = NULL;
36 tmp_list->policy = POLICY_DENY;
37 tmp_list->id = 0;
38 tmp_list->empty = access_ll_new(NULL);
39
40 access_list = tmp_list;
41
42 pthread_rwlock_init(&tmp_list->lock, NULL);
43 } else {
44 allow = tmp_list->allow;
45 deny = tmp_list->deny;
46 }
47
48 while ((xml_list = xml_section(xml_list, "<access>"))) {
49 XML_LIST_LOOP(xml_list, "<access>") {
50 XML_LIST_CMP(xml_list, "<allow>") {
51 allow = access_ll_new(allow);
52 allow->id = access_list->id++;
53
54 if (tmp_list->allow == NULL)
55 tmp_list->allow = allow;
56 XML_LIST_LOOP(xml_list, "<allow>") {
57 XML_LIST_CMP(xml_list, "<enabled>") {
58 xml_list = xml_list->next;
59 if (xml_list->type == XML_VALUE) {
60 if (!strcasecmp(xml_list->item, "false"))
61 allow->enabled = FALSE;
62 else
63 allow->enabled = TRUE;
64 }
65 }
66 XML_LIST_CMP(xml_list, "<comment>") {
67 xml_list = xml_list->next;
68 if (xml_list->type == XML_VALUE)
69 access_ll_insert(allow, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL);
70 }
71 XML_LIST_CMP(xml_list, "<profiles>") {
72 xml_list = xml_list->next;
73 if (xml_list->type == XML_VALUE)
74 access_ll_insert(allow, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL);
75 }
76 XML_LIST_CMP(xml_list, "<ip>") {
77 xml_list = xml_list->next;
78 if (xml_list->type == XML_VALUE)
79 access_ll_insert(allow, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL);
80 }
81 XML_LIST_CMP(xml_list, "<access>") {
82 xml_list = xml_list->next;
83 if (xml_list->type == XML_VALUE)
84 access_ll_insert(allow, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL);
85 }
86 XML_LIST_CMP(xml_list, "<bypass>") {
87 xml_list = xml_list->next;
88 if (xml_list->type == XML_VALUE)
89 access_ll_insert(allow, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL);
90 }
91 XML_LIST_CMP(xml_list, "<pamauth>") {
92 xml_list = xml_list->next;
93 if (xml_list->type == XML_VALUE) {
94 if (!strcasecmp(xml_list->item, "true"))
95 allow->pamauth = TRUE;
96 else
97 allow->pamauth = FALSE;
98 }
99 }
100 XML_LIST_CMP(xml_list, "<username>") {
101 xml_list = xml_list->next;
102 if (xml_list->type == XML_VALUE)
103 access_ll_insert(allow, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL);
104 }
105 XML_LIST_CMP(xml_list, "<password>") {
106 xml_list = xml_list->next;
107 if (xml_list->type == XML_VALUE)
108 access_ll_insert(allow, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item);
109 }
110 }
111 }
112 XML_LIST_CMP(xml_list, "<deny>") {
113 deny = access_ll_new(deny);
114 deny->id = access_list->id++;
115
116 if (tmp_list->deny == NULL)
117 tmp_list->deny = deny;
118 XML_LIST_LOOP(xml_list, "<deny>") {
119 XML_LIST_CMP(xml_list, "<enabled>") {
120 xml_list = xml_list->next;
121 if (xml_list->type == XML_VALUE) {
122 if (!strcasecmp(xml_list->item, "false"))
123 deny->enabled = FALSE;
124 else
125 deny->enabled = TRUE;
126 }
127 }
128 XML_LIST_CMP(xml_list, "<profiles>") {
129 xml_list = xml_list->next;
130 if (xml_list->type == XML_VALUE)
131 access_ll_insert(deny, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL);
132 }
133 XML_LIST_CMP(xml_list, "<comment>") {
134 xml_list = xml_list->next;
135 if (xml_list->type == XML_VALUE)
136 access_ll_insert(deny, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL);
137 }
138 XML_LIST_CMP(xml_list, "<ip>") {
139 xml_list = xml_list->next;
140 if (xml_list->type == XML_VALUE)
141 access_ll_insert(deny, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL);
142 }
143 XML_LIST_CMP(xml_list, "<access>") {
144 xml_list = xml_list->next;
145 if (xml_list->type == XML_VALUE)
146 access_ll_insert(deny, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL);
147 }
148 XML_LIST_CMP(xml_list, "<bypass>") {
149 xml_list = xml_list->next;
150 if (xml_list->type == XML_VALUE)
151 access_ll_insert(deny, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL);
152 }
153 XML_LIST_CMP(xml_list, "<pamauth>") {
154 xml_list = xml_list->next;
155 if (xml_list->type == XML_VALUE) {
156 if (!strcasecmp(xml_list->item, "true"))
157 deny->pamauth = TRUE;
158 else
159 deny->pamauth = FALSE;
160 }
161 }
162 XML_LIST_CMP(xml_list, "<username>") {
163 xml_list = xml_list->next;
164 if (xml_list->type == XML_VALUE)
165 access_ll_insert(deny, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL);
166 }
167 XML_LIST_CMP(xml_list, "<password>") {
168 xml_list = xml_list->next;
169 if (xml_list->type == XML_VALUE)
170 access_ll_insert(deny, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item);
171 }
172 }
173 }
174 XML_LIST_CMP(xml_list, "<policy>") {
175 xml_list = xml_list->next;
176 if (xml_list->type == XML_VALUE) {
177 if (!strcasecmp(xml_list->item, "allow"))
178 tmp_list->policy = POLICY_ALLOW;
179 else if (!strcasecmp(xml_list->item, "deny"))
180 tmp_list->policy = POLICY_DENY;
181 }
182 }
183 }
184 }
185
186 return access_list;
187 }
188
access_xml(ACCESS_LIST * access_list,XML_LIST * xml_list)189 XML_LIST *access_xml(ACCESS_LIST * access_list, XML_LIST * xml_list)
190 {
191 int i;
192 char *ptr, buf[128];
193 struct ACCESS_LIST_LIST *al = NULL;
194
195 if (access_list == NULL)
196 return xml_list;
197
198 pthread_rwlock_rdlock(&access_list->lock);
199
200 xml_list = xml_list_add(xml_list, "<access>", XML_TAG);
201
202 xml_list = xml_list_add(xml_list, "<policy>", XML_TAG);
203 xml_list = xml_list_add(xml_list, (access_list->policy == POLICY_ALLOW) ? "allow" : "deny", XML_VALUE);
204 xml_list = xml_list_add(xml_list, "</policy>", XML_TAG);
205
206 for (i = 0; i < 2; i++) {
207 switch (i) {
208 case 0:
209 al = access_list->allow;
210 break;
211 case 1:
212 al = access_list->deny;
213 break;
214 }
215
216 for (; al; al = al->next) {
217 xml_list = xml_list_add(xml_list, (i == 0) ? "<allow>" : "<deny>", XML_TAG);
218
219 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
220 xml_list = xml_list_add(xml_list, (al->enabled == TRUE) ? "true" : "false", XML_VALUE);
221 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
222
223 if (al->comment != NULL) {
224 xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
225 ptr = string_to_xml(al->comment);
226 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
227 xfree(ptr);
228 xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
229 }
230 if (al->profiles != NULL) {
231 xml_list = xml_list_add(xml_list, "<profiles>", XML_TAG);
232 ptr = array_merge(al->profiles, ',');
233 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
234 xfree(ptr);
235 xml_list = xml_list_add(xml_list, "</profiles>", XML_TAG);
236 }
237 if (al->ip != NULL) {
238 xml_list = xml_list_add(xml_list, "<ip>", XML_TAG);
239 ptr = string_to_xml(al->ip);
240 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
241 xfree(ptr);
242 xml_list = xml_list_add(xml_list, "</ip>", XML_TAG);
243 }
244
245 xml_list = xml_list_add(xml_list, "<pamauth>", XML_TAG);
246 xml_list = xml_list_add(xml_list, (al->pamauth == TRUE) ? "true" : "false", XML_VALUE);
247 xml_list = xml_list_add(xml_list, "</pamauth>", XML_TAG);
248
249 if (al->username != NULL) {
250 xml_list = xml_list_add(xml_list, "<username>", XML_TAG);
251 ptr = string_to_xml(al->username);
252 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
253 xfree(ptr);
254 xml_list = xml_list_add(xml_list, "</username>", XML_TAG);
255 }
256 if (al->password != NULL) {
257 xml_list = xml_list_add(xml_list, "<password>", XML_TAG);
258 ptr = string_to_xml(al->password);
259 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
260 xfree(ptr);
261 xml_list = xml_list_add(xml_list, "</password>", XML_TAG);
262 }
263 if (al->bypass != 0) {
264 xml_list = xml_list_add(xml_list, "<bypass>", XML_TAG);
265 snprintf(buf, sizeof(buf), "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", (al->bypass & FEATURE_FILTER) ? "filter" : "", (al->bypass & FEATURE_HEADER) ? "header" : "", (al->bypass & FEATURE_MIME) ? "mime" : "", (al->bypass & FEATURE_REDIRECT) ? "redirect" : "", (al->bypass & FEATURE_COOKIES) ? "cookies" : "", (al->bypass & FEATURE_REWRITE) ? "rewrite" : "", (al->bypass & FEATURE_EXTERNAL) ? "external" : "", (al->bypass & FEATURE_FORWARD) ? "forward" : "", (al->bypass & FEATURE_KEYWORDS) ? "keywords" : "", (al->bypass & FEATURE_DNSBL) ? "dnsbl" : "", (al->bypass & FEATURE_LIMITS) ? "limits" : "");
266 xml_list = xml_list_add(xml_list, buf, XML_VALUE);
267 xml_list = xml_list_add(xml_list, "</bypass>", XML_TAG);
268 }
269
270 xml_list = xml_list_add(xml_list, "<access>", XML_TAG);
271 snprintf(buf, sizeof(buf), "%s,%s,%s,%s,%s,%s,%s", (al->access & ACCESS_CONFIG) ? "config" : "", (al->access & ACCESS_PROXY) ? "proxy" : "", (al->access & ACCESS_CONNECT) ? "connect" : "", (al->access & ACCESS_HTTP) ? "http" : "", (al->access & ACCESS_TRANSPARENT) ? "transparent" : "", (al->access & ACCESS_BYPASS) ? "bypass" : "", (al->access & ACCESS_URLCOMMAND) ? "urlcommand" : "");
272 xml_list = xml_list_add(xml_list, buf, XML_VALUE);
273 xml_list = xml_list_add(xml_list, "</access>", XML_TAG);
274
275 xml_list = xml_list_add(xml_list, (i == 0) ? "</allow>" : "</deny>", XML_TAG);
276 }
277 }
278
279 xml_list = xml_list_add(xml_list, "</access>", XML_TAG);
280
281 pthread_rwlock_unlock(&access_list->lock);
282
283 return xml_list;
284 }
285
286 /*
287 free memory used by ACCESS_LIST linked list
288 */
access_free(ACCESS_LIST * access_list)289 void access_free(ACCESS_LIST * access_list)
290 {
291 if (!access_list)
292 return;
293
294 access_ll_free(access_list->allow);
295 access_ll_free(access_list->deny);
296 access_ll_free(access_list->empty);
297
298 pthread_rwlock_destroy(&access_list->lock);
299
300 xfree(access_list);
301 }
302
access_ll_free(struct ACCESS_LIST_LIST * al)303 void access_ll_free(struct ACCESS_LIST_LIST *al)
304 {
305 struct ACCESS_LIST_LIST *tmp;
306
307 while (al != NULL) {
308 tmp = al->next;
309
310 if (al->ie != NULL)
311 reg_free(al->ie);
312 if (al->ue != NULL)
313 reg_free(al->ue);
314 if (al->profiles != NULL)
315 array_free(al->profiles);
316 FREE_AND_NULL(al->comment);
317 FREE_AND_NULL(al->ip);
318 FREE_AND_NULL(al->username);
319 FREE_AND_NULL(al->password);
320
321 xfree(al);
322 al = tmp;
323 }
324 }
325
326 /*
327 check whether or not an ip address is allowed access based on the rules supplied
328 in the access_list linked list
329 */
access_check(ACCESS_LIST * access_list,CONNECTION * connection,char * username,char * password)330 struct ACCESS_LIST_LIST *access_check(ACCESS_LIST * access_list, CONNECTION * connection, char *username, char *password)
331 {
332 int action = FALSE, result = TRUE, i, ret;
333 struct ACCESS_LIST_LIST *current = NULL, *match = NULL;
334
335 if (!access_list)
336 return 0;
337
338 pthread_rwlock_rdlock(&access_list->lock);
339
340 for (i = 0; i < 2; i++) {
341 if (i == 0) {
342 if (access_list->policy == POLICY_ALLOW) {
343 current = access_list->deny;
344 action = FALSE;
345 result = TRUE;
346 } else {
347 current = access_list->allow;
348 action = TRUE;
349 result = FALSE;
350 }
351 } else if (result == action) {
352 if (access_list->policy == POLICY_ALLOW) {
353 current = access_list->allow;
354 action = TRUE;
355 } else {
356 current = access_list->deny;
357 action = FALSE;
358 }
359 } else
360 break;
361
362 for (; current != NULL; current = current->next) {
363 if (current->enabled == FALSE)
364 continue;
365
366 if (current->ie != NULL) {
367 ret = reg_exec(current->ie, connection->ip);
368 if (ret)
369 continue;
370 }
371
372 if (current->ue != NULL && username != NULL) {
373 ret = reg_exec(current->ue, username);
374 if (ret)
375 continue;
376 }
377
378 if (current->pamauth == FALSE && current->password != NULL && password != NULL && strcmp(current->password, password))
379 continue;
380
381 match = current;
382 result = action;
383
384 break;
385 }
386 }
387
388 return (result) ? (match != NULL) ? match : access_list->empty : NULL;
389 }
390
access_ll_insert(struct ACCESS_LIST_LIST * x,char * profiles,char * a,char * b,char * c,char * d,char * e,char * f)391 void access_ll_insert(struct ACCESS_LIST_LIST *x, char *profiles, char *a, char *b, char *c, char *d, char *e, char *f)
392 {
393 int i;
394 char **args;
395
396 if (profiles != NULL) {
397 if (x->profiles != NULL)
398 array_free(x->profiles);
399
400 if (strcmp(profiles, ""))
401 x->profiles = string_break(profiles, ',');
402 else
403 x->profiles = NULL;
404 }
405 if (a != NULL) {
406 FREE_AND_NULL(x->comment);
407
408 if (strcmp(a, ""))
409 x->comment = xstrdup(a);
410 }
411 if (b != NULL) {
412 if (x->ie != NULL)
413 reg_free(x->ie);
414 FREE_AND_NULL(x->ip);
415
416 if (strcmp(b, "")) {
417 x->ip = xstrdup(b);
418 x->ie = reg_compile(b, REGFLAGS);
419 } else
420 x->ie = NULL;
421 }
422 if (c != NULL) {
423 x->access = 0;
424
425 if (strcmp(c, "")) {
426 args = string_break(c, ',');
427 for (i = 0; args[i]; i++) {
428 if (!strcasecmp(args[i], "config"))
429 x->access |= ACCESS_CONFIG;
430 else if (!strcasecmp(args[i], "proxy"))
431 x->access |= ACCESS_PROXY;
432 else if (!strcasecmp(args[i], "connect"))
433 x->access |= ACCESS_CONNECT;
434 else if (!strcasecmp(args[i], "http"))
435 x->access |= ACCESS_HTTP;
436 else if (!strcasecmp(args[i], "transparent"))
437 x->access |= ACCESS_TRANSPARENT;
438 else if (!strcasecmp(args[i], "bypass"))
439 x->access |= ACCESS_BYPASS;
440 else if (!strcasecmp(args[i], "urlcommand"))
441 x->access |= ACCESS_URLCOMMAND;
442
443 xfree(args[i]);
444 }
445 xfree(args);
446 }
447 }
448 if (d != NULL) {
449 x->bypass = 0;
450
451 if (strcmp(d, "")) {
452 args = string_break(d, ',');
453 for (i = 0; args[i]; i++) {
454 if (!strcasecmp(args[i], "filter"))
455 x->bypass |= FEATURE_FILTER;
456 else if (!strcasecmp(args[i], "header"))
457 x->bypass |= FEATURE_HEADER;
458 else if (!strcasecmp(args[i], "mime"))
459 x->bypass |= FEATURE_MIME;
460 else if (!strcasecmp(args[i], "redirect"))
461 x->bypass |= FEATURE_REDIRECT;
462 else if (!strcasecmp(args[i], "cookies"))
463 x->bypass |= FEATURE_COOKIES;
464 else if (!strcasecmp(args[i], "rewrite"))
465 x->bypass |= FEATURE_REWRITE;
466 else if (!strcasecmp(args[i], "external"))
467 x->bypass |= FEATURE_EXTERNAL;
468 else if (!strcasecmp(args[i], "forward"))
469 x->bypass |= FEATURE_FORWARD;
470 else if (!strcasecmp(args[i], "keywords"))
471 x->bypass |= FEATURE_KEYWORDS;
472 else if (!strcasecmp(args[i], "dnsbl"))
473 x->bypass |= FEATURE_DNSBL;
474 else if (!strcasecmp(args[i], "limits"))
475 x->bypass |= FEATURE_LIMITS;
476 xfree(args[i]);
477 }
478 xfree(args);
479 }
480 }
481 if (e != NULL) {
482 FREE_AND_NULL(x->username);
483 if (x->ue != NULL) reg_free(x->ue);
484
485 if (strcmp(e, "")) {
486 x->username = xstrdup(e);
487 x->ue = reg_compile(e, REGFLAGS);
488 } else x->ue = NULL;
489 }
490 if (f != NULL) {
491 FREE_AND_NULL(x->password);
492
493 if (strcmp(f, ""))
494 x->password = xstrdup(f);
495 }
496 }
497
access_ll_new(struct ACCESS_LIST_LIST * x)498 struct ACCESS_LIST_LIST *access_ll_new(struct ACCESS_LIST_LIST *x)
499 {
500 if (x == NULL) {
501 x = xmalloc(sizeof(struct ACCESS_LIST_LIST));
502 x->prev = NULL;
503 } else {
504 while (x->next != NULL)
505 x = x->next;
506 x->next = xmalloc(sizeof(struct ACCESS_LIST_LIST));
507 x->next->prev = x;
508 x = x->next;
509 }
510
511 x->enabled = TRUE;
512 x->profiles = NULL;
513 x->comment = NULL;
514 x->ie = NULL;
515 x->ue = NULL;
516 x->ip = NULL;
517 x->pamauth = FALSE;
518 x->username = NULL;
519 x->password = NULL;
520 x->access = 0;
521 x->bypass = 0;
522 x->next = NULL;
523
524 return x;
525 }
526
access_ll_delete(struct ACCESS_LIST_LIST * x)527 struct ACCESS_LIST_LIST *access_ll_delete(struct ACCESS_LIST_LIST *x)
528 {
529 struct ACCESS_LIST_LIST *start = x;
530
531 while (start->prev != NULL)
532 start = start->prev;
533
534 if (x->next != NULL)
535 x->next->prev = x->prev;
536 if (x->prev != NULL)
537 x->prev->next = x->next;
538 else
539 start = start->next;
540
541 if (x->ie != NULL)
542 reg_free(x->ie);
543 if (x->ue != NULL)
544 reg_free(x->ue);
545 if (x->profiles != NULL)
546 array_free(x->profiles);
547 FREE_AND_NULL(x->comment);
548 FREE_AND_NULL(x->ip);
549 FREE_AND_NULL(x->username);
550 FREE_AND_NULL(x->password);
551
552 xfree(x);
553
554 return start;
555 }
556
access_setup(CONNECTION * connection,struct ACCESS_LIST_LIST * al)557 void access_setup(CONNECTION *connection, struct ACCESS_LIST_LIST *al) {
558 if (al->pamauth == TRUE || (al->username != NULL && al->password != NULL))
559 connection->authenticate = TRUE;
560
561 if (connection->profiles != NULL) {
562 array_free(connection->profiles);
563 connection->profiles = NULL;
564 }
565
566 if (al->profiles != NULL)
567 connection->profiles = array_dup(al->profiles);
568
569 connection->access = al->access;
570 }
571