Changeset 123 for pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c
- Timestamp:
- Jan 18, 2006 11:34:15 PM (18 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c
r112 r123 17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 */ 19 19 20 #include <pjsip/sip_auth.h> 20 21 #include <pjsip/sip_auth_parser.h> /* just to get pjsip_DIGEST_STR */ 21 22 #include <pjsip/sip_transport.h> 22 23 #include <pjsip/sip_endpoint.h> 24 #include <pjsip/sip_errno.h> 23 25 #include <pjlib-util/md5.h> 24 26 #include <pj/log.h> … … 29 31 #include <pj/ctype.h> 30 32 31 /* Length of digest string. */ 32 #define MD5STRLEN 32 33 34 /* Maximum stack size we use for storing username+realm+password etc. */ 35 #define MAX_TEMP 128 33 36 34 37 35 /* A macro just to get rid of type mismatch between char and unsigned char */ … … 39 37 40 38 /* Logging. */ 41 #define THIS_FILE "sip_auth .c"39 #define THIS_FILE "sip_auth_client.c" 42 40 #if 0 43 41 # define AUTH_TRACE_(expr) PJ_LOG(3, expr) … … 46 44 #endif 47 45 48 static const char hex[] = "0123456789abcdef";49 50 46 /* Transform digest to string. 51 * output must be at least MD5STRLEN+1 bytes.47 * output must be at least PJSIP_MD5STRLEN+1 bytes. 52 48 * 53 49 * NOTE: THE OUTPUT STRING IS NOT NULL TERMINATED! … … 55 51 static void digest2str(const unsigned char digest[], char *output) 56 52 { 57 char *p = output;58 53 int i; 59 60 54 for (i = 0; i<16; ++i) { 61 int val = digest[i];62 *p++ = hex[val >> 4];63 *p++ = hex[val & 0x0F]; 64 65 } 55 pj_val_to_hex_digit(digest[i], output); 56 output += 2; 57 } 58 } 59 66 60 67 61 /* … … 69 63 * digest ASCII in 'result'. 70 64 */ 71 static voidcreate_digest( pj_str_t *result,72 const pj_str_t *nonce,73 const pj_str_t *nc,74 const pj_str_t *cnonce,75 const pj_str_t *qop,76 const pj_str_t *uri,77 const pjsip_cred_info *cred_info,78 const pj_str_t *method)79 { 80 char ha1[ MD5STRLEN];81 char ha2[ MD5STRLEN];65 void pjsip_auth_create_digest( pj_str_t *result, 66 const pj_str_t *nonce, 67 const pj_str_t *nc, 68 const pj_str_t *cnonce, 69 const pj_str_t *qop, 70 const pj_str_t *uri, 71 const pjsip_cred_info *cred_info, 72 const pj_str_t *method) 73 { 74 char ha1[PJSIP_MD5STRLEN]; 75 char ha2[PJSIP_MD5STRLEN]; 82 76 unsigned char digest[16]; 83 77 pj_md5_context pms; 84 78 85 pj_assert(result->slen >= MD5STRLEN);79 pj_assert(result->slen >= PJSIP_MD5STRLEN); 86 80 87 81 AUTH_TRACE_((THIS_FILE, "Begin creating digest")); … … 128 122 ***/ 129 123 pj_md5_init(&pms); 130 MD5_APPEND( &pms, ha1, MD5STRLEN);124 MD5_APPEND( &pms, ha1, PJSIP_MD5STRLEN); 131 125 MD5_APPEND( &pms, ":", 1); 132 126 MD5_APPEND( &pms, nonce->ptr, nonce->slen); … … 140 134 } 141 135 MD5_APPEND( &pms, ":", 1); 142 MD5_APPEND( &pms, ha2, MD5STRLEN);136 MD5_APPEND( &pms, ha2, PJSIP_MD5STRLEN); 143 137 144 138 /* This is the final response digest. */ … … 146 140 147 141 /* Convert digest to string and store in chal->response. */ 148 result->slen = MD5STRLEN;142 result->slen = PJSIP_MD5STRLEN; 149 143 digest2str(digest, result->ptr); 150 144 … … 207 201 PJ_LOG(4,(THIS_FILE, "Unsupported digest algorithm \"%.*s\"", 208 202 chal->algorithm.slen, chal->algorithm.ptr)); 209 return -1;203 return PJSIP_EINVALIDALGORITHM; 210 204 } 211 205 … … 219 213 220 214 /* Allocate memory. */ 221 cred->response.ptr = pj_pool_alloc(pool, MD5STRLEN);222 cred->response.slen = MD5STRLEN;215 cred->response.ptr = pj_pool_alloc(pool, PJSIP_MD5STRLEN); 216 cred->response.slen = PJSIP_MD5STRLEN; 223 217 224 218 if (chal->qop.slen == 0) { … … 226 220 227 221 /* Convert digest to string and store in chal->response. */ 228 create_digest( &cred->response, &cred->nonce, NULL, NULL, NULL,229 222 pjsip_auth_create_digest( &cred->response, &cred->nonce, NULL, NULL, 223 NULL, uri, cred_info, method); 230 224 231 225 } else if (has_auth_qop(pool, &chal->qop)) { … … 244 238 } 245 239 246 create_digest( &cred->response, &cred->nonce, &cred->nc, cnonce, 247 &pjsip_AUTH_STR, uri, cred_info, method ); 240 pjsip_auth_create_digest( &cred->response, &cred->nonce, &cred->nc, 241 cnonce, &pjsip_AUTH_STR, uri, cred_info, 242 method ); 248 243 249 244 } else { … … 251 246 PJ_LOG(4,(THIS_FILE, "Unsupported qop offer %.*s", 252 247 chal->qop.slen, chal->qop.ptr)); 253 return -1;254 } 255 256 return 0;257 } 258 259 #if PJSIP_AUTH_QOP_SUPPORT248 return PJSIP_EINVALIDQOP; 249 } 250 251 return PJ_SUCCESS; 252 } 253 254 #if defined(PJSIP_AUTH_QOP_SUPPORT) && PJSIP_AUTH_QOP_SUPPORT!=0 260 255 /* 261 256 * Update authentication session with a challenge. 262 257 */ 263 258 static void update_digest_session( pj_pool_t *ses_pool, 264 pjsip_ auth_session *auth_sess,259 pjsip_cached_auth *cached_auth, 265 260 const pjsip_www_authenticate_hdr *hdr ) 266 261 { … … 269 264 270 265 /* Initialize cnonce and qop if not present. */ 271 if ( auth_sess->cnonce.slen == 0) {266 if (cached_auth->cnonce.slen == 0) { 272 267 /* Save the whole challenge */ 273 auth_sess->last_chal = pjsip_hdr_clone(ses_pool, hdr);268 cached_auth->last_chal = pjsip_hdr_clone(ses_pool, hdr); 274 269 275 270 /* Create cnonce */ 276 pj_create_unique_string( ses_pool, & auth_sess->cnonce );271 pj_create_unique_string( ses_pool, &cached_auth->cnonce ); 277 272 278 273 /* Initialize nonce-count */ 279 auth_sess->nc = 1;274 cached_auth->nc = 1; 280 275 281 276 /* Save realm. */ 282 pj_assert( auth_sess->realm.slen != 0);283 if ( auth_sess->realm.slen == 0) {284 pj_strdup(ses_pool, & auth_sess->realm,277 pj_assert(cached_auth->realm.slen != 0); 278 if (cached_auth->realm.slen == 0) { 279 pj_strdup(ses_pool, &cached_auth->realm, 285 280 &hdr->challenge.digest.realm); 286 281 } … … 289 284 /* Update last_nonce and nonce-count */ 290 285 if (!pj_strcmp(&hdr->challenge.digest.nonce, 291 & auth_sess->last_chal->challenge.digest.nonce))286 &cached_auth->last_chal->challenge.digest.nonce)) 292 287 { 293 288 /* Same nonce, increment nonce-count */ 294 ++ auth_sess->nc;289 ++cached_auth->nc; 295 290 } else { 296 291 /* Server gives new nonce. */ 297 pj_strdup(ses_pool, & auth_sess->last_chal->challenge.digest.nonce,292 pj_strdup(ses_pool, &cached_auth->last_chal->challenge.digest.nonce, 298 293 &hdr->challenge.digest.nonce); 299 294 /* Has the opaque changed? */ 300 if (pj_strcmp(& auth_sess->last_chal->challenge.digest.opaque,295 if (pj_strcmp(&cached_auth->last_chal->challenge.digest.opaque, 301 296 &hdr->challenge.digest.opaque)) 302 297 { 303 298 pj_strdup(ses_pool, 304 & auth_sess->last_chal->challenge.digest.opaque,299 &cached_auth->last_chal->challenge.digest.opaque, 305 300 &hdr->challenge.digest.opaque); 306 301 } 307 auth_sess->nc = 1;302 cached_auth->nc = 1; 308 303 } 309 304 } … … 312 307 313 308 314 /* Find authentication session in the list. */315 static pjsip_ auth_session *find_session( pjsip_auth_session *sess_list,316 const pj_str_t *realm )317 { 318 pjsip_ auth_session *sess = sess_list->next;319 while ( sess != sess_list) {320 if (pj_stricmp(& sess->realm, realm) == 0)321 return sess;322 sess = sess->next;309 /* Find cached authentication in the list for the specified realm. */ 310 static pjsip_cached_auth *find_cached_auth( pjsip_auth_clt_sess *sess, 311 const pj_str_t *realm ) 312 { 313 pjsip_cached_auth *auth = sess->cached_auth.next; 314 while (auth != &sess->cached_auth) { 315 if (pj_stricmp(&auth->realm, realm) == 0) 316 return auth; 317 auth = auth->next; 323 318 } 324 319 325 320 return NULL; 326 321 } 322 323 /* Find credential to use for the specified realm and auth scheme. */ 324 static const pjsip_cred_info* auth_find_cred( const pjsip_auth_clt_sess *sess, 325 const pj_str_t *realm, 326 const pj_str_t *auth_scheme) 327 { 328 unsigned i; 329 PJ_UNUSED_ARG(auth_scheme); 330 for (i=0; i<sess->cred_cnt; ++i) { 331 if (pj_stricmp(&sess->cred_info[i].realm, realm) == 0) 332 return &sess->cred_info[i]; 333 } 334 return NULL; 335 } 336 337 338 /* Init client session. */ 339 PJ_DEF(pj_status_t) pjsip_auth_clt_init( pjsip_auth_clt_sess *sess, 340 pjsip_endpoint *endpt, 341 pj_pool_t *pool, 342 unsigned options) 343 { 344 PJ_ASSERT_RETURN(sess && endpt && pool && (options==0), PJ_EINVAL); 345 346 sess->pool = pool; 347 sess->endpt = endpt; 348 sess->cred_cnt = 0; 349 sess->cred_info = NULL; 350 pj_list_init(&sess->cached_auth); 351 352 return PJ_SUCCESS; 353 } 354 355 356 /* Set client credentials. */ 357 PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess, 358 int cred_cnt, 359 const pjsip_cred_info *c) 360 { 361 PJ_ASSERT_RETURN(sess && cred_cnt && c, PJ_EINVAL); 362 363 sess->cred_info = pj_pool_alloc(sess->pool, cred_cnt * sizeof(*c)); 364 pj_memcpy(sess->cred_info, c, cred_cnt * sizeof(*c)); 365 sess->cred_cnt = cred_cnt; 366 367 return PJ_SUCCESS; 368 } 369 327 370 328 371 /* … … 330 373 * in WWW-Authenticate/Proxy-Authenticate header. 331 374 */ 332 PJ_DEF(pjsip_authorization_hdr*) 333 pjsip_auth_respond( pj_pool_t *req_pool,334 const pjsip_www_authenticate_hdr *hdr,335 const pjsip_uri *uri,336 const pjsip_cred_info *cred_info,337 const pjsip_method *method,338 pj_pool_t *sess_pool,339 pjsip_auth_session *auth_sess)340 { 341 pjsip_authorization_hdr * auth;375 static pj_status_t auth_respond( pj_pool_t *req_pool, 376 const pjsip_www_authenticate_hdr *hdr, 377 const pjsip_uri *uri, 378 const pjsip_cred_info *cred_info, 379 const pjsip_method *method, 380 pj_pool_t *sess_pool, 381 pjsip_cached_auth *cached_auth, 382 pjsip_authorization_hdr **p_h_auth) 383 { 384 pjsip_authorization_hdr *hauth; 342 385 char tmp[PJSIP_MAX_URL_SIZE]; 343 386 pj_str_t uri_str; 344 387 pj_pool_t *pool; 345 346 pj_assert(hdr != NULL); 347 pj_assert(uri != NULL);348 pj_assert(cred_info != NULL);349 pj_assert(method != NULL);388 pj_status_t status; 389 390 /* Verify arguments. */ 391 PJ_ASSERT_RETURN(req_pool && hdr && uri && cred_info && method && 392 sess_pool && cached_auth && p_h_auth, PJ_EINVAL); 350 393 351 394 /* Print URL in the original request. */ 352 395 uri_str.ptr = tmp; 353 uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp, 396 uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp,sizeof(tmp)); 354 397 if (uri_str.slen < 1) { 355 398 pj_assert(!"URL is too long!"); 356 PJ_LOG(4,(THIS_FILE, "Unable to authorize: URI is too long!")); 357 return NULL; 399 return PJSIP_EURITOOLONG; 358 400 } 359 401 … … 371 413 372 414 if (hdr->type == PJSIP_H_WWW_AUTHENTICATE) 373 auth = pjsip_authorization_hdr_create(pool);415 hauth = pjsip_authorization_hdr_create(pool); 374 416 else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE) 375 auth = pjsip_proxy_authorization_hdr_create(pool);417 hauth = pjsip_proxy_authorization_hdr_create(pool); 376 418 else { 377 pj_assert( 0);378 return NULL;419 pj_assert(!"Invalid response header!"); 420 return PJSIP_EINVALIDHDR; 379 421 } 380 422 381 423 /* Only support digest scheme at the moment. */ 382 424 if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) { 383 pj_status_t rc;384 425 pj_str_t *cnonce = NULL; 385 426 pj_uint32_t nc = 1; … … 388 429 # if PJSIP_AUTH_QOP_SUPPORT 389 430 { 390 if ( auth_sess) {391 update_digest_session( sess_pool, auth_sess, hdr );392 393 cnonce = & auth_sess->cnonce;394 nc = auth_sess->nc;431 if (cached_auth) { 432 update_digest_session( sess_pool, cached_auth, hdr ); 433 434 cnonce = &cached_auth->cnonce; 435 nc = cached_auth->nc; 395 436 } 396 437 } 397 438 # endif /* PJSIP_AUTH_QOP_SUPPORT */ 398 439 399 auth->scheme = pjsip_DIGEST_STR;400 rc = respond_digest( pool, &auth->credential.digest,401 402 403 if ( rc != 0)404 return NULL;440 hauth->scheme = pjsip_DIGEST_STR; 441 status = respond_digest( pool, &hauth->credential.digest, 442 &hdr->challenge.digest, &uri_str, cred_info, 443 cnonce, nc, &method->name); 444 if (status != PJ_SUCCESS) 445 return status; 405 446 406 447 /* Set qop type in auth session the first time only. */ 407 if (hdr->challenge.digest.qop.slen != 0 && auth_sess) {408 if ( auth_sess->qop_value == PJSIP_AUTH_QOP_NONE) {409 pj_str_t *qop_val = & auth->credential.digest.qop;448 if (hdr->challenge.digest.qop.slen != 0 && cached_auth) { 449 if (cached_auth->qop_value == PJSIP_AUTH_QOP_NONE) { 450 pj_str_t *qop_val = &hauth->credential.digest.qop; 410 451 if (!pj_strcmp(qop_val, &pjsip_AUTH_STR)) { 411 auth_sess->qop_value = PJSIP_AUTH_QOP_AUTH;452 cached_auth->qop_value = PJSIP_AUTH_QOP_AUTH; 412 453 } else { 413 auth_sess->qop_value = PJSIP_AUTH_QOP_UNKNOWN;454 cached_auth->qop_value = PJSIP_AUTH_QOP_UNKNOWN; 414 455 } 415 456 } 416 457 } 417 458 } else { 418 auth = NULL;459 return PJSIP_EINVALIDAUTHSCHEME; 419 460 } 420 461 … … 424 465 # if PJSIP_AUTH_HEADER_CACHING 425 466 { 426 if ( auth && auth_sess && auth_sess->qop_value == PJSIP_AUTH_QOP_NONE) {467 if (hauth && cached_auth && cached_auth->qop_value == PJSIP_AUTH_QOP_NONE) { 427 468 pjsip_cached_auth_hdr *cached_hdr; 428 469 429 470 /* Delete old header with the same method. */ 430 cached_hdr = auth_sess->cached_hdr.next;431 while (cached_hdr != & auth_sess->cached_hdr) {471 cached_hdr = cached_auth->cached_hdr.next; 472 while (cached_hdr != &cached_auth->cached_hdr) { 432 473 if (pjsip_method_cmp(method, &cached_hdr->method)==0) 433 474 break; … … 436 477 437 478 /* Save the header to the list. */ 438 if (cached_hdr != & auth_sess->cached_hdr) {439 cached_hdr->hdr = auth;479 if (cached_hdr != &cached_auth->cached_hdr) { 480 cached_hdr->hdr = hauth; 440 481 } else { 441 482 cached_hdr = pj_pool_alloc(pool, sizeof(*cached_hdr)); 442 483 pjsip_method_copy( pool, &cached_hdr->method, method); 443 cached_hdr->hdr = auth;444 pj_list_insert_before( & auth_sess->cached_hdr, cached_hdr );484 cached_hdr->hdr = hauth; 485 pj_list_insert_before( &cached_auth->cached_hdr, cached_hdr ); 445 486 } 446 487 } … … 448 489 # endif 449 490 450 return auth; 451 452 } 453 454 /* Verify incoming Authorization/Proxy-Authorization header against existing 455 * credentials. Will return TRUE if the authorization request matches any of 456 * the credential. 457 */ 458 PJ_DEF(pj_bool_t) pjsip_auth_verify(const pjsip_authorization_hdr *hdr, 459 const pj_str_t *method, 460 const pjsip_cred_info *cred_info ) 461 { 462 if (pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR) == 0) { 463 char digest_buf[MD5STRLEN]; 464 pj_str_t digest; 465 const pjsip_digest_credential *dig = &hdr->credential.digest; 466 467 /* Check that username match. */ 468 if (pj_strcmp(&dig->username, &cred_info->username) != 0) 469 return PJ_FALSE; 470 471 /* Check that realm match. */ 472 if (pj_strcmp(&dig->realm, &cred_info->realm) != 0) 473 return PJ_FALSE; 474 475 /* Prepare for our digest calculation. */ 476 digest.ptr = digest_buf; 477 digest.slen = MD5STRLEN; 478 479 /* Create digest for comparison. */ 480 create_digest( &digest, 481 &hdr->credential.digest.nonce, 482 &hdr->credential.digest.nc, 483 &hdr->credential.digest.cnonce, 484 &hdr->credential.digest.qop, 485 &hdr->credential.digest.uri, 486 cred_info, 487 method ); 488 489 return pj_stricmp(&digest, &hdr->credential.digest.response) == 0; 490 491 } else { 492 pj_assert(0); 493 return PJ_FALSE; 494 } 495 } 496 497 /* Find credential to use for the specified realm and scheme. */ 498 PJ_DEF(const pjsip_cred_info*) pjsip_auth_find_cred( unsigned count, 499 const pjsip_cred_info cred[], 500 const pj_str_t *realm, 501 const pj_str_t *scheme) 502 { 503 unsigned i; 504 PJ_UNUSED_ARG(scheme); 505 for (i=0; i<count; ++i) { 506 if (pj_stricmp(&cred[i].realm, realm) == 0) 507 return &cred[i]; 508 } 509 return NULL; 510 } 511 512 #if PJSIP_AUTH_AUTO_SEND_NEXT 513 static void new_auth_for_req( pjsip_tx_data *tdata, 514 pj_pool_t *sess_pool, 515 pjsip_auth_session *sess, 516 int cred_count, 517 const pjsip_cred_info cred_info[]) 491 *p_h_auth = hauth; 492 return PJ_SUCCESS; 493 494 } 495 496 497 #if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && PJSIP_AUTH_AUTO_SEND_NEXT!=0 498 static pj_status_t new_auth_for_req( pjsip_tx_data *tdata, 499 pjsip_auth_clt_sess *sess, 500 pjsip_cached_auth *auth, 501 pjsip_authorization_hdr **p_h_auth) 518 502 { 519 503 const pjsip_cred_info *cred; 520 504 pjsip_authorization_hdr *hauth; 521 522 pj_assert(sess->last_chal != NULL); 523 524 cred = pjsip_auth_find_cred( cred_count, cred_info, &sess->realm, 525 &sess->last_chal->scheme ); 505 pj_status_t status; 506 507 PJ_ASSERT_RETURN(tdata && sess && auth, PJ_EINVAL); 508 PJ_ASSERT_RETURN(auth->last_chal != NULL, PJSIP_EAUTHNOPREVCHAL); 509 510 cred = auth_find_cred( sess, &auth->realm, &auth->last_chal->scheme ); 526 511 if (!cred) 527 return; 528 512 return PJSIP_ENOCREDENTIAL; 513 514 status = auth_respond( tdata->pool, auth->last_chal, 515 tdata->msg->line.req.uri, 516 cred, &tdata->msg->line.req.method, 517 sess->pool, auth, &hauth); 518 if (status != PJ_SUCCESS) 519 return status; 529 520 530 hauth = pjsip_auth_respond( tdata->pool, sess->last_chal, 531 tdata->msg->line.req.uri, 532 cred, &tdata->msg->line.req.method, 533 sess_pool, sess); 534 if (hauth) { 535 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hauth); 536 } 521 pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hauth); 522 523 if (p_h_auth) 524 *p_h_auth = hauth; 525 526 return PJ_SUCCESS; 537 527 } 538 528 #endif 539 529 540 /* 541 * Initialize new request message with authorization headers. 542 * This function will put Authorization/Proxy-Authorization headers to the 543 * outgoing request message. If caching is enabled (PJSIP_AUTH_HEADER_CACHING) 544 * and the session has previously sent Authorization/Proxy-Authorization header 545 * with the same method, then the same Authorization/Proxy-Authorization header 546 * will be resent from the cache only if qop is not present. If the stack is 547 * configured to automatically generate next Authorization/Proxy-Authorization 548 * headers (PJSIP_AUTH_AUTO_SEND_NEXT flag), then new Authorization/Proxy- 549 * Authorization headers are calculated and generated when they are not present 550 * in the case or if authorization session has qop. 551 * 552 * If both PJSIP_AUTH_HEADER_CACHING flag and PJSIP_AUTH_AUTO_SEND_NEXT flag 553 * are not set, this function will do nothing. The stack then will only send 554 * Authorization/Proxy-Authorization to respond 401/407 response. 555 */ 556 PJ_DEF(pj_status_t) pjsip_auth_init_req( pj_pool_t *sess_pool, 557 pjsip_tx_data *tdata, 558 pjsip_auth_session *sess_list, 559 int cred_count, 560 const pjsip_cred_info cred_info[]) 561 { 562 pjsip_auth_session *sess; 563 pjsip_method *method = &tdata->msg->line.req.method; 564 565 pj_assert(tdata->msg->type == PJSIP_REQUEST_MSG); 566 567 if (!sess_list) 568 return 0; 569 570 sess = sess_list->next; 571 while (sess != sess_list) { 572 if (sess->qop_value == PJSIP_AUTH_QOP_NONE) { 573 # if (PJSIP_AUTH_HEADER_CACHING) 530 531 532 /* Initialize outgoing request. */ 533 PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess, 534 pjsip_tx_data *tdata ) 535 { 536 const pjsip_method *method; 537 pjsip_cached_auth *auth; 538 pj_status_t status; 539 540 PJ_ASSERT_RETURN(sess && tdata, PJ_EINVAL); 541 PJ_ASSERT_RETURN(sess->pool, PJSIP_ENOTINITIALIZED); 542 PJ_ASSERT_RETURN(tdata->msg->type==PJSIP_REQUEST_MSG, 543 PJSIP_ENOTREQUESTMSG); 544 545 /* Get the method. */ 546 method = &tdata->msg->line.req.method; 547 548 auth = sess->cached_auth.next; 549 while (auth != &sess->cached_auth) { 550 if (auth->qop_value == PJSIP_AUTH_QOP_NONE) { 551 # if defined(PJSIP_AUTH_HEADER_CACHING) && \ 552 PJSIP_AUTH_HEADER_CACHING!=0 574 553 { 575 pjsip_cached_auth_hdr *entry = sess->cached_hdr.next;576 while (entry != & sess->cached_hdr) {554 pjsip_cached_auth_hdr *entry = auth->cached_hdr.next; 555 while (entry != &auth->cached_hdr) { 577 556 if (pjsip_method_cmp(&entry->method, method)==0) { 578 557 pjsip_authorization_hdr *hauth; … … 580 559 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth); 581 560 } else { 582 # if (PJSIP_AUTH_AUTO_SEND_NEXT) 561 # if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \ 562 PJSIP_AUTH_AUTO_SEND_NEXT!=0 583 563 { 584 new_auth_for_req( tdata, sess_pool, sess, 585 cred_count, cred_info); 564 new_auth_for_req( tdata, sess, auth, NULL); 586 565 } 587 # else 588 { 589 PJ_UNUSED_ARG(sess_pool); 590 PJ_UNUSED_ARG(cred_count); 591 PJ_UNUSED_ARG(cred_info); 592 } 593 # endif /* PJSIP_AUTH_AUTO_SEND_NEXT */ 566 # endif 594 567 } 595 568 entry = entry->next; 596 569 } 597 570 } 598 # elif (PJSIP_AUTH_AUTO_SEND_NEXT) 571 # elif defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \ 572 PJSIP_AUTH_AUTO_SEND_NEXT!=0 599 573 { 600 new_auth_for_req( tdata, sess_pool, sess, 601 cred_count, cred_info); 602 } 603 # else 604 { 605 PJ_UNUSED_ARG(sess_pool); 606 PJ_UNUSED_ARG(cred_count); 607 PJ_UNUSED_ARG(cred_info); 608 } 609 # endif /* PJSIP_AUTH_HEADER_CACHING */ 574 new_auth_for_req( tdata, sess, auth, NULL); 575 } 576 # endif 610 577 611 578 } 612 # if (PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT) 613 else if (sess->qop_value == PJSIP_AUTH_QOP_AUTH) { 579 # if defined(PJSIP_AUTH_QOP_SUPPORT) && \ 580 defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \ 581 (PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT) 582 else if (auth->qop_value == PJSIP_AUTH_QOP_AUTH) { 614 583 /* For qop="auth", we have to re-create the authorization header. 615 584 */ … … 617 586 pjsip_authorization_hdr *hauth; 618 587 619 cred = pjsip_auth_find_cred( cred_count, cred_info, 620 &sess->realm, 621 &sess->last_chal->scheme); 588 cred = auth_find_cred(sess, &auth->realm, 589 &auth->last_chal->scheme); 622 590 if (!cred) { 623 sess = sess->next;591 auth = auth->next; 624 592 continue; 625 593 } 626 594 627 hauth = pjsip_auth_respond( tdata->pool, sess->last_chal, 628 tdata->msg->line.req.uri, 629 cred, 630 &tdata->msg->line.req.method, 631 sess_pool, sess ); 632 if (hauth) { 633 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth); 634 } 595 status = auth_respond( tdata->pool, auth->last_chal, 596 tdata->msg->line.req.uri, 597 cred, 598 &tdata->msg->line.req.method, 599 sess->pool, auth, &hauth); 600 if (status != PJ_SUCCESS) 601 return status; 602 603 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth); 635 604 } 636 605 # endif /* PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT */ 637 606 638 sess = sess->next; 639 } 640 return 0; 641 } 607 auth = auth->next; 608 } 609 610 return PJ_SUCCESS; 611 } 612 642 613 643 614 /* Process authorization challenge */ 644 static pjsip_authorization_hdr *process_auth( pj_pool_t *req_pool, 645 const pjsip_www_authenticate_hdr *hchal, 646 const pjsip_uri *uri, 647 pjsip_tx_data *tdata, 648 int cred_count, 649 const pjsip_cred_info cred_info[], 650 pj_pool_t *ses_pool, 651 pjsip_auth_session *auth_sess) 615 static pj_status_t process_auth( pj_pool_t *req_pool, 616 const pjsip_www_authenticate_hdr *hchal, 617 const pjsip_uri *uri, 618 pjsip_tx_data *tdata, 619 pjsip_auth_clt_sess *sess, 620 pjsip_cached_auth *cached_auth, 621 pjsip_authorization_hdr **h_auth) 652 622 { 653 623 const pjsip_cred_info *cred; 654 pjsip_authorization_hdr *sent_auth = NULL , *hauth;624 pjsip_authorization_hdr *sent_auth = NULL; 655 625 pjsip_hdr *hdr; 626 pj_status_t status; 656 627 657 628 /* See if we have sent authorization header for this realm */ … … 686 657 sent_auth->credential.digest.realm.slen, 687 658 sent_auth->credential.digest.realm.ptr)); 688 return NULL;659 return PJSIP_EFAILEDCREDENTIAL; 689 660 } 690 661 … … 696 667 697 668 /* Find credential to be used for the challenge. */ 698 cred = pjsip_auth_find_cred( cred_count, cred_info,699 &hchal->challenge.common.realm,&hchal->scheme);669 cred = auth_find_cred( sess, &hchal->challenge.common.realm, 670 &hchal->scheme); 700 671 if (!cred) { 701 672 const pj_str_t *realm = &hchal->challenge.common.realm; … … 705 676 realm->slen, realm->ptr, 706 677 hchal->scheme.slen, hchal->scheme.ptr)); 707 return NULL;678 return PJSIP_ENOCREDENTIAL; 708 679 } 709 680 710 681 /* Respond to authorization challenge. */ 711 hauth = pjsip_auth_respond( req_pool, hchal, uri, cred,712 713 ses_pool, auth_sess);714 return hauth;682 status = auth_respond( req_pool, hchal, uri, cred, 683 &tdata->msg->line.req.method, 684 sess->pool, cached_auth, h_auth); 685 return status; 715 686 } 716 687 … … 722 693 * in cached_list. 723 694 */ 724 PJ_DEF(pjsip_tx_data*) pjsip_auth_reinit_req( pjsip_endpoint *endpt, 725 pj_pool_t *ses_pool, 726 pjsip_auth_session *sess_list, 727 int cred_count, 728 const pjsip_cred_info cred_info[], 729 pjsip_tx_data *tdata, 730 const pjsip_rx_data *rdata) 731 { 695 PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req( pjsip_auth_clt_sess *sess, 696 const pjsip_rx_data *rdata, 697 pjsip_tx_data *old_request, 698 pjsip_tx_data **new_request ) 699 { 700 pjsip_tx_data *tdata; 732 701 const pjsip_hdr *hdr; 733 702 pjsip_via_hdr *via; 734 735 PJ_UNUSED_ARG(endpt); 736 737 pj_assert(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG); 738 pj_assert(rdata->msg_info.msg->line.status.code == 401 || 739 rdata->msg_info.msg->line.status.code == 407 ); 740 703 pj_status_t status; 704 705 PJ_ASSERT_RETURN(sess && rdata && old_request && new_request, 706 PJ_EINVAL); 707 PJ_ASSERT_RETURN(sess->pool, PJSIP_ENOTINITIALIZED); 708 PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG, 709 PJSIP_ENOTRESPONSEMSG); 710 PJ_ASSERT_RETURN(old_request->msg->type == PJSIP_REQUEST_MSG, 711 PJSIP_ENOTREQUESTMSG); 712 PJ_ASSERT_RETURN(rdata->msg_info.msg->line.status.code == 401 || 713 rdata->msg_info.msg->line.status.code == 407, 714 PJSIP_EINVALIDSTATUS); 715 716 tdata = old_request; 717 741 718 /* 742 719 * Respond to each authentication challenge. … … 744 721 hdr = rdata->msg_info.msg->hdr.next; 745 722 while (hdr != &rdata->msg_info.msg->hdr) { 746 pjsip_ auth_session *sess;723 pjsip_cached_auth *cached_auth; 747 724 const pjsip_www_authenticate_hdr *hchal; 748 725 pjsip_authorization_hdr *hauth; … … 763 740 * if not present. 764 741 */ 765 sess = find_session(sess_list, &hchal->challenge.common.realm );766 if (! sess) {767 sess = pj_pool_calloc( ses_pool, 1, sizeof(*sess));768 pj_strdup( ses _pool, &sess->realm, &hchal->challenge.common.realm);769 sess->is_proxy = (hchal->type == PJSIP_H_PROXY_AUTHENTICATE);742 cached_auth = find_cached_auth(sess, &hchal->challenge.common.realm ); 743 if (!cached_auth) { 744 cached_auth = pj_pool_zalloc( sess->pool, sizeof(*cached_auth)); 745 pj_strdup( sess->pool, &cached_auth->realm, &hchal->challenge.common.realm); 746 cached_auth->is_proxy = (hchal->type == PJSIP_H_PROXY_AUTHENTICATE); 770 747 # if (PJSIP_AUTH_HEADER_CACHING) 771 748 { 772 pj_list_init(& sess->cached_hdr);749 pj_list_init(&cached_auth->cached_hdr); 773 750 } 774 751 # endif 775 pj_list_insert_before( sess_list, sess);752 pj_list_insert_before( &sess->cached_auth, cached_auth ); 776 753 } 777 754 … … 779 756 * authorization session. 780 757 */ 781 hauth= process_auth( tdata->pool, hchal, tdata->msg->line.req.uri,782 tdata, cred_count, cred_info, ses_pool, sess);783 if ( !hauth)784 return NULL;758 status = process_auth( tdata->pool, hchal, tdata->msg->line.req.uri, 759 tdata, sess, cached_auth, &hauth); 760 if (status != PJ_SUCCESS) 761 return status; 785 762 786 763 /* Add to the message. */ … … 800 777 801 778 /* Done. */ 802 return tdata; 803 } 804 779 *new_request = tdata; 780 return PJ_SUCCESS; 781 782 } 783
Note: See TracChangeset
for help on using the changeset viewer.