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

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

Webmaster