opensips/modules/uac/auth.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: auth.c 5901 2009-07-21 07:45:05Z bogdan_iancu $
michael@16 3 *
michael@16 4 * Copyright (C) 2005 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 * 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan)
michael@18 27 * 2010-01-18 UAC replaces proxy-auth entries with new credentials (msvb)
michael@16 28 */
michael@16 29
michael@16 30
michael@16 31 #include <ctype.h>
michael@16 32 #include <string.h>
michael@16 33
michael@16 34 #include "../../str.h"
michael@16 35 #include "../../dprint.h"
michael@16 36 #include "../../pvar.h"
michael@16 37 #include "../../data_lump.h"
michael@16 38 #include "../../mem/mem.h"
michael@16 39 #include "../tm/tm_load.h"
michael@16 40
michael@16 41 #include "auth.h"
michael@16 42 #include "auth_alg.h"
michael@16 43 #include "auth_hdr.h"
michael@16 44
michael@16 45
michael@16 46 extern struct tm_binds uac_tmb;
michael@16 47 extern pv_spec_t auth_username_spec;
michael@16 48 extern pv_spec_t auth_realm_spec;
michael@16 49 extern pv_spec_t auth_password_spec;
michael@16 50
michael@16 51
michael@16 52 static struct uac_credential *crd_list = 0;
michael@16 53
michael@16 54
michael@16 55 #define duplicate_str(_strd, _strs, _error) \
michael@16 56 do { \
michael@16 57 _strd.s = (char*)pkg_malloc(_strs.len); \
michael@16 58 if (_strd.s==0) \
michael@16 59 { \
michael@16 60 LM_ERR("no more pkg memory\n");\
michael@16 61 goto _error; \
michael@16 62 } \
michael@16 63 memcpy( _strd.s, _strs.s, _strs.len); \
michael@16 64 _strd.len = _strs.len; \
michael@16 65 }while(0)
michael@16 66
michael@16 67
michael@16 68 #define WWW_AUTH_CODE 401
michael@16 69 #define WWW_AUTH_HDR "WWW-Authenticate"
michael@16 70 #define WWW_AUTH_HDR_LEN (sizeof(WWW_AUTH_HDR)-1)
michael@16 71 #define PROXY_AUTH_CODE 407
michael@16 72 #define PROXY_AUTH_HDR "Proxy-Authenticate"
michael@16 73 #define PROXY_AUTH_HDR_LEN (sizeof(PROXY_AUTH_HDR)-1)
michael@16 74
michael@16 75 static str nc = {"00000001", 8};
michael@16 76 static str cnonce = {"o", 1};
michael@16 77
michael@16 78 int has_credentials(void)
michael@16 79 {
michael@16 80 return (crd_list!=0)?1:0;
michael@16 81 }
michael@16 82
michael@16 83 void free_credential(struct uac_credential *crd)
michael@16 84 {
michael@16 85 if (crd)
michael@16 86 {
michael@16 87 if (crd->realm.s)
michael@16 88 pkg_free(crd->realm.s);
michael@16 89 if (crd->user.s)
michael@16 90 pkg_free(crd->user.s);
michael@16 91 if (crd->passwd.s)
michael@16 92 pkg_free(crd->passwd.s);
michael@16 93 pkg_free(crd);
michael@16 94 }
michael@16 95 }
michael@16 96
michael@16 97
michael@16 98 int add_credential( unsigned int type, void *val)
michael@16 99 {
michael@16 100 struct uac_credential *crd;
michael@16 101 char *p;
michael@16 102 str foo;
michael@16 103
michael@16 104 p = (char*)val;
michael@16 105 crd = 0;
michael@16 106
michael@16 107 if (p==0 || *p==0)
michael@16 108 goto error;
michael@16 109
michael@16 110 crd = (struct uac_credential*)pkg_malloc(sizeof(struct uac_credential));
michael@16 111 if (crd==0)
michael@16 112 {
michael@16 113 LM_ERR("no more pkg mem\n");
michael@16 114 goto error;
michael@16 115 }
michael@16 116 memset( crd, 0, sizeof(struct uac_credential));
michael@16 117
michael@16 118 /*parse the user */
michael@16 119 while (*p && isspace((int)*p)) p++;
michael@16 120 foo.s = p;
michael@16 121 while (*p && *p!=':' && !isspace((int)*p)) p++;
michael@16 122 if (foo.s==p || *p==0)
michael@16 123 /* missing or empty user */
michael@16 124 goto parse_error;
michael@16 125 foo.len = p - foo.s;
michael@16 126 /* dulicate it */
michael@16 127 duplicate_str( crd->user, foo, error);
michael@16 128
michael@16 129 /* parse the ':' separator */
michael@16 130 while (*p && isspace((int)*p)) p++;
michael@16 131 if (*p!=':')
michael@16 132 goto parse_error;
michael@16 133 p++;
michael@16 134 while (*p && isspace((int)*p)) p++;
michael@16 135 if (*p==0)
michael@16 136 goto parse_error;
michael@16 137
michael@16 138 /*parse the realm */
michael@16 139 while (*p && isspace((int)*p)) p++;
michael@16 140 foo.s = p;
michael@16 141 while (*p && *p!=':' && !isspace((int)*p)) p++;
michael@16 142 if (foo.s==p || *p==0)
michael@16 143 /* missing or empty realm */
michael@16 144 goto parse_error;
michael@16 145 foo.len = p - foo.s;
michael@16 146 /* dulicate it */
michael@16 147 duplicate_str( crd->realm, foo, error);
michael@16 148
michael@16 149 /* parse the ':' separator */
michael@16 150 while (*p && isspace((int)*p)) p++;
michael@16 151 if (*p!=':')
michael@16 152 goto parse_error;
michael@16 153 p++;
michael@16 154 while (*p && isspace((int)*p)) p++;
michael@16 155 if (*p==0)
michael@16 156 goto parse_error;
michael@16 157
michael@16 158 /*parse the passwd */
michael@16 159 while (*p && isspace((int)*p)) p++;
michael@16 160 foo.s = p;
michael@16 161 while (*p && !isspace((int)*p)) p++;
michael@16 162 if (foo.s==p)
michael@16 163 /* missing or empty passwd */
michael@16 164 goto parse_error;
michael@16 165 foo.len = p - foo.s;
michael@16 166 /* dulicate it */
michael@16 167 duplicate_str( crd->passwd, foo, error);
michael@16 168
michael@16 169 /* end of string */
michael@16 170 while (*p && isspace((int)*p)) p++;
michael@16 171 if (*p!=0)
michael@16 172 goto parse_error;
michael@16 173
michael@16 174 /* link the new cred struct */
michael@16 175 crd->next = crd_list;
michael@16 176 crd_list = crd;
michael@16 177
michael@16 178 pkg_free(val);
michael@16 179 return 0;
michael@16 180 parse_error:
michael@16 181 LM_ERR("parse error in <%s> "
michael@16 182 "around %ld\n", (char*)val, (long)(p-(char*)val));
michael@16 183 error:
michael@16 184 if (crd)
michael@16 185 free_credential(crd);
michael@16 186 return -1;
michael@16 187 }
michael@16 188
michael@16 189
michael@16 190 void destroy_credentials(void)
michael@16 191 {
michael@16 192 struct uac_credential *foo;
michael@16 193
michael@16 194 while (crd_list)
michael@16 195 {
michael@16 196 foo = crd_list;
michael@16 197 crd_list = crd_list->next;
michael@16 198 free_credential(foo);
michael@16 199 }
michael@16 200 crd_list = 0;
michael@16 201 }
michael@16 202
michael@16 203
michael@16 204 static inline struct hdr_field *get_autenticate_hdr(struct sip_msg *rpl,
michael@16 205 int rpl_code)
michael@16 206 {
michael@16 207 struct hdr_field *hdr;
michael@16 208 str hdr_name;
michael@16 209
michael@16 210 /* what hdr should we look for */
michael@16 211 if (rpl_code==WWW_AUTH_CODE)
michael@16 212 {
michael@16 213 hdr_name.s = WWW_AUTH_HDR;
michael@16 214 hdr_name.len = WWW_AUTH_HDR_LEN;
michael@16 215 } else if (rpl_code==PROXY_AUTH_CODE) {
michael@16 216 hdr_name.s = PROXY_AUTH_HDR;
michael@16 217 hdr_name.len = PROXY_AUTH_HDR_LEN;
michael@16 218 } else {
michael@16 219 LM_ERR("reply is not an "
michael@16 220 "auth request\n");
michael@16 221 goto error;
michael@16 222 }
michael@16 223
michael@16 224 LM_DBG("looking for header \"%.*s\"\n",
michael@16 225 hdr_name.len, hdr_name.s);
michael@16 226
michael@16 227 /* search the auth hdr, but first parse them all */
michael@16 228 if (parse_headers( rpl, HDR_EOH_F, 0)<0)
michael@16 229 {
michael@16 230 LM_ERR("failed to parse reply\n");
michael@16 231 goto error;
michael@16 232 }
michael@16 233 hdr = get_header_by_name( rpl , hdr_name.s, hdr_name.len);
michael@16 234 if (hdr)
michael@16 235 return hdr;
michael@16 236
michael@16 237 LM_ERR("reply has no "
michael@16 238 "auth hdr (%.*s)\n", hdr_name.len, hdr_name.s);
michael@16 239 error:
michael@16 240 return 0;
michael@16 241 }
michael@16 242
michael@16 243
michael@16 244 static inline struct uac_credential *lookup_realm( str *realm)
michael@16 245 {
michael@16 246 struct uac_credential *crd;
michael@16 247
michael@16 248 for( crd=crd_list ; crd ; crd=crd->next )
michael@16 249 if (realm->len==crd->realm.len &&
michael@16 250 strncmp( realm->s, crd->realm.s, realm->len)==0 )
michael@16 251 return crd;
michael@16 252 return 0;
michael@16 253 }
michael@16 254
michael@16 255
michael@16 256 static inline struct uac_credential *get_avp_credential(struct sip_msg *msg,
michael@16 257 str *realm)
michael@16 258 {
michael@16 259 static struct uac_credential crd;
michael@16 260 pv_value_t pv_val;
michael@16 261
michael@16 262 if(pv_get_spec_value( msg, &auth_realm_spec, &pv_val)!=0
michael@16 263 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
michael@16 264 return 0;
michael@16 265
michael@16 266 crd.realm = pv_val.rs;
michael@16 267 /* is it the domain we are looking for? */
michael@16 268 if (realm->len!=crd.realm.len ||
michael@16 269 strncmp( realm->s, crd.realm.s, realm->len)!=0 )
michael@16 270 return 0;
michael@16 271
michael@16 272 /* get username and password */
michael@16 273 if(pv_get_spec_value( msg, &auth_username_spec, &pv_val)!=0
michael@16 274 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
michael@16 275 return 0;
michael@16 276 crd.user = pv_val.rs;
michael@16 277
michael@16 278 if(pv_get_spec_value( msg, &auth_password_spec, &pv_val)!=0
michael@16 279 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
michael@16 280 return 0;
michael@16 281 crd.passwd = pv_val.rs;
michael@16 282
michael@16 283 return &crd;
michael@16 284 }
michael@16 285
michael@16 286
michael@16 287 static inline void do_uac_auth(struct sip_msg *req, str *uri,
michael@16 288 struct uac_credential *crd, struct authenticate_body *auth,
michael@16 289 HASHHEX response)
michael@16 290 {
michael@16 291 HASHHEX ha1;
michael@16 292 HASHHEX ha2;
michael@16 293
michael@16 294 if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT))
michael@16 295 {
michael@16 296 /* if qop generate nonce-count and cnonce */
michael@16 297 cnonce.s = int2str(core_hash(&auth->nonce, 0, 0),&cnonce.len);
michael@16 298
michael@16 299 /* do authentication */
michael@16 300 uac_calc_HA1( crd, auth, &cnonce, ha1);
michael@16 301 uac_calc_HA2( &req->first_line.u.request.method, uri,
michael@16 302 auth, 0/*hentity*/, ha2 );
michael@16 303
michael@16 304 uac_calc_response( ha1, ha2, auth, &nc, &cnonce, response);
michael@16 305 auth->nc = &nc;
michael@16 306 auth->cnonce = &cnonce;
michael@16 307 } else {
michael@16 308 /* do authentication */
michael@16 309 uac_calc_HA1( crd, auth, 0/*cnonce*/, ha1);
michael@16 310 uac_calc_HA2( &req->first_line.u.request.method, uri,
michael@16 311 auth, 0/*hentity*/, ha2 );
michael@16 312
michael@16 313 uac_calc_response( ha1, ha2, auth, 0/*nc*/, 0/*cnonce*/, response);
michael@16 314 }
michael@16 315 }
michael@16 316
michael@16 317
michael@16 318 static inline int apply_urihdr_changes( struct sip_msg *req,
michael@16 319 str *uri, str *hdr)
michael@16 320 {
michael@16 321 struct lump* anchor;
michael@16 322
michael@16 323 /* add the uri - move it to branch directly FIXME (bogdan)*/
michael@16 324 if (req->new_uri.s)
michael@16 325 {
michael@16 326 pkg_free(req->new_uri.s);
michael@16 327 req->new_uri.len=0;
michael@16 328 }
michael@16 329 req->parsed_uri_ok=0;
michael@16 330 req->new_uri.s = (char*)pkg_malloc(uri->len+1);
michael@16 331 if (req->new_uri.s==0)
michael@16 332 {
michael@16 333 LM_ERR("no more pkg\n");
michael@16 334 goto error;
michael@16 335 }
michael@16 336 memcpy( req->new_uri.s, uri->s, uri->len);
michael@16 337 req->new_uri.s[uri->len]=0;
michael@16 338 req->new_uri.len=uri->len;
michael@16 339
michael@16 340 /* add the header */
michael@16 341 if (parse_headers(req, HDR_EOH_F, 0) == -1)
michael@16 342 {
michael@16 343 LM_ERR("failed to parse message\n");
michael@16 344 goto error;
michael@16 345 }
michael@16 346
michael@16 347 anchor = anchor_lump(req, req->unparsed - req->buf, 0, 0);
michael@16 348 if (anchor==0)
michael@16 349 {
michael@16 350 LM_ERR("failed to get anchor\n");
michael@16 351 goto error;
michael@16 352 }
michael@16 353
michael@16 354 if (insert_new_lump_before(anchor, hdr->s, hdr->len, 0) == 0)
michael@16 355 {
michael@16 356 LM_ERR("faield to insert lump\n");
michael@16 357 goto error;
michael@16 358 }
michael@16 359
michael@16 360 return 0;
michael@16 361 error:
michael@16 362 pkg_free( hdr->s );
michael@16 363 return -1;
michael@16 364 }
michael@16 365
michael@16 366
michael@16 367
michael@16 368 int uac_auth( struct sip_msg *msg)
michael@16 369 {
michael@16 370 static struct authenticate_body auth;
michael@16 371 struct uac_credential *crd;
michael@16 372 int code, branch;
michael@16 373 struct sip_msg *rpl;
michael@16 374 struct cell *t;
michael@16 375 struct hdr_field *hdr;
michael@16 376 HASHHEX response;
michael@16 377 str *new_hdr;
michael@16 378
michael@18 379 /* pretransact */
michael@18 380 int nret = 0;
michael@18 381 pv_value_t pv_val;
michael@18 382 str *newuri = 0;
michael@18 383 struct uac_credential *tst = 0;
michael@18 384 struct hdr_field *tmp_hdr = 0;
michael@18 385 struct hdr_field *del_hdr = 0;
michael@18 386
michael@18 387
michael@18 388 /* Goes something like this... */
michael@18 389 /* HA1 = echo -n 'username:realm:password' | md5sum */
michael@18 390 /* echo -n 'itsme:mydom.com:stupidpass' | md5sum */
michael@18 391 /* HA2 = echo -n 'message:uri' | md5sum */
michael@18 392 /* echo -n 'INVITE:sip:danc@ing.fool.es' | md5sum */
michael@18 393 /* Response = echo -n 'HA1:nonce:HA2' | md5sum */
michael@16 394 /* get transaction */
michael@16 395 t = uac_tmb.t_gett();
michael@18 396 if (t==T_UNDEFINED || t==T_NULL_CELL) {
michael@18 397 /* begin without any transaction */
michael@18 398 /* set relevant structure variables */
michael@18 399 crd = 0;
michael@18 400 crd = pkg_malloc(sizeof(struct uac_credential));
michael@18 401 if (!crd) {
michael@18 402 LM_ERR("no more pkg memory\n");
michael@18 403 goto error;
michael@18 404 }
michael@16 405
michael@18 406 /* set the realm from existing UAC message */
michael@18 407 tmp_hdr = msg->proxy_auth;
michael@18 408 del_hdr = 0;
michael@18 409 while (tmp_hdr) {
michael@18 410 crd->realm.s = strchr(strstr(tmp_hdr->body.s, "realm="), '"') + 1;
michael@18 411 crd->realm.len = strchr(crd->realm.s, '"') - crd->realm.s;
michael@18 412 if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
michael@18 413 && pv_val.rs.len>0) /* ensure realm is the desired one */
michael@18 414 if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0)
michael@18 415 del_hdr = tmp_hdr;
michael@18 416 tmp_hdr = tmp_hdr->sibling;
michael@18 417 }
michael@18 418 if (del_hdr)
michael@18 419 crd->realm = pv_val.rs; /* success */
michael@18 420 else
michael@18 421 nret++; /* failure */
michael@18 422
michael@18 423 /* set username from new AVP proxy values */
michael@18 424 if(pv_get_spec_value(msg, &auth_username_spec, &pv_val)!=0 \
michael@18 425 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
michael@18 426 nret++; /* signal failure with nonzero value */
michael@18 427 else
michael@18 428 crd->user = pv_val.rs;
michael@18 429
michael@18 430 /* set password from new AVP proxy values */
michael@18 431 if(pv_get_spec_value(msg, &auth_password_spec, &pv_val)!=0 \
michael@18 432 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
michael@18 433 nret++; /* signal failure with nonzero value */
michael@18 434 else
michael@18 435 crd->passwd = pv_val.rs;
michael@18 436
michael@18 437 if (nret) { /* if not found, look into predefined credentials */
michael@18 438 tst = lookup_realm(&crd->realm);
michael@18 439
michael@18 440 if (tst==0) { /* found? */
michael@18 441 LM_DBG("no credential for realm \"%.*s\"\n", \
michael@18 442 crd->realm.len, crd->realm.s);
michael@18 443 pkg_free(crd);
michael@18 444 goto error;
michael@18 445 }
michael@18 446
michael@18 447 crd = tst; /* use predefined credentials */
michael@18 448 /* set the realm from existing UAC message */
michael@18 449 tmp_hdr = msg->proxy_auth;
michael@18 450 del_hdr = 0;
michael@18 451 while (tmp_hdr) {
michael@18 452 if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
michael@18 453 && pv_val.rs.len>0) /* ensure realm is the desired one */
michael@18 454 if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0)
michael@18 455 del_hdr = tmp_hdr;
michael@18 456 tmp_hdr = tmp_hdr->sibling;
michael@18 457 }
michael@18 458 if (del_hdr == 0) { /* proxy-auth header matching realm not found */
michael@18 459 LM_DBG("no credential for realm \"%.*s\"\n", \
michael@18 460 crd->realm.len, crd->realm.s);
michael@18 461 pkg_free(crd);
michael@18 462 goto error;
michael@18 463 }
michael@18 464 }
michael@18 465
michael@18 466 /* set the uri from existing UAC message */
michael@18 467 newuri = pkg_malloc(sizeof(str));
michael@18 468 if (!newuri) {
michael@18 469 LM_ERR("no more pkg memory\n");
michael@18 470 goto error;
michael@18 471 }
michael@18 472 newuri->s = pkg_malloc(msg->new_uri.len);
michael@18 473 if (!newuri->s) {
michael@18 474 LM_ERR("no more pkg memory\n");
michael@18 475 pkg_free(newuri);
michael@18 476 goto error;
michael@18 477 }
michael@18 478 newuri->len = msg->new_uri.len;
michael@18 479 strncpy(newuri->s, msg->new_uri.s, msg->new_uri.len);
michael@18 480 if (!newuri->s) {
michael@18 481 LM_DBG("failed to retrieve URI from UAC message\n");
michael@18 482 pkg_free(newuri->s);
michael@18 483 pkg_free(newuri);
michael@18 484 goto error;
michael@18 485 }
michael@18 486
michael@18 487 /* set the nonce from existing UAC message */
michael@18 488 tmp_hdr = msg->proxy_auth;
michael@18 489 auth.nonce.len = 0;
michael@18 490 auth.nonce.s = 0;
michael@18 491 while (tmp_hdr) {
michael@18 492 if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \
michael@18 493 && pv_val.rs.len>0) /* ensure realm is the desired one */
michael@18 494 if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0) {
michael@18 495 auth.nonce.s = strchr(strstr(tmp_hdr->body.s, "nonce="), '"') + 1;
michael@18 496 auth.nonce.len = strchr(auth.nonce.s, '"') - auth.nonce.s;
michael@18 497 }
michael@18 498 tmp_hdr = tmp_hdr->sibling;
michael@18 499 }
michael@18 500 if (auth.nonce.s == 0) {
michael@18 501 LM_DBG("failed to retrieve nonce from UAC message\n");
michael@18 502 pkg_free(crd);
michael@18 503 goto error;
michael@18 504 }
michael@18 505
michael@18 506 /* do authentication */
michael@18 507 do_uac_auth(msg, newuri, crd, &auth, response);
michael@18 508 if (response==0) {
michael@18 509 LM_ERR("failed to calculate challenge response\n");
michael@18 510 pkg_free(crd);
michael@18 511 goto error;
michael@18 512 }
michael@18 513
michael@18 514 /* build the authorization header */
michael@18 515 new_hdr = build_authorization_hdr(407, newuri, crd, &auth, response);
michael@18 516 if (new_hdr==0) {
michael@18 517 LM_ERR("failed to build authorization hdr\n");
michael@18 518 pkg_free(crd);
michael@18 519 goto error;
michael@18 520 }
michael@18 521
michael@18 522 /* remove the old proxy-auth header and relink message index */
michael@18 523 /* before updating the authorization credentials of the message */
michael@18 524 if (del_hdr) { /* updated a record and must remove the old one */
michael@18 525 if (del_lump(msg, del_hdr->name.s - msg->buf, del_hdr->len, 0)==0) {
michael@18 526 LM_ERR("can't remove credentials\n");
michael@18 527 pkg_free(crd);
michael@18 528 goto error;
michael@18 529 }
michael@18 530 }
michael@18 531
michael@18 532 /* so far, so good -> add the header and set the proper RURI */
michael@18 533 if (apply_urihdr_changes(msg, newuri, new_hdr)<0)
michael@18 534 {
michael@18 535 LM_ERR("failed to apply changes\n");
michael@18 536 pkg_free(crd);
michael@18 537 goto error;
michael@18 538 }
michael@18 539
michael@18 540 pkg_free(crd); /* finished calculating new response string, success */
michael@18 541 return 0;
michael@18 542 } /* if (t==T_UNDEFINED || t==T_NULL_CELL) */
michael@18 543
michael@18 544 /* begin with transaction reply */
michael@16 545 /* get the selected branch */
michael@16 546 branch = uac_tmb.t_get_picked();
michael@16 547 if (branch<0) {
michael@16 548 LM_CRIT("no picked branch (%d)\n",branch);
michael@16 549 goto error;
michael@16 550 }
michael@16 551
michael@16 552 rpl = t->uac[branch].reply;
michael@16 553 code = t->uac[branch].last_received;
michael@16 554 LM_DBG("picked reply is %p, code %d\n",rpl,code);
michael@16 555
michael@16 556 if (rpl==0)
michael@16 557 {
michael@16 558 LM_CRIT("empty reply on picked branch\n");
michael@16 559 goto error;
michael@16 560 }
michael@16 561 if (rpl==FAKED_REPLY)
michael@16 562 {
michael@16 563 LM_ERR("cannot process a FAKED reply\n");
michael@16 564 goto error;
michael@16 565 }
michael@16 566
michael@16 567 hdr = get_autenticate_hdr( rpl, code);
michael@16 568 if (hdr==0)
michael@16 569 {
michael@16 570 LM_ERR("failed to extract authenticate hdr\n");
michael@16 571 goto error;
michael@16 572 }
michael@16 573
michael@16 574 LM_DBG("header found; body=<%.*s>\n",
michael@16 575 hdr->body.len, hdr->body.s);
michael@16 576
michael@16 577 if (parse_authenticate_body( &hdr->body, &auth)<0)
michael@16 578 {
michael@16 579 LM_ERR("failed to parse auth hdr body\n");
michael@16 580 goto error;
michael@16 581 }
michael@16 582
michael@16 583 /* can we authenticate this realm? */
michael@16 584 crd = 0;
michael@16 585 /* first look into AVP, if set */
michael@16 586 if ( auth_realm_spec.type==PVT_AVP )
michael@16 587 crd = get_avp_credential( msg, &auth.realm );
michael@16 588 /* if not found, look into predefined credentials */
michael@16 589 if (crd==0)
michael@16 590 crd = lookup_realm( &auth.realm );
michael@16 591 /* found? */
michael@16 592 if (crd==0)
michael@16 593 {
michael@16 594 LM_DBG("no credential for realm \"%.*s\"\n",
michael@16 595 auth.realm.len, auth.realm.s);
michael@16 596 goto error;
michael@16 597 }
michael@16 598
michael@16 599 /* do authentication */
michael@16 600 do_uac_auth( msg, &t->uac[branch].uri, crd, &auth, response);
michael@16 601
michael@16 602 /* build the authorization header */
michael@16 603 new_hdr = build_authorization_hdr( code, &t->uac[branch].uri,
michael@16 604 crd, &auth, response);
michael@16 605 if (new_hdr==0)
michael@16 606 {
michael@16 607 LM_ERR("failed to build authorization hdr\n");
michael@16 608 goto error;
michael@16 609 }
michael@16 610
michael@16 611 /* so far, so good -> add the header and set the proper RURI */
michael@16 612 if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 )
michael@16 613 {
michael@16 614 LM_ERR("failed to apply changes\n");
michael@16 615 goto error;
michael@16 616 }
michael@16 617
michael@16 618 /* increas the Cseq nr */
michael@16 619
michael@16 620
michael@16 621 return 0;
michael@16 622 error:
michael@16 623 return -1;
michael@16 624 }
michael@16 625
michael@16 626
michael@16 627

mercurial