/* * Test URI against Contact. */ int allow_test(char *file, char *uri, char *contact) { char *pathname; int idx; pathname = get_pathname(file); if (!pathname) { LM_ERR("Cannot get pathname of <%s>\n", file); return 0; } idx = find_index(allow, pathname); if (idx == -1) { LM_ERR("File <%s> has not been loaded\n", pathname); pkg_free(pathname); return 0; } pkg_free(pathname); /* turn off control, allow any routing */ if ((!allow[idx].rules) && (!deny[idx].rules)) { LM_DBG("No rules => Allowed\n"); return 1; } LM_DBG("Looking for URI: %s, Contact: %s\n", uri, contact); /* rule exists in allow file */ if (search_rule(allow[idx].rules, uri, contact)) { LM_DBG("Allow rule found => Allowed\n"); return 1; } /* rule exists in deny file */ if (search_rule(deny[idx].rules, uri, contact)) { LM_DBG("Deny rule found => Denied\n"); return 0; } LM_DBG("Neither allow or deny rule found => Allowed\n"); return 1; }
static Char* parse_extra_rule(Char* read_ptr, Trace_Block* block) { Char* name; tl_assert2(block, "the first group cannot be started by {"); read_ptr++; name = read_ptr; while (*read_ptr != '}') { tl_assert2(*read_ptr && *read_ptr != '\n' && *read_ptr != '\r', "unterminated {"); read_ptr++; } tl_assert2(name != read_ptr, "node has no name"); search_rule(block, name, read_ptr - name); read_ptr++; while (*read_ptr == ' ') read_ptr++; tl_assert2(*read_ptr == '\n' || *read_ptr == '\r' || !*read_ptr, "Garbage at the end of the line"); return read_ptr; }
/* * 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]; pv_spec_t *sp; pv_value_t pv_val; idx = (int)(long)_idx; sp = (pv_spec_t *)_sp; /* turn off control, allow any uri */ if ((!allow[idx].rules) && (!deny[idx].rules)) { LM_DBG("no rules => allow any uri\n"); return 1; } /* looking for FROM HF */ if ((!msg->from) && (parse_headers(msg, HDR_FROM_F, 0) == -1)) { LM_ERR("failed to parse message\n"); return -1; } if (!msg->from) { LM_ERR("FROM header field not found\n"); return -1; } /* we must call parse_from_header explicitly */ if ((!(msg->from)->parsed) && (parse_from_header(msg) < 0)) { LM_ERR("failed to parse From body\n"); return -1; } from = msg->from; len = ((struct to_body*)from->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { LM_ERR("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 && (pv_get_spec_value(msg, sp, &pv_val) == 0)) { if (pv_val.flags & PV_VAL_STR) { if (pv_val.rs.len > EXPRESSION_LENGTH) { LM_ERR("pseudo variable value is too " "long: %d chars\n", pv_val.rs.len); return -1; } strncpy(uri_str, pv_val.rs.s, pv_val.rs.len); uri_str[pv_val.rs.len] = '\0'; } else { LM_ERR("pseudo variable value is not string\n"); return -1; } } else { LM_ERR("cannot get pseudo variable value\n"); return -1; } LM_DBG("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)) { LM_DBG("allow rule found => URI is allowed\n"); return 1; } /* rule exists in deny file */ if (search_rule(deny[idx].rules, from_str, uri_str)) { LM_DBG("deny rule found => URI is denied\n"); return -1; } LM_DBG("neither allow nor deny rule found => URI is allowed\n"); return 1; }
/* * 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)) { LM_DBG("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) { LM_ERR("failed to parse headers\n"); return -1; } if (!msg->to) { LM_ERR("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 */ LM_DBG("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) { LM_ERR("failed to parse Contact HF\n"); return -1; } if (((contact_body_t*)msg->contact->parsed)->star) { LM_DBG("* Contact found, allowing\n"); return 1; } len = ((struct to_body*)msg->to->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { LM_ERR("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) { LM_ERR("can't extract plain Contact URI\n"); return -1; } LM_DBG("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)) { LM_DBG("deny rule found => Register denied\n"); return -1; } skip_deny: if (contact_iterator(&c, msg, c) < 0) { return -1; } } LM_DBG("no contact denied => Allowed\n"); return 1; }
/* * 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)) { LM_DBG("no rules => allow any routing\n"); return 1; } /* looking for FROM HF */ if ((!msg->from) && (parse_headers(msg, HDR_FROM_F, 0) == -1)) { LM_ERR("failed to parse message\n"); return -1; } if (!msg->from) { LM_ERR("FROM header field not found\n"); return -1; } /* we must call parse_from_header explicitly */ if ((!(msg->from)->parsed) && (parse_from_header(msg) < 0)) { LM_ERR("failed to parse From body\n"); return -1; } from = msg->from; len = ((struct to_body*)from->parsed)->uri.len; if (len > EXPRESSION_LENGTH) { LM_ERR("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) { LM_ERR("uri parsing failed\n"); return -1; } len = msg->parsed_uri.user.len + msg->parsed_uri.host.len + 5; if (len > EXPRESSION_LENGTH) { LM_ERR("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'; LM_DBG("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; LM_DBG("allow rule found => routing is allowed\n"); return 1; } /* rule exists in deny file */ if (search_rule(deny[idx].rules, from_str, ruri_str)) { LM_DBG("deny rule found => routing is denied\n"); return -1; } if (!check_all_branches) { LM_DBG("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,0,0))!=0 ; br_idx++ ) { uri_str = get_plain_uri(&branch); if (!uri_str) { LM_ERR("failed to extract plain URI\n"); return -1; } LM_DBG("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)) { LM_DBG("deny rule found for one of branches => routing" "is denied\n"); return -1; } } LM_DBG("check of branches passed => routing is allowed\n"); return 1; }
static void fr_post_clo_init(void) { Rule_List* last_rule_ptr = NULL; Char* read_ptr; Trace_Block* block = NULL; Trace_Block* parent = NULL; Int* indents = (int*)dir_buffer; Int indent; Int depth = -1; Bool is_group; SysRes sres; Int fd; OffT file_size; if (clo_mmap) { #if VG_WORDSIZE == 4 mmap_section.next = NULL; mmap_section.page_addr = 0; mmap_section.trace_blocks = VG_(calloc)("freya.fr_post_clo_init.2", PAGE_NUMBER, sizeof(Trace_Block*)); mmap_section.used_blocks = VG_(calloc)("freya.fr_post_clo_init.3", PAGE_NUMBER, sizeof(Char)); #else mmap_sections = VG_(calloc)("freya.fr_post_clo_init.1", 1, sizeof(Mmap_Section)); mmap_sections->next = NULL; mmap_sections->page_addr = 0; mmap_sections->trace_blocks = VG_(calloc)("freya.fr_post_clo_init.2", PAGE_NUMBER, sizeof(Trace_Block*)); mmap_sections->used_blocks = VG_(calloc)("freya.fr_post_clo_init.3", PAGE_NUMBER, sizeof(Char)); mmap_section_cache = mmap_sections; #endif } read_ptr = NULL; if (clo_config) { sres = VG_(open)(clo_config, VKI_O_RDONLY, 0); if (!sr_isError(sres)) { fd = (Int) sr_Res(sres); file_size = VG_(lseek)(fd, 0, VKI_SEEK_END); VG_(lseek)(fd, 0, VKI_SEEK_SET); if (clo_fr_verb) VG_(printf)("File '%s' (size: %ld bytes) is successfully opened.\n", clo_config, file_size); read_ptr = VG_(malloc)("freya.fr_post_clo_init.3", (file_size + 1) * sizeof(Char)); VG_(read)(fd, read_ptr, file_size); read_ptr[file_size] = '\0'; VG_(close) (fd); } else if (clo_fr_verb) VG_(printf)("Cannot open '%s'. (Fallback to default config)\n", clo_config); } else if (clo_fr_verb) VG_(printf)("No config file provided. (Fallback to default config)\n"); if (!read_ptr) { // Duplicate read_ptr = VG_(malloc)("freya.fr_post_clo_init.4", (VG_(strlen)(default_rule) + 1) * sizeof(Char)); VG_(strcpy)(read_ptr, default_rule); } while (*read_ptr) { // Parsing the next line, first skip spaces indent = 0; while (*read_ptr == ' ') { indent++; read_ptr++; } // Skip comments and empty lines if (*read_ptr == '#' || *read_ptr == '\r' || *read_ptr == '\n') { while (*read_ptr != '\0' && *read_ptr != '\r' && *read_ptr != '\n') read_ptr++; if (*read_ptr) { read_ptr++; continue; } } if (*read_ptr == '{') { read_ptr = parse_extra_rule(read_ptr, block); continue; } else if (*read_ptr != '[' && *read_ptr != '(') { read_ptr = parse_rule(read_ptr, &last_rule_ptr); continue; } is_group = *read_ptr == '['; block = VG_(malloc)("freya.fr_post_clo_init.4", sizeof(Trace_Block)); read_ptr++; block->name = read_ptr; while (!(!is_group && *read_ptr == ')') && !(is_group && *read_ptr == ']')) { tl_assert2(*read_ptr && *read_ptr != '\n' && *read_ptr != '\r', "unterminated ( or ["); read_ptr++; } tl_assert2(block->name != read_ptr, "node has no name"); *read_ptr = '\0'; if (!is_group) search_rule(block, block->name, read_ptr - block->name); read_ptr++; if (*read_ptr == '+') { tl_assert2(default_parent == NULL, "Only one default node is allowed"); default_parent = block; read_ptr++; } while (*read_ptr == ' ') read_ptr++; tl_assert2(*read_ptr == '\n' || *read_ptr == '\r' || !*read_ptr, "Garbage at the end of the line"); if (clo_fr_verb) VG_(printf)("%s '%s' %s\n", is_group ? "Group:" : "Group & Attach:", block->name, default_parent == block ? "(Default)" : ""); if (depth >= 0) { if (indents[depth] != indent) { if (indent > indents[depth]) { tl_assert2(depth < 63, "Maximum allowed depth is 63 for the tree"); depth++; indents[depth] = indent; if (parent) parent = parent->first; else parent = trace_head; } else { do { tl_assert2(depth != 0, "Wrong tree indentation"); depth--; tl_assert(parent); parent = parent->parent; } while (indent != indents[depth]); tl_assert((depth == 0 && !parent) || (depth > 0 && parent)); } } } else { // The indentation of the top element tl_assert(!parent); indents[0] = indent; depth = 0; } block->parent = parent; if (parent) { block->next = parent->first; parent->first = block; } else { block->next = trace_head; trace_head = block; } block->first = NULL; block->hash_next = NULL; block->allocs = 0; block->total = 0; block->current = 0; block->peak = 0; block->ips = 0; } remove_unused_rules(); }