Wed, 10 Feb 2010 21:25:01 +0100
Extend uac_auth() of the UAC module to workaround CSEQ problems.
This logic is meant to complement that of changeset 17, which
added rich authentication credentials to the gw table and its
associated logic in the LCR module.
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 |