Ignore:
Timestamp:
Jan 18, 2006 11:34:15 PM (18 years ago)
Author:
bennylp
Message:

Complete tsx layer selftest, implemented authentication framework

File:
1 moved

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c

    r112 r123  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
    1818 */ 
     19 
    1920#include <pjsip/sip_auth.h> 
    2021#include <pjsip/sip_auth_parser.h>      /* just to get pjsip_DIGEST_STR */ 
    2122#include <pjsip/sip_transport.h> 
    2223#include <pjsip/sip_endpoint.h> 
     24#include <pjsip/sip_errno.h> 
    2325#include <pjlib-util/md5.h> 
    2426#include <pj/log.h> 
     
    2931#include <pj/ctype.h> 
    3032 
    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 
    3634 
    3735/* A macro just to get rid of type mismatch between char and unsigned char */ 
     
    3937 
    4038/* Logging. */ 
    41 #define THIS_FILE   "sip_auth.c" 
     39#define THIS_FILE   "sip_auth_client.c" 
    4240#if 0 
    4341#  define AUTH_TRACE_(expr)  PJ_LOG(3, expr) 
     
    4644#endif 
    4745 
    48 static const char hex[] = "0123456789abcdef"; 
    49  
    5046/* Transform digest to string. 
    51  * output must be at least MD5STRLEN+1 bytes. 
     47 * output must be at least PJSIP_MD5STRLEN+1 bytes. 
    5248 * 
    5349 * NOTE: THE OUTPUT STRING IS NOT NULL TERMINATED! 
     
    5551static void digest2str(const unsigned char digest[], char *output) 
    5652{ 
    57     char *p = output; 
    5853    int i; 
    59  
    6054    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 
    6660 
    6761/* 
     
    6963 * digest ASCII in 'result'.  
    7064 */ 
    71 static void create_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]; 
     65void 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]; 
    8276    unsigned char digest[16]; 
    8377    pj_md5_context pms; 
    8478 
    85     pj_assert(result->slen >= MD5STRLEN); 
     79    pj_assert(result->slen >= PJSIP_MD5STRLEN); 
    8680 
    8781    AUTH_TRACE_((THIS_FILE, "Begin creating digest")); 
     
    128122     ***/ 
    129123    pj_md5_init(&pms); 
    130     MD5_APPEND( &pms, ha1, MD5STRLEN); 
     124    MD5_APPEND( &pms, ha1, PJSIP_MD5STRLEN); 
    131125    MD5_APPEND( &pms, ":", 1); 
    132126    MD5_APPEND( &pms, nonce->ptr, nonce->slen); 
     
    140134    } 
    141135    MD5_APPEND( &pms, ":", 1); 
    142     MD5_APPEND( &pms, ha2, MD5STRLEN); 
     136    MD5_APPEND( &pms, ha2, PJSIP_MD5STRLEN); 
    143137 
    144138    /* This is the final response digest. */ 
     
    146140     
    147141    /* Convert digest to string and store in chal->response. */ 
    148     result->slen = MD5STRLEN; 
     142    result->slen = PJSIP_MD5STRLEN; 
    149143    digest2str(digest, result->ptr); 
    150144 
     
    207201        PJ_LOG(4,(THIS_FILE, "Unsupported digest algorithm \"%.*s\"", 
    208202                  chal->algorithm.slen, chal->algorithm.ptr)); 
    209         return -1; 
     203        return PJSIP_EINVALIDALGORITHM; 
    210204    } 
    211205 
     
    219213     
    220214    /* 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; 
    223217 
    224218    if (chal->qop.slen == 0) { 
     
    226220 
    227221        /* Convert digest to string and store in chal->response. */ 
    228         create_digest( &cred->response, &cred->nonce, NULL, NULL, NULL, 
    229                       uri, cred_info, method); 
     222        pjsip_auth_create_digest( &cred->response, &cred->nonce, NULL, NULL,  
     223                                  NULL, uri, cred_info, method); 
    230224 
    231225    } else if (has_auth_qop(pool, &chal->qop)) { 
     
    244238        } 
    245239 
    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 ); 
    248243 
    249244    } else { 
     
    251246        PJ_LOG(4,(THIS_FILE, "Unsupported qop offer %.*s",  
    252247                  chal->qop.slen, chal->qop.ptr)); 
    253         return -1; 
    254     } 
    255  
    256     return 0; 
    257 } 
    258  
    259 #if PJSIP_AUTH_QOP_SUPPORT 
     248        return PJSIP_EINVALIDQOP; 
     249    } 
     250 
     251    return PJ_SUCCESS; 
     252} 
     253 
     254#if defined(PJSIP_AUTH_QOP_SUPPORT) && PJSIP_AUTH_QOP_SUPPORT!=0 
    260255/* 
    261256 * Update authentication session with a challenge. 
    262257 */ 
    263258static void update_digest_session( pj_pool_t *ses_pool,  
    264                                    pjsip_auth_session *auth_sess, 
     259                                   pjsip_cached_auth *cached_auth, 
    265260                                   const pjsip_www_authenticate_hdr *hdr ) 
    266261{ 
     
    269264 
    270265    /* Initialize cnonce and qop if not present. */ 
    271     if (auth_sess->cnonce.slen == 0) { 
     266    if (cached_auth->cnonce.slen == 0) { 
    272267        /* 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); 
    274269 
    275270        /* Create cnonce */ 
    276         pj_create_unique_string( ses_pool, &auth_sess->cnonce ); 
     271        pj_create_unique_string( ses_pool, &cached_auth->cnonce ); 
    277272 
    278273        /* Initialize nonce-count */ 
    279         auth_sess->nc = 1; 
     274        cached_auth->nc = 1; 
    280275 
    281276        /* 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,  
    285280                      &hdr->challenge.digest.realm); 
    286281        } 
     
    289284        /* Update last_nonce and nonce-count */ 
    290285        if (!pj_strcmp(&hdr->challenge.digest.nonce,  
    291                        &auth_sess->last_chal->challenge.digest.nonce))  
     286                       &cached_auth->last_chal->challenge.digest.nonce))  
    292287        { 
    293288            /* Same nonce, increment nonce-count */ 
    294             ++auth_sess->nc; 
     289            ++cached_auth->nc; 
    295290        } else { 
    296291            /* 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, 
    298293                      &hdr->challenge.digest.nonce); 
    299294            /* 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, 
    301296                          &hdr->challenge.digest.opaque))  
    302297            { 
    303298                pj_strdup(ses_pool,  
    304                           &auth_sess->last_chal->challenge.digest.opaque, 
     299                          &cached_auth->last_chal->challenge.digest.opaque, 
    305300                          &hdr->challenge.digest.opaque); 
    306301            } 
    307             auth_sess->nc = 1; 
     302            cached_auth->nc = 1; 
    308303        } 
    309304    } 
     
    312307 
    313308 
    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. */ 
     310static 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; 
    323318    } 
    324319 
    325320    return NULL; 
    326321} 
     322 
     323/* Find credential to use for the specified realm and auth scheme. */ 
     324static 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. */ 
     339PJ_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. */ 
     357PJ_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 
    327370 
    328371/*  
     
    330373 * in WWW-Authenticate/Proxy-Authenticate header. 
    331374 */ 
    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; 
     375static 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; 
    342385    char tmp[PJSIP_MAX_URL_SIZE]; 
    343386    pj_str_t uri_str; 
    344387    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); 
    350393 
    351394    /* Print URL in the original request. */ 
    352395    uri_str.ptr = tmp; 
    353     uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp, sizeof(tmp)); 
     396    uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp,sizeof(tmp)); 
    354397    if (uri_str.slen < 1) { 
    355398        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; 
    358400    } 
    359401 
     
    371413 
    372414    if (hdr->type == PJSIP_H_WWW_AUTHENTICATE) 
    373         auth = pjsip_authorization_hdr_create(pool); 
     415        hauth = pjsip_authorization_hdr_create(pool); 
    374416    else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE) 
    375         auth = pjsip_proxy_authorization_hdr_create(pool); 
     417        hauth = pjsip_proxy_authorization_hdr_create(pool); 
    376418    else { 
    377         pj_assert(0); 
    378         return NULL; 
     419        pj_assert(!"Invalid response header!"); 
     420        return PJSIP_EINVALIDHDR; 
    379421    } 
    380422 
    381423    /* Only support digest scheme at the moment. */ 
    382424    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) { 
    383         pj_status_t rc; 
    384425        pj_str_t *cnonce = NULL; 
    385426        pj_uint32_t nc = 1; 
     
    388429#       if PJSIP_AUTH_QOP_SUPPORT 
    389430        { 
    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; 
    395436            } 
    396437        } 
    397438#       endif   /* PJSIP_AUTH_QOP_SUPPORT */ 
    398439 
    399         auth->scheme = pjsip_DIGEST_STR; 
    400         rc = respond_digest( pool, &auth->credential.digest, 
    401                             &hdr->challenge.digest, &uri_str, cred_info, 
    402                             cnonce, nc, &method->name); 
    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; 
    405446 
    406447        /* 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; 
    410451                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; 
    412453                } else { 
    413                     auth_sess->qop_value = PJSIP_AUTH_QOP_UNKNOWN; 
     454                    cached_auth->qop_value = PJSIP_AUTH_QOP_UNKNOWN; 
    414455                } 
    415456            } 
    416457        } 
    417458    } else { 
    418         auth = NULL; 
     459        return PJSIP_EINVALIDAUTHSCHEME; 
    419460    } 
    420461 
     
    424465#   if PJSIP_AUTH_HEADER_CACHING 
    425466    { 
    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) { 
    427468            pjsip_cached_auth_hdr *cached_hdr; 
    428469 
    429470            /* 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) { 
    432473                if (pjsip_method_cmp(method, &cached_hdr->method)==0) 
    433474                    break; 
     
    436477 
    437478            /* 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; 
    440481            } else { 
    441482                cached_hdr = pj_pool_alloc(pool, sizeof(*cached_hdr)); 
    442483                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 ); 
    445486            } 
    446487        } 
     
    448489#   endif 
    449490 
    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 
     498static 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) 
    518502{ 
    519503    const pjsip_cred_info *cred; 
    520504    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 ); 
    526511    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; 
    529520     
    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; 
    537527} 
    538528#endif 
    539529 
    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. */ 
     533PJ_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 
    574553            { 
    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) { 
    577556                    if (pjsip_method_cmp(&entry->method, method)==0) { 
    578557                        pjsip_authorization_hdr *hauth; 
     
    580559                        pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth); 
    581560                    } else { 
    582 #                       if (PJSIP_AUTH_AUTO_SEND_NEXT) 
     561#                       if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \ 
     562                           PJSIP_AUTH_AUTO_SEND_NEXT!=0 
    583563                        { 
    584                             new_auth_for_req( tdata, sess_pool, sess,  
    585                                               cred_count, cred_info); 
     564                            new_auth_for_req( tdata, sess, auth, NULL); 
    586565                        } 
    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 
    594567                    } 
    595568                    entry = entry->next; 
    596569                } 
    597570            } 
    598 #           elif (PJSIP_AUTH_AUTO_SEND_NEXT) 
     571#           elif defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \ 
     572                 PJSIP_AUTH_AUTO_SEND_NEXT!=0 
    599573            { 
    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 
    610577 
    611578        }  
    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) { 
    614583            /* For qop="auth", we have to re-create the authorization header.  
    615584             */ 
     
    617586            pjsip_authorization_hdr *hauth; 
    618587 
    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); 
    622590            if (!cred) { 
    623                 sess = sess->next; 
     591                auth = auth->next; 
    624592                continue; 
    625593            } 
    626594 
    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); 
    635604        } 
    636605#       endif   /* PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT */ 
    637606 
    638         sess = sess->next; 
    639     } 
    640     return 0; 
    641 } 
     607        auth = auth->next; 
     608    } 
     609 
     610    return PJ_SUCCESS; 
     611} 
     612 
    642613 
    643614/* 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) 
     615static 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) 
    652622{ 
    653623    const pjsip_cred_info *cred; 
    654     pjsip_authorization_hdr *sent_auth = NULL, *hauth; 
     624    pjsip_authorization_hdr *sent_auth = NULL; 
    655625    pjsip_hdr *hdr; 
     626    pj_status_t status; 
    656627 
    657628    /* See if we have sent authorization header for this realm */ 
     
    686657                       sent_auth->credential.digest.realm.slen, 
    687658                       sent_auth->credential.digest.realm.ptr)); 
    688             return NULL; 
     659            return PJSIP_EFAILEDCREDENTIAL; 
    689660        } 
    690661 
     
    696667 
    697668    /* 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); 
    700671    if (!cred) { 
    701672        const pj_str_t *realm = &hchal->challenge.common.realm; 
     
    705676                  realm->slen, realm->ptr, 
    706677                  hchal->scheme.slen, hchal->scheme.ptr)); 
    707         return NULL; 
     678        return PJSIP_ENOCREDENTIAL; 
    708679    } 
    709680 
    710681    /* Respond to authorization challenge. */ 
    711     hauth = pjsip_auth_respond( req_pool, hchal, uri, cred,  
    712                                 &tdata->msg->line.req.method,  
    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; 
    715686} 
    716687 
     
    722693 *    in cached_list. 
    723694 */ 
    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 { 
     695PJ_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; 
    732701    const pjsip_hdr *hdr; 
    733702    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     
    741718    /* 
    742719     * Respond to each authentication challenge. 
     
    744721    hdr = rdata->msg_info.msg->hdr.next; 
    745722    while (hdr != &rdata->msg_info.msg->hdr) { 
    746         pjsip_auth_session *sess; 
     723        pjsip_cached_auth *cached_auth; 
    747724        const pjsip_www_authenticate_hdr *hchal; 
    748725        pjsip_authorization_hdr *hauth; 
     
    763740         * if not present. 
    764741         */ 
    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); 
    770747#           if (PJSIP_AUTH_HEADER_CACHING) 
    771748            { 
    772                 pj_list_init(&sess->cached_hdr); 
     749                pj_list_init(&cached_auth->cached_hdr); 
    773750            } 
    774751#           endif 
    775             pj_list_insert_before( sess_list, sess ); 
     752            pj_list_insert_before( &sess->cached_auth, cached_auth ); 
    776753        } 
    777754 
     
    779756         * authorization session. 
    780757         */ 
    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; 
    785762 
    786763        /* Add to the message. */ 
     
    800777 
    801778    /* 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.