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