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

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.45    ! frystyk     6: **     @(#) $Id: HTAABrow.c,v 2.44 1996/09/08 22:08:02 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:        /*
                    213:        ** If we don't have a basic context then add a new one to the tree.
2.42      frystyk   214:        ** We use different trees for normal and proxy authentication
2.40      frystyk   215:        */
2.36      frystyk   216:        if (!basic) {
2.42      frystyk   217:            if (proxy) {
                    218:                char * url = HTRequest_proxy(request);
                    219:                basic = HTBasic_new();
                    220:                basic->proxy = YES;
                    221:                HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
                    222:            } else {
                    223:                char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
                    224:                basic = HTBasic_new();
                    225:                HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
                    226:                HT_FREE(url);
                    227:            }
2.36      frystyk   228:        }
                    229: 
2.32      frystyk   230:        /*
2.36      frystyk   231:        ** If we have a set of credentials (or the user provides a new set)
                    232:        ** then store it in the request object as the credentials
2.32      frystyk   233:        */
2.39      frystyk   234:        if ((basic->retry && prompt_user(request, realm, basic) == HT_OK) ||
                    235:            (!basic->retry && basic->uid)) {
2.38      frystyk   236:            basic->retry = NO;
2.36      frystyk   237:            return basic_credentials(request, basic);
2.38      frystyk   238:        } else
2.37      frystyk   239:            return HT_ERROR;
2.1       luotonen  240:     }
2.36      frystyk   241:     return HT_OK;
2.1       luotonen  242: }
                    243: 
2.32      frystyk   244: /*     HTBasic_parse
                    245: **     -------------
                    246: **     This function parses the contents of a "basic" challenge 
                    247: **     and stores the challenge in our authentication information datebase.
                    248: **     We also store the realm in the request object which will help finding
                    249: **     the right set of credentials to generate.
                    250: **     The function is a callback function for the AA handler.
                    251: */
2.45    ! frystyk   252: PUBLIC int HTBasic_parse (HTRequest * request, HTResponse * response,
        !           253:                          void * context, int status)
2.32      frystyk   254: {
2.45    ! frystyk   255:     HTAssocList * challenge = HTResponse_challenge(response);
2.38      frystyk   256:     HTBasic * basic = NULL;
2.40      frystyk   257:     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
2.36      frystyk   258:     if (request && challenge) {
                    259:        char * p = HTAssocList_findObject(challenge, BASIC_AUTH);
                    260:        char * realm = HTNextField(&p);
                    261:        char * rm = HTNextField(&p);
2.38      frystyk   262: 
2.32      frystyk   263:        /*
2.36      frystyk   264:        ** If valid challenge then make a template for the resource and
                    265:        ** store this information in our authentication URL Tree
2.32      frystyk   266:        */
2.36      frystyk   267:        if (realm && !strcasecomp(realm, "realm") && rm) {
                    268:            if (AUTH_TRACE) HTTrace("Basic Parse. Realm `%s\' found\n", rm);
                    269:            HTRequest_setRealm(request, rm);
2.40      frystyk   270: 
                    271:            /*
                    272:            **  If we are in proxy mode then add the proxy - not the final URL
                    273:            */
                    274:            if (proxy) {
                    275:                char * url = HTRequest_proxy(request);
2.42      frystyk   276:                if (AUTH_TRACE) HTTrace("Basic Parse. Proxy authentication\n");
2.40      frystyk   277:                basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
                    278:                                                    url, NULL);
                    279:            } else {
                    280:                char * url = HTAnchor_address((HTAnchor *)
                    281:                                              HTRequest_anchor(request));
                    282:                char * tmplate = make_template(url);
                    283:                basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
                    284:                                                    tmplate, NULL);
                    285:                HT_FREE(url);
                    286:                HT_FREE(tmplate);
                    287:            }
2.1       luotonen  288:        }
2.38      frystyk   289: 
                    290:        /*
                    291:        ** For some reason the authentication failed so we have to ask the user
                    292:        ** if we should try again. It may be because the user typed the wrong
                    293:        ** user name and password
                    294:        */
                    295:        if (basic) {
                    296:            HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
2.40      frystyk   297: 
                    298:            /*
2.42      frystyk   299:            ** Do we haev a method registered for prompting the user whether
                    300:            ** we should retry
2.40      frystyk   301:            */
2.38      frystyk   302:            if (prompt) {
2.40      frystyk   303:                int code = proxy ?
                    304:                    HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
                    305:                if ((*prompt)(request, HT_A_CONFIRM, code,
2.38      frystyk   306:                              NULL, NULL, NULL) != YES)
                    307:                    return HT_ERROR;
                    308:                basic->retry = YES;
                    309:            }
                    310:        }
2.36      frystyk   311:        return HT_OK;
2.1       luotonen  312:     }
2.36      frystyk   313:     if (AUTH_TRACE) HTTrace("Auth........ No challenges found\n");
2.38      frystyk   314:     return HT_ERROR;
2.7       luotonen  315: }
2.44      frystyk   316: 
                    317: /* ------------------------------------------------------------------------- */
                    318: /*                             Digest Authentication                        */
                    319: /* ------------------------------------------------------------------------- */
                    320: 
                    321: /*
                    322: **     Prompt the user for username and password.
                    323: **     Returns YES if user name was typed in, else NO
                    324: */
                    325: PRIVATE int prompt_digest_user (HTRequest * request, const char * realm,
                    326:                                HTDigest * digest)
                    327: {
                    328:     HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
                    329:     if (request && cbf) {
                    330:        HTAlertPar * reply = HTAlert_newReply();
                    331:        int msg = digest->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
                    332:        BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
                    333:                          digest->uid, (char *) realm, reply);
                    334:        if (res) {
                    335:            HT_FREE(digest->uid);
                    336:            HT_FREE(digest->pw);
                    337:            digest->uid = HTAlert_replyMessage(reply);
                    338:            digest->pw = HTAlert_replySecret(reply);
                    339:        }
                    340:        HTAlert_deleteReply(reply);
                    341:        return res ? HT_OK : HT_ERROR;
                    342:     }
                    343:     return HT_OK;
                    344: }
                    345: 
                    346: PRIVATE HTDigest * HTDigest_new()
                    347: {
                    348:     HTDigest * me = NULL;
                    349:     if ((me = (HTDigest *) HT_CALLOC(1, sizeof(HTDigest))) == NULL)
                    350:        HT_OUTOFMEM("HTDigest_new");
                    351:     me->retry = YES;                          /* Ask the first time through */
                    352:     return me;
                    353: }
                    354: 
                    355: /*     HTDigest_delete
                    356: **     --------------
                    357: **     Deletes a "digest" information object
                    358: **     A single object may be registered multiple places in the URL tree.
                    359: **     We keep a simple reference count on the object so that we know
                    360: **     when to delete the object.
                    361: */
                    362: PUBLIC int HTDigest_delete (void * context)
                    363: {
                    364:     HTDigest * digest = (HTDigest *) context;
                    365:     if (digest) {
                    366:        if (digest->references <= 0) {
                    367:            HT_FREE(digest->uid);
                    368:            HT_FREE(digest->pw);
                    369:            HT_FREE(digest->nounce);
                    370:            HT_FREE(digest->opaque);
                    371:            HT_FREE(digest);
                    372:        } else
                    373:            digest->references--;
                    374:        return YES;
                    375:     }
                    376:     return NO;
                    377: }
                    378: 
                    379: /*
                    380: **     Make digest authentication scheme credentials and register this
                    381: **     information in the request object as credentials. They will then
                    382: **     be included in the request header.
                    383: **     The function can both create normal and proxy credentials
                    384: **     Returns HT_OK or HT_ERROR
                    385: */
                    386: PRIVATE BOOL digest_credentials (HTRequest * request, HTDigest * digest)
                    387: {
                    388:     if (request && digest) {
                    389: 
                    390:        /* THIS IS CURRENTLY FOR BASIC AUTH. CHANGE THIS TO DIGEST */
                    391: 
                    392:        char * cleartext = NULL;
                    393:        char * cipher = NULL;
                    394:        int cl_len = strlen(digest->uid ? digest->uid : "") +
                    395:            strlen(digest->pw ? digest->pw : "") + 5;
                    396:        int ci_len = 4 * (((cl_len+2)/3) + 1);
                    397:        if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL)
                    398:            HT_OUTOFMEM("digest_credentials");
                    399:        *cleartext = '\0';
                    400:        if (digest->uid) strcpy(cleartext, digest->uid);
                    401:        strcat(cleartext, ":");
                    402:        if (digest->pw) strcat(cleartext, digest->pw);
                    403:        if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL)
                    404:            HT_OUTOFMEM("digest_credentials");
                    405:        HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher);
                    406: 
                    407:        /* Create the credentials and assign them to the request object */
                    408:        {
                    409:            int cr_len = strlen("digest") + ci_len + 3;
                    410:            char * cookie = (char *) HT_MALLOC(cr_len+1);
                    411:            if (!cookie) HT_OUTOFMEM("digest_credentials");
                    412:            strcpy(cookie, "Digest ");
                    413:            strcat(cookie, cipher);
                    414:            if (AUTH_TRACE) HTTrace("Digest Cookie `%s\'\n", cookie);
                    415: 
                    416:            /* Check whether it is proxy or normal credentials */
                    417:            if (digest->proxy)
                    418:                HTRequest_addCredentials(request, "Proxy-Authorization", cookie);
                    419:            else
                    420:                HTRequest_addCredentials(request, "Authorization", cookie);
                    421: 
                    422:            HT_FREE(cookie);
                    423:        }
                    424:        HT_FREE(cleartext);
                    425:        HT_FREE(cipher);
                    426:        return HT_OK;
                    427:     }
                    428:     return HT_ERROR;
                    429: }
                    430: 
                    431: /*     HTDigest_generate
                    432: **     ----------------
                    433: **     This function generates "digest" credentials for the challenge found in
                    434: **     the authentication information base for this request. The result is
                    435: **     stored as an association list in the request object.
                    436: **     This is a callback function for the AA handler.
                    437: */
2.45    ! frystyk   438: PUBLIC int HTDigest_generate (HTRequest * request, void * context, int mode)
2.44      frystyk   439: { 
                    440:     HTDigest * digest = (HTDigest *) context;
2.45    ! frystyk   441:     BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO;
2.44      frystyk   442:     if (request) {
                    443:        const char * realm = HTRequest_realm(request);
                    444: 
                    445:        /*
                    446:        ** If we don't have a digest context then add a new one to the tree.
                    447:        ** We use different trees for normal and proxy authentication
                    448:        */
                    449:        if (!digest) {
                    450:            if (proxy) {
                    451:                char * url = HTRequest_proxy(request);
                    452:                digest = HTDigest_new();
                    453:                digest->proxy = YES;
                    454:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest);
                    455:            } else {
                    456:                char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
                    457:                digest = HTDigest_new();
                    458:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest);
                    459:                HT_FREE(url);
                    460:            }
                    461:        }
                    462: 
                    463:        /*
                    464:        ** If we have a set of credentials (or the user provides a new set)
                    465:        ** then store it in the request object as the credentials
                    466:        */
                    467:        if ((digest->retry &&
                    468:             prompt_digest_user(request, realm, digest) == HT_OK) ||
                    469:            (!digest->retry && digest->uid)) {
                    470:            digest->retry = NO;
                    471:            return digest_credentials(request, digest);
                    472:        } else
                    473:            return HT_ERROR;
                    474:     }
                    475:     return HT_OK;
                    476: }
                    477: 
                    478: /*     HTDigest_parse
                    479: **     -------------
                    480: **     This function parses the contents of a "digest" challenge 
                    481: **     and stores the challenge in our authentication information datebase.
                    482: **     We also store the realm in the request object which will help finding
                    483: **     the right set of credentials to generate.
                    484: **     The function is a callback function for the AA handler.
                    485: */
2.45    ! frystyk   486: PUBLIC int HTDigest_parse (HTRequest * request, HTResponse * response,
        !           487:                           void * context, int status)
2.44      frystyk   488: {
2.45    ! frystyk   489:     HTAssocList * challenge = HTResponse_challenge(response);
2.44      frystyk   490:     HTDigest * digest = NULL;    
                    491:     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
                    492:     if (request && challenge) {
                    493:        char * p = HTAssocList_findObject(challenge, DIGEST_AUTH);
                    494:        char * realm =  HTNextField(&p);
                    495:        char * value =  HTNextField(&p);
                    496:        char * token = NULL;
                    497:        char * uris = NULL;
                    498:        BOOL found = NO;
                    499: 
                    500:        /*
                    501:        **  Search for the realm and see if we have an entry for it. If not
                    502:        **  then create a new entry.
                    503:        */
                    504:        if (realm && !strcasecomp(realm, "realm") && value) {
                    505:            if (AUTH_TRACE) HTTrace("Basic Parse. Realm `%s\' found\n", value);
                    506:            HTRequest_setRealm(request, value);
                    507:            digest = (HTDigest *)
                    508:                HTAA_updateNode(proxy, DIGEST_AUTH, value, NULL, NULL);
                    509:        }
                    510:        if (!digest)
                    511:            digest = HTDigest_new();
                    512:        else
                    513:            found = YES;
                    514: 
                    515:        /*
                    516:        **  Search through the set of parameters in the digest header.
                    517:        **  If valid challenge then make a template for the resource and
                    518:        **  store this information in our authentication URL Tree
                    519:        */
                    520:        while ((token = HTNextField(&p))) {
                    521:            if (!strcasecomp(token, "domain")) {
                    522:                if ((value = HTNextField(&p)))
                    523:                    uris = value;
                    524:            } else if (!strcasecomp(token, "nounce")) {
                    525:                if ((value = HTNextField(&p)))
                    526:                    StrAllocCopy(digest->nounce, value);
                    527:            } else if (!strcasecomp(token, "opaque")) {
                    528:                if ((value = HTNextField(&p)))
                    529:                    StrAllocCopy(digest->opaque, value);
                    530:            } else if (!strcasecomp(token, "stale")) {
                    531:                if ((value = HTNextField(&p)) && !strcasecomp(value, "true"))
                    532:                    digest->stale = YES;
                    533:            } else if (!strcasecomp(token, "algorithm")) {
                    534:                if ((value = HTNextField(&p)) && strcasecomp(value, "md5")) {
                    535:                    /*
                    536:                    **  We only support MD5 for the moment
                    537:                    */
                    538:                    if (AUTH_TRACE) HTTrace("Digest Parse Unknown algorithm `%s\'\n", value);
                    539:                    HTDigest_delete(digest);
                    540:                    return HT_ERROR;
                    541:                }
                    542:            }
                    543:        }
                    544: 
                    545:        /*
                    546:        **  Now as we have parsed the full digest header we update the URL tree
                    547:        **  with the new information. If we didn't get a "domain" token then
                    548:        **  add the node using a template. If we have multiple URIs in the
                    549:        **  domain token then add a digest node at each URI.
                    550:        */
                    551:        if (!uris) {
                    552:            if (proxy) {
                    553:                char * location = HTRequest_proxy(request);
                    554:                if (AUTH_TRACE) HTTrace("Digest Parse Proxy authentication\n");
                    555:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, location, digest);
                    556:            } else {
                    557:                char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
                    558:                char * tmplate = make_template(url);
                    559:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, tmplate, digest);
                    560:                HT_FREE(url);
                    561:                HT_FREE(tmplate);
                    562:            }
                    563:        } else {
                    564: 
                    565:            /*
                    566:            **  ADD THE DIGEST FOR EACH URL IN THE LIST AND INCREMENT THE
                    567:            **  REFERENCE COUNT IN THE DIGEST BY ONE
                    568:            */
                    569: 
                    570:        }
                    571: 
                    572:        /*
                    573:        ** For some reason the authentication failed so we have to ask the user
                    574:        ** if we should try again. It may be because the user typed the wrong
                    575:        ** user name and password
                    576:        */
                    577:        if (found) {
                    578:            HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
                    579: 
                    580:            /*
                    581:            ** Do we have a method registered for prompting the user whether
                    582:            ** we should retry
                    583:            */
                    584:            if (prompt) {
                    585:                int code = proxy ?
                    586:                    HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
                    587:                if ((*prompt)(request, HT_A_CONFIRM, code,
                    588:                              NULL, NULL, NULL) != YES)
                    589:                    return HT_ERROR;
                    590:                digest->retry = YES;
                    591:            }
                    592:        }
                    593:        return HT_OK;
                    594:     }
                    595:     if (AUTH_TRACE) HTTrace("Auth........ No challenges found\n");
                    596:     return HT_ERROR;
                    597: }
                    598: 

Webmaster