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

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

Webmaster