Annotation of libwww/Library/src/HTAABrow.c, revision 2.46

2.15      frystyk     1: /*                                                                  HTAABrow.c
2.32      frystyk     2: **     BROWSER SIDE ACCESS AUTHORIZATION MODULE
2.15      frystyk     3: **
2.19      frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.15      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
2.46    ! frystyk     6: **     @(#) $Id: HTAABrow.c,v 2.45 1996/10/07 02:04:10 frystyk Exp $
2.1       luotonen    7: **
2.32      frystyk     8: **     Contains code for parsing challenges and creating credentials for 
2.36      frystyk     9: **     basic authentication schemes. See also the HTAAUtil module
2.32      frystyk    10: **     for how to handle other authentication schemes. You don't have to use
                     11: **     this code at all.
2.1       luotonen   12: **
                     13: ** AUTHORS:
                     14: **     AL      Ari Luotonen    luotonen@dxcern.cern.ch
2.32      frystyk    15: **     HFN     Henrik Frystyk
2.1       luotonen   16: **
                     17: ** HISTORY:
2.5       luotonen   18: **     Oct 17  AL      Made corrections suggested by marca:
                     19: **                     Added  if (!realm->username) return NULL;
                     20: **                     Changed some ""s to NULLs.
2.33      frystyk    21: **                     Now doing HT_CALLOC() to init uuencode source;
2.5       luotonen   22: **                     otherwise HTUU_encode() reads uninitialized memory
                     23: **                     every now and then (not a real bug but not pretty).
                     24: **                     Corrected the formula for uuencode destination size.
2.32      frystyk    25: **     Feb 96 HFN      Rewritten to make it scheme independent and based on
                     26: **                     callback functions and an info structure
2.1       luotonen   27: */
                     28: 
2.17      frystyk    29: /* Library include files */
2.27      frystyk    30: #include "WWWLib.h"
                     31: #include "HTAAUtil.h"
                     32: #include "HTAABrow.h"                                   /* Implemented here */
2.1       luotonen   33: 
2.36      frystyk    34: #define BASIC_AUTH     "basic"
2.44      frystyk    35: #define DIGEST_AUTH    "digest"
2.36      frystyk    36: 
2.32      frystyk    37: typedef struct _HTBasic {                /* Basic challenge and credentials */
                     38:     char *     uid;
                     39:     char *     pw;
2.38      frystyk    40:     BOOL       retry;                      /* Should we ask the user again? */
2.40      frystyk    41:     BOOL       proxy;                               /* Proxy authentication */
2.32      frystyk    42: } HTBasic;
                     43: 
2.44      frystyk    44: typedef struct _HTDigest {              /* Digest challenge and credentials */
                     45:     char *     uid;
                     46:     char *     pw;
                     47:     char *     nounce;
                     48:     char *     opaque;
                     49:     BOOL       stale;
                     50:     BOOL       retry;                      /* Should we ask the user again? */
                     51:     BOOL       proxy;                               /* Proxy authentication */
                     52:     int                references;             /* Number of pointers to this object */
                     53: } HTDigest;
                     54: 
2.36      frystyk    55: /* ------------------------------------------------------------------------- */
                     56: 
2.32      frystyk    57: /*
                     58: **     Create a protection template for the files
                     59: **     in the same directory as the given file
                     60: **     Returns a template matching docname, and other files in that directory.
                     61: **
                     62: **             E.g.  /foo/bar/x.html  =>  /foo/bar/ *
                     63: **                                                 ^
                     64: **                             Space only to prevent it from
                     65: **                             being a comment marker here,
                     66: **                             there really isn't any space.
2.1       luotonen   67: */
2.33      frystyk    68: PRIVATE char * make_template (const char * docname)
2.1       luotonen   69: {
2.39      frystyk    70:     char * tmplate = NULL;
2.32      frystyk    71:     if (docname) {
2.39      frystyk    72:        char * host = HTParse(docname, "", PARSE_ACCESS|PARSE_HOST|PARSE_PUNCTUATION);
                     73:        char * path = HTParse(docname, "", PARSE_PATH|PARSE_PUNCTUATION);
                     74:        char * slash = strrchr(path, '/');
                     75:        if (slash) {
                     76:            if (*(slash+1)) {           
                     77:                strcpy(slash, "*");
                     78:                StrAllocCat(host, path);
                     79:            } else
2.43      frystyk    80:                StrAllocCat(host, "/*");
2.39      frystyk    81:        }
                     82:        HT_FREE(path);
                     83:        tmplate = host;
                     84:     } else
                     85:        StrAllocCopy(tmplate, "*");
2.32      frystyk    86:     if (AUTH_TRACE)
                     87:        HTTrace("Template.... Made template `%s' for file `%s'\n",
2.39      frystyk    88:                tmplate, docname ? docname : "<null>");
2.32      frystyk    89:     return tmplate;
2.1       luotonen   90: }
                     91: 
2.44      frystyk    92: /* ------------------------------------------------------------------------- */
                     93: /*                             Basic Authentication                         */
                     94: /* ------------------------------------------------------------------------- */
                     95: 
                     96: /*
                     97: **     Prompt the user for username and password.
                     98: **     Returns YES if user name was typed in, else NO
                     99: */
                    100: PRIVATE int prompt_user (HTRequest * request, const char * realm,
                    101:                         HTBasic * basic)
                    102: {
                    103:     HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
                    104:     if (request && cbf) {
                    105:        HTAlertPar * reply = HTAlert_newReply();
                    106:        int msg = basic->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
                    107:        BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
                    108:                          basic->uid, (char *) realm, reply);
                    109:        if (res) {
                    110:            HT_FREE(basic->uid);
                    111:            HT_FREE(basic->pw);
                    112:            basic->uid = HTAlert_replyMessage(reply);
                    113:            basic->pw = HTAlert_replySecret(reply);
                    114:        }
                    115:        HTAlert_deleteReply(reply);
                    116:        return res ? HT_OK : HT_ERROR;
                    117:     }
                    118:     return HT_OK;
                    119: }
                    120: 
                    121: PRIVATE HTBasic * HTBasic_new()
                    122: {
                    123:     HTBasic * me = NULL;
                    124:     if ((me = (HTBasic *) HT_CALLOC(1, sizeof(HTBasic))) == NULL)
                    125:        HT_OUTOFMEM("HTBasic_new");
                    126:     me->retry = YES;                          /* Ask the first time through */
                    127:     return me;
                    128: }
                    129: 
                    130: /*     HTBasic_delete
                    131: **     --------------
                    132: **     Deletes a "basic" information object
                    133: */
                    134: PUBLIC int HTBasic_delete (void * context)
                    135: {
                    136:     HTBasic * basic = (HTBasic *) context;
                    137:     if (basic) {
                    138:        HT_FREE(basic->uid);
                    139:        HT_FREE(basic->pw);
                    140:        HT_FREE(basic);
                    141:        return YES;
                    142:     }
                    143:     return NO;
                    144: }
                    145: 
2.32      frystyk   146: /*
                    147: **     Make basic authentication scheme credentials and register this
                    148: **     information in the request object as credentials. They will then
                    149: **     be included in the request header. An example is 
                    150: **
                    151: **             "Basic AkRDIhEF8sdEgs72F73bfaS=="
                    152: **
2.40      frystyk   153: **     The function can both create normal and proxy credentials
2.36      frystyk   154: **     Returns HT_OK or HT_ERROR
2.32      frystyk   155: */
2.36      frystyk   156: PRIVATE BOOL basic_credentials (HTRequest * request, HTBasic * basic)
2.32      frystyk   157: {
                    158:     if (request && basic) {
                    159:        char * cleartext = NULL;
                    160:        char * cipher = NULL;
                    161:        int cl_len = strlen(basic->uid ? basic->uid : "") +
2.42      frystyk   162:            strlen(basic->pw ? basic->pw : "") + 5;
2.37      frystyk   163:        int ci_len = 4 * (((cl_len+2)/3) + 1);
                    164:        if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL)
2.32      frystyk   165:            HT_OUTOFMEM("basic_credentials");
                    166:        *cleartext = '\0';
                    167:        if (basic->uid) strcpy(cleartext, basic->uid);
                    168:        strcat(cleartext, ":");
                    169:        if (basic->pw) strcat(cleartext, basic->pw);
2.37      frystyk   170:        if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL)
2.32      frystyk   171:            HT_OUTOFMEM("basic_credentials");
2.37      frystyk   172:        HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher);
2.1       luotonen  173: 
2.32      frystyk   174:        /* Create the credentials and assign them to the request object */
                    175:        {
2.37      frystyk   176:            int cr_len = strlen("basic") + ci_len + 3;
2.32      frystyk   177:            char * cookie = (char *) HT_MALLOC(cr_len+1);
                    178:            if (!cookie) HT_OUTOFMEM("basic_credentials");
                    179:            strcpy(cookie, "Basic ");
                    180:            strcat(cookie, cipher);
2.37      frystyk   181:            if (AUTH_TRACE) HTTrace("Basic Cookie `%s\'\n", cookie);
2.40      frystyk   182: 
                    183:            /* Check whether it is proxy or normal credentials */
                    184:            if (basic->proxy)
                    185:                HTRequest_addCredentials(request, "Proxy-Authorization", cookie);
                    186:            else
                    187:                HTRequest_addCredentials(request, "Authorization", cookie);
                    188: 
2.32      frystyk   189:            HT_FREE(cookie);
2.1       luotonen  190:        }
2.32      frystyk   191:        HT_FREE(cleartext);
                    192:        HT_FREE(cipher);
2.36      frystyk   193:        return HT_OK;
2.32      frystyk   194:     }
2.36      frystyk   195:     return HT_ERROR;
2.1       luotonen  196: }
                    197: 
2.32      frystyk   198: /*     HTBasic_generate
                    199: **     ----------------
                    200: **     This function generates "basic" credentials for the challenge found in
                    201: **     the authentication information base for this request. The result is
                    202: **     stored as an association list in the request object.
                    203: **     This is a callback function for the AA handler.
                    204: */
2.45      frystyk   205: PUBLIC int HTBasic_generate (HTRequest * request, void * context, int mode)
2.32      frystyk   206: { 
2.36      frystyk   207:     HTBasic * basic = (HTBasic *) context;
2.45      frystyk   208:     BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO;
2.36      frystyk   209:     if (request) {
                    210:        const char * realm = HTRequest_realm(request);
                    211: 
2.40      frystyk   212:        /*
2.46    ! frystyk   213:        **  If we were asked to explicitly ask the user again
        !           214:        */
        !           215:        if (mode == HT_REAUTH || mode == HT_PROXY_REAUTH)
        !           216:            basic->retry = YES;
        !           217: 
        !           218:        /*
2.40      frystyk   219:        ** If we don't have a basic context then add a new one to the tree.
2.42      frystyk   220:        ** We use different trees for normal and proxy authentication
2.40      frystyk   221:        */
2.36      frystyk   222:        if (!basic) {
2.42      frystyk   223:            if (proxy) {
                    224:                char * url = HTRequest_proxy(request);
                    225:                basic = HTBasic_new();
                    226:                basic->proxy = YES;
                    227:                HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
                    228:            } else {
                    229:                char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
                    230:                basic = HTBasic_new();
                    231:                HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
                    232:                HT_FREE(url);
                    233:            }
2.36      frystyk   234:        }
                    235: 
2.32      frystyk   236:        /*
2.36      frystyk   237:        ** If we have a set of credentials (or the user provides a new set)
                    238:        ** then store it in the request object as the credentials
2.32      frystyk   239:        */
2.39      frystyk   240:        if ((basic->retry && prompt_user(request, realm, basic) == HT_OK) ||
                    241:            (!basic->retry && basic->uid)) {
2.38      frystyk   242:            basic->retry = NO;
2.36      frystyk   243:            return basic_credentials(request, basic);
2.38      frystyk   244:        } else
2.37      frystyk   245:            return HT_ERROR;
2.1       luotonen  246:     }
2.36      frystyk   247:     return HT_OK;
2.1       luotonen  248: }
                    249: 
2.32      frystyk   250: /*     HTBasic_parse
                    251: **     -------------
                    252: **     This function parses the contents of a "basic" challenge 
                    253: **     and stores the challenge in our authentication information datebase.
                    254: **     We also store the realm in the request object which will help finding
                    255: **     the right set of credentials to generate.
                    256: **     The function is a callback function for the AA handler.
                    257: */
2.45      frystyk   258: PUBLIC int HTBasic_parse (HTRequest * request, HTResponse * response,
                    259:                          void * context, int status)
2.32      frystyk   260: {
2.45      frystyk   261:     HTAssocList * challenge = HTResponse_challenge(response);
2.38      frystyk   262:     HTBasic * basic = NULL;
2.40      frystyk   263:     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
2.36      frystyk   264:     if (request && challenge) {
                    265:        char * p = HTAssocList_findObject(challenge, BASIC_AUTH);
                    266:        char * realm = HTNextField(&p);
                    267:        char * rm = HTNextField(&p);
2.38      frystyk   268: 
2.32      frystyk   269:        /*
2.36      frystyk   270:        ** If valid challenge then make a template for the resource and
                    271:        ** store this information in our authentication URL Tree
2.32      frystyk   272:        */
2.36      frystyk   273:        if (realm && !strcasecomp(realm, "realm") && rm) {
                    274:            if (AUTH_TRACE) HTTrace("Basic Parse. Realm `%s\' found\n", rm);
                    275:            HTRequest_setRealm(request, rm);
2.40      frystyk   276: 
                    277:            /*
                    278:            **  If we are in proxy mode then add the proxy - not the final URL
                    279:            */
                    280:            if (proxy) {
                    281:                char * url = HTRequest_proxy(request);
2.42      frystyk   282:                if (AUTH_TRACE) HTTrace("Basic Parse. Proxy authentication\n");
2.40      frystyk   283:                basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
                    284:                                                    url, NULL);
                    285:            } else {
                    286:                char * url = HTAnchor_address((HTAnchor *)
                    287:                                              HTRequest_anchor(request));
                    288:                char * tmplate = make_template(url);
                    289:                basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
                    290:                                                    tmplate, NULL);
                    291:                HT_FREE(url);
                    292:                HT_FREE(tmplate);
                    293:            }
2.1       luotonen  294:        }
2.38      frystyk   295: 
                    296:        /*
                    297:        ** For some reason the authentication failed so we have to ask the user
                    298:        ** if we should try again. It may be because the user typed the wrong
                    299:        ** user name and password
                    300:        */
                    301:        if (basic) {
                    302:            HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
2.40      frystyk   303: 
                    304:            /*
2.42      frystyk   305:            ** Do we haev a method registered for prompting the user whether
                    306:            ** we should retry
2.40      frystyk   307:            */
2.38      frystyk   308:            if (prompt) {
2.40      frystyk   309:                int code = proxy ?
                    310:                    HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
                    311:                if ((*prompt)(request, HT_A_CONFIRM, code,
2.38      frystyk   312:                              NULL, NULL, NULL) != YES)
                    313:                    return HT_ERROR;
                    314:                basic->retry = YES;
                    315:            }
                    316:        }
2.36      frystyk   317:        return HT_OK;
2.1       luotonen  318:     }
2.36      frystyk   319:     if (AUTH_TRACE) HTTrace("Auth........ No challenges found\n");
2.38      frystyk   320:     return HT_ERROR;
2.7       luotonen  321: }
2.44      frystyk   322: 
                    323: /* ------------------------------------------------------------------------- */
                    324: /*                             Digest Authentication                        */
                    325: /* ------------------------------------------------------------------------- */
                    326: 
                    327: /*
                    328: **     Prompt the user for username and password.
                    329: **     Returns YES if user name was typed in, else NO
                    330: */
                    331: PRIVATE int prompt_digest_user (HTRequest * request, const char * realm,
                    332:                                HTDigest * digest)
                    333: {
                    334:     HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
                    335:     if (request && cbf) {
                    336:        HTAlertPar * reply = HTAlert_newReply();
                    337:        int msg = digest->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
                    338:        BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
                    339:                          digest->uid, (char *) realm, reply);
                    340:        if (res) {
                    341:            HT_FREE(digest->uid);
                    342:            HT_FREE(digest->pw);
                    343:            digest->uid = HTAlert_replyMessage(reply);
                    344:            digest->pw = HTAlert_replySecret(reply);
                    345:        }
                    346:        HTAlert_deleteReply(reply);
                    347:        return res ? HT_OK : HT_ERROR;
                    348:     }
                    349:     return HT_OK;
                    350: }
                    351: 
                    352: PRIVATE HTDigest * HTDigest_new()
                    353: {
                    354:     HTDigest * me = NULL;
                    355:     if ((me = (HTDigest *) HT_CALLOC(1, sizeof(HTDigest))) == NULL)
                    356:        HT_OUTOFMEM("HTDigest_new");
                    357:     me->retry = YES;                          /* Ask the first time through */
                    358:     return me;
                    359: }
                    360: 
                    361: /*     HTDigest_delete
                    362: **     --------------
                    363: **     Deletes a "digest" information object
                    364: **     A single object may be registered multiple places in the URL tree.
                    365: **     We keep a simple reference count on the object so that we know
                    366: **     when to delete the object.
                    367: */
                    368: PUBLIC int HTDigest_delete (void * context)
                    369: {
                    370:     HTDigest * digest = (HTDigest *) context;
                    371:     if (digest) {
                    372:        if (digest->references <= 0) {
                    373:            HT_FREE(digest->uid);
                    374:            HT_FREE(digest->pw);
                    375:            HT_FREE(digest->nounce);
                    376:            HT_FREE(digest->opaque);
                    377:            HT_FREE(digest);
                    378:        } else
                    379:            digest->references--;
                    380:        return YES;
                    381:     }
                    382:     return NO;
                    383: }
                    384: 
                    385: /*
                    386: **     Make digest authentication scheme credentials and register this
                    387: **     information in the request object as credentials. They will then
                    388: **     be included in the request header.
                    389: **     The function can both create normal and proxy credentials
                    390: **     Returns HT_OK or HT_ERROR
                    391: */
                    392: PRIVATE BOOL digest_credentials (HTRequest * request, HTDigest * digest)
                    393: {
                    394:     if (request && digest) {
                    395: 
                    396:        /* THIS IS CURRENTLY FOR BASIC AUTH. CHANGE THIS TO DIGEST */
                    397: 
                    398:        char * cleartext = NULL;
                    399:        char * cipher = NULL;
                    400:        int cl_len = strlen(digest->uid ? digest->uid : "") +
                    401:            strlen(digest->pw ? digest->pw : "") + 5;
                    402:        int ci_len = 4 * (((cl_len+2)/3) + 1);
                    403:        if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL)
                    404:            HT_OUTOFMEM("digest_credentials");
                    405:        *cleartext = '\0';
                    406:        if (digest->uid) strcpy(cleartext, digest->uid);
                    407:        strcat(cleartext, ":");
                    408:        if (digest->pw) strcat(cleartext, digest->pw);
                    409:        if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL)
                    410:            HT_OUTOFMEM("digest_credentials");
                    411:        HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher);
                    412: 
                    413:        /* Create the credentials and assign them to the request object */
                    414:        {
                    415:            int cr_len = strlen("digest") + ci_len + 3;
                    416:            char * cookie = (char *) HT_MALLOC(cr_len+1);
                    417:            if (!cookie) HT_OUTOFMEM("digest_credentials");
                    418:            strcpy(cookie, "Digest ");
                    419:            strcat(cookie, cipher);
                    420:            if (AUTH_TRACE) HTTrace("Digest Cookie `%s\'\n", cookie);
                    421: 
                    422:            /* Check whether it is proxy or normal credentials */
                    423:            if (digest->proxy)
                    424:                HTRequest_addCredentials(request, "Proxy-Authorization", cookie);
                    425:            else
                    426:                HTRequest_addCredentials(request, "Authorization", cookie);
                    427: 
                    428:            HT_FREE(cookie);
                    429:        }
                    430:        HT_FREE(cleartext);
                    431:        HT_FREE(cipher);
                    432:        return HT_OK;
                    433:     }
                    434:     return HT_ERROR;
                    435: }
                    436: 
                    437: /*     HTDigest_generate
                    438: **     ----------------
                    439: **     This function generates "digest" credentials for the challenge found in
                    440: **     the authentication information base for this request. The result is
                    441: **     stored as an association list in the request object.
                    442: **     This is a callback function for the AA handler.
                    443: */
2.45      frystyk   444: PUBLIC int HTDigest_generate (HTRequest * request, void * context, int mode)
2.44      frystyk   445: { 
                    446:     HTDigest * digest = (HTDigest *) context;
2.45      frystyk   447:     BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO;
2.44      frystyk   448:     if (request) {
                    449:        const char * realm = HTRequest_realm(request);
2.46    ! frystyk   450: 
        !           451:        /*
        !           452:        **  If we were asked to explicitly ask the user again
        !           453:        */
        !           454:        if (mode == HT_REAUTH || mode == HT_PROXY_REAUTH)
        !           455:            digest->retry = YES;
2.44      frystyk   456: 
                    457:        /*
                    458:        ** If we don't have a digest context then add a new one to the tree.
                    459:        ** We use different trees for normal and proxy authentication
                    460:        */
                    461:        if (!digest) {
                    462:            if (proxy) {
                    463:                char * url = HTRequest_proxy(request);
                    464:                digest = HTDigest_new();
                    465:                digest->proxy = YES;
                    466:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest);
                    467:            } else {
                    468:                char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
                    469:                digest = HTDigest_new();
                    470:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest);
                    471:                HT_FREE(url);
                    472:            }
                    473:        }
                    474: 
                    475:        /*
                    476:        ** If we have a set of credentials (or the user provides a new set)
                    477:        ** then store it in the request object as the credentials
                    478:        */
                    479:        if ((digest->retry &&
                    480:             prompt_digest_user(request, realm, digest) == HT_OK) ||
                    481:            (!digest->retry && digest->uid)) {
                    482:            digest->retry = NO;
                    483:            return digest_credentials(request, digest);
                    484:        } else
                    485:            return HT_ERROR;
                    486:     }
                    487:     return HT_OK;
                    488: }
                    489: 
                    490: /*     HTDigest_parse
                    491: **     -------------
                    492: **     This function parses the contents of a "digest" challenge 
                    493: **     and stores the challenge in our authentication information datebase.
                    494: **     We also store the realm in the request object which will help finding
                    495: **     the right set of credentials to generate.
                    496: **     The function is a callback function for the AA handler.
                    497: */
2.45      frystyk   498: PUBLIC int HTDigest_parse (HTRequest * request, HTResponse * response,
                    499:                           void * context, int status)
2.44      frystyk   500: {
2.45      frystyk   501:     HTAssocList * challenge = HTResponse_challenge(response);
2.44      frystyk   502:     HTDigest * digest = NULL;    
                    503:     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
                    504:     if (request && challenge) {
                    505:        char * p = HTAssocList_findObject(challenge, DIGEST_AUTH);
                    506:        char * realm =  HTNextField(&p);
                    507:        char * value =  HTNextField(&p);
                    508:        char * token = NULL;
                    509:        char * uris = NULL;
                    510:        BOOL found = NO;
                    511: 
                    512:        /*
                    513:        **  Search for the realm and see if we have an entry for it. If not
                    514:        **  then create a new entry.
                    515:        */
                    516:        if (realm && !strcasecomp(realm, "realm") && value) {
                    517:            if (AUTH_TRACE) HTTrace("Basic Parse. Realm `%s\' found\n", value);
                    518:            HTRequest_setRealm(request, value);
                    519:            digest = (HTDigest *)
                    520:                HTAA_updateNode(proxy, DIGEST_AUTH, value, NULL, NULL);
                    521:        }
                    522:        if (!digest)
                    523:            digest = HTDigest_new();
                    524:        else
                    525:            found = YES;
                    526: 
                    527:        /*
                    528:        **  Search through the set of parameters in the digest header.
                    529:        **  If valid challenge then make a template for the resource and
                    530:        **  store this information in our authentication URL Tree
                    531:        */
                    532:        while ((token = HTNextField(&p))) {
                    533:            if (!strcasecomp(token, "domain")) {
                    534:                if ((value = HTNextField(&p)))
                    535:                    uris = value;
                    536:            } else if (!strcasecomp(token, "nounce")) {
                    537:                if ((value = HTNextField(&p)))
                    538:                    StrAllocCopy(digest->nounce, value);
                    539:            } else if (!strcasecomp(token, "opaque")) {
                    540:                if ((value = HTNextField(&p)))
                    541:                    StrAllocCopy(digest->opaque, value);
                    542:            } else if (!strcasecomp(token, "stale")) {
                    543:                if ((value = HTNextField(&p)) && !strcasecomp(value, "true"))
                    544:                    digest->stale = YES;
                    545:            } else if (!strcasecomp(token, "algorithm")) {
                    546:                if ((value = HTNextField(&p)) && strcasecomp(value, "md5")) {
                    547:                    /*
                    548:                    **  We only support MD5 for the moment
                    549:                    */
                    550:                    if (AUTH_TRACE) HTTrace("Digest Parse Unknown algorithm `%s\'\n", value);
                    551:                    HTDigest_delete(digest);
                    552:                    return HT_ERROR;
                    553:                }
                    554:            }
                    555:        }
                    556: 
                    557:        /*
                    558:        **  Now as we have parsed the full digest header we update the URL tree
                    559:        **  with the new information. If we didn't get a "domain" token then
                    560:        **  add the node using a template. If we have multiple URIs in the
                    561:        **  domain token then add a digest node at each URI.
                    562:        */
                    563:        if (!uris) {
                    564:            if (proxy) {
                    565:                char * location = HTRequest_proxy(request);
                    566:                if (AUTH_TRACE) HTTrace("Digest Parse Proxy authentication\n");
                    567:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, location, digest);
                    568:            } else {
                    569:                char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
                    570:                char * tmplate = make_template(url);
                    571:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, tmplate, digest);
                    572:                HT_FREE(url);
                    573:                HT_FREE(tmplate);
                    574:            }
                    575:        } else {
                    576: 
                    577:            /*
                    578:            **  ADD THE DIGEST FOR EACH URL IN THE LIST AND INCREMENT THE
                    579:            **  REFERENCE COUNT IN THE DIGEST BY ONE
                    580:            */
                    581: 
                    582:        }
                    583: 
                    584:        /*
                    585:        ** For some reason the authentication failed so we have to ask the user
                    586:        ** if we should try again. It may be because the user typed the wrong
                    587:        ** user name and password
                    588:        */
                    589:        if (found) {
                    590:            HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
                    591: 
                    592:            /*
                    593:            ** Do we have a method registered for prompting the user whether
                    594:            ** we should retry
                    595:            */
                    596:            if (prompt) {
                    597:                int code = proxy ?
                    598:                    HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
                    599:                if ((*prompt)(request, HT_A_CONFIRM, code,
                    600:                              NULL, NULL, NULL) != YES)
                    601:                    return HT_ERROR;
                    602:                digest->retry = YES;
                    603:            }
                    604:        }
                    605:        return HT_OK;
                    606:     }
                    607:     if (AUTH_TRACE) HTTrace("Auth........ No challenges found\n");
                    608:     return HT_ERROR;
                    609: }
                    610: 

Webmaster