/* MiddleMan filtering proxy server Copyright (C) 2002 Jason McLaughlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "proto.h" /* load section from XML file into a linked list */ REWRITE_LIST *rewrite_load(REWRITE_LIST * rewrite_list, XML_LIST * xml_list) { REWRITE_LIST *tmp_list = rewrite_list; struct REWRITE_LIST_LIST *rewrite = NULL; if (tmp_list == NULL) { tmp_list = xmalloc(sizeof(REWRITE_LIST)); tmp_list->rewrite = NULL; tmp_list->id = 0; tmp_list->enabled = TRUE; rewrite_list = tmp_list; pthread_rwlock_init(&tmp_list->lock, NULL); } else rewrite = tmp_list->rewrite; while ((xml_list = xml_section(xml_list, ""))) { XML_LIST_LOOP(xml_list, "") { XML_LIST_CMP(xml_list, "") { rewrite = rewrite_list_new(rewrite); rewrite->id = rewrite_list->id++; if (tmp_list->rewrite == NULL) tmp_list->rewrite = rewrite; XML_LIST_LOOP(xml_list, "") { XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) { if (!strcasecmp(xml_list->item, "false")) rewrite->enabled = FALSE; else rewrite->enabled = TRUE; } } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) rewrite_list_insert(rewrite, xml_list->item, NULL, NULL, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) rewrite_list_insert(rewrite, NULL, xml_list->item, NULL, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) rewrite_list_insert(rewrite, NULL, NULL, xml_list->item, NULL, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) rewrite_list_insert(rewrite, NULL, NULL, NULL, xml_list->item, NULL, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) rewrite_list_insert(rewrite, NULL, NULL, NULL, NULL, xml_list->item, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) rewrite_list_insert(rewrite, NULL, NULL, NULL, NULL, NULL, xml_list->item, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) rewrite_list_insert(rewrite, NULL, NULL, NULL, NULL, NULL, NULL, xml_list->item); } } } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) { if (!strcasecmp(xml_list->item, "false")) tmp_list->enabled = FALSE; else tmp_list->enabled = TRUE; } } } } return rewrite_list; } XML_LIST *rewrite_xml(REWRITE_LIST * rewrite_list, XML_LIST * xml_list) { char *ptr, buf[128]; struct REWRITE_LIST_LIST *rl; if (rewrite_list == NULL) return xml_list; pthread_rwlock_rdlock(&rewrite_list->lock); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, (rewrite_list->enabled == TRUE) ? "true" : "false", XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); for (rl = rewrite_list->rewrite; rl; rl = rl->next) { xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, (rl->enabled == TRUE) ? "true" : "false", XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); if (rl->comment != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(rl->comment); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (rl->host != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(rl->host); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (rl->file != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(rl->file); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (rl->mime != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(rl->mime); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (rl->pattern != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(rl->pattern); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } if (rl->replace != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(rl->replace); xml_list = xml_list_add(xml_list, ptr, XML_VALUE); xfree(ptr); xml_list = xml_list_add(xml_list, "", XML_TAG); } xml_list = xml_list_add(xml_list, "", XML_TAG); 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" : ""); xml_list = xml_list_add(xml_list, buf, XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, "", XML_TAG); } xml_list = xml_list_add(xml_list, "", XML_TAG); pthread_rwlock_unlock(&rewrite_list->lock); return xml_list; } void rewrite_list_insert(struct REWRITE_LIST_LIST *x, char *a, char *b, char *c, char *d, char *e, char *f, char *g) { int i; char **args; if (a != NULL) { FREE_AND_NULL(x->comment); if (strcmp(a, "")) x->comment = xstrdup(a); } if (b != NULL) { if (x->pe != NULL) reg_sub_free(x->pe); FREE_AND_NULL(x->pattern); if (strcmp(b, "")) { x->pe = reg_sub_compile(b, PCREFLAGS); x->pattern = xstrdup(b); } else x->pe = NULL; } if (c != NULL) { FREE_AND_NULL(x->replace); if (strcmp(c, "")) x->replace = xstrdup(c); } if (d != NULL) { x->which = 0; if (strcmp(d, "")) { args = string_break(d, ','); for (i = 0; args[i]; i++) { if (!strcasecmp(args[i], "server")) x->which |= REWRITE_SERVER; else if (!strcasecmp(args[i], "client")) x->which |= REWRITE_CLIENT; else if (!strcasecmp(args[i], "body")) x->which |= REWRITE_BODY; else if (!strcasecmp(args[i], "post")) x->which |= REWRITE_POST; xfree(args[i]); } xfree(args); } } if (e != NULL) { if (x->he != NULL) reg_free(x->he); FREE_AND_NULL(x->host); if (strcmp(e, "")) { x->he = reg_compile(e, REGFLAGS); x->host = xstrdup(e); } else x->he = NULL; } if (f != NULL) { if (x->fe != NULL) reg_free(x->fe); FREE_AND_NULL(x->file); if (strcmp(f, "")) { x->fe = reg_compile(f, REGFLAGS); x->file = xstrdup(f); } else x->fe = NULL; } if (g != NULL) { if (x->me != NULL) reg_free(x->me); FREE_AND_NULL(x->mime); if (strcmp(g, "")) { x->me = reg_compile(g, REGFLAGS); x->mime = xstrdup(g); } else x->me = NULL; } } struct REWRITE_LIST_LIST *rewrite_list_new(struct REWRITE_LIST_LIST *x) { if (x == NULL) { x = xmalloc(sizeof(struct REWRITE_LIST_LIST)); x->prev = NULL; } else { while (x->next != NULL) x = x->next; x->next = xmalloc(sizeof(struct REWRITE_LIST_LIST)); x->next->prev = x; x = x->next; } x->next = NULL; x->enabled = TRUE; x->comment = NULL; x->pe = NULL; x->he = NULL; x->fe = NULL; x->me = NULL; x->host = NULL; x->file = NULL; x->mime = NULL; x->pattern = NULL; x->replace = NULL; x->which = REWRITE_BODY; return x; } struct REWRITE_LIST_LIST *rewrite_list_delete(struct REWRITE_LIST_LIST *x) { struct REWRITE_LIST_LIST *start = x; while (start->prev != NULL) start = start->prev; if (x->next != NULL) x->next->prev = x->prev; if (x->prev != NULL) x->prev->next = x->next; else start = start->next; if (x->pe != NULL) reg_sub_free(x->pe); if (x->he != NULL) reg_free(x->he); if (x->fe != NULL) reg_free(x->fe); if (x->me != NULL) reg_free(x->me); FREE_AND_NULL(x->comment); FREE_AND_NULL(x->pattern); FREE_AND_NULL(x->replace); FREE_AND_NULL(x->host); FREE_AND_NULL(x->file); FREE_AND_NULL(x->mime); xfree(x); return start; } /* free memory used by REWRITE_LIST-type structure */ void rewrite_free(REWRITE_LIST * rewrite_list) { if (!rewrite_list) return; rewrite_list_free(rewrite_list->rewrite); pthread_rwlock_destroy(&rewrite_list->lock); xfree(rewrite_list); } void rewrite_list_free(struct REWRITE_LIST_LIST *rl) { struct REWRITE_LIST_LIST *tmp; while (rl != NULL) { tmp = rl->next; if (rl->pe != NULL) reg_sub_free(rl->pe); if (rl->he != NULL) reg_free(rl->he); if (rl->fe != NULL) reg_free(rl->fe); if (rl->me != NULL) reg_free(rl->me); FREE_AND_NULL(rl->comment); FREE_AND_NULL(rl->pattern); FREE_AND_NULL(rl->replace); FREE_AND_NULL(rl->host); FREE_AND_NULL(rl->file); FREE_AND_NULL(rl->mime); xfree(rl); rl = tmp; } } /* remove areas of text matching patterns in REWRITE_LIST-type struct, and possibly replace with something else */ int rewrite_do(REWRITE_LIST * rewrite_list, CONNECTION * connection, FILEBUF * filebuf, int flags, int action) { int x = FALSE, ret; struct REWRITE_LIST_LIST *rewrite; if (!rewrite_list || connection->bypass & FEATURE_REWRITE) return FALSE; pthread_rwlock_rdlock(&rewrite_list->lock); if (rewrite_list->enabled == FALSE) { pthread_rwlock_unlock(&rewrite_list->lock); return FALSE; } for (rewrite = rewrite_list->rewrite; rewrite != NULL; rewrite = rewrite->next) { if (rewrite->enabled == FALSE) continue; if (!(rewrite->which & flags)) continue; if (connection->header != NULL) { if (rewrite->he != NULL) { ret = reg_exec(rewrite->he, connection->header->host); if (ret) continue; } if (rewrite->fe != NULL) { ret = reg_exec(rewrite->fe, connection->header->file); if (ret) continue; } if (flags == REWRITE_BODY && rewrite->me != NULL && connection->rheader->content_type != NULL) { ret = reg_exec(rewrite->me, connection->rheader->content_type); if (ret) continue; } else if (rewrite->me != NULL) { ret = reg_exec(rewrite->me, ""); if (ret) continue; } } if (rewrite->pe != NULL) { x = TRUE; if (action == FALSE) break; reg_replace(filebuf, rewrite->pe, rewrite->replace); } else if (rewrite->he != NULL || rewrite->fe != NULL || rewrite->me != NULL) break; } pthread_rwlock_unlock(&rewrite_list->lock); return x; }