opensips/modules/uac/uac.c

Wed, 10 Feb 2010 21:25:01 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 10 Feb 2010 21:25:01 +0100
changeset 18
8ec65b8f6e2c
parent 16
c5c55937e44c
permissions
-rw-r--r--

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

mercurial