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