userblacklist.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2007 1&1 Internet AG
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00041 #include <string.h>
00042 
00043 #include "../../parser/parse_uri.h"
00044 #include "../../mem/shm_mem.h"
00045 #include "../../sr_module.h"
00046 #include "../../lib/kmi/mi.h"
00047 #include "../../mem/mem.h"
00048 #include "../../usr_avp.h"
00049 #include "../../locking.h"
00050 #include "../../error.h"
00051 #include "../../ut.h"
00052 #include "../../mod_fix.h"
00053 
00054 #include "../../lib/trie/dtrie.h"
00055 #include "db.h"
00056 #include "db_userblacklist.h"
00057 
00058 MODULE_VERSION
00059 
00060 
00061 #define MAXNUMBERLEN 31
00062 
00063 
00064 typedef struct _avp_check
00065 {
00066         int avp_flags;
00067         int_str avp_name;
00068 } avp_check_t;
00069 
00070 
00071 struct check_blacklist_fs_t {
00072   struct dtrie_node_t *dtrie_root;
00073 };
00074 
00075 str userblacklist_db_url = str_init(DEFAULT_RODB_URL);
00076 int use_domain   = 0;
00077 int match_mode = 10; /* numeric */
00078 static struct dtrie_node_t *gnode = NULL;
00079 
00080 /* ---- fixup functions: */
00081 static int check_blacklist_fixup(void** param, int param_no);
00082 static int check_user_blacklist_fixup(void** param, int param_no);
00083 static int check_globalblacklist_fixup(void** param, int param_no);
00084 
00085 /* ---- exported commands: */
00086 static int check_user_blacklist(struct sip_msg *msg, char* str1, char* str2, char* str3, char* str4);
00087 static int check_user_whitelist(struct sip_msg *msg, char* str1, char* str2, char* str3, char* str4);
00088 static int check_user_blacklist2(struct sip_msg *msg, char* str1, char* str2);
00089 static int check_user_whitelist2(struct sip_msg *msg, char* str1, char* str2);
00090 static int check_user_blacklist3(struct sip_msg *msg, char* str1, char* str2, char* str3);
00091 static int check_user_whitelist3(struct sip_msg *msg, char* str1, char* str2, char* str3);
00092 static int check_blacklist(struct sip_msg *msg, struct check_blacklist_fs_t *arg1);
00093 static int check_globalblacklist(struct sip_msg *msg);
00094 
00095 
00096 /* ---- module init functions: */
00097 static int mod_init(void);
00098 static int child_init(int rank);
00099 static int mi_child_init(void);
00100 static void mod_destroy(void);
00101 
00102 /* --- fifo functions */
00103 struct mi_root * mi_reload_blacklist(struct mi_root* cmd, void* param);  /* usage: kamctl fifo reload_blacklist */
00104 
00105 
00106 static cmd_export_t cmds[]={
00107         { "check_user_blacklist", (cmd_function)check_user_blacklist2, 2, check_user_blacklist_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00108         { "check_user_whitelist", (cmd_function)check_user_whitelist2, 2, check_user_blacklist_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00109         { "check_user_blacklist", (cmd_function)check_user_blacklist3, 3, check_user_blacklist_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00110         { "check_user_whitelist", (cmd_function)check_user_whitelist3, 3, check_user_blacklist_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00111         { "check_user_blacklist", (cmd_function)check_user_blacklist, 4, check_user_blacklist_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00112         { "check_user_whitelist", (cmd_function)check_user_whitelist, 4, check_user_blacklist_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00113         { "check_blacklist", (cmd_function)check_blacklist, 1, check_blacklist_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00114         { "check_blacklist", (cmd_function)check_globalblacklist, 0, check_globalblacklist_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE },
00115         { 0, 0, 0, 0, 0, 0}
00116 };
00117 
00118 
00119 static param_export_t params[] = {
00120         userblacklist_DB_URL
00121         userblacklist_DB_TABLE
00122         globalblacklist_DB_TABLE
00123         userblacklist_DB_COLS
00124         globalblacklist_DB_COLS
00125         { "use_domain",      INT_PARAM, &use_domain },
00126         { "match_mode",      INT_PARAM, &match_mode},
00127         { 0, 0, 0}
00128 };
00129 
00130 
00131 /* Exported MI functions */
00132 static mi_export_t mi_cmds[] = {
00133         { "reload_blacklist", mi_reload_blacklist, MI_NO_INPUT_FLAG, 0, mi_child_init },
00134         { 0, 0, 0, 0, 0}
00135 };
00136 
00137 
00138 struct module_exports exports= {
00139         "userblacklist",
00140         DEFAULT_DLFLAGS,
00141         cmds,
00142         params,
00143         0,
00144         mi_cmds,
00145         0,
00146         0,
00147         mod_init,
00148         0,
00149         mod_destroy,
00150         child_init
00151 };
00152 
00153 
00154 struct source_t {
00155         struct source_t *next;
00157         char *table;
00159         struct dtrie_node_t *dtrie_root;
00160 };
00161 
00162 
00163 struct source_list_t {
00164   struct source_t *head;
00165 };
00166 
00167 
00168 static gen_lock_t *lock = NULL;
00169 static struct source_list_t *sources = NULL;
00170 static struct dtrie_node_t *dtrie_root;
00171 
00172 
00173 static int check_user_blacklist_fixup(void** param, int param_no)
00174 {
00175         pv_elem_t *model=NULL;
00176         str s;
00177 
00178         /* convert to str */
00179         s.s = (char*)*param;
00180         s.len = strlen(s.s);
00181 
00182         if (param_no > 0 && param_no <= 4) {
00183                 if(s.len == 0 && param_no != 4) {
00184                         LM_ERR("no parameter %d\n", param_no);
00185                         return E_UNSPEC;
00186                 }
00187 
00188                 if(pv_parse_format(&s, &model) < 0 || !model) {
00189                         LM_ERR("wrong format [%.*s] for parameter %d\n", s.len, s.s, param_no);
00190                         return E_UNSPEC;
00191                 }
00192 
00193                 if(!model->spec.getf) {
00194                         if(param_no == 1) {
00195                                 if(str2int(&s, (unsigned int*)&model->spec.pvp.pvn.u.isname.name.n) != 0) {
00196                                         LM_ERR("wrong value [%.*s] for parameter %d\n", s.len, s.s, param_no);
00197                                         return E_UNSPEC;
00198                                 }
00199                         } else {
00200                                 if(param_no == 2 || param_no == 3) {
00201                                         LM_ERR("wrong value [%.*s] for parameter %d\n", s.len, s.s, param_no);
00202                                         return E_UNSPEC;
00203                                 } else {
00204                                         // only a string
00205                                         return 0;
00206                                 }
00207                         }
00208                 }
00209                 *param = (void*)model;
00210         } else {
00211                 LM_ERR("wrong number of parameters\n");
00212         }
00213 
00214         return 0;
00215 }
00216 
00217 
00218 static int check_user_list(struct sip_msg *msg, char* str1, char* str2, char* str3, char* str4, int listtype)
00219 {
00220         str user = { .len = 0, .s = NULL };
00221         str domain = { .len = 0, .s = NULL};
00222         str table = { .len = 0, .s = NULL};
00223         str number = { .len = 0, .s = NULL};
00224 
00225         void **nodeflags;
00226         char *ptr;
00227         char req_number[MAXNUMBERLEN+1];
00228 
00229         /* user */
00230         if(((pv_elem_p)str1)->spec.getf) {
00231                 if(pv_printf_s(msg, (pv_elem_p)str1, &user) != 0) {
00232                         LM_ERR("cannot print user pseudo-variable\n");
00233                         return -1;
00234                 }
00235         }
00236         /* domain */
00237         if(((pv_elem_p)str2)->spec.getf) {
00238                 if(pv_printf_s(msg, (pv_elem_p)str2, &domain) != 0) {
00239                         LM_ERR("cannot print domain pseudo-variable\n");
00240                         return -1;
00241                 }
00242         }
00243         /* source number */
00244         if(str3 != NULL && ((pv_elem_p)str3)->spec.getf) {
00245                 if(pv_printf_s(msg, (pv_elem_p)str3, &number) != 0) {
00246                         LM_ERR("cannot print number pseudo-variable\n");
00247                         return -1;
00248                 }
00249         }
00250         /* table name */
00251         if(str4 != NULL && strlen(str4) > 0) {
00252                 /* string */
00253                 table.s=str4;
00254                 table.len=strlen(str4);
00255         } else {
00256                 /* use default table name */
00257                 table.len=userblacklist_table.len;
00258                 table.s=userblacklist_table.s;
00259         }
00260 
00261         if (msg->first_line.type != SIP_REQUEST) {
00262                 LM_ERR("SIP msg is not a request\n");
00263                 return -1;
00264         }
00265 
00266         if(number.s == NULL) {
00267                 /* use R-URI */
00268                 if ((parse_sip_msg_uri(msg) < 0) || (!msg->parsed_uri.user.s) || (msg->parsed_uri.user.len > MAXNUMBERLEN)) {
00269                         LM_ERR("cannot parse msg URI\n");
00270                         return -1;
00271                 }
00272                 strncpy(req_number, msg->parsed_uri.user.s, msg->parsed_uri.user.len);
00273                 req_number[msg->parsed_uri.user.len] = '\0';
00274         } else {
00275                 if (number.len > MAXNUMBERLEN) {
00276                         LM_ERR("number to long\n");
00277                         return -1;
00278                 }
00279                 strncpy(req_number, number.s, number.len);
00280                 req_number[number.len] = '\0';
00281         }
00282 
00283         LM_DBG("check entry %s for user %.*s on domain %.*s in table %.*s\n", req_number,
00284                 user.len, user.s, domain.len, domain.s, table.len, table.s);
00285         if (db_build_userbl_tree(&user, &domain, &table, dtrie_root, use_domain) < 0) {
00286                 LM_ERR("cannot build d-tree\n");
00287                 return -1;
00288         }
00289 
00290         ptr = req_number;
00291         /* Skip over non-digits.  */
00292         while (match_mode == 10 && strlen(ptr) > 0 && !isdigit(*ptr)) {
00293                 ptr = ptr + 1;
00294         }
00295 
00296         nodeflags = dtrie_longest_match(dtrie_root, ptr, strlen(ptr), NULL, match_mode);
00297         if (nodeflags) {
00298                 if (*nodeflags == (void *)MARK_WHITELIST) {
00299                         /* LM_ERR("whitelisted"); */
00300                         return 1; /* found, but is whitelisted */
00301                 }
00302         } else {
00303                 if(!listtype) {
00304                         /* LM_ERR("not found return 1"); */
00305                         return 1; /* not found is ok */
00306                 } else {
00307                         /* LM_ERR("not found return -1"); */
00308                         return -1; /* not found is not ok */
00309                 }
00310         }
00311         LM_DBG("entry %s is blacklisted\n", req_number);
00312         return -1;
00313 }
00314 
00315 
00316 static int check_user_whitelist(struct sip_msg *msg, char* str1, char* str2, char* str3, char* str4)
00317 {
00318         return check_user_list(msg, str1, str2, str3, str4, 1);
00319 }
00320 
00321 
00322 static int check_user_blacklist(struct sip_msg *msg, char* str1, char* str2, char* str3, char* str4)
00323 {
00324         return check_user_list(msg, str1, str2, str3, str4, 0);
00325 }
00326 
00327 static int check_user_whitelist2(struct sip_msg *msg, char* str1, char* str2)
00328 {
00329         return check_user_list(msg, str1, str2, NULL, NULL, 1);
00330 }
00331 
00332 
00333 static int check_user_blacklist2(struct sip_msg *msg, char* str1, char* str2)
00334 {
00335         return check_user_list(msg, str1, str2, NULL, NULL, 0);
00336 }
00337 
00338 static int check_user_whitelist3(struct sip_msg *msg, char* str1, char* str2, char* str3)
00339 {
00340         return check_user_list(msg, str1, str2, str3, NULL, 1);
00341 }
00342 
00343 
00344 static int check_user_blacklist3(struct sip_msg *msg, char* str1, char* str2, char* str3)
00345 {
00346         return check_user_list(msg, str1, str2, str3, NULL, 0);
00347 }
00348 
00349 
00354 static struct dtrie_node_t *table2dt(const char *table)
00355 {
00356         struct source_t *src = sources->head;
00357         while (src) {
00358                 if (strcmp(table, src->table) == 0) return src->dtrie_root;
00359                 src = src->next;
00360         }
00361 
00362         LM_ERR("invalid table '%s'.\n", table);
00363         return NULL;
00364 }
00365 
00366 
00372 static int add_source(const char *table)
00373 {
00374         /* check if the table is already present */
00375         struct source_t *src = sources->head;
00376         while (src) {
00377                 if (strcmp(table, src->table) == 0) return 0;
00378                 src = src->next;
00379         }
00380 
00381         src = shm_malloc(sizeof(struct source_t));
00382         if (!src) {
00383                 SHM_MEM_ERROR;
00384                 return -1;
00385         }
00386         memset(src, 0, sizeof(struct source_t));
00387 
00388         src->next = sources->head;
00389         sources->head = src;
00390 
00391         src->table = shm_malloc(strlen(table)+1);
00392         if (!src->table) {
00393                 SHM_MEM_ERROR;
00394                 shm_free(src);
00395                 return -1;
00396         }
00397         strcpy(src->table, table);
00398         LM_DBG("add table %s", table);
00399 
00400         src->dtrie_root = dtrie_init(match_mode);
00401 
00402         if (src->dtrie_root == NULL) {
00403                 LM_ERR("could not initialize data");
00404                 return -1;
00405         }
00406 
00407         return 0;
00408 }
00409 
00410 
00411 static int check_globalblacklist_fixup(void** param, int param_no)
00412 {
00413         char * table = globalblacklist_table.s;
00414         if(param_no > 0){
00415                 LM_ERR("Wrong number of parameters\n");
00416                 return -1;
00417         }
00418 
00419         if (!table) {
00420                 LM_ERR("no table name\n");
00421                 return -1;
00422         }
00423         /* try to add the table */
00424         if (add_source(table) != 0) {
00425                 LM_ERR("could not add table");
00426                 return -1;
00427         }
00428 
00429         gnode = table2dt(table);
00430         if (!gnode) {
00431                 LM_ERR("invalid table '%s'\n", table);
00432                 return -1;
00433         }
00434 
00435         return 0;
00436 }
00437 
00438 static int check_globalblacklist(struct sip_msg* msg)
00439 {
00440         static struct check_blacklist_fs_t* arg = NULL;
00441         if(!arg){
00442                 arg = pkg_malloc(sizeof(struct check_blacklist_fs_t));
00443                 if (!arg) {
00444                         PKG_MEM_ERROR;
00445                         return -1;
00446                 }
00447                 memset(arg, 0, sizeof(struct check_blacklist_fs_t));
00448                 arg->dtrie_root = gnode;
00449         }
00450         return check_blacklist(msg, arg);
00451 }
00452 
00453 static int check_blacklist_fixup(void **arg, int arg_no)
00454 {
00455         char *table = (char *)(*arg);
00456         struct dtrie_node_t *node = NULL;
00457         struct check_blacklist_fs_t *new_arg;
00458         
00459         if (arg_no != 1) {
00460                 LM_ERR("wrong number of parameters\n");
00461                 return -1;
00462         }
00463 
00464         if (!table) {
00465                 LM_ERR("no table name\n");
00466                 return -1;
00467         }
00468         /* try to add the table */
00469         if (add_source(table) != 0) {
00470                 LM_ERR("could not add table");
00471                 return -1;
00472         }       
00473 
00474         /* get the node that belongs to the table */
00475         node = table2dt(table);
00476         if (!node) {
00477                 LM_ERR("invalid table '%s'\n", table);
00478                 return -1;
00479         }
00480 
00481         new_arg = pkg_malloc(sizeof(struct check_blacklist_fs_t));
00482         if (!new_arg) {
00483                 PKG_MEM_ERROR;
00484                 return -1;
00485         }
00486         memset(new_arg, 0, sizeof(struct check_blacklist_fs_t));
00487         new_arg->dtrie_root = node;
00488         *arg=(void*)new_arg;
00489 
00490         return 0;
00491 }
00492 
00493 
00494 static int check_blacklist(struct sip_msg *msg, struct check_blacklist_fs_t *arg1)
00495 {
00496         void **nodeflags;
00497         char *ptr;
00498         char req_number[MAXNUMBERLEN+1];
00499         int ret = -1;
00500 
00501         if (msg->first_line.type != SIP_REQUEST) {
00502                 LM_ERR("SIP msg is not a request\n");
00503                 return -1;
00504         }
00505 
00506         if ((parse_sip_msg_uri(msg) < 0) || (!msg->parsed_uri.user.s) || (msg->parsed_uri.user.len > MAXNUMBERLEN)) {
00507                 LM_ERR("cannot parse msg URI\n");
00508                 return -1;
00509         }
00510         strncpy(req_number, msg->parsed_uri.user.s, msg->parsed_uri.user.len);
00511         req_number[msg->parsed_uri.user.len] = '\0';
00512 
00513         ptr = req_number;
00514         /* Skip over non-digits.  */
00515         while (match_mode == 10 && strlen(ptr) > 0 && !isdigit(*ptr)) {
00516                         ptr = ptr + 1;
00517         }
00518 
00519         LM_DBG("check entry %s\n", req_number);
00520 
00521         /* avoids dirty reads when updating d-tree */
00522         lock_get(lock);
00523         nodeflags = dtrie_longest_match(arg1->dtrie_root, ptr, strlen(ptr), NULL, match_mode);
00524         if (nodeflags) {
00525                 if (*nodeflags == (void *)MARK_WHITELIST) {
00526                         /* LM_DBG("whitelisted"); */
00527                         ret = 1; /* found, but is whitelisted */
00528                 }
00529         }
00530         else {
00531                 /* LM_ERR("not found"); */
00532                 ret = 1; /* not found is ok */
00533         }
00534         lock_release(lock);
00535 
00536         LM_DBG("entry %s is blacklisted\n", req_number);
00537         return ret;
00538 }
00539 
00540 
00545 static int reload_sources(void)
00546 {
00547         int result = 0;
00548         str tmp;
00549         struct source_t *src;
00550         int n;
00551 
00552         /* critical section start: avoids dirty reads when updating d-tree */
00553         lock_get(lock);
00554 
00555         src = sources->head;
00556         while (src) {
00557                 tmp.s = src->table;
00558                 tmp.len = strlen(src->table);
00559                 n = db_reload_source(&tmp, src->dtrie_root);
00560                 if (n < 0) {
00561                         LM_ERR("cannot reload source from '%.*s'\n", tmp.len, tmp.s);
00562                         result = -1;
00563                         break;
00564                 }
00565                 LM_INFO("got %d entries from '%.*s'\n", n, tmp.len, tmp.s);
00566                 src = src->next;
00567         }
00568 
00569         /* critical section end */
00570         lock_release(lock);
00571 
00572         return result;
00573 }
00574 
00575 
00576 static int init_source_list(void)
00577 {
00578         sources = shm_malloc(sizeof(struct source_list_t));
00579         if (!sources) {
00580                 SHM_MEM_ERROR;
00581                 return -1;
00582         }
00583         sources->head = NULL;
00584         return 0;
00585 }
00586 
00587 
00588 static void destroy_source_list(void)
00589 {
00590         if (sources) {
00591                 while (sources->head) {
00592                         struct source_t *src = sources->head;
00593                         sources->head = src->next;
00594 
00595                         if (src->table) shm_free(src->table);
00596                         dtrie_destroy(&(src->dtrie_root), NULL, match_mode);
00597                         shm_free(src);
00598                 }
00599 
00600                 shm_free(sources);
00601                 sources = NULL;
00602         }
00603 }
00604 
00605 
00606 static int init_shmlock(void)
00607 {
00608         lock = lock_alloc();
00609         if (!lock) {
00610                 LM_CRIT("cannot allocate memory for lock.\n");
00611                 return -1;
00612         }
00613         if (lock_init(lock) == 0) {
00614                 LM_CRIT("cannot initialize lock.\n");
00615                 return -1;
00616         }
00617 
00618         return 0;
00619 }
00620 
00621 
00622 static void destroy_shmlock(void)
00623 {
00624         if (lock) {
00625                 lock_destroy(lock);
00626                 lock_dealloc((void *)lock);
00627                 lock = NULL;
00628         }
00629 }
00630 
00631 
00632 struct mi_root * mi_reload_blacklist(struct mi_root* cmd, void* param)
00633 {
00634         struct mi_root * tmp = NULL;
00635         if(reload_sources() == 0) {
00636                 tmp = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00637         } else {
00638                 tmp = init_mi_tree( 500, "cannot reload blacklist", 21);
00639         }
00640 
00641         return tmp;
00642 }
00643 
00644 
00645 static int mod_init(void)
00646 {
00647         if(register_mi_mod(exports.name, mi_cmds)!=0)
00648         {
00649                 LM_ERR("failed to register MI commands\n");
00650                 return -1;
00651         }
00652 
00653         userblacklist_db_vars();
00654 
00655         if (userblacklist_db_init() != 0) return -1;
00656         if (init_shmlock() != 0) return -1;
00657         if (init_source_list() != 0) return -1;
00658         return 0;
00659 }
00660 
00661 
00662 static int child_init(int rank)
00663 {
00664         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00665                 return 0; /* do nothing for the main process */
00666 
00667         return mi_child_init();
00668 }
00669 
00670 
00671 static int userblacklist_child_initialized = 0;
00672 
00673 static int mi_child_init(void)
00674 {
00675         if(userblacklist_child_initialized)
00676                 return 0;
00677         if (userblacklist_db_open() != 0) return -1;
00678         dtrie_root=dtrie_init(match_mode);
00679         if (dtrie_root == NULL) {
00680                 LM_ERR("could not initialize data");
00681                 return -1;
00682         }
00683         /* because we've added new sources during the fixup */
00684         if (reload_sources() != 0) return -1;
00685 
00686         userblacklist_child_initialized = 1;
00687 
00688         return 0;
00689 }
00690 
00691 
00692 static void mod_destroy(void)
00693 {
00694         destroy_source_list();
00695         destroy_shmlock();
00696         userblacklist_db_close();
00697         dtrie_destroy(&dtrie_root, NULL, match_mode);
00698 }