/* * $Id: uac.c 1394 2006-12-13 18:57:29Z bogdan_iancu $ * * Copyright (C) 2005 Voice Sistem SRL * * This file is part of openser, a free SIP server. * * UAC OpenSER-module is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * UAC OpenSER-module is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * History: * --------- * 2005-01-31 first version (ramona) * 2005-08-12 some TM callbacks replaced with RR callback - more efficient; * (bogdan) * 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan) * 2006-03-03 the RR parameter is encrypted via XOR with a password * (bogdan) */ #include #include #include #include "../../sr_module.h" #include "../../dprint.h" #include "../../error.h" #include "../../items.h" #include "../../mem/mem.h" #include "../tm/tm_load.h" #include "../tm/t_hooks.h" #include "../rr/api.h" #include "from.h" #include "auth.h" MODULE_VERSION /* local variable used for init */ static char* from_restore_mode_str = NULL; static char* auth_username_avp = NULL; static char* auth_realm_avp = NULL; static char* auth_password_avp = NULL; /* global param variables */ str rr_param = str_init("vsf"); str uac_passwd = str_init(""); int from_restore_mode = FROM_AUTO_RESTORE; struct tm_binds uac_tmb; struct rr_binds uac_rrb; xl_spec_t auth_username_spec; xl_spec_t auth_realm_spec; xl_spec_t auth_password_spec; static int w_replace_from1(struct sip_msg* msg, char* str, char* str2); static int w_replace_from2(struct sip_msg* msg, char* str, char* str2); static int w_restore_from(struct sip_msg* msg, char* foo, char* bar); static int w_uac_auth(struct sip_msg* msg, char* str, char* str2); static int fixup_replace_from1(void** param, int param_no); static int fixup_replace_from2(void** param, int param_no); static int mod_init(void); static void mod_destroy(); /* Exported functions */ static cmd_export_t cmds[]={ {"uac_replace_from", w_replace_from2, 2, fixup_replace_from2, REQUEST_ROUTE }, {"uac_replace_from", w_replace_from1, 1, fixup_replace_from1, REQUEST_ROUTE }, {"uac_restore_from", w_restore_from, 0, 0, REQUEST_ROUTE }, {"uac_auth", w_uac_auth, 0, 0, FAILURE_ROUTE }, {0,0,0,0,0} }; /* Exported parameters */ static param_export_t params[] = { {"rr_store_param", STR_PARAM, &rr_param.s }, {"from_restore_mode", STR_PARAM, &from_restore_mode_str }, {"from_passwd", STR_PARAM, &uac_passwd.s }, {"credential", STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential }, {"auth_username_avp", STR_PARAM, &auth_username_avp }, {"auth_realm_avp", STR_PARAM, &auth_realm_avp }, {"auth_password_avp", STR_PARAM, &auth_password_avp }, {0, 0, 0} }; struct module_exports exports= { "uac", DEFAULT_DLFLAGS, /* dlopen flags */ cmds, /* exported functions */ params, /* param exports */ 0, /* exported statistics */ 0, /* exported MI functions */ 0, /* exported pseudo-variables */ mod_init, /* module initialization function */ (response_function) 0, mod_destroy, 0 /* per-child init function */ }; inline static int parse_auth_avp( char *avp_spec, xl_spec_t *avp, char *txt) { if (xl_parse_spec( avp_spec, avp, XL_THROW_ERROR|XL_DISABLE_MULTI| XL_DISABLE_COLORS)==0 || avp->type!=XL_AVP) { LOG(L_ERR, "ERROR:uac:parse_auth_avp: malformed or non AVP %s " "AVP definition\n",txt); return -1; } return 0; } static int mod_init(void) { LOG(L_INFO,"UAC - initializing\n"); if (from_restore_mode_str && *from_restore_mode_str) { if (strcasecmp(from_restore_mode_str,"none")==0) { from_restore_mode = FROM_NO_RESTORE; } else if (strcasecmp(from_restore_mode_str,"manual")==0) { from_restore_mode = FROM_MANUAL_RESTORE; } else if (strcasecmp(from_restore_mode_str,"auto")==0) { from_restore_mode = FROM_AUTO_RESTORE; } else { LOG(L_ERR,"ERROR:uac:mod_init: unsupported value '%s' for " "from_restore_mode\n",from_restore_mode_str); goto error; } } rr_param.len = strlen(rr_param.s); if (rr_param.len==0 && from_restore_mode!=FROM_NO_RESTORE) { LOG(L_ERR,"ERROR:uac:mod_init: rr_store_param cannot be empty " "if FROM is restoreable\n"); goto error; } uac_passwd.len = strlen(uac_passwd.s); /* parse the auth AVP spesc, if any */ if ( auth_username_avp || auth_password_avp || auth_realm_avp) { if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) { LOG(L_ERR,"ERROR:uac:mod_init: partial definition of auth AVP!"); goto error; } if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0 || parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0 || parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0 ) { goto error; } } else { memset( &auth_realm_spec, 0, sizeof(xl_spec_t)); memset( &auth_password_spec, 0, sizeof(xl_spec_t)); memset( &auth_username_spec, 0, sizeof(xl_spec_t)); } /* load the TM API - FIXME it should be loaded only * if NO_RESTORE and AUTH */ if (load_tm_api(&uac_tmb)!=0) { LOG(L_ERR, "ERROR:uac:mod_init: can't load TM API\n"); goto error; } if (from_restore_mode!=FROM_NO_RESTORE) { /* load the RR API */ if (load_rr_api(&uac_rrb)!=0) { LOG(L_ERR, "ERROR:uac:mod_init: can't load RR API\n"); goto error; } if (from_restore_mode==FROM_AUTO_RESTORE) { /* get all requests doing loose route */ if (uac_rrb.register_rrcb( rr_checker, 0)!=0) { LOG(L_ERR,"ERROR:uac:mod_init: failed to install " "RR callback\n"); goto error; } } } init_from_replacer(); return 0; error: return -1; } static void mod_destroy() { destroy_credentials(); } /************************** fixup functions ******************************/ static int fixup_replace_from1(void** param, int param_no) { xl_elem_t *model; model=NULL; if(xl_parse_format((char*)(*param),&model,XL_DISABLE_COLORS)<0) { LOG(L_ERR, "ERROR:uac:fixup_replace_from1: wrong format[%s]!\n", (char*)(*param)); return E_UNSPEC; } if (model==NULL) { LOG(L_ERR, "ERROR:uac:fixup_replace_from1: empty parameter!\n"); return E_UNSPEC; } *param = (void*)model; return 0; } static int fixup_replace_from2(void** param, int param_no) { xl_elem_t *model; char *p; str s; /* convert to str */ s.s = (char*)*param; s.len = strlen(s.s); model=NULL; if (param_no==1) { if (s.len) { /* put " around display name */ p = (char*)pkg_malloc(s.len+3); if (p==0) { LOG(L_CRIT,"ERROR:uac:fixup_replace_from2: no more pkg mem\n"); return E_OUT_OF_MEM; } p[0] = '\"'; memcpy(p+1, s.s, s.len); p[s.len+1] = '\"'; p[s.len+2] = '\0'; pkg_free(s.s); s.s = p; s.len += 2; } } if(s.len!=0) { if(xl_parse_format(s.s,&model,XL_DISABLE_COLORS)<0) { LOG(L_ERR, "ERROR:uac:fixup_replace_from2: wrong format [%s] " "for param no %d!\n", s.s, param_no); pkg_free(s.s); return E_UNSPEC; } } *param = (void*)model; return 0; } /************************** wrapper functions ******************************/ static int w_restore_from(struct sip_msg *msg, char* foo, char* bar) { /* safety checks - must be a request */ if (msg->first_line.type!=SIP_REQUEST) { LOG(L_ERR,"ERROR:uac:w_restore_from: called for something " "not request\n"); return -1; } return (restore_from(msg,0)==0)?1:-1; } static int w_replace_from1(struct sip_msg* msg, char* uri, char* str2) { str uri_s; if(xl_printf_s( msg, (xl_elem_p)uri, &uri_s)!=0) return -1; return (replace_from(msg, 0, &uri_s)==0)?1:-1; } static int w_replace_from2(struct sip_msg* msg, char* dsp, char* uri) { str uri_s; str dsp_s; if (dsp!=NULL) { if(dsp!=NULL) if(xl_printf_s( msg, (xl_elem_p)dsp, &dsp_s)!=0) return -1; } else { dsp_s.s = 0; dsp_s.len = 0; } if(uri!=NULL) { if(xl_printf_s( msg, (xl_elem_p)uri, &uri_s)!=0) return -1; } return (replace_from(msg, &dsp_s, (uri)?&uri_s:0)==0)?1:-1; } static int w_uac_auth(struct sip_msg* msg, char* str, char* str2) { return (uac_auth(msg)==0)?1:-1; }