/* 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 "proto.h" /* read the section from xml_list and load into another linked list */ COOKIE_LIST *cookie_load(COOKIE_LIST * cookie_list, XML_LIST * xml_list) { COOKIE_LIST *tmp_list = cookie_list; struct COOKIE_LIST_LIST *allow = NULL, *deny = NULL; if (tmp_list == NULL) { tmp_list = xmalloc(sizeof(COOKIE_LIST)); cookie_list = tmp_list; tmp_list->allow = NULL; tmp_list->deny = NULL; tmp_list->policy = POLICY_ALLOW; tmp_list->id = 0; tmp_list->enabled = TRUE; pthread_rwlock_init(&tmp_list->lock, NULL); } else { allow = tmp_list->allow; deny = tmp_list->deny; } while ((xml_list = xml_section(xml_list, ""))) { XML_LIST_LOOP(xml_list, "") { XML_LIST_CMP(xml_list, "") { allow = cookie_ll_new(allow); allow->id = cookie_list->id++; if (tmp_list->allow == NULL) tmp_list->allow = allow; 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")) allow->enabled = FALSE; else allow->enabled = TRUE; } } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) cookie_ll_insert(allow, xml_list->item, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) cookie_ll_insert(allow, NULL, xml_list->item, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) cookie_ll_insert(allow, NULL, NULL, xml_list->item); } } } XML_LIST_CMP(xml_list, "") { deny = cookie_ll_new(deny); deny->id = cookie_list->id++; if (tmp_list->deny == NULL) tmp_list->deny = deny; 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")) deny->enabled = FALSE; else deny->enabled = TRUE; } } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) cookie_ll_insert(deny, xml_list->item, NULL, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) cookie_ll_insert(deny, NULL, xml_list->item, NULL); } XML_LIST_CMP(xml_list, "") { xml_list = xml_list->next; if (xml_list->type == XML_VALUE) cookie_ll_insert(deny, 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, "allow")) tmp_list->policy = POLICY_ALLOW; else if (!strcasecmp(xml_list->item, "deny")) tmp_list->policy = POLICY_DENY; } } 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 cookie_list; } XML_LIST *cookie_xml(COOKIE_LIST * cookie_list, XML_LIST * xml_list) { int i; char *ptr; struct COOKIE_LIST_LIST *cl = NULL; if (cookie_list == NULL) return xml_list; pthread_rwlock_rdlock(&cookie_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, (cookie_list->enabled == TRUE) ? "true" : "false", 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, (cookie_list->policy == POLICY_ALLOW) ? "allow" : "deny", XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); for (i = 0; i < 2; i++) { switch (i) { case 0: cl = cookie_list->allow; break; case 1: cl = cookie_list->deny; break; } for (; cl; cl = cl->next) { xml_list = xml_list_add(xml_list, (i == 0) ? "" : "", XML_TAG); xml_list = xml_list_add(xml_list, "", XML_TAG); xml_list = xml_list_add(xml_list, (cl->enabled == TRUE) ? "true" : "false", XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); if (cl->comment != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(cl->comment); 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); xml_list = xml_list_add(xml_list, (cl->direction == COOKIE_BOTH) ? "both" : (cl->direction == COOKIE_IN) ? "in" : "out", XML_VALUE); xml_list = xml_list_add(xml_list, "", XML_TAG); if (cl->host != NULL) { xml_list = xml_list_add(xml_list, "", XML_TAG); ptr = string_to_xml(cl->host); 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, (i == 0) ? "" : "", XML_TAG); } } xml_list = xml_list_add(xml_list, "", XML_TAG); pthread_rwlock_unlock(&cookie_list->lock); return xml_list; } void cookie_ll_insert(struct COOKIE_LIST_LIST *x, char *a, char *b, char *c) { if (a != NULL) { FREE_AND_NULL(x->comment); if (strcmp(a, "")) x->comment = xstrdup(a); } if (b != NULL) { if (!strcasecmp(b, "in")) x->direction = COOKIE_IN; else if (!strcasecmp(b, "out")) x->direction = COOKIE_OUT; else if (!strcasecmp(b, "both")) x->direction = COOKIE_BOTH; } if (c != NULL) { if (x->he != NULL) reg_free(x->he); FREE_AND_NULL(x->host); if (strcmp(c, "")) { x->host = xstrdup(c); x->he = reg_compile(c, REGFLAGS); } else x->he = NULL; } } struct COOKIE_LIST_LIST *cookie_ll_new(struct COOKIE_LIST_LIST *x) { if (x == NULL) { x = xmalloc(sizeof(struct COOKIE_LIST_LIST)); x->prev = NULL; } else { while (x->next != NULL) x = x->next; x->next = xmalloc(sizeof(struct COOKIE_LIST_LIST)); x->next->prev = x; x = x->next; } x->enabled = TRUE; x->comment = NULL; x->he = NULL; x->host = NULL; x->direction = COOKIE_BOTH; x->next = NULL; return x; } struct COOKIE_LIST_LIST *cookie_ll_delete(struct COOKIE_LIST_LIST *x) { struct COOKIE_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->he != NULL) reg_free(x->he); FREE_AND_NULL(x->comment); FREE_AND_NULL(x->host); xfree(x); return start; } /* free memory used by COOKIE_LIST type structure */ void cookie_free(COOKIE_LIST * cookie_list) { if (!cookie_list) return; cookie_ll_free(cookie_list->allow); cookie_ll_free(cookie_list->deny); xfree(cookie_list); } void cookie_ll_free(struct COOKIE_LIST_LIST *cl) { struct COOKIE_LIST_LIST *tmp; while (cl != NULL) { tmp = cl->next; if (cl->he != NULL) reg_free(cl->he); FREE_AND_NULL(cl->comment); FREE_AND_NULL(cl->host); xfree(cl); cl = tmp; } } /* check if a cookie is allowed to pass in a given direction for a host */ int cookie_check(COOKIE_LIST * cookie_list, int direction, CONNECTION * connection) { int action = FALSE, result = TRUE, ret, i; struct COOKIE_LIST_LIST *current; if (connection->bypass & FEATURE_COOKIES) return TRUE; pthread_rwlock_rdlock(&cookie_list->lock); if (cookie_list->enabled == FALSE) { pthread_rwlock_unlock(&cookie_list->lock); return TRUE; } for (i = 0; i < 2; i++) { if (i == 0) { if (cookie_list->policy == POLICY_ALLOW) { current = cookie_list->deny; action = FALSE; result = TRUE; } else { current = cookie_list->allow; action = TRUE; result = FALSE; } } else if (action == result) { if (cookie_list->policy == POLICY_ALLOW) { current = cookie_list->allow; action = TRUE; } else { current = cookie_list->deny; action = FALSE; } } else break; for (; current != NULL; current = current->next) { if (current->enabled == FALSE) continue; if (current->he != NULL && (current->direction == direction || current->direction == COOKIE_BOTH)) { ret = reg_exec(current->he, connection->header->host); if (ret) continue; } result = action; break; } } pthread_rwlock_unlock(&cookie_list->lock); return result; }