/* * $Id: permissions.c 1808 2007-03-10 17:36:19Z bogdan_iancu $ * * PERMISSIONS module * * Copyright (C) 2003 Miklós Tirpák (mtirpak@sztaki.hu) * Copyright (C) 2003 iptel.org * Copyright (C) 2003-2006 Juha Heinanen * * This file is part of openser, a free SIP server. * * openser 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 * * openser 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 "permissions.h" #include "parse_config.h" #include "trusted.h" #include "address.h" #include "hash.h" #include "mi.h" #include "../../mem/mem.h" #include "../../parser/parse_from.h" #include "../../parser/parse_uri.h" #include "../../parser/parse_refer_to.h" #include "../../parser/contact/parse_contact.h" #include "../../str.h" #include "../../dset.h" #include "../../globals.h" #include "../../items.h" #include "../../ut.h" MODULE_VERSION static rule_file_t allow[MAX_RULE_FILES]; /* Parsed allow files */ static rule_file_t deny[MAX_RULE_FILES]; /* Parsed deny files */ static int rules_num; /* Number of parsed allow/deny files */ /* Module parameter variables */ static char* default_allow_file = DEFAULT_ALLOW_FILE; static char* default_deny_file = DEFAULT_DENY_FILE; static char* allow_suffix = ".allow"; static char* deny_suffix = ".deny"; /* for allow_trusted and allow_address function */ char* db_url = 0; /* Don't connect to the database by default */ /* for allow_trusted function */ int db_mode = DISABLE_CACHE; /* Database usage mode: 0=no cache, 1=cache */ char* trusted_table = "trusted"; /* Name of trusted table */ char* source_col = "src_ip"; /* Name of source address column */ char* proto_col = "proto"; /* Name of protocol column */ char* from_col = "from_pattern"; /* Name of from pattern column */ char* tag_col = "tag"; /* Name of tag column */ char* tag_avp_param = 0; /* Peer tag AVP spec */ /* for allow_address function */ char* address_table = "address"; /* Name of address table */ char* grp_col = "grp"; /* Name of address group column */ char* ip_addr_col = "ip_addr"; /* Name of ip address column */ char* mask_col = "mask"; /* Name of mask column */ char* port_col = "port"; /* Name of port column */ /* * By default we check all branches */ static int check_all_branches = 1; /* * Convert the name of the files into table index */ static int load_fixup(void** param, int param_no); /* * Convert the name of the file into table index, this * function takes just one name, appends .allow and .deny * to and and the rest is same as in load_fixup */ static int single_fixup(void** param, int param_no); /* * Fixes up allow_addess() parameters */ static int address_fixup(void** param, int param_no); /* * Convert int or pvar parameter into int_or_pvar struct */ static int int_or_pvar_fixup(void** param, int param_no); /* * Parse pseudo variable parameter */ static int double_fixup(void** param, int param_no); static int allow_routing_0(struct sip_msg* msg, char* str1, char* str2); static int allow_routing_1(struct sip_msg* msg, char* basename, char* str2); static int allow_routing_2(struct sip_msg* msg, char* allow_file, char* deny_file); static int allow_register_1(struct sip_msg* msg, char* basename, char* s); static int allow_register_2(struct sip_msg* msg, char* allow_file, char* deny_file); static int allow_uri(struct sip_msg* msg, char* basename, char* uri); static int mod_init(void); static void mod_exit(void); static int child_init(int rank); static int mi_trusted_child_init(); static int mi_addr_child_init(); /* Exported functions */ static cmd_export_t cmds[] = { {"allow_routing", allow_routing_0, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE}, {"allow_routing", allow_routing_1, 1, single_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {"allow_routing", allow_routing_2, 2, load_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {"allow_register", allow_register_1, 1, single_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {"allow_register", allow_register_2, 2, load_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {"allow_trusted", allow_trusted, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE}, {"allow_uri", allow_uri, 2, double_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {"set_address_group", set_address_group, 1, int_or_pvar_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {"allow_address", allow_address, 2, address_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {"allow_source_address", allow_source_address, 1, int_or_pvar_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {0, 0, 0, 0, 0} }; /* Exported parameters */ static param_export_t params[] = { {"default_allow_file", STR_PARAM, &default_allow_file}, {"default_deny_file", STR_PARAM, &default_deny_file }, {"check_all_branches", INT_PARAM, &check_all_branches}, {"allow_suffix", STR_PARAM, &allow_suffix }, {"deny_suffix", STR_PARAM, &deny_suffix }, {"db_url", STR_PARAM, &db_url }, {"db_mode", INT_PARAM, &db_mode }, {"trusted_table", STR_PARAM, &trusted_table }, {"source_col", STR_PARAM, &source_col }, {"proto_col", STR_PARAM, &proto_col }, {"from_col", STR_PARAM, &from_col }, {"tag_col", STR_PARAM, &tag_col }, {"peer_tag_avp", STR_PARAM, &tag_avp_param }, {"address_table", STR_PARAM, &address_table }, {"grp_col", STR_PARAM, &grp_col }, {"ip_addr_col", STR_PARAM, &ip_addr_col }, {"mask_col", STR_PARAM, &mask_col }, {"port_col", STR_PARAM, &port_col }, {0, 0, 0} }; /* * Exported MI functions */ static mi_export_t mi_cmds[] = { { MI_TRUSTED_RELOAD, mi_trusted_reload, MI_NO_INPUT_FLAG, 0, mi_trusted_child_init }, { MI_TRUSTED_DUMP, mi_trusted_dump, MI_NO_INPUT_FLAG, 0, 0 }, { MI_ADDRESS_RELOAD, mi_address_reload, MI_NO_INPUT_FLAG, 0, mi_addr_child_init }, { MI_ADDRESS_DUMP, mi_address_dump, MI_NO_INPUT_FLAG, 0, 0 }, { MI_SUBNET_DUMP, mi_subnet_dump, MI_NO_INPUT_FLAG, 0, 0 }, { 0, 0, 0, 0, 0 } }; /* Module interface */ struct module_exports exports = { "permissions", DEFAULT_DLFLAGS, /* dlopen flags */ cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ mi_cmds, /* exported MI functions */ 0, /* exported pseudo-variables */ mod_init, /* module initialization function */ 0, /* response function */ mod_exit, /* destroy function */ child_init /* child initialization function */ }; /* * Extract path (the beginning of the string * up to the last / character * Returns length of the path */ static int get_path(char* pathname) { char* c; if (!pathname) return 0; c = strrchr(pathname, '/'); if (!c) return 0; return c - pathname + 1; } /* * Prepend path if necessary */ static char* get_pathname(char* name) { char* buffer; int path_len, name_len; if (!name) return 0; name_len = strlen(name); if (strchr(name, '/')) { buffer = (char*)pkg_malloc(name_len + 1); if (!buffer) goto err; strcpy(buffer, name); return buffer; } else { path_len = get_path(cfg_file); buffer = (char*)pkg_malloc(path_len + name_len + 1); if (!buffer) goto err; memcpy(buffer, cfg_file, path_len); memcpy(buffer + path_len, name, name_len); buffer[path_len + name_len] = '\0'; return buffer; } err: LOG(L_ERR, "get_pathname(): No memory left\n"); return 0; } /* * If the file pathname has been parsed already then the * function returns its index in the tables, otherwise it * returns -1 to indicate that the file needs to be read * and parsed yet */ static int find_index(rule_file_t* array, char* pathname) { int i; for(i = 0; i < rules_num; i++) { if (!strcmp(pathname, array[i].filename)) return i; } return -1; } /* * Return URI without all the bells and whistles, that means only * sip:username@domain, resulting buffer is statically allocated and * zero terminated */ static char* get_plain_uri(const str* uri) { static char buffer[EXPRESSION_LENGTH + 1]; struct sip_uri puri; int len; if (!uri) return 0; if (parse_uri(uri->s, uri->len, &puri) < 0) { LOG(L_ERR, "get_plain_uri(): Error while parsing URI\n"); return 0; } if (puri.user.len) { len = puri.user.len + puri.host.len + 5; } else { len = puri.host.len + 4; } if (len > EXPRESSION_LENGTH) { LOG(L_ERR, "allow_register(): (module permissions) Request-URI is too long: %d chars\n", len); return 0; } strcpy(buffer, "sip:"); if (puri.user.len) { memcpy(buffer + 4, puri.user.s, puri.user.len); buffer[puri.user.len + 4] = '@'; memcpy(buffer + puri.user.len + 5, puri.host.s, puri.host.len); } else { memcpy(buffer + 4, puri.host.s, puri.host.len); } buffer[len] = '\0'; return buffer; } /* * determines the permission of the call * return values: * -1: deny * 1: allow */ static int check_routing(struct sip_msg* msg, int idx) { struct hdr_field *from; int len, q; static char from_str[EXPRESSION_LENGTH+1]; static char ruri_str[EXPRESSION_LENGTH+1]; char* uri_str; str branch; int br_idx; /* turn off control, allow any routing */ if ((!allow[idx].rules) && (!deny[idx].rules)) { DBG("check_routing(): No rules => allow any routing\n"); return 1; } /* looking for FROM HF */ if ((!msg->from) && (parse_headers(msg, HDR_FROM_F, 0) == -1)) { LOG(L_ERR, "check_routing(): Error while parsing message\n"); return -1; } if (!msg->from) { LOG(L_ERR, "check_routing(): FROM header field not found\n"); return -1; } /* we must call parse_from_header explicitly */ if ((!(msg->from)->parsed) && (parse_from_header(msg) < 0)) { LOG(L_ERR, "check_routing(): Error while parsing From body\n"); return -1; } from = msg->from; len = ((struct to_body*)from->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { LOG(L_ERR, "check_routing(): From header field is too long: %d chars\n", len); return -1; } strncpy(from_str, ((struct to_body*)from->parsed)->uri.s, len); from_str[len] = '\0'; /* looking for request URI */ if (parse_sip_msg_uri(msg) < 0) { LOG(L_ERR, "check_routing(): uri parsing failed\n"); return -1; } len = msg->parsed_uri.user.len + msg->parsed_uri.host.len + 5; if (len > EXPRESSION_LENGTH) { LOG(L_ERR, "check_routing(): Request URI is too long: %d chars\n", len); return -1; } strcpy(ruri_str, "sip:"); memcpy(ruri_str + 4, msg->parsed_uri.user.s, msg->parsed_uri.user.len); ruri_str[msg->parsed_uri.user.len + 4] = '@'; memcpy(ruri_str + msg->parsed_uri.user.len + 5, msg->parsed_uri.host.s, msg->parsed_uri.host.len); ruri_str[len] = '\0'; DBG("check_routing(): looking for From: %s Request-URI: %s\n", from_str, ruri_str); /* rule exists in allow file */ if (search_rule(allow[idx].rules, from_str, ruri_str)) { if (check_all_branches) goto check_branches; DBG("check_routing(): allow rule found => routing is allowed\n"); return 1; } /* rule exists in deny file */ if (search_rule(deny[idx].rules, from_str, ruri_str)) { DBG("check_routing(): deny rule found => routing is denied\n"); return -1; } if (!check_all_branches) { DBG("check_routing(): Neither allow nor deny rule found => routing is allowed\n"); return 1; } check_branches: for( br_idx=0 ; (branch.s=get_branch(br_idx,&branch.len,&q,0,0,0,0))!=0 ; br_idx++ ) { uri_str = get_plain_uri(&branch); if (!uri_str) { LOG(L_ERR, "check_uri(): Error while extracting plain URI\n"); return -1; } DBG("check_routing: Looking for From: %s Branch: %s\n", from_str, uri_str); if (search_rule(allow[idx].rules, from_str, uri_str)) { continue; } if (search_rule(deny[idx].rules, from_str, uri_str)) { LOG(LOG_INFO, "check_routing(): Deny rule found for one of branches => routing is denied\n"); return -1; } } LOG(LOG_INFO, "check_routing(): Check of branches passed => routing is allowed\n"); return 1; } /* * Convert the name of the files into table index */ static int load_fixup(void** param, int param_no) { char* pathname; int idx; rule_file_t* table; if (param_no == 1) { table = allow; } else { table = deny; } pathname = get_pathname(*param); idx = find_index(table, pathname); if (idx == -1) { /* Not opened yet, open the file and parse it */ table[rules_num].filename = pathname; table[rules_num].rules = parse_config_file(pathname); if (table[rules_num].rules) { LOG(L_INFO, "load_fixup(): File (%s) parsed\n", pathname); } else { LOG(L_WARN, "load_fixup(): File (%s) not found => empty rule set\n", pathname); } *param = (void*)(long)rules_num; if (param_no == 2) rules_num++; } else { /* File already parsed, re-use it */ LOG(L_INFO, "load_fixup(): File (%s) already loaded, re-using\n", pathname); pkg_free(pathname); *param = (void*)(long)idx; } return 0; } /* * Convert the name of the file into table index */ static int single_fixup(void** param, int param_no) { char* buffer; void* tmp; int param_len, ret, suffix_len; if (param_no != 1) return 0; param_len = strlen((char*)*param); if (strlen(allow_suffix) > strlen(deny_suffix)) { suffix_len = strlen(allow_suffix); } else { suffix_len = strlen(deny_suffix); } buffer = pkg_malloc(param_len + suffix_len + 1); if (!buffer) { LOG(L_ERR, "single_fixup(): No memory left\n"); return -1; } strcpy(buffer, (char*)*param); strcat(buffer, allow_suffix); tmp = buffer; ret = load_fixup(&tmp, 1); strcpy(buffer + param_len, deny_suffix); tmp = buffer; ret |= load_fixup(&tmp, 2); *param = tmp; pkg_free(buffer); return ret; } /* * Convert the name of the file into table index and pvar into parsed pseudo * variable specification */ static int double_fixup(void** param, int param_no) { char* buffer; void* tmp; int param_len, ret, suffix_len; xl_spec_t *sp; if (param_no == 1) { /* basename */ param_len = strlen((char*)*param); if (strlen(allow_suffix) > strlen(deny_suffix)) { suffix_len = strlen(allow_suffix); } else { suffix_len = strlen(deny_suffix); } buffer = pkg_malloc(param_len + suffix_len + 1); if (!buffer) { LOG(L_ERR, "permissions:double_fixup(): No memory left\n"); return -1; } strcpy(buffer, (char*)*param); strcat(buffer, allow_suffix); tmp = buffer; ret = load_fixup(&tmp, 1); strcpy(buffer + param_len, deny_suffix); tmp = buffer; ret |= load_fixup(&tmp, 2); *param = tmp; pkg_free(buffer); return 0; } else if (param_no == 2) { /* pseudo variable */ sp = (xl_spec_t*)pkg_malloc(sizeof(xl_spec_t)); if (sp == 0) { LOG(L_ERR,"permissions:double_fixup(): no pkg memory left\n"); return -1; } if (xl_parse_spec((char*)*param, sp, XL_THROW_ERROR|XL_DISABLE_MULTI|XL_DISABLE_COLORS) == 0) { LOG(L_ERR,"permissions:double_fixup(): parsing of " "pseudo variable %s failed!\n", (char*)*param); pkg_free(sp); return -1; } if (sp->type == XL_NULL) { LOG(L_ERR,"permissions:double_fixup(): bad pseudo " "variable\n"); pkg_free(sp); return -1; } *param = (void*)sp; return 0; } *param = (void *)0; return 0; } /* * Convert pvars into parsed pseudo variable specifications */ static int address_fixup(void** param, int param_no) { xl_spec_t *sp; if ((param_no == 1) || (param_no == 2)) { /* pseudo variables */ sp = (xl_spec_t*)pkg_malloc(sizeof(xl_spec_t)); if (sp == 0) { LOG(L_ERR,"permissions:single_pvar_fixup(): no pkg memory left\n"); return -1; } if (xl_parse_spec((char*)*param, sp, XL_THROW_ERROR|XL_DISABLE_MULTI|XL_DISABLE_COLORS) == 0) { LOG(L_ERR,"permissions:single_pvar_fixup(): parsing of " "pseudo variable %s failed!\n", (char*)*param); pkg_free(sp); return -1; } if (sp->type == XL_NULL) { LOG(L_ERR,"permissions:single_pvap_fixup(): bad pseudo " "variable\n"); pkg_free(sp); return -1; } *param = (void*)sp; return 0; } *param = (void *)0; return 0; } /* * Convert int or pvar parameter into int_or_pvar struct */ static int int_or_pvar_fixup(void** param, int param_no) { char *s; str str_param; int_or_pvar_t *res; if (param_no != 1) return 0; res = (int_or_pvar_t *)pkg_malloc(sizeof(int_or_pvar_t)); if (res == 0) { LOG(L_ERR,"permissions:int_or_pvar_fixup(): " "no pkg memory left for int_or_pvar_t\n"); return -1; } s = (char *)*param; if (*s == '$') { /* pvar */ res->pvar = (xl_spec_t*)pkg_malloc(sizeof(xl_spec_t)); if (res->pvar == 0) { LOG(L_ERR,"permissions:int_or_pvar_fixup(): " "no pkg memory left for xl_spec_t\n"); pkg_free(res); return -1; } if (xl_parse_spec(s, res->pvar, XL_THROW_ERROR|XL_DISABLE_MULTI|XL_DISABLE_COLORS) == 0) { LOG(L_ERR,"permissions:int_or_pvar_fixup(): parsing of " "pseudo variable %s failed!\n", (char*)*param); pkg_free(res->pvar); pkg_free(res); return -1; } if (res->pvar->type == XL_NULL) { LOG(L_ERR,"permissions:int_or_pvap_fixup(): bad pseudo " "variable\n"); pkg_free(res->pvar); pkg_free(res); return -1; } *param = (void*)res; return 0; } /* int */ str_param.s = s; str_param.len = strlen(s); if (str2int(&str_param, &(res->i)) == 1) { LOG(L_ERR, "permissions:int_or_pvar_fixup: bad integer <%s>\n", s); pkg_free(res); return -1; } else { res->pvar = (xl_spec_t *)0; *param = (void *)res; return 0; } } /* * module initialization function */ static int mod_init(void) { LOG(L_INFO, "permissions - initializing\n"); allow[0].filename = get_pathname(DEFAULT_ALLOW_FILE); allow[0].rules = parse_config_file(allow[0].filename); if (allow[0].rules) { LOG(L_INFO, "Default allow file (%s) parsed\n", allow[0].filename); } else { LOG(L_WARN, "Default allow file (%s) not found => empty rule set\n", allow[0].filename); } deny[0].filename = get_pathname(DEFAULT_DENY_FILE); deny[0].rules = parse_config_file(deny[0].filename); if (deny[0].rules) { LOG(L_INFO, "Default deny file (%s) parsed\n", deny[0].filename); } else { LOG(L_WARN, "Default deny file (%s) not found => empty rule set\n", deny[0].filename); } if (init_trusted() != 0) { LOG(L_ERR, "Error while initializing allow_trusted function\n"); return -1; } if (init_tag_avp( tag_avp_param) < 0) { LOG(L_ERR,"ERROR:permissions:mod_init: failed to process tag AVP\n"); return -1; } if (init_addresses() != 0) { LOG(L_ERR, "Error while initializing allow_address function\n"); return -1; } rules_num = 1; return 0; } static int child_init(int rank) { if (init_child_trusted(rank) == -1) return -1; return 0; } static int mi_trusted_child_init() { return mi_init_trusted(); } static int mi_addr_child_init() { return mi_init_addresses(); } /* * destroy function */ static void mod_exit(void) { int i; for(i = 0; i < rules_num; i++) { free_rule(allow[i].rules); pkg_free(allow[i].filename); free_rule(deny[i].rules); pkg_free(deny[i].filename); } clean_trusted(); clean_addresses(); } /* * Uses default rule files from the module parameters */ int allow_routing_0(struct sip_msg* msg, char* str1, char* str2) { return check_routing(msg, 0); } int allow_routing_1(struct sip_msg* msg, char* basename, char* s) { return check_routing(msg, (int)(long)basename); } /* * Accepts allow and deny files as parameters */ int allow_routing_2(struct sip_msg* msg, char* allow_file, char* deny_file) { /* Index converted by load_lookup */ return check_routing(msg, (int)(long)allow_file); } /* * Test of REGISTER messages. Creates To-Contact pairs and compares them * against rules in allow and deny files passed as parameters. The function * iterates over all Contacts and creates a pair with To for each contact * found. That allows to restrict what IPs may be used in registrations, for * example */ static int check_register(struct sip_msg* msg, int idx) { int len; static char to_str[EXPRESSION_LENGTH + 1]; char* contact_str; contact_t* c; /* turn off control, allow any routing */ if ((!allow[idx].rules) && (!deny[idx].rules)) { DBG("check_register(): No rules => allow any registration\n"); return 1; } /* * Note: We do not parse the whole header field here although the message can * contain multiple Contact header fields. We try contacts one by one and if one * of them causes reject then we don't look at others, this could improve performance * a little bit in some situations */ if (parse_headers(msg, HDR_TO_F | HDR_CONTACT_F, 0) == -1) { LOG(L_ERR, "check_register(): Error while parsing headers\n"); return -1; } if (!msg->to) { LOG(L_ERR, "check_register(): To or Contact not found\n"); return -1; } if (!msg->contact) { /* REGISTER messages that contain no Contact header field * are allowed. Such messages do not modify the contents of * the user location database anyway and thus are not harmful */ DBG("check_register(): No Contact found, allowing\n"); return 1; } /* Check if the REGISTER message contains start Contact and if * so then allow it */ if (parse_contact(msg->contact) < 0) { LOG(L_ERR, "check_register(): Error while parsing Contact HF\n"); return -1; } if (((contact_body_t*)msg->contact->parsed)->star) { DBG("check_register(): * Contact found, allowing\n"); return 1; } len = ((struct to_body*)msg->to->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { LOG(L_ERR, "check_register(): To header field is too long: %d chars\n", len); return -1; } strncpy(to_str, ((struct to_body*)msg->to->parsed)->uri.s, len); to_str[len] = '\0'; if (contact_iterator(&c, msg, 0) < 0) { return -1; } while(c) { contact_str = get_plain_uri(&c->uri); if (!contact_str) { LOG(L_ERR, "check_register(): Can't extract plain Contact URI\n"); return -1; } DBG("check_register(): Looking for To: %s Contact: %s\n", to_str, contact_str); /* rule exists in allow file */ if (search_rule(allow[idx].rules, to_str, contact_str)) { if (check_all_branches) goto skip_deny; } /* rule exists in deny file */ if (search_rule(deny[idx].rules, to_str, contact_str)) { DBG("check_register(): Deny rule found => Register denied\n"); return -1; } skip_deny: if (contact_iterator(&c, msg, c) < 0) { return -1; } } DBG("check_register(): No contact denied => Allowed\n"); return 1; } int allow_register_1(struct sip_msg* msg, char* basename, char* s) { return check_register(msg, (int)(long)basename); } int allow_register_2(struct sip_msg* msg, char* allow_file, char* deny_file) { return check_register(msg, (int)(long)allow_file); } /* * determines the permission to an uri * return values: * -1: deny * 1: allow */ static int allow_uri(struct sip_msg* msg, char* _idx, char* _sp) { struct hdr_field *from; int idx, len; static char from_str[EXPRESSION_LENGTH+1]; static char uri_str[EXPRESSION_LENGTH+1]; xl_spec_t *sp; xl_value_t xl_val; idx = (int)(long)_idx; sp = (xl_spec_t *)_sp; /* turn off control, allow any uri */ if ((!allow[idx].rules) && (!deny[idx].rules)) { DBG("allow_uri(): No rules => allow any uri\n"); return 1; } /* looking for FROM HF */ if ((!msg->from) && (parse_headers(msg, HDR_FROM_F, 0) == -1)) { LOG(L_ERR, "allow_uri(): Error while parsing message\n"); return -1; } if (!msg->from) { LOG(L_ERR, "allow_uri(): FROM header field not found\n"); return -1; } /* we must call parse_from_header explicitly */ if ((!(msg->from)->parsed) && (parse_from_header(msg) < 0)) { LOG(L_ERR, "allow_uri(): Error while parsing From body\n"); return -1; } from = msg->from; len = ((struct to_body*)from->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { LOG(L_ERR, "allow_uri(): From header field is too long: " "%d chars\n", len); return -1; } strncpy(from_str, ((struct to_body*)from->parsed)->uri.s, len); from_str[len] = '\0'; if (sp && (xl_get_spec_value(msg, sp, &xl_val, 0) == 0)) { if (xl_val.flags & XL_VAL_STR) { if (xl_val.rs.len > EXPRESSION_LENGTH) { LOG(L_ERR, "allow_uri(): pseudo variable value is too " "long: %d chars\n", xl_val.rs.len); return -1; } strncpy(uri_str, xl_val.rs.s, xl_val.rs.len); uri_str[xl_val.rs.len] = '\0'; } else { LOG(L_ERR, "allow_uri(): pseudo variable value is not " "string\n"); return -1; } } else { LOG(L_ERR, "allow_uri(): cannot get pseudo variable value\n"); return -1; } DBG("allow_uri(): looking for From: %s URI: %s\n", from_str, uri_str); /* rule exists in allow file */ if (search_rule(allow[idx].rules, from_str, uri_str)) { DBG("allow_uri(): allow rule found => URI is allowed\n"); return 1; } /* rule exists in deny file */ if (search_rule(deny[idx].rules, from_str, uri_str)) { DBG("allow_uri(): deny rule found => URI is denied\n"); return -1; } DBG("allow_uri(): Neither allow nor deny rule found => URI is allowed\n"); return 1; }