diff --git a/modules/permissions/hash.c b/modules/permissions/hash.c index 7b11ebd..97e0578 100644 --- a/modules/permissions/hash.c +++ b/modules/permissions/hash.c @@ -22,6 +22,7 @@ #include #include +#include "parse_config.h" #include "../../mem/shm_mem.h" #include "../../parser/parse_from.h" #include "../../ut.h" @@ -116,11 +117,11 @@ void free_hash_table(struct trusted_list** table) /* - * Add into hash table, where proto is integer + * Add into hash table, where proto is integer * representation of string argument proto. */ int hash_table_insert(struct trusted_list** table, char* src_ip, - char* proto, char* pattern, char* tag) + char* proto, char* pattern, char* ruri_pattern, char* tag) { struct trusted_list *np; unsigned int hash_val; @@ -178,14 +179,28 @@ int hash_table_insert(struct trusted_list** table, char* src_ip, } else { np->pattern = 0; } + + if (ruri_pattern) { + np->ruri_pattern = (char *) shm_malloc(strlen(ruri_pattern)+1); + if (np->ruri_pattern == NULL) { + LM_CRIT("cannot allocate shm memory for ruri_pattern string\n"); + shm_free(np->src_ip.s); + shm_free(np); + return -1; + } + (void) strcpy(np->ruri_pattern, ruri_pattern); + } else { + np->ruri_pattern = 0; + } if (tag) { np->tag.len = strlen(tag); np->tag.s = (char *) shm_malloc((np->tag.len) + 1); if (np->tag.s == NULL) { - LM_CRIT("cannot allocate shm memory for pattern string\n"); + LM_CRIT("cannot allocate shm memory for pattern or ruri_pattern string\n"); shm_free(np->src_ip.s); shm_free(np->pattern); + shm_free(np->ruri_pattern); shm_free(np); return -1; } @@ -220,9 +235,23 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg, int_str val; int count = 0; + int len; + static char ruri_str[EXPRESSION_LENGTH+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'; + src_ip.s = src_ip_c_str; src_ip.len = strlen(src_ip.s); - + if (IS_SIP(msg)) { if (parse_from_header(msg) < 0) return -1; @@ -236,33 +265,46 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg, } for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) { - if ((np->src_ip.len == src_ip.len) && - (strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) && - ((np->proto == PROTO_NONE) || (proto == PROTO_NONE) || - (np->proto == proto))) { - if (np->pattern && IS_SIP(msg)) { - if (regcomp(&preg, np->pattern, REG_NOSUB)) { - LM_ERR("invalid regular expression\n"); - continue; - } - if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) { - regfree(&preg); - continue; - } - regfree(&preg); - } - /* Found a match */ - if (tag_avp.n && np->tag.s) { - val.s = np->tag; - if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) { - LM_ERR("setting of tag_avp failed\n"); - return -1; - } + if ((np->src_ip.len == src_ip.len) && + (strncmp(np->src_ip.s, src_ip.s, src_ip.len) == 0) && + ((np->proto == PROTO_NONE) || (proto == PROTO_NONE) || + (np->proto == proto))) { + if (np->pattern && IS_SIP(msg)) { + if (regcomp(&preg, np->pattern, REG_NOSUB)) { + LM_ERR("invalid regular expression\n"); + if (!np->ruri_pattern) { + continue; + } + } + if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) { + regfree(&preg); + continue; + } + regfree(&preg); + if (np->ruri_pattern) { + if (regcomp(&preg, np->ruri_pattern, REG_NOSUB)) { + LM_ERR("invalid regular expression\n"); + continue; + } + if (regexec(&preg, ruri_str, 0, (regmatch_t *)0, 0)) { + regfree(&preg); + continue; + } + regfree(&preg); + } + } + /* Found a match */ + if (tag_avp.n && np->tag.s) { + val.s = np->tag; + if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, val) != 0) { + LM_ERR("setting of tag_avp failed\n"); + return -1; + } + } + if (!peer_tag_mode) + return 1; + count++; } - if (!peer_tag_mode) - return 1; - count++; - } } if (!count) return -1; @@ -288,6 +330,7 @@ int hash_table_mi_print(struct trusted_list** table, struct mi_node* rpl) np->src_ip.len, ZSW(np->src_ip.s), np->proto, np->pattern?np->pattern:"NULL", + np->ruri_pattern?np->ruri_pattern:"NULL", np->tag.len?np->tag.s:"NULL") == 0) { return -1; } @@ -329,8 +372,9 @@ int hash_table_rpc_print(struct trusted_list** hash_table, rpc_t* rpc, void* c) rpc->fault(c, 500, "Internal error creating rpc data (ip)"); return -1; } - if(rpc->struct_add(ih, "dss", "proto", np->proto, + if(rpc->struct_add(ih, "dsss", "proto", np->proto, "pattern", np->pattern ? np->pattern : "NULL", + "ruri_pattern", np->ruri_pattern ? np->ruri_pattern : "NULL", "tag", np->tag.len ? np->tag.s : "NULL") < 0) { rpc->fault(c, 500, "Internal error creating rpc data"); @@ -356,6 +400,7 @@ void empty_hash_table(struct trusted_list **table) while (np) { if (np->src_ip.s) shm_free(np->src_ip.s); if (np->pattern) shm_free(np->pattern); + if (np->ruri_pattern) shm_free(np->ruri_pattern); if (np->tag.s) shm_free(np->tag.s); next = np->next; shm_free(np); diff --git a/modules/permissions/hash.h b/modules/permissions/hash.h index 1ae0072..81eebb0 100644 --- a/modules/permissions/hash.h +++ b/modules/permissions/hash.h @@ -41,6 +41,7 @@ struct trusted_list { str src_ip; /* Source IP of SIP message */ int proto; /* Protocol -- UDP, TCP, TLS, or SCTP */ char *pattern; /* Pattern matching From header field */ + char *ruri_pattern; /* Pattern matching Request URI */ str tag; /* Tag to be assigned to AVP */ struct trusted_list *next; /* Next element in the list */ }; @@ -77,16 +78,16 @@ void destroy_hash_table(struct trusted_list** table); /* - * Add into hash table, where proto is integer + * Add into hash table, where proto is integer * representation of string argument proto. */ int hash_table_insert(struct trusted_list** hash_table, char* src_ip, - char* proto, char* pattern, char* tag); + char* proto, char* pattern, char* ruri_pattern, char* tag); /* * Check if an entry exists in hash table that has given src_ip and protocol - * value and pattern that matches to From URI. + * value and pattern or ruri_pattern that matches to From URI. */ int match_hash_table(struct trusted_list** table, struct sip_msg* msg, char *scr_ip, int proto); diff --git a/modules/permissions/permissions.c b/modules/permissions/permissions.c index 4170fef..9200406 100644 --- a/modules/permissions/permissions.c +++ b/modules/permissions/permissions.c @@ -68,6 +68,7 @@ str trusted_table = str_init("trusted"); /* Name of trusted table */ str source_col = str_init("src_ip"); /* Name of source address column */ str proto_col = str_init("proto"); /* Name of protocol column */ str from_col = str_init("from_pattern"); /* Name of from pattern column */ +str ruri_col = str_init("ruri_pattern"); /* Name of RURI pattern column */ str tag_col = str_init("tag"); /* Name of tag column */ str tag_avp_param = {NULL, 0}; /* Peer tag AVP spec */ int peer_tag_mode = 0; /* Add tags form all mathcing peers to avp */ @@ -166,6 +167,7 @@ static param_export_t params[] = { {"source_col", PARAM_STR, &source_col }, {"proto_col", PARAM_STR, &proto_col }, {"from_col", PARAM_STR, &from_col }, + {"ruri_col", PARAM_STR, &ruri_col }, {"tag_col", PARAM_STR, &tag_col }, {"peer_tag_avp", PARAM_STR, &tag_avp_param }, {"peer_tag_mode", INT_PARAM, &peer_tag_mode }, diff --git a/modules/permissions/permissions.h b/modules/permissions/permissions.h index 0d2fa39..0c0c9ac 100644 --- a/modules/permissions/permissions.h +++ b/modules/permissions/permissions.h @@ -25,6 +25,7 @@ * History: * -------- * 2003-09-03 replaced /usr/local/et/ser/ with CFG_DIR (andrei) + * 2015-05-06 added regular expression matching R-URI (eschmidbauer@voipxswitch.com) */ #ifndef PERMISSIONS_H @@ -55,6 +56,7 @@ extern str trusted_table; /* Name of trusted table */ extern str source_col; /* Name of source address column */ extern str proto_col; /* Name of protocol column */ extern str from_col; /* Name of from pattern column */ +extern str ruri_col; /* Name of RURI pattern column */ extern str tag_col; /* Name of tag column */ extern str address_table; /* Name of address table */ extern str grp_col; /* Name of address group column */ diff --git a/modules/permissions/trusted.c b/modules/permissions/trusted.c index db20e8f..08a989d 100644 --- a/modules/permissions/trusted.c +++ b/modules/permissions/trusted.c @@ -41,7 +41,7 @@ #include "../../parser/parse_from.h" #include "../../usr_avp.h" -#define TABLE_VERSION 5 +#define TABLE_VERSION 6 struct trusted_list ***hash_table; /* Pointer to current hash table pointer */ struct trusted_list **hash_table_1; /* Pointer to hash table 1 */ @@ -58,7 +58,7 @@ static db_func_t perm_dbf; */ int reload_trusted_table(void) { - db_key_t cols[4]; + db_key_t cols[5]; db1_res_t* res = NULL; db_row_t* row; db_val_t* val; @@ -67,12 +67,13 @@ int reload_trusted_table(void) struct trusted_list **old_hash_table; int i; - char *pattern, *tag; + char *pattern, *ruri_pattern, *tag; cols[0] = &source_col; cols[1] = &proto_col; cols[2] = &from_col; - cols[3] = &tag_col; + cols[3] = &ruri_col; + cols[4] = &tag_col; if (db_handle == 0) { LM_ERR("no connection to database\n"); @@ -84,7 +85,7 @@ int reload_trusted_table(void) return -1; } - if (perm_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 4, 0, &res) < 0) { + if (perm_dbf.query(db_handle, NULL, 0, NULL, cols, 0, 5, 0, &res) < 0) { LM_ERR("failed to query database\n"); return -1; } @@ -103,7 +104,7 @@ int reload_trusted_table(void) for (i = 0; i < RES_ROW_N(res); i++) { val = ROW_VALUES(row + i); - if ((ROW_N(row + i) == 4) && + if ((ROW_N(row + i) == 5) && ((VAL_TYPE(val) == DB1_STRING) || (VAL_TYPE(val) == DB1_STR) ) && !VAL_NULL(val) && ((VAL_TYPE(val + 1) == DB1_STRING) || (VAL_TYPE(val + 1) == DB1_STR)) @@ -112,29 +113,36 @@ int reload_trusted_table(void) (((VAL_TYPE(val + 2) == DB1_STRING) || (VAL_TYPE(val + 2) == DB1_STR)) && !VAL_NULL(val + 2))) && (VAL_NULL(val + 3) || (((VAL_TYPE(val + 3) == DB1_STRING) || (VAL_TYPE(val + 3) == DB1_STR) )&& - !VAL_NULL(val + 3)))) { + !VAL_NULL(val + 3))) && (VAL_NULL(val + 4) || + (((VAL_TYPE(val + 4) == DB1_STRING) || (VAL_TYPE(val + 4) == DB1_STR) )&& + !VAL_NULL(val + 4)))) { if (VAL_NULL(val + 2)) { pattern = 0; } else { pattern = (char *)VAL_STRING(val + 2); } if (VAL_NULL(val + 3)) { + ruri_pattern = 0; + } else { + ruri_pattern = (char *)VAL_STRING(val + 3); + } + if (VAL_NULL(val + 4)) { tag = 0; } else { - tag = (char *)VAL_STRING(val + 3); + tag = (char *)VAL_STRING(val + 4); } if (hash_table_insert(new_hash_table, (char *)VAL_STRING(val), (char *)VAL_STRING(val + 1), - pattern, tag) == -1) { + pattern, ruri_pattern, tag) == -1) { LM_ERR("hash table problem\n"); perm_dbf.free_result(db_handle, res); empty_hash_table(new_hash_table); return -1; } - LM_DBG("tuple <%s, %s, %s, %s> inserted into trusted hash " + LM_DBG("tuple <%s, %s, %s, %s, %s> inserted into trusted hash " "table\n", VAL_STRING(val), VAL_STRING(val + 1), - pattern, tag); + pattern, ruri_pattern, tag); } else { LM_ERR("database problem\n"); perm_dbf.free_result(db_handle, res); @@ -369,6 +377,20 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r) regex_t preg; int_str tag_avp, avp_val; int count = 0; + + int len; + static char ruri_str[EXPRESSION_LENGTH+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'; if (IS_SIP(msg)) { if (parse_from_header(msg) < 0) return -1; @@ -385,39 +407,56 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r) row = RES_ROWS(_r); for(i = 0; i < RES_ROW_N(_r); i++) { - val = ROW_VALUES(row + i); - if ((ROW_N(row + i) == 3) && - (VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) && - match_proto(VAL_STRING(val), proto) && - (VAL_NULL(val + 1) || - ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) && - (VAL_NULL(val + 2) || - ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2)))) - { - if (!VAL_NULL(val + 1) && IS_SIP(msg)) { - if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) { - LM_ERR("invalid regular expression\n"); - continue; - } - if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) { - regfree(&preg); - continue; + val = ROW_VALUES(row + i); + if ((ROW_N(row + i) == 4) && + (VAL_TYPE(val) == DB1_STRING) && !VAL_NULL(val) && + match_proto(VAL_STRING(val), proto) && + (VAL_NULL(val + 1) || + ((VAL_TYPE(val + 1) == DB1_STRING) && !VAL_NULL(val + 1))) && + (VAL_NULL(val + 2) || + ((VAL_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))) && + (VAL_NULL(val + 3) || + ((VAL_TYPE(val + 3) == DB1_STRING) && !VAL_NULL(val + 3)))) + { + if (IS_SIP(msg)) { + if (!VAL_NULL(val + 1)) { + if (regcomp(&preg, (char *)VAL_STRING(val + 1), REG_NOSUB)) { + LM_ERR("invalid regular expression\n"); + if (VAL_NULL(val + 2)) { + continue; + } + } + if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) { + regfree(&preg); + continue; + } + regfree(&preg); + if (!VAL_NULL(val + 2)) { + if (regcomp(&preg, (char *)VAL_STRING(val + 2), REG_NOSUB)) { + LM_ERR("invalid regular expression\n"); + continue; + } + if (regexec(&preg, ruri_str, 0, (regmatch_t *)0, 0)) { + regfree(&preg); + continue; + } + regfree(&preg); + } + } } - regfree(&preg); - } - /* Found a match */ - if (tag_avp.n && !VAL_NULL(val + 2)) { - avp_val.s.s = (char *)VAL_STRING(val + 2); - avp_val.s.len = strlen(avp_val.s.s); - if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) { - LM_ERR("failed to set of tag_avp failed\n"); - return -1; + /* Found a match */ + if (tag_avp.n && !VAL_NULL(val + 3)) { + avp_val.s.s = (char *)VAL_STRING(val + 3); + avp_val.s.len = strlen(avp_val.s.s); + if (add_avp(tag_avp_type|AVP_VAL_STR, tag_avp, avp_val) != 0) { + LM_ERR("failed to set of tag_avp failed\n"); + return -1; + } } + if (!peer_tag_mode) + return 1; + count++; } - if (!peer_tag_mode) - return 1; - count++; - } } if (!count) return -1; @@ -437,7 +476,7 @@ int allow_trusted(struct sip_msg* msg, char *src_ip, int proto) db_key_t keys[1]; db_val_t vals[1]; - db_key_t cols[3]; + db_key_t cols[4]; if (db_mode == DISABLE_CACHE) { @@ -449,7 +488,8 @@ int allow_trusted(struct sip_msg* msg, char *src_ip, int proto) keys[0] = &source_col; cols[0] = &proto_col; cols[1] = &from_col; - cols[2] = &tag_col; + cols[2] = &ruri_col; + cols[3] = &tag_col; if (perm_dbf.use_table(db_handle, &trusted_table) < 0) { LM_ERR("failed to use trusted table\n"); @@ -460,7 +500,7 @@ int allow_trusted(struct sip_msg* msg, char *src_ip, int proto) VAL_NULL(vals) = 0; VAL_STRING(vals) = src_ip; - if (perm_dbf.query(db_handle, keys, 0, vals, cols, 1, 3, 0, + if (perm_dbf.query(db_handle, keys, 0, vals, cols, 1, 4, 0, &res) < 0){ LM_ERR("failed to query database\n"); return -1; diff --git a/utils/kamctl/postgres/permissions-create.sql b/utils/kamctl/postgres/permissions-create.sql index 95f13de..e005243 100644 --- a/utils/kamctl/postgres/permissions-create.sql +++ b/utils/kamctl/postgres/permissions-create.sql @@ -1,9 +1,10 @@ -INSERT INTO version (table_name, table_version) values ('trusted','5'); +INSERT INTO version (table_name, table_version) values ('trusted','6'); CREATE TABLE trusted ( id SERIAL PRIMARY KEY NOT NULL, src_ip VARCHAR(50) NOT NULL, proto VARCHAR(4) NOT NULL, from_pattern VARCHAR(64) DEFAULT NULL, + ruri_pattern VARCHAR(64) DEFAULT NULL, tag VARCHAR(64) );