Removed threading
[middleman.git] / src / rewrite.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 /*
25 load <rewrite> section from XML file into a linked list
26 */
27 REWRITE_LIST *rewrite_load(REWRITE_LIST * rewrite_list, XML_LIST * xml_list)
28 {
29         REWRITE_LIST *tmp_list = rewrite_list;
30         struct REWRITE_LIST_LIST *rewrite = NULL;
31
32         if (tmp_list == NULL) {
33                 tmp_list = xmalloc(sizeof(REWRITE_LIST));
34                 tmp_list->rewrite = NULL;
35                 tmp_list->id = 0;
36                 tmp_list->enabled = TRUE;
37
38                 rewrite_list = tmp_list;
39
40                 pthread_rwlock_init(&tmp_list->lock, NULL);
41         } else
42                 rewrite = tmp_list->rewrite;
43
44         while ((xml_list = xml_section(xml_list, "<rewrite>"))) {
45                 XML_LIST_LOOP(xml_list, "<rewrite>") {
46                         XML_LIST_CMP(xml_list, "<item>") {
47                                 rewrite = rewrite_list_new(rewrite);
48                                 rewrite->id = rewrite_list->id++;
49
50                                 if (tmp_list->rewrite == NULL)
51                                         tmp_list->rewrite = rewrite;
52                                 XML_LIST_LOOP(xml_list, "<item>") {
53                                         XML_LIST_CMP(xml_list, "<enabled>") {
54                                                 xml_list = xml_list->next;
55                                                 if (xml_list->type == XML_VALUE) {
56                                                         if (!strcasecmp(xml_list->item, "false"))
57                                                                 rewrite->enabled = FALSE;
58                                                         else
59                                                                 rewrite->enabled = TRUE;
60                                                 }
61                                         }
62                                         XML_LIST_CMP(xml_list, "<comment>") {
63                                                 xml_list = xml_list->next;
64                                                 if (xml_list->type == XML_VALUE)
65                                                         rewrite_list_insert(rewrite, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL);
66                                         }
67                                         XML_LIST_CMP(xml_list, "<pattern>") {
68                                                 xml_list = xml_list->next;
69                                                 if (xml_list->type == XML_VALUE)
70                                                         rewrite_list_insert(rewrite, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL);
71                                         }
72                                         XML_LIST_CMP(xml_list, "<replace>") {
73                                                 xml_list = xml_list->next;
74                                                 if (xml_list->type == XML_VALUE)
75                                                         rewrite_list_insert(rewrite, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL);
76                                         }
77                                         XML_LIST_CMP(xml_list, "<which>") {
78                                                 xml_list = xml_list->next;
79                                                 if (xml_list->type == XML_VALUE)
80                                                         rewrite_list_insert(rewrite, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL);
81                                         }
82                                         XML_LIST_CMP(xml_list, "<host>") {
83                                                 xml_list = xml_list->next;
84                                                 if (xml_list->type == XML_VALUE)
85                                                         rewrite_list_insert(rewrite, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL);
86                                         }
87                                         XML_LIST_CMP(xml_list, "<file>") {
88                                                 xml_list = xml_list->next;
89                                                 if (xml_list->type == XML_VALUE)
90                                                         rewrite_list_insert(rewrite, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL);
91                                         }
92                                         XML_LIST_CMP(xml_list, "<mime>") {
93                                                 xml_list = xml_list->next;
94                                                 if (xml_list->type == XML_VALUE)
95                                                         rewrite_list_insert(rewrite, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item);
96                                         }
97                                 }
98                         }
99                         XML_LIST_CMP(xml_list, "<enabled>") {
100                                 xml_list = xml_list->next;
101                                 if (xml_list->type == XML_VALUE) {
102                                         if (!strcasecmp(xml_list->item, "false"))
103                                                 tmp_list->enabled = FALSE;
104                                         else
105                                                 tmp_list->enabled = TRUE;
106                                 }
107                         }
108                 }
109         }
110
111         return rewrite_list;
112 }
113
114 XML_LIST *rewrite_xml(REWRITE_LIST * rewrite_list, XML_LIST * xml_list)
115 {
116         char *ptr, buf[128];
117         struct REWRITE_LIST_LIST *rl;
118
119         if (rewrite_list == NULL)
120                 return xml_list;
121
122         pthread_rwlock_rdlock(&rewrite_list->lock);
123
124         xml_list = xml_list_add(xml_list, "<rewrite>", XML_TAG);
125
126         xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
127         xml_list = xml_list_add(xml_list, (rewrite_list->enabled == TRUE) ? "true" : "false", XML_VALUE);
128         xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
129
130         for (rl = rewrite_list->rewrite; rl; rl = rl->next) {
131                 xml_list = xml_list_add(xml_list, "<item>", XML_TAG);
132
133                 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
134                 xml_list = xml_list_add(xml_list, (rl->enabled == TRUE) ? "true" : "false", XML_VALUE);
135                 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
136
137                 if (rl->comment != NULL) {
138                         xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
139                         ptr = string_to_xml(rl->comment);
140                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
141                         xfree(ptr);
142                         xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
143                 }
144                 if (rl->host != NULL) {
145                         xml_list = xml_list_add(xml_list, "<host>", XML_TAG);
146                         ptr = string_to_xml(rl->host);
147                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
148                         xfree(ptr);
149                         xml_list = xml_list_add(xml_list, "</host>", XML_TAG);
150                 }
151                 if (rl->file != NULL) {
152                         xml_list = xml_list_add(xml_list, "<file>", XML_TAG);
153                         ptr = string_to_xml(rl->file);
154                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
155                         xfree(ptr);
156                         xml_list = xml_list_add(xml_list, "</file>", XML_TAG);
157                 }
158                 if (rl->mime != NULL) {
159                         xml_list = xml_list_add(xml_list, "<mime>", XML_TAG);
160                         ptr = string_to_xml(rl->mime);
161                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
162                         xfree(ptr);
163                         xml_list = xml_list_add(xml_list, "</mime>", XML_TAG);
164                 }
165                 if (rl->pattern != NULL) {
166                         xml_list = xml_list_add(xml_list, "<pattern>", XML_TAG);
167                         ptr = string_to_xml(rl->pattern);
168                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
169                         xfree(ptr);
170                         xml_list = xml_list_add(xml_list, "</pattern>", XML_TAG);
171                 }
172                 if (rl->replace != NULL) {
173                         xml_list = xml_list_add(xml_list, "<replace>", XML_TAG);
174                         ptr = string_to_xml(rl->replace);
175                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
176                         xfree(ptr);
177                         xml_list = xml_list_add(xml_list, "</replace>", XML_TAG);
178                 }
179
180                 xml_list = xml_list_add(xml_list, "<which>", XML_TAG);
181                 snprintf(buf, sizeof(buf), "%s,%s,%s,%s", (rl->which & REWRITE_SERVER) ? "server" : "", (rl->which & REWRITE_CLIENT) ? "client" : "", (rl->which & REWRITE_BODY) ? "body" : "", (rl->which & REWRITE_POST) ? "post" : "");
182                 xml_list = xml_list_add(xml_list, buf, XML_VALUE);
183                 xml_list = xml_list_add(xml_list, "</which>", XML_TAG);
184
185                 xml_list = xml_list_add(xml_list, "</item>", XML_TAG);
186         }
187
188         xml_list = xml_list_add(xml_list, "</rewrite>", XML_TAG);
189
190         pthread_rwlock_unlock(&rewrite_list->lock);
191
192         return xml_list;
193 }
194 void rewrite_list_insert(struct REWRITE_LIST_LIST *x, char *a, char *b, char *c, char *d, char *e, char *f, char *g)
195 {
196         int i;
197         char **args;
198
199         if (a != NULL) {
200                 FREE_AND_NULL(x->comment);
201
202                 if (strcmp(a, ""))
203                         x->comment = xstrdup(a);
204         }
205
206         if (b != NULL) {
207                 if (x->pe != NULL)
208                         reg_sub_free(x->pe);
209                 FREE_AND_NULL(x->pattern);
210
211                 if (strcmp(b, "")) {
212                         x->pe = reg_sub_compile(b, PCREFLAGS);
213                         x->pattern = xstrdup(b);
214                 } else
215                         x->pe = NULL;
216         }
217
218         if (c != NULL) {
219                 FREE_AND_NULL(x->replace);
220
221                 if (strcmp(c, ""))
222                         x->replace = xstrdup(c);
223         }
224         if (d != NULL) {
225                 x->which = 0;
226
227                 if (strcmp(d, "")) {
228                         args = string_break(d, ',');
229                         for (i = 0; args[i]; i++) {
230                                 if (!strcasecmp(args[i], "server"))
231                                         x->which |= REWRITE_SERVER;
232                                 else if (!strcasecmp(args[i], "client"))
233                                         x->which |= REWRITE_CLIENT;
234                                 else if (!strcasecmp(args[i], "body"))
235                                         x->which |= REWRITE_BODY;
236                                 else if (!strcasecmp(args[i], "post"))
237                                         x->which |= REWRITE_POST;
238
239                                 xfree(args[i]);
240                         }
241
242                         xfree(args);
243                 }
244         }
245         if (e != NULL) {
246                 if (x->he != NULL)
247                         reg_free(x->he);
248                 FREE_AND_NULL(x->host);
249
250                 if (strcmp(e, "")) {
251                         x->he = reg_compile(e, REGFLAGS);
252                         x->host = xstrdup(e);
253                 } else
254                         x->he = NULL;
255
256         }
257         if (f != NULL) {
258                 if (x->fe != NULL)
259                         reg_free(x->fe);
260                 FREE_AND_NULL(x->file);
261
262                 if (strcmp(f, "")) {
263                         x->fe = reg_compile(f, REGFLAGS);
264                         x->file = xstrdup(f);
265                 } else
266                         x->fe = NULL;
267         }
268         if (g != NULL) {
269                 if (x->me != NULL)
270                         reg_free(x->me);
271                 FREE_AND_NULL(x->mime);
272
273                 if (strcmp(g, "")) {
274                         x->me = reg_compile(g, REGFLAGS);
275                         x->mime = xstrdup(g);
276                 } else
277                         x->me = NULL;
278         }
279 }
280
281 struct REWRITE_LIST_LIST *rewrite_list_new(struct REWRITE_LIST_LIST *x)
282 {
283         if (x == NULL) {
284                 x = xmalloc(sizeof(struct REWRITE_LIST_LIST));
285                 x->prev = NULL;
286         } else {
287                 while (x->next != NULL)
288                         x = x->next;
289                 x->next = xmalloc(sizeof(struct REWRITE_LIST_LIST));
290                 x->next->prev = x;
291                 x = x->next;
292         }
293         x->next = NULL;
294         x->enabled = TRUE;
295         x->comment = NULL;
296         x->pe = NULL;
297         x->he = NULL;
298         x->fe = NULL;
299         x->me = NULL;
300         x->host = NULL;
301         x->file = NULL;
302         x->mime = NULL;
303         x->pattern = NULL;
304         x->replace = NULL;
305         x->which = REWRITE_BODY;
306
307         return x;
308 }
309
310 struct REWRITE_LIST_LIST *rewrite_list_delete(struct REWRITE_LIST_LIST *x)
311 {
312         struct REWRITE_LIST_LIST *start = x;
313
314         while (start->prev != NULL)
315                 start = start->prev;
316
317         if (x->next != NULL)
318                 x->next->prev = x->prev;
319         if (x->prev != NULL)
320                 x->prev->next = x->next;
321         else
322                 start = start->next;
323
324         if (x->pe != NULL)
325                 reg_sub_free(x->pe);
326         if (x->he != NULL)
327                 reg_free(x->he);
328         if (x->fe != NULL)
329                 reg_free(x->fe);
330         if (x->me != NULL)
331                 reg_free(x->me);
332         FREE_AND_NULL(x->comment);
333         FREE_AND_NULL(x->pattern);
334         FREE_AND_NULL(x->replace);
335         FREE_AND_NULL(x->host);
336         FREE_AND_NULL(x->file);
337         FREE_AND_NULL(x->mime);
338
339         xfree(x);
340
341         return start;
342 }
343
344 /*
345 free memory used by REWRITE_LIST-type structure
346 */
347 void rewrite_free(REWRITE_LIST * rewrite_list)
348 {
349         if (!rewrite_list)
350                 return;
351
352         rewrite_list_free(rewrite_list->rewrite);
353
354         pthread_rwlock_destroy(&rewrite_list->lock);
355
356         xfree(rewrite_list);
357 }
358
359 void rewrite_list_free(struct REWRITE_LIST_LIST *rl)
360 {
361         struct REWRITE_LIST_LIST *tmp;
362
363         while (rl != NULL) {
364                 tmp = rl->next;
365
366                 if (rl->pe != NULL)
367                         reg_sub_free(rl->pe);
368                 if (rl->he != NULL)
369                         reg_free(rl->he);
370                 if (rl->fe != NULL)
371                         reg_free(rl->fe);
372                 if (rl->me != NULL)
373                         reg_free(rl->me);
374                 FREE_AND_NULL(rl->comment);
375                 FREE_AND_NULL(rl->pattern);
376                 FREE_AND_NULL(rl->replace);
377                 FREE_AND_NULL(rl->host);
378                 FREE_AND_NULL(rl->file);
379                 FREE_AND_NULL(rl->mime);
380
381                 xfree(rl);
382                 rl = tmp;
383         }
384 }
385
386 /*
387 remove areas of text matching patterns in REWRITE_LIST-type struct, and possibly
388 replace with something else
389 */
390 int rewrite_do(REWRITE_LIST * rewrite_list, CONNECTION * connection, FILEBUF * filebuf, int flags, int action)
391 {
392         int x = FALSE, ret;
393         struct REWRITE_LIST_LIST *rewrite;
394
395         if (!rewrite_list || connection->bypass & FEATURE_REWRITE)
396                 return FALSE;
397
398         pthread_rwlock_rdlock(&rewrite_list->lock);
399
400         if (rewrite_list->enabled == FALSE) {
401                 pthread_rwlock_unlock(&rewrite_list->lock);
402
403                 return FALSE;
404         }
405
406         for (rewrite = rewrite_list->rewrite; rewrite != NULL; rewrite = rewrite->next) {
407                 if (rewrite->enabled == FALSE)
408                         continue;
409
410                 if (!(rewrite->which & flags))
411                         continue;
412
413                 if (connection->header != NULL) {
414                         if (rewrite->he != NULL) {
415                                 ret = reg_exec(rewrite->he, connection->header->host);
416                                 if (ret)
417                                         continue;
418                         }
419                         if (rewrite->fe != NULL) {
420                                 ret = reg_exec(rewrite->fe, connection->header->file);
421                                 if (ret)
422                                         continue;
423                         }
424                         if (flags == REWRITE_BODY && rewrite->me != NULL && connection->rheader->content_type != NULL) {
425                                 ret = reg_exec(rewrite->me, connection->rheader->content_type);
426                                 if (ret)
427                                         continue;
428                         } else if (rewrite->me != NULL) {
429                                 ret = reg_exec(rewrite->me, "");
430                                 if (ret) continue;
431                         }
432                 }
433
434                 if (rewrite->pe != NULL) {
435                         x = TRUE;
436
437                         if (action == FALSE)
438                                 break;
439
440                         reg_replace(filebuf, rewrite->pe, rewrite->replace);
441                 } else if (rewrite->he != NULL || rewrite->fe != NULL || rewrite->me != NULL)
442                         break;
443         }
444
445         pthread_rwlock_unlock(&rewrite_list->lock);
446
447         return x;
448 }