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 extern GLOBAL *global;
25 
26 KEYWORD_LIST *keyword_load(KEYWORD_LIST * keyword_list, XML_LIST * xml_list)
27 {
28 	KEYWORD_LIST *tmp_list = keyword_list;
29 	struct KEYWORD_LIST_LIST *keywords = NULL;
30 
31 	if (tmp_list == NULL) {
32 		tmp_list = xmalloc(sizeof(KEYWORD_LIST));
33 		tmp_list->keyword_list = NULL;
34 		tmp_list->threshold = 0;
35 		tmp_list->template = NULL;
36 		tmp_list->id = 0;
37 		tmp_list->enabled = TRUE;
38 
39 		keyword_list = tmp_list;
40 
41 		pthread_rwlock_init(&tmp_list->lock, NULL);
42 	} else
43 		keywords = tmp_list->keyword_list;
44 
45 	while ((xml_list = xml_section(xml_list, "<keywords>"))) {
46 		XML_LIST_LOOP(xml_list, "<keywords>") {
47 			XML_LIST_CMP(xml_list, "<item>") {
48 				keywords = keyword_list_new(keywords);
49 				keywords->id = tmp_list->id++;
50 
51 				if (tmp_list->keyword_list == NULL)
52 					tmp_list->keyword_list = keywords;
53 
54 				XML_LIST_LOOP(xml_list, "<item>") {
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 								keywords->enabled = FALSE;
60 							else
61 								keywords->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 							keyword_list_insert(keywords, NULL, xml_list->item, NULL, NULL, NULL, NULL);
68 					}
69 					XML_LIST_CMP(xml_list, "<profiles>") {
70 						xml_list = xml_list->next;
71 						if (xml_list->type == XML_VALUE)
72 							keyword_list_insert(keywords, xml_list->item, NULL, NULL, NULL, NULL, NULL);
73 					}
74 					XML_LIST_CMP(xml_list, "<mime>") {
75 						xml_list = xml_list->next;
76 						if (xml_list->type == XML_VALUE)
77 							keyword_list_insert(keywords, NULL, NULL, xml_list->item, NULL, NULL, NULL);
78 					}
79 					XML_LIST_CMP(xml_list, "<keyword>") {
80 						xml_list = xml_list->next;
81 						if (xml_list->type == XML_VALUE)
82 							keyword_list_insert(keywords, NULL, NULL, NULL, xml_list->item, NULL, NULL);
83 					}
84 					XML_LIST_CMP(xml_list, "<score>") {
85 						xml_list = xml_list->next;
86 						if (xml_list->type == XML_VALUE)
87 							keyword_list_insert(keywords, NULL, NULL, NULL, NULL, xml_list->item, NULL);
88 					}
89 					XML_LIST_CMP(xml_list, "<size>") {
90 						xml_list = xml_list->next;
91 						if (xml_list->type == XML_VALUE)
92 							keyword_list_insert(keywords, NULL, NULL, NULL, NULL, NULL, xml_list->item);
93 					}
94 				}
95 			}
96 			XML_LIST_CMP(xml_list, "<enabled>") {
97 				xml_list = xml_list->next;
98 				if (xml_list->type == XML_VALUE) {
99 					if (!strcasecmp(xml_list->item, "false"))
100 						tmp_list->enabled = FALSE;
101 					else
102 						tmp_list->enabled = TRUE;
103 				}
104 			}
105 			XML_LIST_CMP(xml_list, "<threshold>") {
106 				xml_list = xml_list->next;
107 				if (xml_list->type == XML_VALUE)
108 					tmp_list->threshold = atoi(xml_list->item);
109 			}
110 			XML_LIST_CMP(xml_list, "<template>") {
111 				xml_list = xml_list->next;
112 				if (xml_list->type == XML_VALUE) {
113 					FREE_AND_NULL(tmp_list->template);
114 					tmp_list->template = xstrdup(xml_list->item);
115 				}
116 			}
117 		}
118 	}
119 
120 	return tmp_list;
121 }
122 
123 XML_LIST *keyword_xml(KEYWORD_LIST * keyword_list, XML_LIST * xml_list)
124 {
125 	char *ptr, buf[128];
126 	struct KEYWORD_LIST_LIST *kl;
127 
128 	pthread_rwlock_rdlock(&keyword_list->lock);
129 
130 	xml_list = xml_list_add(xml_list, "<keywords>", XML_TAG);
131 
132 	xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
133 	xml_list = xml_list_add(xml_list, (keyword_list->enabled == TRUE) ? "true" : "false", XML_VALUE);
134 	xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
135 
136 	xml_list = xml_list_add(xml_list, "<threshold>", XML_TAG);
137 	snprintf(buf, sizeof(buf), "%d", keyword_list->threshold);
138 	xml_list = xml_list_add(xml_list, buf, XML_VALUE);
139 	xml_list = xml_list_add(xml_list, "</threshold>", XML_TAG);
140 
141 	if (keyword_list->template != NULL) {
142 		xml_list = xml_list_add(xml_list, "<template>", XML_TAG);
143 		ptr = string_to_xml(keyword_list->template);
144 		xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
145 		xfree(ptr);
146 		xml_list = xml_list_add(xml_list, "</template>", XML_TAG);
147 	}
148 
149 	for (kl = keyword_list->keyword_list; kl; kl = kl->next) {
150 		xml_list = xml_list_add(xml_list, "<item>", XML_TAG);
151 
152 		xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
153 		xml_list = xml_list_add(xml_list, (kl->enabled == TRUE) ? "true" : "false", XML_VALUE);
154 		xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
155 
156 		if (kl->comment != NULL) {
157 			xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
158 			ptr = string_to_xml(kl->comment);
159 			xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
160 			xfree(ptr);
161 			xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
162 		}
163 		if (kl->profiles != NULL) {
164 			xml_list = xml_list_add(xml_list, "<profiles>", XML_TAG);
165 			ptr = array_merge(kl->profiles, ',');
166 			xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
167 			xfree(ptr);
168 			xml_list = xml_list_add(xml_list, "</profiles>", XML_TAG);
169 		}
170 		if (kl->mime != NULL) {
171 			xml_list = xml_list_add(xml_list, "<mime>", XML_TAG);
172 			ptr = string_to_xml(kl->mime);
173 			xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
174 			xfree(ptr);
175 			xml_list = xml_list_add(xml_list, "</mime>", XML_TAG);
cgi_parse_request(char * file)176 		}
177 
178 		if (kl->keyword != NULL) {
179 			xml_list = xml_list_add(xml_list, "<keyword>", XML_TAG);
180 			ptr = string_to_xml(kl->keyword);
181 			xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
182 			xfree(ptr);
183 			xml_list = xml_list_add(xml_list, "</keyword>", XML_TAG);
184 		}
185 
186 		if (kl->size != 0) {
187 			xml_list = xml_list_add(xml_list, "<size>", XML_TAG);
188                         snprintf(buf, sizeof(buf), "%d", kl->size);
189 			xml_list = xml_list_add(xml_list, buf, XML_VALUE);
190 			xml_list = xml_list_add(xml_list, "</size>", XML_TAG);
191 		}
192 
193 		xml_list = xml_list_add(xml_list, "<score>", XML_TAG);
194 		snprintf(buf, sizeof(buf), "%d", kl->score);
195 		xml_list = xml_list_add(xml_list, buf, XML_VALUE);
196 		xml_list = xml_list_add(xml_list, "</score>", XML_TAG);
197 
198 		xml_list = xml_list_add(xml_list, "</item>", XML_TAG);
199 	}
200 
201 	xml_list = xml_list_add(xml_list, "</keywords>", XML_TAG);
202 
203 	pthread_rwlock_unlock(&keyword_list->lock);
204 
205 	return xml_list;
206 }
207 
208 struct KEYWORD_LIST_LIST *keyword_list_new(struct KEYWORD_LIST_LIST *x)
209 {
210 	if (x == NULL) {
211 		x = xmalloc(sizeof(struct KEYWORD_LIST_LIST));
212 		x->prev = NULL;
213 	} else {
214 		while (x->next != NULL)
215 			x = x->next;
216 		x->next = xmalloc(sizeof(struct KEYWORD_LIST_LIST));
217 		x->next->prev = x;
218 		x = x->next;
219 	}
220 
221 	x->enabled = TRUE;
222 	x->comment = NULL;
cgi_args_free(struct cgi_args_t * args)223 	x->profiles = NULL;
224 	x->score = 0;
225 	x->mime = NULL;
226 	x->keyword = NULL;
227 	x->me = NULL;
228 	x->ke = NULL;
229 	x->size = 0;
230 	x->next = NULL;
231 
232 	return x;
233 }
234 
235 void keyword_list_insert(struct KEYWORD_LIST_LIST *x, char *profiles, char *comment, char *mime, char *keyword, char *score, char *size)
236 {
237 	if (profiles != NULL) {
interface_check_referer(CONNECTION * connection)238 		if (x->profiles != NULL)
239 			array_free(x->profiles);
240 
241 		if (strcmp(profiles, ""))
242 			x->profiles = string_break(profiles, ',');
243 		else
244 			x->profiles = NULL;
245 	}
246 	if (comment != NULL) {
247 		FREE_AND_NULL(x->comment);
248 
249 		if (strcmp(comment, ""))
250 			x->comment = xstrdup(comment);
251 	}
252 	if (mime != NULL) {
interface_handle_request(CONNECTION * connection)253 		if (x->me != NULL)
254 			reg_free(x->me);
255 		FREE_AND_NULL(x->mime);
256 
257 		if (strcmp(mime, "")) {
258 			x->me = reg_compile(mime, REGFLAGS);
259 			x->mime = xstrdup(mime);
260 		} else
261 			x->me = NULL;
262 	}
263 	if (keyword != NULL) {
264 		if (x->ke != NULL)
265 			reg_free(x->ke);
266 		FREE_AND_NULL(x->keyword);
267 
268 		if (strcmp(keyword, "")) {
269 			x->ke = reg_compile(keyword, REGFLAGS);
270 			x->keyword = xstrdup(keyword);
271 		} else
272 			x->ke = NULL;
273 	}
274 	if (score != NULL) {
275 		x->score = 0;
276 
277 		if (strcmp(score, ""))
278 			x->score = atoi(score);
279 	}
280 	if (size != NULL) {
281 		x->size = 0;
282 
283 		if (strcmp(size, ""))
284 	                x->size = string_to_size(size);
285 	}
286 }
287 
288 struct KEYWORD_LIST_LIST *keyword_list_delete(struct KEYWORD_LIST_LIST *x)
289 {
290 	struct KEYWORD_LIST_LIST *start = x;
291 
292 	while (start->prev != NULL)
293 		start = start->prev;
294 
295 	if (x->next != NULL)
296 		x->next->prev = x->prev;
297 	if (x->prev != NULL)
298 		x->prev->next = x->next;
299 	else
300 		start = start->next;
301 
302 	if (x->me != NULL)
303 		reg_free(x->me);
304 	if (x->ke != NULL)
305 		reg_free(x->ke);
306 	if (x->profiles != NULL)
307 		array_free(x->profiles);
308 	FREE_AND_NULL(x->comment);
309 	FREE_AND_NULL(x->mime);
310 	FREE_AND_NULL(x->keyword);
311 
312 	xfree(x);
313 
314 	return start;
315 }
316 
317 void keyword_list_free(struct KEYWORD_LIST_LIST *kl)
318 {
319 	struct KEYWORD_LIST_LIST *tmp;
320 
321 	while (kl != NULL) {
322 		tmp = kl->next;
323 
324 		if (kl->me != NULL)
325 			reg_free(kl->me);
326 		if (kl->ke != NULL)
327 			reg_free(kl->ke);
328 		if (kl->profiles != NULL)
329 			array_free(kl->profiles);
330 		FREE_AND_NULL(kl->comment);
331 		FREE_AND_NULL(kl->mime);
332 		FREE_AND_NULL(kl->keyword);
333 
334 		xfree(kl);
335 
336 		kl = tmp;
337 	}
338 }
339 
340 void keyword_free(KEYWORD_LIST * keyword_list)
341 {
342 	if (keyword_list == NULL)
343 		return;
344 
345 	keyword_list_free(keyword_list->keyword_list);
346 
347 	FREE_AND_NULL(keyword_list->template);
348 
349 	pthread_rwlock_destroy(&keyword_list->lock);
350 
351 	xfree(keyword_list);
352 }
353 
354 int keyword_check(KEYWORD_LIST * keyword_list, CONNECTION * connection, FILEBUF * filebuf, int action)
355 {
356 	int ret, x = FALSE, maxbuffer;
357 	struct KEYWORD_LIST_LIST *kl;
358 
359 	if (!keyword_list || connection->bypass & FEATURE_KEYWORDS)
360 		return FALSE;
361 
362 	pthread_rwlock_rdlock(&keyword_list->lock);
363 
364 	if (keyword_list->enabled == FALSE) {
365 		pthread_rwlock_unlock(&keyword_list->lock);
366 
367 		return FALSE;
interface_page_connections(FILEBUF * filebuf,struct cgi_args_t * args,CONNECTION * connection)368 	}
369 
370 	if (filebuf != NULL)
371 		filebuf_add(filebuf, "", 1);
372 
373         maxbuffer = atomic_read_rwlock(&global->general->lock, &global->general->maxbuffer);
374 
375 	for (kl = keyword_list->keyword_list; kl; kl = kl->next) {
376 		if (kl->enabled == FALSE)
377 			continue;
378 
379 		if (!profile_find(connection->profiles, kl->profiles))
380 			continue;
381 
382 		if (kl->me != NULL && connection->rheader->content_type != NULL) {
383 			ret = reg_exec(kl->me, connection->rheader->content_type);
384 			if (ret)
385 				continue;
386 		} else if (kl->me != NULL) {
interface_page_dnscache(FILEBUF * filebuf,struct cgi_args_t * args,CONNECTION * connection)387 			ret = reg_exec(kl->me, "");
388 			if (ret)
389 				continue;
390 		}
391 
392                 if (kl->size != 0) {
393                     ret = (kl->size == -1)? maxbuffer : kl->size;
394 
395                     if (action == FALSE) {
396                         if (connection->rheader->content_length > ret)
397                             continue;
398                     } else {
399                         if (connection->rheader->content_length == -1 || connection->rheader->content_length > ret)
400                             continue;
401                     }
402                 }
403 
404 		if (kl->ke != NULL && filebuf != NULL) {
405 			ret = reg_exec(kl->ke, filebuf->data);
406 			if (ret)
407 				continue;
408 		}
409 
interface_page_headers(FILEBUF * filebuf,struct cgi_args_t * args,CONNECTION * connection)410 		if (action == FALSE) {
411 			/* just check if any entires apply to current page */
412 			x = TRUE;
413 
414 			break;
415 		}
416 
417 		x += kl->score;
418 	}
419 
420 	if (filebuf != NULL)
421 		filebuf_resize(filebuf, filebuf->size - 1);
422 
423 	pthread_rwlock_unlock(&keyword_list->lock);
424 
425 	return x;
426 }
427