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

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

Webmaster