Wed, 10 Feb 2010 21:14:04 +0100
Import unmodified vendor sources for correction and improvement.
michael@16 | 1 | /* |
michael@16 | 2 | * $Id: uac.c 6481 2009-12-29 13:49:37Z bogdan_iancu $ |
michael@16 | 3 | * |
michael@16 | 4 | * Copyright (C) 2005-2009 Voice Sistem SRL |
michael@16 | 5 | * |
michael@16 | 6 | * This file is part of opensips, a free SIP server. |
michael@16 | 7 | * |
michael@16 | 8 | * UAC OpenSIPS-module is free software; you can redistribute it and/or |
michael@16 | 9 | * modify it under the terms of the GNU General Public License |
michael@16 | 10 | * as published by the Free Software Foundation; either version 2 |
michael@16 | 11 | * of the License, or (at your option) any later version. |
michael@16 | 12 | * |
michael@16 | 13 | * UAC OpenSIPS-module is distributed in the hope that it will be useful, |
michael@16 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
michael@16 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
michael@16 | 16 | * GNU General Public License for more details. |
michael@16 | 17 | * |
michael@16 | 18 | * You should have received a copy of the GNU General Public License |
michael@16 | 19 | * along with this program; if not, write to the Free Software |
michael@16 | 20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
michael@16 | 21 | * |
michael@16 | 22 | * |
michael@16 | 23 | * History: |
michael@16 | 24 | * --------- |
michael@16 | 25 | * 2005-01-31 first version (ramona) |
michael@16 | 26 | * 2005-08-12 some TM callbacks replaced with RR callback - more efficient; |
michael@16 | 27 | * (bogdan) |
michael@16 | 28 | * 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan) |
michael@16 | 29 | * 2006-03-03 the RR parameter is encrypted via XOR with a password |
michael@16 | 30 | * (bogdan) |
michael@16 | 31 | * 2009-08-22 TO header replacement added (bogdan) |
michael@16 | 32 | |
michael@16 | 33 | */ |
michael@16 | 34 | |
michael@16 | 35 | |
michael@16 | 36 | #include <stdio.h> |
michael@16 | 37 | #include <string.h> |
michael@16 | 38 | #include <stdlib.h> |
michael@16 | 39 | |
michael@16 | 40 | #include "../../sr_module.h" |
michael@16 | 41 | #include "../../dprint.h" |
michael@16 | 42 | #include "../../error.h" |
michael@16 | 43 | #include "../../pvar.h" |
michael@16 | 44 | #include "../../mem/mem.h" |
michael@16 | 45 | #include "../../parser/parse_from.h" |
michael@16 | 46 | #include "../tm/tm_load.h" |
michael@16 | 47 | #include "../tm/t_hooks.h" |
michael@16 | 48 | #include "../rr/api.h" |
michael@16 | 49 | |
michael@16 | 50 | #include "replace.h" |
michael@16 | 51 | #include "auth.h" |
michael@16 | 52 | |
michael@16 | 53 | |
michael@16 | 54 | |
michael@16 | 55 | |
michael@16 | 56 | |
michael@16 | 57 | /* local variable used for init */ |
michael@16 | 58 | static char* restore_mode_str = NULL; |
michael@16 | 59 | static char* auth_username_avp = NULL; |
michael@16 | 60 | static char* auth_realm_avp = NULL; |
michael@16 | 61 | static char* auth_password_avp = NULL; |
michael@16 | 62 | |
michael@16 | 63 | /* global param variables */ |
michael@16 | 64 | str rr_from_param = str_init("vsf"); |
michael@16 | 65 | str rr_to_param = str_init("vst"); |
michael@16 | 66 | str uac_passwd = str_init(""); |
michael@16 | 67 | int restore_mode = UAC_AUTO_RESTORE; |
michael@16 | 68 | struct tm_binds uac_tmb; |
michael@16 | 69 | struct rr_binds uac_rrb; |
michael@16 | 70 | pv_spec_t auth_username_spec; |
michael@16 | 71 | pv_spec_t auth_realm_spec; |
michael@16 | 72 | pv_spec_t auth_password_spec; |
michael@16 | 73 | |
michael@16 | 74 | static int w_replace_from(struct sip_msg* msg, char* p1, char* p2); |
michael@16 | 75 | static int w_restore_from(struct sip_msg* msg); |
michael@16 | 76 | |
michael@16 | 77 | static int w_replace_to(struct sip_msg* msg, char* p1, char* p2); |
michael@16 | 78 | static int w_restore_to(struct sip_msg* msg); |
michael@16 | 79 | |
michael@16 | 80 | static int w_uac_auth(struct sip_msg* msg, char* str, char* str2); |
michael@16 | 81 | static int fixup_replace_uri(void** param, int param_no); |
michael@16 | 82 | static int fixup_replace_disp_uri(void** param, int param_no); |
michael@16 | 83 | static int mod_init(void); |
michael@16 | 84 | static void mod_destroy(void); |
michael@16 | 85 | |
michael@16 | 86 | |
michael@16 | 87 | /* Exported functions */ |
michael@16 | 88 | static cmd_export_t cmds[]={ |
michael@16 | 89 | {"uac_replace_from", (cmd_function)w_replace_from, 2, |
michael@16 | 90 | fixup_replace_disp_uri, 0, |
michael@16 | 91 | REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, |
michael@16 | 92 | {"uac_replace_from", (cmd_function)w_replace_from, 1, |
michael@16 | 93 | fixup_replace_uri, 0, |
michael@16 | 94 | REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, |
michael@16 | 95 | {"uac_restore_from", (cmd_function)w_restore_from, 0, |
michael@16 | 96 | 0, 0, |
michael@16 | 97 | REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, |
michael@16 | 98 | {"uac_replace_to", (cmd_function)w_replace_to, 2, |
michael@16 | 99 | fixup_replace_disp_uri, 0, |
michael@16 | 100 | REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, |
michael@16 | 101 | {"uac_replace_to", (cmd_function)w_replace_to, 1, |
michael@16 | 102 | fixup_replace_uri, 0, |
michael@16 | 103 | REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, |
michael@16 | 104 | {"uac_restore_to", (cmd_function)w_restore_to, 0, |
michael@16 | 105 | 0, 0, |
michael@16 | 106 | REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, |
michael@16 | 107 | {"uac_auth", (cmd_function)w_uac_auth, 0, |
michael@16 | 108 | 0, 0, |
michael@16 | 109 | FAILURE_ROUTE }, |
michael@16 | 110 | {0,0,0,0,0,0} |
michael@16 | 111 | }; |
michael@16 | 112 | |
michael@16 | 113 | |
michael@16 | 114 | |
michael@16 | 115 | /* Exported parameters */ |
michael@16 | 116 | static param_export_t params[] = { |
michael@16 | 117 | {"rr_from_store_param", STR_PARAM, &rr_from_param.s }, |
michael@16 | 118 | {"rr_to_store_param", STR_PARAM, &rr_to_param.s }, |
michael@16 | 119 | {"restore_mode", STR_PARAM, &restore_mode_str }, |
michael@16 | 120 | {"restore_passwd", STR_PARAM, &uac_passwd.s }, |
michael@16 | 121 | {"credential", STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential }, |
michael@16 | 122 | {"auth_username_avp", STR_PARAM, &auth_username_avp }, |
michael@16 | 123 | {"auth_realm_avp", STR_PARAM, &auth_realm_avp }, |
michael@16 | 124 | {"auth_password_avp", STR_PARAM, &auth_password_avp }, |
michael@16 | 125 | {0, 0, 0} |
michael@16 | 126 | }; |
michael@16 | 127 | |
michael@16 | 128 | |
michael@16 | 129 | |
michael@16 | 130 | struct module_exports exports= { |
michael@16 | 131 | "uac", |
michael@16 | 132 | MODULE_VERSION, |
michael@16 | 133 | DEFAULT_DLFLAGS, /* dlopen flags */ |
michael@16 | 134 | cmds, /* exported functions */ |
michael@16 | 135 | params, /* param exports */ |
michael@16 | 136 | 0, /* exported statistics */ |
michael@16 | 137 | 0, /* exported MI functions */ |
michael@16 | 138 | 0, /* exported pseudo-variables */ |
michael@16 | 139 | 0, /* extra processes */ |
michael@16 | 140 | mod_init, /* module initialization function */ |
michael@16 | 141 | (response_function) 0, |
michael@16 | 142 | mod_destroy, |
michael@16 | 143 | 0 /* per-child init function */ |
michael@16 | 144 | }; |
michael@16 | 145 | |
michael@16 | 146 | |
michael@16 | 147 | inline static int parse_auth_avp( char *avp_spec, pv_spec_t *avp, char *txt) |
michael@16 | 148 | { |
michael@16 | 149 | str s; |
michael@16 | 150 | s.s = avp_spec; s.len = strlen(s.s); |
michael@16 | 151 | if (pv_parse_spec(&s, avp)==NULL) { |
michael@16 | 152 | LM_ERR("malformed or non AVP %s AVP definition\n",txt); |
michael@16 | 153 | return -1; |
michael@16 | 154 | } |
michael@16 | 155 | return 0; |
michael@16 | 156 | } |
michael@16 | 157 | |
michael@16 | 158 | |
michael@16 | 159 | static int mod_init(void) |
michael@16 | 160 | { |
michael@16 | 161 | LM_INFO("initializing...\n"); |
michael@16 | 162 | |
michael@16 | 163 | if (restore_mode_str && *restore_mode_str) { |
michael@16 | 164 | if (strcasecmp(restore_mode_str,"none")==0) { |
michael@16 | 165 | restore_mode = UAC_NO_RESTORE; |
michael@16 | 166 | } else if (strcasecmp(restore_mode_str,"manual")==0) { |
michael@16 | 167 | restore_mode = UAC_MANUAL_RESTORE; |
michael@16 | 168 | } else if (strcasecmp(restore_mode_str,"auto")==0) { |
michael@16 | 169 | restore_mode = UAC_AUTO_RESTORE; |
michael@16 | 170 | } else { |
michael@16 | 171 | LM_ERR("unsupported value '%s' for restore_mode\n", |
michael@16 | 172 | restore_mode_str); |
michael@16 | 173 | goto error; |
michael@16 | 174 | } |
michael@16 | 175 | } |
michael@16 | 176 | |
michael@16 | 177 | rr_from_param.len = strlen(rr_from_param.s); |
michael@16 | 178 | rr_to_param.len = strlen(rr_to_param.s); |
michael@16 | 179 | if ( (rr_from_param.len==0 || rr_to_param.len==0) && |
michael@16 | 180 | restore_mode!=UAC_NO_RESTORE) |
michael@16 | 181 | { |
michael@16 | 182 | LM_ERR("rr_store_param cannot be empty if FROM is restoreable\n"); |
michael@16 | 183 | goto error; |
michael@16 | 184 | } |
michael@16 | 185 | |
michael@16 | 186 | uac_passwd.len = strlen(uac_passwd.s); |
michael@16 | 187 | |
michael@16 | 188 | /* parse the auth AVP spesc, if any */ |
michael@16 | 189 | if ( auth_username_avp || auth_password_avp || auth_realm_avp) { |
michael@16 | 190 | if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) { |
michael@16 | 191 | LM_ERR("partial definition of auth AVP!"); |
michael@16 | 192 | goto error; |
michael@16 | 193 | } |
michael@16 | 194 | if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0 |
michael@16 | 195 | || parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0 |
michael@16 | 196 | || parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0 |
michael@16 | 197 | ) { |
michael@16 | 198 | goto error; |
michael@16 | 199 | } |
michael@16 | 200 | } else { |
michael@16 | 201 | memset( &auth_realm_spec, 0, sizeof(pv_spec_t)); |
michael@16 | 202 | memset( &auth_password_spec, 0, sizeof(pv_spec_t)); |
michael@16 | 203 | memset( &auth_username_spec, 0, sizeof(pv_spec_t)); |
michael@16 | 204 | } |
michael@16 | 205 | |
michael@16 | 206 | /* load the TM API - FIXME it should be loaded only |
michael@16 | 207 | * if NO_RESTORE and AUTH */ |
michael@16 | 208 | if (load_tm_api(&uac_tmb)!=0) { |
michael@16 | 209 | LM_ERR("can't load TM API\n"); |
michael@16 | 210 | goto error; |
michael@16 | 211 | } |
michael@16 | 212 | |
michael@16 | 213 | if (restore_mode!=UAC_NO_RESTORE) { |
michael@16 | 214 | /* load the RR API */ |
michael@16 | 215 | if (load_rr_api(&uac_rrb)!=0) { |
michael@16 | 216 | LM_ERR("can't load RR API\n"); |
michael@16 | 217 | goto error; |
michael@16 | 218 | } |
michael@16 | 219 | |
michael@16 | 220 | if (restore_mode==UAC_AUTO_RESTORE) { |
michael@16 | 221 | /* we need the append_fromtag on in RR */ |
michael@16 | 222 | if (!uac_rrb.append_fromtag) { |
michael@16 | 223 | LM_ERR("'append_fromtag' RR param is not enabled!" |
michael@16 | 224 | " - required by AUTO restore mode\n"); |
michael@16 | 225 | goto error; |
michael@16 | 226 | } |
michael@16 | 227 | /* get all requests doing loose route */ |
michael@16 | 228 | if (uac_rrb.register_rrcb( rr_checker, 0)!=0) { |
michael@16 | 229 | LM_ERR("failed to install RR callback\n"); |
michael@16 | 230 | goto error; |
michael@16 | 231 | } |
michael@16 | 232 | } |
michael@16 | 233 | } |
michael@16 | 234 | |
michael@16 | 235 | init_from_replacer(); |
michael@16 | 236 | |
michael@16 | 237 | return 0; |
michael@16 | 238 | error: |
michael@16 | 239 | return -1; |
michael@16 | 240 | } |
michael@16 | 241 | |
michael@16 | 242 | |
michael@16 | 243 | static void mod_destroy(void) |
michael@16 | 244 | { |
michael@16 | 245 | destroy_credentials(); |
michael@16 | 246 | } |
michael@16 | 247 | |
michael@16 | 248 | |
michael@16 | 249 | |
michael@16 | 250 | /************************** fixup functions ******************************/ |
michael@16 | 251 | |
michael@16 | 252 | static int fixup_replace_uri(void** param, int param_no) |
michael@16 | 253 | { |
michael@16 | 254 | pv_elem_t *model; |
michael@16 | 255 | str s; |
michael@16 | 256 | |
michael@16 | 257 | model=NULL; |
michael@16 | 258 | s.s = (char*)(*param); s.len = strlen(s.s); |
michael@16 | 259 | if(pv_parse_format(&s, &model)<0) |
michael@16 | 260 | { |
michael@16 | 261 | LM_ERR("wrong format[%s]!\n",(char*)(*param)); |
michael@16 | 262 | return E_UNSPEC; |
michael@16 | 263 | } |
michael@16 | 264 | if (model==NULL) |
michael@16 | 265 | { |
michael@16 | 266 | LM_ERR("empty parameter!\n"); |
michael@16 | 267 | return E_UNSPEC; |
michael@16 | 268 | } |
michael@16 | 269 | *param = (void*)model; |
michael@16 | 270 | |
michael@16 | 271 | return 0; |
michael@16 | 272 | } |
michael@16 | 273 | |
michael@16 | 274 | |
michael@16 | 275 | static int fixup_replace_disp_uri(void** param, int param_no) |
michael@16 | 276 | { |
michael@16 | 277 | pv_elem_t *model; |
michael@16 | 278 | char *p; |
michael@16 | 279 | str s; |
michael@16 | 280 | |
michael@16 | 281 | /* convert to str */ |
michael@16 | 282 | s.s = (char*)*param; |
michael@16 | 283 | s.len = strlen(s.s); |
michael@16 | 284 | |
michael@16 | 285 | model=NULL; |
michael@16 | 286 | if (param_no==1 && s.len) { |
michael@16 | 287 | /* put " around display name */ |
michael@16 | 288 | p = (char*)pkg_malloc(s.len+3); |
michael@16 | 289 | if (p==0) { |
michael@16 | 290 | LM_CRIT("no more pkg mem\n"); |
michael@16 | 291 | return E_OUT_OF_MEM; |
michael@16 | 292 | } |
michael@16 | 293 | p[0] = '\"'; |
michael@16 | 294 | memcpy(p+1, s.s, s.len); |
michael@16 | 295 | p[s.len+1] = '\"'; |
michael@16 | 296 | p[s.len+2] = '\0'; |
michael@16 | 297 | pkg_free(s.s); |
michael@16 | 298 | s.s = p; |
michael@16 | 299 | s.len += 2; |
michael@16 | 300 | } |
michael@16 | 301 | if(pv_parse_format(&s ,&model)<0) { |
michael@16 | 302 | LM_ERR("wrong format [%s] for param no %d!\n", s.s, param_no); |
michael@16 | 303 | pkg_free(s.s); |
michael@16 | 304 | return E_UNSPEC; |
michael@16 | 305 | } |
michael@16 | 306 | *param = (void*)model; |
michael@16 | 307 | |
michael@16 | 308 | return 0; |
michael@16 | 309 | } |
michael@16 | 310 | |
michael@16 | 311 | |
michael@16 | 312 | |
michael@16 | 313 | /************************** wrapper functions ******************************/ |
michael@16 | 314 | |
michael@16 | 315 | static int w_restore_from(struct sip_msg *msg) |
michael@16 | 316 | { |
michael@16 | 317 | /* safety checks - must be a request */ |
michael@16 | 318 | if (msg->first_line.type!=SIP_REQUEST) { |
michael@16 | 319 | LM_ERR("called for something not request\n"); |
michael@16 | 320 | return -1; |
michael@16 | 321 | } |
michael@16 | 322 | |
michael@16 | 323 | return (restore_uri(msg,&rr_from_param,1)==0)?1:-1; |
michael@16 | 324 | } |
michael@16 | 325 | |
michael@16 | 326 | |
michael@16 | 327 | static int w_replace_from(struct sip_msg* msg, char* p1, char* p2) |
michael@16 | 328 | { |
michael@16 | 329 | str uri_s; |
michael@16 | 330 | str dsp_s; |
michael@16 | 331 | str *uri; |
michael@16 | 332 | str *dsp; |
michael@16 | 333 | |
michael@16 | 334 | if (p2==NULL) { |
michael@16 | 335 | p2 = p1; |
michael@16 | 336 | p1 = NULL; |
michael@16 | 337 | dsp = NULL; |
michael@16 | 338 | } |
michael@16 | 339 | |
michael@16 | 340 | /* p1 dispaly , p2 uri */ |
michael@16 | 341 | |
michael@16 | 342 | if ( p1!=NULL ) { |
michael@16 | 343 | if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0) |
michael@16 | 344 | return -1; |
michael@16 | 345 | dsp = &dsp_s; |
michael@16 | 346 | } |
michael@16 | 347 | |
michael@16 | 348 | /* compute the URI string; if empty string -> make it NULL */ |
michael@16 | 349 | if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0) |
michael@16 | 350 | return -1; |
michael@16 | 351 | uri = uri_s.len?&uri_s:NULL; |
michael@16 | 352 | |
michael@16 | 353 | if (parse_from_header(msg)<0 ) { |
michael@16 | 354 | LM_ERR("failed to find/parse FROM hdr\n"); |
michael@16 | 355 | return -1; |
michael@16 | 356 | } |
michael@16 | 357 | |
michael@16 | 358 | LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n", |
michael@16 | 359 | dsp,dsp?dsp->len:0,uri,uri?uri->len:0); |
michael@16 | 360 | |
michael@16 | 361 | return (replace_uri(msg, dsp, uri, msg->from, &rr_from_param)==0)?1:-1; |
michael@16 | 362 | } |
michael@16 | 363 | |
michael@16 | 364 | |
michael@16 | 365 | static int w_restore_to(struct sip_msg *msg) |
michael@16 | 366 | { |
michael@16 | 367 | /* safety checks - must be a request */ |
michael@16 | 368 | if (msg->first_line.type!=SIP_REQUEST) { |
michael@16 | 369 | LM_ERR("called for something not request\n"); |
michael@16 | 370 | return -1; |
michael@16 | 371 | } |
michael@16 | 372 | |
michael@16 | 373 | return (restore_uri(msg,&rr_to_param,0)==0)?1:-1; |
michael@16 | 374 | } |
michael@16 | 375 | |
michael@16 | 376 | |
michael@16 | 377 | static int w_replace_to(struct sip_msg* msg, char* p1, char* p2) |
michael@16 | 378 | { |
michael@16 | 379 | str uri_s; |
michael@16 | 380 | str dsp_s; |
michael@16 | 381 | str *uri; |
michael@16 | 382 | str *dsp; |
michael@16 | 383 | |
michael@16 | 384 | if (p2==NULL) { |
michael@16 | 385 | p2 = p1; |
michael@16 | 386 | p1 = NULL; |
michael@16 | 387 | dsp = NULL; |
michael@16 | 388 | } |
michael@16 | 389 | |
michael@16 | 390 | /* p1 dispaly , p2 uri */ |
michael@16 | 391 | |
michael@16 | 392 | if ( p1!=NULL ) { |
michael@16 | 393 | if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0) |
michael@16 | 394 | return -1; |
michael@16 | 395 | dsp = &dsp_s; |
michael@16 | 396 | } |
michael@16 | 397 | |
michael@16 | 398 | /* compute the URI string; if empty string -> make it NULL */ |
michael@16 | 399 | if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0) |
michael@16 | 400 | return -1; |
michael@16 | 401 | uri = uri_s.len?&uri_s:NULL; |
michael@16 | 402 | |
michael@16 | 403 | /* parse TO hdr */ |
michael@16 | 404 | if ( msg->to==0 && (parse_headers(msg,HDR_TO_F,0)!=0 || msg->to==0) ) { |
michael@16 | 405 | LM_ERR("failed to parse TO hdr\n"); |
michael@16 | 406 | return -1; |
michael@16 | 407 | } |
michael@16 | 408 | |
michael@16 | 409 | return (replace_uri(msg, dsp, uri, msg->to, &rr_to_param)==0)?1:-1; |
michael@16 | 410 | } |
michael@16 | 411 | |
michael@16 | 412 | |
michael@16 | 413 | |
michael@16 | 414 | |
michael@16 | 415 | static int w_uac_auth(struct sip_msg* msg, char* str, char* str2) |
michael@16 | 416 | { |
michael@16 | 417 | return (uac_auth(msg)==0)?1:-1; |
michael@16 | 418 | } |
michael@16 | 419 | |
michael@16 | 420 |