opensips/modules/uac/auth.c

Wed, 10 Feb 2010 21:14:04 +0100

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

Import unmodified vendor sources for correction and improvement.

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@16 27 */
michael@16 28
michael@16 29
michael@16 30 #include <ctype.h>
michael@16 31 #include <string.h>
michael@16 32
michael@16 33 #include "../../str.h"
michael@16 34 #include "../../dprint.h"
michael@16 35 #include "../../pvar.h"
michael@16 36 #include "../../data_lump.h"
michael@16 37 #include "../../mem/mem.h"
michael@16 38 #include "../tm/tm_load.h"
michael@16 39
michael@16 40 #include "auth.h"
michael@16 41 #include "auth_alg.h"
michael@16 42 #include "auth_hdr.h"
michael@16 43
michael@16 44
michael@16 45 extern struct tm_binds uac_tmb;
michael@16 46 extern pv_spec_t auth_username_spec;
michael@16 47 extern pv_spec_t auth_realm_spec;
michael@16 48 extern pv_spec_t auth_password_spec;
michael@16 49
michael@16 50
michael@16 51 static struct uac_credential *crd_list = 0;
michael@16 52
michael@16 53
michael@16 54 #define duplicate_str(_strd, _strs, _error) \
michael@16 55 do { \
michael@16 56 _strd.s = (char*)pkg_malloc(_strs.len); \
michael@16 57 if (_strd.s==0) \
michael@16 58 { \
michael@16 59 LM_ERR("no more pkg memory\n");\
michael@16 60 goto _error; \
michael@16 61 } \
michael@16 62 memcpy( _strd.s, _strs.s, _strs.len); \
michael@16 63 _strd.len = _strs.len; \
michael@16 64 }while(0)
michael@16 65
michael@16 66
michael@16 67 #define WWW_AUTH_CODE 401
michael@16 68 #define WWW_AUTH_HDR "WWW-Authenticate"
michael@16 69 #define WWW_AUTH_HDR_LEN (sizeof(WWW_AUTH_HDR)-1)
michael@16 70 #define PROXY_AUTH_CODE 407
michael@16 71 #define PROXY_AUTH_HDR "Proxy-Authenticate"
michael@16 72 #define PROXY_AUTH_HDR_LEN (sizeof(PROXY_AUTH_HDR)-1)
michael@16 73
michael@16 74 static str nc = {"00000001", 8};
michael@16 75 static str cnonce = {"o", 1};
michael@16 76
michael@16 77 int has_credentials(void)
michael@16 78 {
michael@16 79 return (crd_list!=0)?1:0;
michael@16 80 }
michael@16 81
michael@16 82 void free_credential(struct uac_credential *crd)
michael@16 83 {
michael@16 84 if (crd)
michael@16 85 {
michael@16 86 if (crd->realm.s)
michael@16 87 pkg_free(crd->realm.s);
michael@16 88 if (crd->user.s)
michael@16 89 pkg_free(crd->user.s);
michael@16 90 if (crd->passwd.s)
michael@16 91 pkg_free(crd->passwd.s);
michael@16 92 pkg_free(crd);
michael@16 93 }
michael@16 94 }
michael@16 95
michael@16 96
michael@16 97 int add_credential( unsigned int type, void *val)
michael@16 98 {
michael@16 99 struct uac_credential *crd;
michael@16 100 char *p;
michael@16 101 str foo;
michael@16 102
michael@16 103 p = (char*)val;
michael@16 104 crd = 0;
michael@16 105
michael@16 106 if (p==0 || *p==0)
michael@16 107 goto error;
michael@16 108
michael@16 109 crd = (struct uac_credential*)pkg_malloc(sizeof(struct uac_credential));
michael@16 110 if (crd==0)
michael@16 111 {
michael@16 112 LM_ERR("no more pkg mem\n");
michael@16 113 goto error;
michael@16 114 }
michael@16 115 memset( crd, 0, sizeof(struct uac_credential));
michael@16 116
michael@16 117 /*parse the user */
michael@16 118 while (*p && isspace((int)*p)) p++;
michael@16 119 foo.s = p;
michael@16 120 while (*p && *p!=':' && !isspace((int)*p)) p++;
michael@16 121 if (foo.s==p || *p==0)
michael@16 122 /* missing or empty user */
michael@16 123 goto parse_error;
michael@16 124 foo.len = p - foo.s;
michael@16 125 /* dulicate it */
michael@16 126 duplicate_str( crd->user, foo, error);
michael@16 127
michael@16 128 /* parse the ':' separator */
michael@16 129 while (*p && isspace((int)*p)) p++;
michael@16 130 if (*p!=':')
michael@16 131 goto parse_error;
michael@16 132 p++;
michael@16 133 while (*p && isspace((int)*p)) p++;
michael@16 134 if (*p==0)
michael@16 135 goto parse_error;
michael@16 136
michael@16 137 /*parse the realm */
michael@16 138 while (*p && isspace((int)*p)) p++;
michael@16 139 foo.s = p;
michael@16 140 while (*p && *p!=':' && !isspace((int)*p)) p++;
michael@16 141 if (foo.s==p || *p==0)
michael@16 142 /* missing or empty realm */
michael@16 143 goto parse_error;
michael@16 144 foo.len = p - foo.s;
michael@16 145 /* dulicate it */
michael@16 146 duplicate_str( crd->realm, foo, error);
michael@16 147
michael@16 148 /* parse the ':' separator */
michael@16 149 while (*p && isspace((int)*p)) p++;
michael@16 150 if (*p!=':')
michael@16 151 goto parse_error;
michael@16 152 p++;
michael@16 153 while (*p && isspace((int)*p)) p++;
michael@16 154 if (*p==0)
michael@16 155 goto parse_error;
michael@16 156
michael@16 157 /*parse the passwd */
michael@16 158 while (*p && isspace((int)*p)) p++;
michael@16 159 foo.s = p;
michael@16 160 while (*p && !isspace((int)*p)) p++;
michael@16 161 if (foo.s==p)
michael@16 162 /* missing or empty passwd */
michael@16 163 goto parse_error;
michael@16 164 foo.len = p - foo.s;
michael@16 165 /* dulicate it */
michael@16 166 duplicate_str( crd->passwd, foo, error);
michael@16 167
michael@16 168 /* end of string */
michael@16 169 while (*p && isspace((int)*p)) p++;
michael@16 170 if (*p!=0)
michael@16 171 goto parse_error;
michael@16 172
michael@16 173 /* link the new cred struct */
michael@16 174 crd->next = crd_list;
michael@16 175 crd_list = crd;
michael@16 176
michael@16 177 pkg_free(val);
michael@16 178 return 0;
michael@16 179 parse_error:
michael@16 180 LM_ERR("parse error in <%s> "
michael@16 181 "around %ld\n", (char*)val, (long)(p-(char*)val));
michael@16 182 error:
michael@16 183 if (crd)
michael@16 184 free_credential(crd);
michael@16 185 return -1;
michael@16 186 }
michael@16 187
michael@16 188
michael@16 189 void destroy_credentials(void)
michael@16 190 {
michael@16 191 struct uac_credential *foo;
michael@16 192
michael@16 193 while (crd_list)
michael@16 194 {
michael@16 195 foo = crd_list;
michael@16 196 crd_list = crd_list->next;
michael@16 197 free_credential(foo);
michael@16 198 }
michael@16 199 crd_list = 0;
michael@16 200 }
michael@16 201
michael@16 202
michael@16 203 static inline struct hdr_field *get_autenticate_hdr(struct sip_msg *rpl,
michael@16 204 int rpl_code)
michael@16 205 {
michael@16 206 struct hdr_field *hdr;
michael@16 207 str hdr_name;
michael@16 208
michael@16 209 /* what hdr should we look for */
michael@16 210 if (rpl_code==WWW_AUTH_CODE)
michael@16 211 {
michael@16 212 hdr_name.s = WWW_AUTH_HDR;
michael@16 213 hdr_name.len = WWW_AUTH_HDR_LEN;
michael@16 214 } else if (rpl_code==PROXY_AUTH_CODE) {
michael@16 215 hdr_name.s = PROXY_AUTH_HDR;
michael@16 216 hdr_name.len = PROXY_AUTH_HDR_LEN;
michael@16 217 } else {
michael@16 218 LM_ERR("reply is not an "
michael@16 219 "auth request\n");
michael@16 220 goto error;
michael@16 221 }
michael@16 222
michael@16 223 LM_DBG("looking for header \"%.*s\"\n",
michael@16 224 hdr_name.len, hdr_name.s);
michael@16 225
michael@16 226 /* search the auth hdr, but first parse them all */
michael@16 227 if (parse_headers( rpl, HDR_EOH_F, 0)<0)
michael@16 228 {
michael@16 229 LM_ERR("failed to parse reply\n");
michael@16 230 goto error;
michael@16 231 }
michael@16 232 hdr = get_header_by_name( rpl , hdr_name.s, hdr_name.len);
michael@16 233 if (hdr)
michael@16 234 return hdr;
michael@16 235
michael@16 236 LM_ERR("reply has no "
michael@16 237 "auth hdr (%.*s)\n", hdr_name.len, hdr_name.s);
michael@16 238 error:
michael@16 239 return 0;
michael@16 240 }
michael@16 241
michael@16 242
michael@16 243 static inline struct uac_credential *lookup_realm( str *realm)
michael@16 244 {
michael@16 245 struct uac_credential *crd;
michael@16 246
michael@16 247 for( crd=crd_list ; crd ; crd=crd->next )
michael@16 248 if (realm->len==crd->realm.len &&
michael@16 249 strncmp( realm->s, crd->realm.s, realm->len)==0 )
michael@16 250 return crd;
michael@16 251 return 0;
michael@16 252 }
michael@16 253
michael@16 254
michael@16 255 static inline struct uac_credential *get_avp_credential(struct sip_msg *msg,
michael@16 256 str *realm)
michael@16 257 {
michael@16 258 static struct uac_credential crd;
michael@16 259 pv_value_t pv_val;
michael@16 260
michael@16 261 if(pv_get_spec_value( msg, &auth_realm_spec, &pv_val)!=0
michael@16 262 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
michael@16 263 return 0;
michael@16 264
michael@16 265 crd.realm = pv_val.rs;
michael@16 266 /* is it the domain we are looking for? */
michael@16 267 if (realm->len!=crd.realm.len ||
michael@16 268 strncmp( realm->s, crd.realm.s, realm->len)!=0 )
michael@16 269 return 0;
michael@16 270
michael@16 271 /* get username and password */
michael@16 272 if(pv_get_spec_value( msg, &auth_username_spec, &pv_val)!=0
michael@16 273 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
michael@16 274 return 0;
michael@16 275 crd.user = pv_val.rs;
michael@16 276
michael@16 277 if(pv_get_spec_value( msg, &auth_password_spec, &pv_val)!=0
michael@16 278 || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0)
michael@16 279 return 0;
michael@16 280 crd.passwd = pv_val.rs;
michael@16 281
michael@16 282 return &crd;
michael@16 283 }
michael@16 284
michael@16 285
michael@16 286 static inline void do_uac_auth(struct sip_msg *req, str *uri,
michael@16 287 struct uac_credential *crd, struct authenticate_body *auth,
michael@16 288 HASHHEX response)
michael@16 289 {
michael@16 290 HASHHEX ha1;
michael@16 291 HASHHEX ha2;
michael@16 292
michael@16 293 if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT))
michael@16 294 {
michael@16 295 /* if qop generate nonce-count and cnonce */
michael@16 296 cnonce.s = int2str(core_hash(&auth->nonce, 0, 0),&cnonce.len);
michael@16 297
michael@16 298 /* do authentication */
michael@16 299 uac_calc_HA1( crd, auth, &cnonce, ha1);
michael@16 300 uac_calc_HA2( &req->first_line.u.request.method, uri,
michael@16 301 auth, 0/*hentity*/, ha2 );
michael@16 302
michael@16 303 uac_calc_response( ha1, ha2, auth, &nc, &cnonce, response);
michael@16 304 auth->nc = &nc;
michael@16 305 auth->cnonce = &cnonce;
michael@16 306 } else {
michael@16 307 /* do authentication */
michael@16 308 uac_calc_HA1( crd, auth, 0/*cnonce*/, ha1);
michael@16 309 uac_calc_HA2( &req->first_line.u.request.method, uri,
michael@16 310 auth, 0/*hentity*/, ha2 );
michael@16 311
michael@16 312 uac_calc_response( ha1, ha2, auth, 0/*nc*/, 0/*cnonce*/, response);
michael@16 313 }
michael@16 314 }
michael@16 315
michael@16 316
michael@16 317 static inline int apply_urihdr_changes( struct sip_msg *req,
michael@16 318 str *uri, str *hdr)
michael@16 319 {
michael@16 320 struct lump* anchor;
michael@16 321
michael@16 322 /* add the uri - move it to branch directly FIXME (bogdan)*/
michael@16 323 if (req->new_uri.s)
michael@16 324 {
michael@16 325 pkg_free(req->new_uri.s);
michael@16 326 req->new_uri.len=0;
michael@16 327 }
michael@16 328 req->parsed_uri_ok=0;
michael@16 329 req->new_uri.s = (char*)pkg_malloc(uri->len+1);
michael@16 330 if (req->new_uri.s==0)
michael@16 331 {
michael@16 332 LM_ERR("no more pkg\n");
michael@16 333 goto error;
michael@16 334 }
michael@16 335 memcpy( req->new_uri.s, uri->s, uri->len);
michael@16 336 req->new_uri.s[uri->len]=0;
michael@16 337 req->new_uri.len=uri->len;
michael@16 338
michael@16 339 /* add the header */
michael@16 340 if (parse_headers(req, HDR_EOH_F, 0) == -1)
michael@16 341 {
michael@16 342 LM_ERR("failed to parse message\n");
michael@16 343 goto error;
michael@16 344 }
michael@16 345
michael@16 346 anchor = anchor_lump(req, req->unparsed - req->buf, 0, 0);
michael@16 347 if (anchor==0)
michael@16 348 {
michael@16 349 LM_ERR("failed to get anchor\n");
michael@16 350 goto error;
michael@16 351 }
michael@16 352
michael@16 353 if (insert_new_lump_before(anchor, hdr->s, hdr->len, 0) == 0)
michael@16 354 {
michael@16 355 LM_ERR("faield to insert lump\n");
michael@16 356 goto error;
michael@16 357 }
michael@16 358
michael@16 359 return 0;
michael@16 360 error:
michael@16 361 pkg_free( hdr->s );
michael@16 362 return -1;
michael@16 363 }
michael@16 364
michael@16 365
michael@16 366
michael@16 367 int uac_auth( struct sip_msg *msg)
michael@16 368 {
michael@16 369 static struct authenticate_body auth;
michael@16 370 struct uac_credential *crd;
michael@16 371 int code, branch;
michael@16 372 struct sip_msg *rpl;
michael@16 373 struct cell *t;
michael@16 374 struct hdr_field *hdr;
michael@16 375 HASHHEX response;
michael@16 376 str *new_hdr;
michael@16 377
michael@16 378 /* get transaction */
michael@16 379 t = uac_tmb.t_gett();
michael@16 380 if (t==T_UNDEFINED || t==T_NULL_CELL)
michael@16 381 {
michael@16 382 LM_CRIT("no current transaction found\n");
michael@16 383 goto error;
michael@16 384 }
michael@16 385
michael@16 386 /* get the selected branch */
michael@16 387 branch = uac_tmb.t_get_picked();
michael@16 388 if (branch<0) {
michael@16 389 LM_CRIT("no picked branch (%d)\n",branch);
michael@16 390 goto error;
michael@16 391 }
michael@16 392
michael@16 393 rpl = t->uac[branch].reply;
michael@16 394 code = t->uac[branch].last_received;
michael@16 395 LM_DBG("picked reply is %p, code %d\n",rpl,code);
michael@16 396
michael@16 397 if (rpl==0)
michael@16 398 {
michael@16 399 LM_CRIT("empty reply on picked branch\n");
michael@16 400 goto error;
michael@16 401 }
michael@16 402 if (rpl==FAKED_REPLY)
michael@16 403 {
michael@16 404 LM_ERR("cannot process a FAKED reply\n");
michael@16 405 goto error;
michael@16 406 }
michael@16 407
michael@16 408 hdr = get_autenticate_hdr( rpl, code);
michael@16 409 if (hdr==0)
michael@16 410 {
michael@16 411 LM_ERR("failed to extract authenticate hdr\n");
michael@16 412 goto error;
michael@16 413 }
michael@16 414
michael@16 415 LM_DBG("header found; body=<%.*s>\n",
michael@16 416 hdr->body.len, hdr->body.s);
michael@16 417
michael@16 418 if (parse_authenticate_body( &hdr->body, &auth)<0)
michael@16 419 {
michael@16 420 LM_ERR("failed to parse auth hdr body\n");
michael@16 421 goto error;
michael@16 422 }
michael@16 423
michael@16 424 /* can we authenticate this realm? */
michael@16 425 crd = 0;
michael@16 426 /* first look into AVP, if set */
michael@16 427 if ( auth_realm_spec.type==PVT_AVP )
michael@16 428 crd = get_avp_credential( msg, &auth.realm );
michael@16 429 /* if not found, look into predefined credentials */
michael@16 430 if (crd==0)
michael@16 431 crd = lookup_realm( &auth.realm );
michael@16 432 /* found? */
michael@16 433 if (crd==0)
michael@16 434 {
michael@16 435 LM_DBG("no credential for realm \"%.*s\"\n",
michael@16 436 auth.realm.len, auth.realm.s);
michael@16 437 goto error;
michael@16 438 }
michael@16 439
michael@16 440 /* do authentication */
michael@16 441 do_uac_auth( msg, &t->uac[branch].uri, crd, &auth, response);
michael@16 442
michael@16 443 /* build the authorization header */
michael@16 444 new_hdr = build_authorization_hdr( code, &t->uac[branch].uri,
michael@16 445 crd, &auth, response);
michael@16 446 if (new_hdr==0)
michael@16 447 {
michael@16 448 LM_ERR("failed to build authorization hdr\n");
michael@16 449 goto error;
michael@16 450 }
michael@16 451
michael@16 452 /* so far, so good -> add the header and set the proper RURI */
michael@16 453 if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 )
michael@16 454 {
michael@16 455 LM_ERR("failed to apply changes\n");
michael@16 456 goto error;
michael@16 457 }
michael@16 458
michael@16 459 /* increas the Cseq nr */
michael@16 460
michael@16 461
michael@16 462 return 0;
michael@16 463 error:
michael@16 464 return -1;
michael@16 465 }
michael@16 466
michael@16 467
michael@16 468

mercurial