permissions: match trusted rules considering priority and regexp over r-uri
authorEmmanuel Schmidbauer <eschmidbauer@voipxswitch.com>
Wed, 17 Jun 2015 14:18:18 +0000 (16:18 +0200)
committerDaniel-Constantin Mierla <miconda@gmail.com>
Wed, 17 Jun 2015 14:18:18 +0000 (16:18 +0200)
- two new columns to set priority of the rule as well as regular
  expression matching over r-uri

modules/permissions/hash.c
modules/permissions/hash.h
modules/permissions/permissions.c
modules/permissions/permissions.h
modules/permissions/trusted.c

index 7b11ebd..2aee8b8 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <sys/types.h>
 #include <regex.h>
+#include "parse_config.h"
 #include "../../mem/shm_mem.h"
 #include "../../parser/parse_from.h"
 #include "../../ut.h"
@@ -116,13 +117,15 @@ void free_hash_table(struct trusted_list** table)
 
 
 /* 
- * Add <src_ip, proto, pattern, tag> into hash table, where proto is integer
+ * Add <src_ip, proto, pattern, ruri_pattern, tag, priority> 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, int priority)
 {
        struct trusted_list *np;
+       struct trusted_list *np0 = NULL;
+       struct trusted_list *np1 = NULL;
        unsigned int hash_val;
 
        np = (struct trusted_list *) shm_malloc(sizeof(*np));
@@ -179,13 +182,27 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
                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;
                }
@@ -195,9 +212,29 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
                np->tag.s = 0;
        }
 
+       np->priority = priority;
+
        hash_val = perm_hash(np->src_ip);
-       np->next = table[hash_val];
-       table[hash_val] = np;
+       if(table[hash_val]==NULL) {
+               np->next = NULL;
+               table[hash_val] = np;
+       } else {
+               np1 = NULL;
+               np0 = table[hash_val];
+               while(np0) {
+                       if(np0->priority < np->priority)
+                               break;
+                       np1 = np0;
+                       np0 = np0->next;
+               }
+               if(np1==NULL) {
+                       np->next = table[hash_val];
+                       table[hash_val] = np;
+               } else {
+                       np->next = np1->next;
+                       np1->next = np;
+               }
+       }
 
        return 1;
 }
@@ -212,8 +249,9 @@ int hash_table_insert(struct trusted_list** table, char* src_ip,
 int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
                char *src_ip_c_str, int proto)
 {
-       str uri;
+       str uri, ruri;
        char uri_string[MAX_URI_SIZE + 1];
+       char ruri_string[MAX_URI_SIZE + 1];
        regex_t preg;
        struct trusted_list *np;
        str src_ip;
@@ -233,6 +271,13 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
                }
                memcpy(uri_string, uri.s, uri.len);
                uri_string[uri.len] = (char)0;
+               ruri = msg->first_line.u.request.uri;
+               if (ruri.len > MAX_URI_SIZE) {
+                       LM_ERR("message has Request URI too large\n");
+                       return -1;
+               }
+               memcpy(ruri_string, ruri.s, ruri.len);
+               ruri_string[ruri.len] = (char)0;
        }
 
        for (np = table[perm_hash(src_ip)]; np != NULL; np = np->next) {
@@ -240,16 +285,31 @@ int match_hash_table(struct trusted_list** table, struct sip_msg* msg,
                (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 (IS_SIP(msg)) {
+                   if (np->pattern) {
+                       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 (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
+                   if (np->ruri_pattern) {
+                       if (regcomp(&preg, np->ruri_pattern, REG_NOSUB)) {
+                           LM_ERR("invalid regular expression\n");
+                           continue;
+                       }
+                       if (regexec(&preg, ruri_string, 0, (regmatch_t *)0, 0)) {
+                           regfree(&preg);
+                           continue;
+                       }
                        regfree(&preg);
-                       continue;
                    }
-                   regfree(&preg);
                }
                /* Found a match */
                if (tag_avp.n && np->tag.s) {
@@ -283,12 +343,14 @@ int hash_table_mi_print(struct trusted_list** table, struct mi_node* rpl)
                np = table[i];
                while (np) {
                        if (addf_mi_node_child(rpl, 0, 0, 0,
-                                               "%4d <%.*s, %d, %s, %s>",
+                                               "%4d <%.*s, %d, %s, %s, %s, %d>",
                                                i,
                                                np->src_ip.len, ZSW(np->src_ip.s),
                                                np->proto,
                                                np->pattern?np->pattern:"NULL",
-                                               np->tag.len?np->tag.s:"NULL") == 0) {
+                                               np->ruri_pattern?np->ruri_pattern:"NULL",
+                                               np->tag.len?np->tag.s:"NULL",
+                                               np->priority) == 0) {
                                return -1;
                        }
                        np = np->next;
@@ -329,9 +391,11 @@ 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, "dsssd", "proto",  np->proto,
                                                "pattern",  np->pattern ? np->pattern : "NULL",
-                                               "tag",  np->tag.len ? np->tag.s : "NULL") < 0)
+                                               "ruri_pattern",  np->ruri_pattern ? np->ruri_pattern : "NULL",
+                                               "tag",  np->tag.len ? np->tag.s : "NULL",
+                                               "priority", np->priority) < 0)
                        {
                                rpc->fault(c, 500, "Internal error creating rpc data");
                                return -1;
index 1ae0072..1823084 100644 (file)
@@ -41,7 +41,9 @@ 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 */
+       int priority;               /* priority */
        struct trusted_list *next;  /* Next element in the list */
 };
 
@@ -77,16 +79,16 @@ void destroy_hash_table(struct trusted_list** table);
 
 
 /* 
- * Add <src_ip, proto, pattern> into hash table, where proto is integer
+ * Add <src_ip, proto, pattern, ruri_pattern, priority> 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, int priority);
 
 
 /* 
  * 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);
index 4170fef..724e4e8 100644 (file)
@@ -68,7 +68,9 @@ 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 priority_col = str_init("priority");   /* Name of priority 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,7 +168,9 @@ 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         },
+       {"priority_col",       PARAM_STR, &priority_col    },
        {"peer_tag_avp",       PARAM_STR, &tag_avp_param   },
        {"peer_tag_mode",      INT_PARAM, &peer_tag_mode     },
        {"address_table",      PARAM_STR, &address_table   },
index 0d2fa39..1e0066f 100644 (file)
@@ -55,7 +55,9 @@ 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 priority_col;  /* Name of priority column */
 extern str address_table; /* Name of address table */
 extern str grp_col;       /* Name of address group column */
 extern str ip_addr_col;   /* Name of ip address column */
index db20e8f..8da51ff 100644 (file)
@@ -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[6];
        db1_res_t* res = NULL;
        db_row_t* row;
        db_val_t* val;
@@ -66,13 +66,16 @@ int reload_trusted_table(void)
        struct trusted_list **new_hash_table;
        struct trusted_list **old_hash_table;
        int i;
+       int priority;
 
-       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;
+       cols[5] = &priority_col;
 
        if (db_handle == 0) {
            LM_ERR("no connection to database\n");
@@ -84,7 +87,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, 6, 0, &res) < 0) {
                LM_ERR("failed to query database\n");
                return -1;
        }
@@ -103,7 +106,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) == 6) &&
                ((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))
@@ -111,30 +114,42 @@ int reload_trusted_table(void)
                (VAL_NULL(val + 2) ||
                 (((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_TYPE(val + 3) == DB1_STRING) || (VAL_TYPE(val + 3) == DB1_STR) )&&
+               !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 (VAL_NULL(val + 5)) {
+                   priority = 0;
+               } else {
+                   priority = (int)VAL_INT(val + 5);
                }
                if (hash_table_insert(new_hash_table,
                                      (char *)VAL_STRING(val),
                                      (char *)VAL_STRING(val + 1),
-                                     pattern, tag) == -1) {
+                                     pattern, ruri_pattern, tag, priority) == -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);
@@ -362,8 +377,9 @@ static inline int match_proto(const char *proto_string, int proto_int)
 static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 {
        int i, tag_avp_type;
-       str uri;
+       str uri, ruri;
        char uri_string[MAX_URI_SIZE+1];
+       char ruri_string[MAX_URI_SIZE+1];
        db_row_t* row;
        db_val_t* val;
        regex_t preg;
@@ -379,6 +395,13 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
                }
                memcpy(uri_string, uri.s, uri.len);
                uri_string[uri.len] = (char)0;
+               ruri = msg->first_line.u.request.uri;
+               if (ruri.len > MAX_URI_SIZE) {
+                       LM_ERR("message has Request URI too large\n");
+                       return -1;
+               }
+               memcpy(ruri_string, ruri.s, ruri.len);
+               ruri_string[ruri.len] = (char)0;
        }
        get_tag_avp(&tag_avp, &tag_avp_type);
 
@@ -386,28 +409,45 @@ static int match_res(struct sip_msg* msg, int proto, db1_res_t* _r)
 
        for(i = 0; i < RES_ROW_N(_r); i++) {
                val = ROW_VALUES(row + i);
-               if ((ROW_N(row + i) == 3) &&
+               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_TYPE(val + 2) == DB1_STRING) && !VAL_NULL(val + 2))) &&
+                   (VAL_NULL(val + 3) ||
+                     ((VAL_TYPE(val + 3) == DB1_STRING) && !VAL_NULL(val + 3))))
                {
-                       if (!VAL_NULL(val + 1) && IS_SIP(msg)) {
+                       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");
-                                       continue;
+                                       if (VAL_NULL(val + 2)) {
+                                               continue;
+                                       }
                                }
                                if (regexec(&preg, uri_string, 0, (regmatch_t *)0, 0)) {
                                        regfree(&preg);
                                        continue;
                                }
-                           regfree(&preg);
+                               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_string, 0, (regmatch_t *)0, 0)) {
+                                       regfree(&preg);
+                                       continue;
+                               }
+                               regfree(&preg);
+                           }
                        }
                        /* Found a match */
-                       if (tag_avp.n && !VAL_NULL(val + 2)) {
-                               avp_val.s.s = (char *)VAL_STRING(val + 2);
+                       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");
@@ -437,9 +477,10 @@ 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) {
+               db_key_t order = &priority_col;
        
                if (db_handle == 0) {
                    LM_ERR("no connection to database\n");
@@ -449,7 +490,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 +502,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, order,
                                   &res) < 0){
                        LM_ERR("failed to query database\n");
                        return -1;