k/uac/uac.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2005 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * UAC Kamailio-module is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * UAC Kamailio-module 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  *
00023  * History:
00024  * ---------
00025  *  2005-01-31  first version (ramona)
00026  *  2005-08-12  some TM callbacks replaced with RR callback - more efficient;
00027  *              (bogdan)
00028  *  2006-03-02  UAC authentication looks first in AVPs for credential (bogdan)
00029  *  2006-03-03  the RR parameter is encrypted via XOR with a password
00030  *              (bogdan)
00031 
00032  */
00033 
00034 
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 
00040 #include "../../sr_module.h"
00041 #include "../../dprint.h"
00042 #include "../../error.h"
00043 #include "../../pvar.h"
00044 #include "../../pt.h"
00045 #include "../../timer.h"
00046 #include "../../mem/mem.h"
00047 #include "../../parser/parse_from.h"
00048 #include "../../modules/tm/tm_load.h"
00049 #include "../../modules/tm/t_hooks.h"
00050 #include "../../mod_fix.h"
00051 #include "../../rpc.h"
00052 #include "../../rpc_lookup.h"
00053 #include "../../cfg/cfg_struct.h"
00054 
00055 #include "../rr/api.h"
00056 
00057 #include "replace.h"
00058 #include "auth.h"
00059 #include "uac_send.h"
00060 #include "uac_reg.h"
00061 #include "api.h"
00062 
00063 
00064 MODULE_VERSION
00065 
00066 
00067 /* local variable used for init */
00068 static char* restore_mode_str = NULL;
00069 static char* auth_username_avp = NULL;
00070 static char* auth_realm_avp = NULL;
00071 static char* auth_password_avp = NULL;
00072 unsigned short restore_from_avp_type;
00073 int_str restore_from_avp_name;
00074 unsigned short restore_to_avp_type;
00075 int_str restore_to_avp_name;
00076 
00077 /* global param variables */
00078 str rr_from_param = str_init("vsf");
00079 str rr_to_param = str_init("vst");
00080 str uac_passwd = str_init("");
00081 str restore_from_avp = {0 ,0 };
00082 str restore_to_avp = {0 ,0 };
00083 int restore_mode = UAC_AUTO_RESTORE;
00084 struct tm_binds uac_tmb;
00085 struct rr_binds uac_rrb;
00086 pv_spec_t auth_username_spec;
00087 pv_spec_t auth_realm_spec;
00088 pv_spec_t auth_password_spec;
00089 
00090 static int w_replace_from(struct sip_msg* msg, char* p1, char* p2);
00091 static int w_restore_from(struct sip_msg* msg);
00092 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2);
00093 static int w_restore_to(struct sip_msg* msg);
00094 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2);
00095 static int w_uac_reg_lookup(struct sip_msg* msg,  char* src, char* dst);
00096 static int w_uac_reg_request_to(struct sip_msg* msg,  char* src, char* mode_s);
00097 static int fixup_replace_uri(void** param, int param_no);
00098 static int fixup_replace_disp_uri(void** param, int param_no);
00099 static int mod_init(void);
00100 static void mod_destroy(void);
00101 static int child_init(int rank);
00102 
00103 extern int reg_timer_interval;
00104 
00105 static pv_export_t mod_pvs[] = {
00106         { {"uac_req", sizeof("uac_req")-1}, PVT_OTHER, pv_get_uac_req, pv_set_uac_req,
00107                 pv_parse_uac_req_name, 0, 0, 0 },
00108         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00109 };
00110 
00111 
00112 /* Exported functions */
00113 static cmd_export_t cmds[]={
00114         {"uac_replace_from",  (cmd_function)w_replace_from,  2, fixup_replace_disp_uri, 0,
00115                         REQUEST_ROUTE | BRANCH_ROUTE },
00116         {"uac_replace_from",  (cmd_function)w_replace_from,  1, fixup_replace_uri, 0,
00117                         REQUEST_ROUTE | BRANCH_ROUTE },
00118         {"uac_restore_from",  (cmd_function)w_restore_from,  0,                  0, 0,
00119                         REQUEST_ROUTE },
00120         {"uac_replace_to",  (cmd_function)w_replace_to,  2, fixup_replace_disp_uri, 0,
00121                         REQUEST_ROUTE | BRANCH_ROUTE },
00122         {"uac_replace_to",  (cmd_function)w_replace_to,  1, fixup_replace_uri, 0,
00123                         REQUEST_ROUTE | BRANCH_ROUTE },
00124         {"uac_restore_to",  (cmd_function)w_restore_to,  0, 0, 0,
00125                         REQUEST_ROUTE },
00126         {"uac_auth",          (cmd_function)w_uac_auth,       0,                  0, 0,
00127                         FAILURE_ROUTE },
00128         {"uac_req_send",  (cmd_function)uac_req_send,         0,                  0, 0, 
00129                 REQUEST_ROUTE | FAILURE_ROUTE |
00130                 ONREPLY_ROUTE | BRANCH_ROUTE | ERROR_ROUTE | LOCAL_ROUTE},
00131         {"uac_reg_lookup",  (cmd_function)w_uac_reg_lookup,  2, fixup_pvar_pvar,
00132                 fixup_free_pvar_pvar, ANY_ROUTE },
00133         {"uac_reg_request_to",  (cmd_function)w_uac_reg_request_to,  2, fixup_pvar_uint, fixup_free_pvar_uint,
00134                 REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE },
00135         {"bind_uac", (cmd_function)bind_uac,                  1,                  0, 0,
00136                 0},
00137         {0,0,0,0,0,0}
00138 };
00139 
00140 
00141 
00142 /* Exported parameters */
00143 static param_export_t params[] = {
00144         {"rr_from_store_param", STR_PARAM,                              &rr_from_param.s       },
00145         {"rr_to_store_param",   STR_PARAM,                              &rr_to_param.s       },
00146         {"restore_mode",        STR_PARAM,                              &restore_mode_str      },
00147         {"restore_passwd",      STR_PARAM,                              &uac_passwd.s          },
00148         {"restore_from_avp",    STR_PARAM,                              &restore_from_avp.s },
00149         {"restore_to_avp",              STR_PARAM,                              &restore_to_avp.s },
00150         {"credential",        STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential },
00151         {"auth_username_avp", STR_PARAM,                &auth_username_avp     },
00152         {"auth_realm_avp",    STR_PARAM,                &auth_realm_avp        },
00153         {"auth_password_avp", STR_PARAM,                &auth_password_avp     },
00154         {"reg_db_url",        STR_PARAM,                &reg_db_url.s          },
00155         {"reg_contact_addr",  STR_PARAM,                &reg_contact_addr.s    },
00156         {"reg_timer_interval", INT_PARAM,               &reg_timer_interval     },
00157         {0, 0, 0}
00158 };
00159 
00160 
00161 
00162 struct module_exports exports= {
00163         "uac",
00164         DEFAULT_DLFLAGS, /* dlopen flags */
00165         cmds,       /* exported functions */
00166         params,     /* param exports */
00167         0,          /* exported statistics */
00168         0,          /* exported MI functions */
00169         mod_pvs,    /* exported pseudo-variables */
00170         0,          /* extra processes */
00171         mod_init,   /* module initialization function */
00172         0,
00173         mod_destroy,
00174         child_init  /* per-child init function */
00175 };
00176 
00177 
00178 inline static int parse_auth_avp( char *avp_spec, pv_spec_t *avp, char *txt)
00179 {
00180         str s;
00181         s.s = avp_spec; s.len = strlen(s.s);
00182         if (pv_parse_spec(&s, avp)==NULL) {
00183                 LM_ERR("malformed or non AVP %s AVP definition\n",txt);
00184                 return -1;
00185         }
00186         return 0;
00187 }
00188 
00189 
00190 static int mod_init(void)
00191 {
00192         pv_spec_t avp_spec;
00193 
00194         if (restore_mode_str && *restore_mode_str) {
00195                 if (strcasecmp(restore_mode_str,"none")==0) {
00196                 restore_mode = UAC_NO_RESTORE;
00197             } else if (strcasecmp(restore_mode_str,"manual")==0) {
00198                 restore_mode = UAC_MANUAL_RESTORE;
00199             } else if (strcasecmp(restore_mode_str,"auto")==0) {
00200                         restore_mode = UAC_AUTO_RESTORE;
00201                 } else {
00202                         LM_ERR("unsupported value '%s' for restore_mode\n",  restore_mode_str);
00203                         goto error;
00204                 }
00205         }
00206 
00207         rr_from_param.len = strlen(rr_from_param.s);
00208         rr_to_param.len = strlen(rr_to_param.s);
00209         if ( (rr_from_param.len==0 || rr_to_param.len==0) && restore_mode!=UAC_NO_RESTORE)
00210         {
00211                 LM_ERR("rr_store_param cannot be empty if FROM is restoreable\n");
00212                 goto error;
00213         }
00214 
00215         uac_passwd.len = strlen(uac_passwd.s);
00216 
00217         /* parse the auth AVP spesc, if any */
00218         if ( auth_username_avp || auth_password_avp || auth_realm_avp) {
00219                 if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) {
00220                         LM_ERR("partial definition of auth AVP!");
00221                         goto error;
00222                 }
00223                 if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0
00224                 || parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0
00225                 || parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0
00226                 ) {
00227                         goto error;
00228                 }
00229         } else {
00230                 memset( &auth_realm_spec, 0, sizeof(pv_spec_t));
00231                 memset( &auth_password_spec, 0, sizeof(pv_spec_t));
00232                 memset( &auth_username_spec, 0, sizeof(pv_spec_t));
00233         }
00234 
00235         /* load the TM API - FIXME it should be loaded only
00236          * if NO_RESTORE and AUTH */
00237         if (load_tm_api(&uac_tmb)!=0) {
00238                 LM_ERR("can't load TM API\n");
00239                 goto error;
00240         }
00241 
00242         if (restore_mode!=UAC_NO_RESTORE) {
00243                 /* load the RR API */
00244                 if (load_rr_api(&uac_rrb)!=0) {
00245                         LM_ERR("can't load RR API\n");
00246                         goto error;
00247                 }
00248 
00249 
00250                 if(restore_from_avp.s) {
00251 
00252                         restore_from_avp.len = strlen(restore_from_avp.s);
00253 
00254                         if (pv_parse_spec(&restore_from_avp, &avp_spec)==0      || avp_spec.type!=PVT_AVP) {
00255                                 LM_ERR("malformed or non AVP %.*s AVP definition\n", restore_from_avp.len, restore_from_avp.s);
00256                                 return -1;
00257                         }
00258 
00259                         if(pv_get_avp_name(0, &avp_spec.pvp, &restore_from_avp_name, &restore_from_avp_type)!=0) {
00260                                 LM_ERR("[%.*s]- invalid AVP definition\n", restore_from_avp.len, restore_from_avp.s);
00261                                 return -1;
00262                         }
00263 
00264                         restore_from_avp_type |= AVP_VAL_STR;
00265 
00266                 }
00267 
00268                 if(restore_to_avp.s) {
00269 
00270                         restore_to_avp.len = strlen(restore_to_avp.s);
00271 
00272                         if (pv_parse_spec(&restore_to_avp, &avp_spec)==0        || avp_spec.type!=PVT_AVP) {
00273                                 LM_ERR("malformed or non AVP %.*s AVP definition\n", restore_to_avp.len, restore_to_avp.s);
00274                                 return -1;
00275                         }
00276 
00277                         if(pv_get_avp_name(0, &avp_spec.pvp, &restore_to_avp_name, &restore_to_avp_type)!=0) {
00278                                 LM_ERR("[%.*s]- invalid AVP definition\n", restore_to_avp.len, restore_to_avp.s);
00279                                 return -1;
00280                         }
00281 
00282                         restore_to_avp_type |= AVP_VAL_STR;
00283 
00284                 }
00285 
00286 
00287                 if (restore_mode==UAC_AUTO_RESTORE) {
00288                         /* we need the append_fromtag on in RR */
00289                         if (!uac_rrb.append_fromtag) {
00290                                 LM_ERR("'append_fromtag' RR param is not enabled"
00291                                         " - required by AUTO restore mode!"
00292                                         " Or you should set from_restore_mode param to 'none'\n");
00293                                 goto error;
00294                         }
00295                         /* get all requests doing loose route */
00296                         if (uac_rrb.register_rrcb( rr_checker, 0)!=0) {
00297                                 LM_ERR("failed to install RR callback\n");
00298                                 goto error;
00299                         }
00300                 }
00301         }
00302 
00303         if(reg_db_url.s!=NULL)
00304         {
00305                 if(reg_contact_addr.s==NULL)
00306                 {
00307                         LM_ERR("contact address parameter not set\n");
00308                         goto error;
00309                 }
00310                 if(reg_htable_size>14)
00311                         reg_htable_size = 14;
00312                 if(reg_htable_size<2)
00313                         reg_htable_size = 2;
00314 
00315                 reg_htable_size = 1<<reg_htable_size;
00316                 if(uac_reg_init_rpc()!=0)
00317                 {
00318                         LM_ERR("failed to register RPC commands\n");
00319                         goto error;
00320                 }
00321                 if(uac_reg_init_ht(reg_htable_size)<0)
00322                 {
00323                         LM_ERR("failed to init reg htable\n");
00324                         goto error;
00325                 }
00326                 uac_reg_init_db();
00327                 register_procs(1);
00328                 /* add child to update local config framework structures */
00329                 cfg_register_child(1);
00330         }
00331         init_from_replacer();
00332 
00333         uac_req_init();
00334 
00335         return 0;
00336 error:
00337         return -1;
00338 }
00339 
00340 static int child_init(int rank)
00341 {
00342         int pid;
00343         if (rank!=PROC_MAIN)
00344                 return 0;
00345 
00346         if(reg_db_url.s==NULL)
00347                 return 0;
00348 
00349         pid=fork_process(PROC_TIMER, "TIMER UAC REG", 1);
00350         if (pid<0)
00351         {
00352                 LM_ERR("failed to register timer routine as process\n");
00353                 return -1;
00354         }
00355         if (pid==0){
00356                 /* child */
00357                 /* initialize the config framework */
00358                 if (cfg_child_init())
00359                         return -1;
00360 
00361                 uac_reg_load_db();
00362                 uac_reg_timer(0);
00363                 for(;;){
00364                         /* update the local config framework structures */
00365                         cfg_update();
00366 
00367                         sleep(reg_timer_interval);
00368                         uac_reg_timer(get_ticks());
00369                 }
00370         }
00371         /* parent */
00372         return 0;
00373 }
00374 
00375 static void mod_destroy(void)
00376 {
00377         destroy_credentials();
00378 }
00379 
00380 
00381 
00382 /************************** fixup functions ******************************/
00383 
00384 static int fixup_replace_uri(void** param, int param_no)
00385 {
00386         pv_elem_t *model;
00387         str s;
00388 
00389         model=NULL;
00390         s.s = (char*)(*param); s.len = strlen(s.s);
00391         if(pv_parse_format(&s, &model)<0)
00392         {
00393                 LM_ERR("wrong format[%s]!\n",(char*)(*param));
00394                 return E_UNSPEC;
00395         }
00396         if (model==NULL)
00397         {
00398                 LM_ERR("empty parameter!\n");
00399                 return E_UNSPEC;
00400         }
00401         *param = (void*)model;
00402 
00403         return 0;
00404 }
00405 
00406 
00407 static int fixup_replace_disp_uri(void** param, int param_no)
00408 {
00409         pv_elem_t *model;
00410         char *p;
00411         str s;
00412 
00413         /* convert to str */
00414         s.s = (char*)*param;
00415         s.len = strlen(s.s);
00416 
00417         model=NULL;
00418         if (param_no==1)
00419         {
00420                 if (s.len)
00421                 {
00422                         /* put " around display name */
00423                         p = (char*)pkg_malloc(s.len+3);
00424                         if (p==0)
00425                         {
00426                                 LM_CRIT("no more pkg mem\n");
00427                                 return E_OUT_OF_MEM;
00428                         }
00429                         p[0] = '\"';
00430                         memcpy(p+1, s.s, s.len);
00431                         p[s.len+1] = '\"';
00432                         p[s.len+2] = '\0';
00433                         pkg_free(s.s);
00434                         s.s = p;
00435                         s.len += 2;
00436                 }
00437         }
00438         if(s.len!=0)
00439         {
00440                 if(pv_parse_format(&s ,&model)<0)
00441                 {
00442                         LM_ERR("wrong format [%s] for param no %d!\n", s.s, param_no);
00443                         pkg_free(s.s);
00444                         return E_UNSPEC;
00445                 }
00446         }
00447         *param = (void*)model;
00448 
00449         return 0;
00450 }
00451 
00452 
00453 
00454 /************************** wrapper functions ******************************/
00455 
00456 static int w_restore_from(struct sip_msg *msg)
00457 {
00458         /* safety checks - must be a request */
00459         if (msg->first_line.type!=SIP_REQUEST) {
00460                 LM_ERR("called for something not request\n");
00461                 return -1;
00462         }
00463 
00464         return (restore_uri(msg,&rr_from_param,&restore_from_avp,1)==0)?1:-1;
00465 }
00466 
00467 
00468 int w_replace_from(struct sip_msg* msg, char* p1, char* p2)
00469 {
00470         str uri_s;
00471         str dsp_s;
00472         str *uri;
00473         str *dsp;
00474 
00475         if (p2==NULL) {
00476                  p2 = p1;
00477                  p1 = NULL;
00478                  dsp = NULL;
00479         }
00480 
00481         /* p1 display , p2 uri */
00482 
00483         if ( p1!=NULL ) {
00484                 if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0)
00485                         return -1;
00486                 dsp = &dsp_s;
00487         }
00488 
00489         /* compute the URI string; if empty string -> make it NULL */
00490         if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0)
00491                 return -1;
00492         uri = uri_s.len?&uri_s:NULL;
00493 
00494         if (parse_from_header(msg)<0 ) {
00495                 LM_ERR("failed to find/parse FROM hdr\n");
00496                 return -1;
00497         }
00498 
00499         LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n",dsp,dsp?dsp->len:0,uri,uri?uri->len:0);
00500 
00501         return (replace_uri(msg, dsp, uri, msg->from, &rr_from_param, &restore_from_avp, 1)==0)?1:-1;
00502 
00503 }
00504 
00505 int replace_from_api(sip_msg_t *msg, str* pd, str* pu)
00506 {
00507         str *uri;
00508         str *dsp;
00509         if (parse_from_header(msg)<0 ) {
00510                 LM_ERR("failed to find/parse FROM hdr\n");
00511                 return -1;
00512         }
00513 
00514         uri = (pu!=NULL && pu->len>0)?pu:NULL;
00515         dsp = (pd!=NULL && pd->len>0)?pd:NULL;
00516 
00517         LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n", dsp, dsp?dsp->len:0,
00518                         uri, uri?uri->len:0);
00519 
00520         return replace_uri(msg, dsp, uri, msg->from, &rr_from_param, &restore_from_avp, 1);
00521 }
00522 
00523 static int w_restore_to(struct sip_msg *msg)
00524 {
00525         /* safety checks - must be a request */
00526         if (msg->first_line.type!=SIP_REQUEST) {
00527                 LM_ERR("called for something not request\n");
00528                 return -1;
00529         }
00530 
00531         return (restore_uri(msg,&rr_to_param,&restore_to_avp,0)==0)?1:-1;
00532 }
00533 
00534 
00535 static int w_replace_to(struct sip_msg* msg, char* p1, char* p2)
00536 {
00537         str uri_s;
00538         str dsp_s;
00539         str *uri;
00540         str *dsp;
00541 
00542         if (p2==NULL) {
00543                 p2 = p1;
00544                 p1 = NULL;
00545                 dsp = NULL;
00546         }
00547 
00548          /* p1 display , p2 uri */
00549 
00550         if( p1!=NULL ) {
00551                 if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0)
00552                         return -1;
00553                 dsp = &dsp_s;
00554         }
00555 
00556         /* compute the URI string; if empty string -> make it NULL */
00557         if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0)
00558                 return -1;
00559         uri = uri_s.len?&uri_s:NULL;
00560 
00561         /* parse TO hdr */
00562         if ( msg->to==0 && (parse_headers(msg,HDR_TO_F,0)!=0 || msg->to==0) ) {
00563                 LM_ERR("failed to parse TO hdr\n");
00564                 return -1;
00565         }
00566 
00567         return (replace_uri(msg, dsp, uri, msg->to, &rr_to_param, &restore_to_avp, 0)==0)?1:-1;
00568 
00569 }
00570 
00571 
00572 static int w_uac_auth(struct sip_msg* msg, char* str, char* str2)
00573 {
00574         return (uac_auth(msg)==0)?1:-1;
00575 }
00576 
00577 
00578 static int w_uac_reg_lookup(struct sip_msg* msg,  char* src, char* dst)
00579 {
00580         pv_spec_t *spv;
00581         pv_spec_t *dpv;
00582         pv_value_t val;
00583 
00584         spv = (pv_spec_t*)src;
00585         dpv = (pv_spec_t*)dst;
00586         if(pv_get_spec_value(msg, spv, &val) != 0)
00587         {
00588                 LM_ERR("cannot get src uri value\n");
00589                 return -1;
00590         }
00591 
00592         if (!(val.flags & PV_VAL_STR))
00593         {
00594             LM_ERR("src pv value is not string\n");
00595             return -1;
00596         }
00597         return uac_reg_lookup(msg, &val.rs, dpv, 0);
00598 }
00599 
00600 
00601 static int w_uac_reg_request_to(struct sip_msg* msg, char* src, char* mode_s)
00602 {
00603         pv_spec_t *spv;
00604         pv_value_t val;
00605         unsigned int mode;
00606 
00607         mode = (unsigned int)(long)mode_s;
00608 
00609         spv = (pv_spec_t*)src;
00610         if(pv_get_spec_value(msg, spv, &val) != 0)
00611         {
00612                 LM_ERR("cannot get src uri value\n");
00613                 return -1;
00614         }
00615 
00616         if (!(val.flags & PV_VAL_STR))
00617         {
00618             LM_ERR("src pv value is not string\n");
00619             return -1;
00620         }
00621 
00622         if (mode > 1)
00623         {
00624                 LM_ERR("invalid mode\n");
00625                 return -1;
00626         }
00627 
00628         return uac_reg_request_to(msg, &val.rs, mode);
00629 }
00630 
00631 
00632 int bind_uac(struct uac_binds *uacb)
00633 {
00634         if (uacb == NULL)
00635         {
00636                 LM_WARN("bind_uac: Cannot load uac API into a NULL pointer\n");
00637                 return -1;
00638         }
00639 
00640         uacb->replace_from = replace_from_api;
00641         return 0;
00642 }