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

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.57    ! kahan       6: **     @(#) $Id: HTAABrow.c,v 2.56 1999/02/22 22:10:10 frystyk Exp $
2.1       luotonen    7: **
2.32      frystyk     8: **     Contains code for parsing challenges and creating credentials for 
2.36      frystyk     9: **     basic authentication schemes. See also the HTAAUtil module
2.32      frystyk    10: **     for how to handle other authentication schemes. You don't have to use
                     11: **     this code at all.
2.1       luotonen   12: **
                     13: ** AUTHORS:
                     14: **     AL      Ari Luotonen    luotonen@dxcern.cern.ch
2.32      frystyk    15: **     HFN     Henrik Frystyk
2.50      kahan      16: **      JKO     Jose Kahan      
2.1       luotonen   17: **
                     18: ** HISTORY:
2.5       luotonen   19: **     Oct 17  AL      Made corrections suggested by marca:
                     20: **                     Added  if (!realm->username) return NULL;
                     21: **                     Changed some ""s to NULLs.
2.33      frystyk    22: **                     Now doing HT_CALLOC() to init uuencode source;
2.5       luotonen   23: **                     otherwise HTUU_encode() reads uninitialized memory
                     24: **                     every now and then (not a real bug but not pretty).
                     25: **                     Corrected the formula for uuencode destination size.
2.32      frystyk    26: **     Feb 96 HFN      Rewritten to make it scheme independent and based on
                     27: **                     callback functions and an info structure
2.50      kahan      28: **      Nov 98 JKO      Added support for message digest authentication
2.1       luotonen   29: */
                     30: 
2.50      kahan      31: /* Portions of this code (as indicated) are derived from the Internet Draft
                     32: ** draft-ietf-http-authentication-03 and are covered by the following
                     33: ** copyright:
                     34: 
                     35: ** Copyright (C) The Internet Society (1998). All Rights Reserved.
                     36: 
                     37: ** This document and translations of it may be copied and furnished to
                     38: ** others, and derivative works that comment on or otherwise explain it or
                     39: ** assist in its implmentation may be prepared, copied, published and
                     40: ** distributed, in whole or in part, without restriction of any kind,
                     41: ** provided that the above copyright notice and this paragraph are included
                     42: ** on all such copies and derivative works. However, this document itself
                     43: ** may not be modified in any way, such as by removing the copyright notice
                     44: ** or references to the Internet Society or other Internet organizations,
                     45: ** except as needed for the purpose of developing Internet standards in
                     46: ** which case the procedures for copyrights defined in the Internet
                     47: ** Standards process must be followed, or as required to translate it into
                     48: ** languages other than English.
                     49: 
                     50: ** The limited permissions granted above are perpetual and will not be
                     51: ** revoked by the Internet Society or its successors or assigns.
                     52: 
                     53: ** This document and the information contained herein is provided on an "AS
                     54: ** IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
                     55: ** FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
                     56: ** LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT
                     57: ** INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR
                     58: ** FITNESS FOR A PARTICULAR PURPOSE.
                     59: **/
                     60: 
2.17      frystyk    61: /* Library include files */
2.27      frystyk    62: #include "WWWLib.h"
                     63: #include "HTAAUtil.h"
2.50      kahan      64: #include "HTParse.h"
2.27      frystyk    65: #include "HTAABrow.h"                                   /* Implemented here */
2.50      kahan      66: #include "HTDigest.h"
2.1       luotonen   67: 
2.36      frystyk    68: #define BASIC_AUTH     "basic"
2.44      frystyk    69: #define DIGEST_AUTH    "digest"
2.52      kahan      70: #define DIGEST_AI       "authentication-info"
                     71: #define PROXY_DIGEST_AI "proxy-authentication-info"
2.36      frystyk    72: 
2.32      frystyk    73: typedef struct _HTBasic {                /* Basic challenge and credentials */
                     74:     char *     uid;
                     75:     char *     pw;
2.38      frystyk    76:     BOOL       retry;                      /* Should we ask the user again? */
2.40      frystyk    77:     BOOL       proxy;                               /* Proxy authentication */
2.32      frystyk    78: } HTBasic;
                     79: 
2.44      frystyk    80: typedef struct _HTDigest {              /* Digest challenge and credentials */
2.50      kahan      81:   /* digest info can be shared by one or more UT entries */
                     82:     int         references;              
                     83:   /* client authentication data */
2.44      frystyk    84:     char *     uid;
                     85:     char *     pw;
2.50      kahan      86:     char *      realm;
                     87:     char *      cnonce;
                     88:     long        nc;
                     89:   /* server authentication data */
                     90:     char *     nonce;
2.44      frystyk    91:     char *     opaque;
2.50      kahan      92:   /* session authentication data */
                     93:     int         algorithm;
                     94:     char *      qop;
2.44      frystyk    95:     BOOL       stale;
                     96:     BOOL       retry;                      /* Should we ask the user again? */
                     97:     BOOL       proxy;                               /* Proxy authentication */
                     98: } HTDigest;
                     99: 
2.50      kahan     100: #define HASHLEN 16
                    101: typedef char HASH[HASHLEN+1];
                    102: #define HASHHEXLEN 32
                    103: typedef char HASHHEX[HASHHEXLEN+1];
                    104: 
2.36      frystyk   105: /* ------------------------------------------------------------------------- */
                    106: 
2.32      frystyk   107: /*
                    108: **     Create a protection template for the files
                    109: **     in the same directory as the given file
                    110: **     Returns a template matching docname, and other files in that directory.
                    111: **
                    112: **             E.g.  /foo/bar/x.html  =>  /foo/bar/ *
                    113: **                                                 ^
                    114: **                             Space only to prevent it from
                    115: **                             being a comment marker here,
                    116: **                             there really isn't any space.
2.1       luotonen  117: */
2.33      frystyk   118: PRIVATE char * make_template (const char * docname)
2.1       luotonen  119: {
2.39      frystyk   120:     char * tmplate = NULL;
2.32      frystyk   121:     if (docname) {
2.39      frystyk   122:        char * host = HTParse(docname, "", PARSE_ACCESS|PARSE_HOST|PARSE_PUNCTUATION);
                    123:        char * path = HTParse(docname, "", PARSE_PATH|PARSE_PUNCTUATION);
                    124:        char * slash = strrchr(path, '/');
                    125:        if (slash) {
2.47      frystyk   126: #if 0
2.39      frystyk   127:            if (*(slash+1)) {           
                    128:                strcpy(slash, "*");
                    129:                StrAllocCat(host, path);
                    130:            } else
2.43      frystyk   131:                StrAllocCat(host, "/*");
2.47      frystyk   132: #else
2.49      kahan     133:            if (*(slash+1)) {
                    134:                strcpy(slash + 1, "*");
2.47      frystyk   135:                StrAllocCat(host, path);
2.49      kahan     136:            } else {
                    137:                 StrAllocCat(host, path);
                    138:                 StrAllocCat(host, "*");
                    139:            }
2.47      frystyk   140: #endif
2.39      frystyk   141:        }
                    142:        HT_FREE(path);
                    143:        tmplate = host;
                    144:     } else
                    145:        StrAllocCopy(tmplate, "*");
2.56      frystyk   146:     HTTRACE(AUTH_TRACE, "Template.... Made template `%s' for file `%s'\n" _ 
                    147:                tmplate _ docname ? docname : "<null>");
2.32      frystyk   148:     return tmplate;
2.1       luotonen  149: }
                    150: 
2.44      frystyk   151: /* ------------------------------------------------------------------------- */
                    152: /*                             Basic Authentication                         */
                    153: /* ------------------------------------------------------------------------- */
                    154: 
                    155: /*
                    156: **     Prompt the user for username and password.
                    157: **     Returns YES if user name was typed in, else NO
                    158: */
                    159: PRIVATE int prompt_user (HTRequest * request, const char * realm,
                    160:                         HTBasic * basic)
                    161: {
                    162:     HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
2.53      frystyk   163: 
                    164:     /* If no method for prompting the user then we might as well give up */
                    165:     if (!cbf) return HT_ERROR;
                    166: 
                    167:     /* Otherwise go ahead and ask the user */
                    168:     if (request) {
2.44      frystyk   169:        HTAlertPar * reply = HTAlert_newReply();
                    170:        int msg = basic->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
                    171:        BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
                    172:                          basic->uid, (char *) realm, reply);
                    173:        if (res) {
                    174:            HT_FREE(basic->uid);
                    175:            HT_FREE(basic->pw);
                    176:            basic->uid = HTAlert_replyMessage(reply);
                    177:            basic->pw = HTAlert_replySecret(reply);
                    178:        }
                    179:        HTAlert_deleteReply(reply);
                    180:        return res ? HT_OK : HT_ERROR;
                    181:     }
                    182:     return HT_OK;
                    183: }
                    184: 
                    185: PRIVATE HTBasic * HTBasic_new()
                    186: {
                    187:     HTBasic * me = NULL;
                    188:     if ((me = (HTBasic *) HT_CALLOC(1, sizeof(HTBasic))) == NULL)
                    189:        HT_OUTOFMEM("HTBasic_new");
                    190:     me->retry = YES;                          /* Ask the first time through */
                    191:     return me;
                    192: }
                    193: 
                    194: /*     HTBasic_delete
                    195: **     --------------
                    196: **     Deletes a "basic" information object
                    197: */
                    198: PUBLIC int HTBasic_delete (void * context)
                    199: {
                    200:     HTBasic * basic = (HTBasic *) context;
                    201:     if (basic) {
                    202:        HT_FREE(basic->uid);
                    203:        HT_FREE(basic->pw);
                    204:        HT_FREE(basic);
                    205:        return YES;
                    206:     }
                    207:     return NO;
                    208: }
                    209: 
2.32      frystyk   210: /*
                    211: **     Make basic authentication scheme credentials and register this
                    212: **     information in the request object as credentials. They will then
                    213: **     be included in the request header. An example is 
                    214: **
                    215: **             "Basic AkRDIhEF8sdEgs72F73bfaS=="
                    216: **
2.40      frystyk   217: **     The function can both create normal and proxy credentials
2.36      frystyk   218: **     Returns HT_OK or HT_ERROR
2.32      frystyk   219: */
2.36      frystyk   220: PRIVATE BOOL basic_credentials (HTRequest * request, HTBasic * basic)
2.32      frystyk   221: {
                    222:     if (request && basic) {
                    223:        char * cleartext = NULL;
                    224:        char * cipher = NULL;
                    225:        int cl_len = strlen(basic->uid ? basic->uid : "") +
2.42      frystyk   226:            strlen(basic->pw ? basic->pw : "") + 5;
2.37      frystyk   227:        int ci_len = 4 * (((cl_len+2)/3) + 1);
                    228:        if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL)
2.32      frystyk   229:            HT_OUTOFMEM("basic_credentials");
                    230:        *cleartext = '\0';
                    231:        if (basic->uid) strcpy(cleartext, basic->uid);
                    232:        strcat(cleartext, ":");
                    233:        if (basic->pw) strcat(cleartext, basic->pw);
2.37      frystyk   234:        if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL)
2.32      frystyk   235:            HT_OUTOFMEM("basic_credentials");
2.37      frystyk   236:        HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher);
2.1       luotonen  237: 
2.32      frystyk   238:        /* Create the credentials and assign them to the request object */
                    239:        {
2.37      frystyk   240:            int cr_len = strlen("basic") + ci_len + 3;
2.32      frystyk   241:            char * cookie = (char *) HT_MALLOC(cr_len+1);
                    242:            if (!cookie) HT_OUTOFMEM("basic_credentials");
                    243:            strcpy(cookie, "Basic ");
                    244:            strcat(cookie, cipher);
2.56      frystyk   245:            HTTRACE(AUTH_TRACE, "Basic Cookie `%s\'\n" _ cookie);
2.40      frystyk   246: 
                    247:            /* Check whether it is proxy or normal credentials */
                    248:            if (basic->proxy)
                    249:                HTRequest_addCredentials(request, "Proxy-Authorization", cookie);
                    250:            else
                    251:                HTRequest_addCredentials(request, "Authorization", cookie);
                    252: 
2.32      frystyk   253:            HT_FREE(cookie);
2.1       luotonen  254:        }
2.32      frystyk   255:        HT_FREE(cleartext);
                    256:        HT_FREE(cipher);
2.36      frystyk   257:        return HT_OK;
2.32      frystyk   258:     }
2.36      frystyk   259:     return HT_ERROR;
2.1       luotonen  260: }
                    261: 
2.32      frystyk   262: /*     HTBasic_generate
                    263: **     ----------------
                    264: **     This function generates "basic" credentials for the challenge found in
                    265: **     the authentication information base for this request. The result is
                    266: **     stored as an association list in the request object.
                    267: **     This is a callback function for the AA handler.
                    268: */
2.45      frystyk   269: PUBLIC int HTBasic_generate (HTRequest * request, void * context, int mode)
2.32      frystyk   270: { 
2.36      frystyk   271:     HTBasic * basic = (HTBasic *) context;
2.45      frystyk   272:     BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO;
2.36      frystyk   273:     if (request) {
                    274:        const char * realm = HTRequest_realm(request);
                    275: 
2.40      frystyk   276:        /*
2.46      frystyk   277:        **  If we were asked to explicitly ask the user again
                    278:        */
                    279:        if (mode == HT_REAUTH || mode == HT_PROXY_REAUTH)
                    280:            basic->retry = YES;
                    281: 
                    282:        /*
2.40      frystyk   283:        ** If we don't have a basic context then add a new one to the tree.
2.42      frystyk   284:        ** We use different trees for normal and proxy authentication
2.40      frystyk   285:        */
2.36      frystyk   286:        if (!basic) {
2.50      kahan     287:                basic = HTBasic_new();
2.42      frystyk   288:            if (proxy) {
                    289:                char * url = HTRequest_proxy(request);
                    290:                basic->proxy = YES;
                    291:                HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
                    292:            } else {
                    293:                char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
                    294:                HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
                    295:                HT_FREE(url);
                    296:            }
2.36      frystyk   297:        }
                    298: 
2.32      frystyk   299:        /*
2.36      frystyk   300:        ** If we have a set of credentials (or the user provides a new set)
                    301:        ** then store it in the request object as the credentials
2.32      frystyk   302:        */
2.39      frystyk   303:        if ((basic->retry && prompt_user(request, realm, basic) == HT_OK) ||
                    304:            (!basic->retry && basic->uid)) {
2.38      frystyk   305:            basic->retry = NO;
2.36      frystyk   306:            return basic_credentials(request, basic);
2.48      frystyk   307:        } else {
                    308:            char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
                    309:            HTAA_deleteNode(proxy, BASIC_AUTH, realm, url);
                    310:            HT_FREE(url);
2.37      frystyk   311:            return HT_ERROR;
2.48      frystyk   312:        }
2.1       luotonen  313:     }
2.36      frystyk   314:     return HT_OK;
2.1       luotonen  315: }
                    316: 
2.32      frystyk   317: /*     HTBasic_parse
                    318: **     -------------
                    319: **     This function parses the contents of a "basic" challenge 
                    320: **     and stores the challenge in our authentication information datebase.
                    321: **     We also store the realm in the request object which will help finding
                    322: **     the right set of credentials to generate.
                    323: **     The function is a callback function for the AA handler.
                    324: */
2.45      frystyk   325: PUBLIC int HTBasic_parse (HTRequest * request, HTResponse * response,
                    326:                          void * context, int status)
2.32      frystyk   327: {
2.45      frystyk   328:     HTAssocList * challenge = HTResponse_challenge(response);
2.38      frystyk   329:     HTBasic * basic = NULL;
2.40      frystyk   330:     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
2.36      frystyk   331:     if (request && challenge) {
                    332:        char * p = HTAssocList_findObject(challenge, BASIC_AUTH);
                    333:        char * realm = HTNextField(&p);
                    334:        char * rm = HTNextField(&p);
2.38      frystyk   335: 
2.32      frystyk   336:        /*
2.36      frystyk   337:        ** If valid challenge then make a template for the resource and
                    338:        ** store this information in our authentication URL Tree
2.32      frystyk   339:        */
2.36      frystyk   340:        if (realm && !strcasecomp(realm, "realm") && rm) {
2.56      frystyk   341:            HTTRACE(AUTH_TRACE, "Basic Parse. Realm `%s\' found\n" _ rm);
2.36      frystyk   342:            HTRequest_setRealm(request, rm);
2.40      frystyk   343: 
                    344:            /*
                    345:            **  If we are in proxy mode then add the proxy - not the final URL
                    346:            */
                    347:            if (proxy) {
                    348:                char * url = HTRequest_proxy(request);
2.56      frystyk   349:                HTTRACE(AUTH_TRACE, "Basic Parse. Proxy authentication\n");
2.40      frystyk   350:                basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
                    351:                                                    url, NULL);
2.49      kahan     352:                /* if the previous authentication failed, then try again */
                    353:                if (HTRequest_AAretrys (request) > 1 
                    354:                    && status == HT_NO_ACCESS && basic)
                    355:                  basic->retry = YES;
2.40      frystyk   356:            } else {
                    357:                char * url = HTAnchor_address((HTAnchor *)
                    358:                                              HTRequest_anchor(request));
                    359:                char * tmplate = make_template(url);
                    360:                basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
                    361:                                                    tmplate, NULL);
2.49      kahan     362:                /* if the previous authentication failed, then try again */
                    363:                if (HTRequest_AAretrys (request) > 1 
                    364:                    && status == HT_NO_ACCESS && basic)
                    365:                  basic->retry = YES;
2.40      frystyk   366:                HT_FREE(url);
                    367:                HT_FREE(tmplate);
                    368:            }
2.1       luotonen  369:        }
2.38      frystyk   370: 
                    371:        /*
                    372:        ** For some reason the authentication failed so we have to ask the user
                    373:        ** if we should try again. It may be because the user typed the wrong
                    374:        ** user name and password
                    375:        */
2.49      kahan     376:        if (basic && basic->retry) {
2.38      frystyk   377:            HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
2.40      frystyk   378: 
                    379:            /*
2.50      kahan     380:            ** Do we have a method registered for prompting the user whether
2.42      frystyk   381:            ** we should retry
2.40      frystyk   382:            */
2.38      frystyk   383:            if (prompt) {
2.40      frystyk   384:                int code = proxy ?
                    385:                    HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
                    386:                if ((*prompt)(request, HT_A_CONFIRM, code,
2.38      frystyk   387:                              NULL, NULL, NULL) != YES)
                    388:                    return HT_ERROR;
                    389:            }
                    390:        }
2.36      frystyk   391:        return HT_OK;
2.1       luotonen  392:     }
2.56      frystyk   393:     HTTRACE(AUTH_TRACE, "Auth........ No challenges found\n");
2.38      frystyk   394:     return HT_ERROR;
2.7       luotonen  395: }
2.44      frystyk   396: 
                    397: /* ------------------------------------------------------------------------- */
                    398: /*                             Digest Authentication                        */
                    399: /* ------------------------------------------------------------------------- */
                    400: 
                    401: /*
                    402: **     Prompt the user for username and password.
                    403: **     Returns YES if user name was typed in, else NO
                    404: */
                    405: PRIVATE int prompt_digest_user (HTRequest * request, const char * realm,
                    406:                                HTDigest * digest)
                    407: {
                    408:     HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
2.53      frystyk   409: 
                    410:     /* If no method for prompting the user then we might as well give up */
                    411:     if (!cbf) return HT_ERROR;
                    412: 
                    413:     /* Otherwise go ahead and ask the user */
                    414:     if (request) {
2.44      frystyk   415:        HTAlertPar * reply = HTAlert_newReply();
                    416:        int msg = digest->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
                    417:        BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
                    418:                          digest->uid, (char *) realm, reply);
                    419:        if (res) {
                    420:            HT_FREE(digest->uid);
                    421:            HT_FREE(digest->pw);
                    422:            digest->uid = HTAlert_replyMessage(reply);
                    423:            digest->pw = HTAlert_replySecret(reply);
                    424:        }
                    425:        HTAlert_deleteReply(reply);
                    426:        return res ? HT_OK : HT_ERROR;
                    427:     }
                    428:     return HT_OK;
                    429: }
                    430: 
                    431: PRIVATE HTDigest * HTDigest_new()
                    432: {
                    433:     HTDigest * me = NULL;
                    434:     if ((me = (HTDigest *) HT_CALLOC(1, sizeof(HTDigest))) == NULL)
                    435:        HT_OUTOFMEM("HTDigest_new");
2.50      kahan     436:     me->algorithm = HTDaMD5;                   /* use md5 as a default value */
2.44      frystyk   437:     me->retry = YES;                          /* Ask the first time through */
                    438:     return me;
                    439: }
                    440: 
                    441: /*     HTDigest_delete
                    442: **     --------------
                    443: **     Deletes a "digest" information object
                    444: **     A single object may be registered multiple places in the URL tree.
                    445: **     We keep a simple reference count on the object so that we know
                    446: **     when to delete the object.
                    447: */
                    448: PUBLIC int HTDigest_delete (void * context)
                    449: {
                    450:     HTDigest * digest = (HTDigest *) context;
                    451:     if (digest) {
                    452:        if (digest->references <= 0) {
                    453:            HT_FREE(digest->uid);
                    454:            HT_FREE(digest->pw);
2.50      kahan     455:            HT_FREE(digest->realm);
                    456:            HT_FREE(digest->cnonce);
                    457:            HT_FREE(digest->nonce);
2.44      frystyk   458:            HT_FREE(digest->opaque);
2.50      kahan     459:            HT_FREE(digest->qop);
2.44      frystyk   460:            HT_FREE(digest);
2.50      kahan     461:            return YES;
                    462:        }
                    463:        else
2.44      frystyk   464:            digest->references--;
2.50      kahan     465:     }
                    466:     return NO;
                    467: }
                    468: 
                    469: /*     HTDigest_reset
                    470: **     --------------
                    471: **      When digest authentication fails, we simulate a new digest by
                    472: **      erasing the old one, but keeping the uid and the password. This is
                    473: **      so that we can take into account the stale nonce protocol, without
                    474: **      prompting the user for a new password.
                    475: */
                    476: 
                    477: PRIVATE int HTDigest_reset (HTDigest *digest)
                    478: {
                    479:     if (digest) {
                    480:        digest->nc = 0l;
                    481:        digest->stale = 0;
                    482:        digest->retry = YES;
                    483:        HT_FREE(digest->cnonce);
                    484:        HT_FREE(digest->nonce);
                    485:        HT_FREE(digest->opaque);
                    486:        HT_FREE(digest->qop);
2.44      frystyk   487:        return YES;
                    488:     }
2.50      kahan     489:     else
                    490:        return NO;
                    491: }
                    492: 
2.52      kahan     493: /*     HTDigest_updateInfo
2.50      kahan     494: **     --------------
                    495: **      This function updates the digest with whatever new 
                    496: **     authentification information the server sent back.
                    497: */
                    498: 
2.52      kahan     499: PUBLIC int HTDigest_updateInfo (HTRequest *request, HTResponse *response,
                    500:                                void * context, int status)
2.50      kahan     501: {
2.52      kahan     502:     HTAssocList * challenge = HTResponse_challenge(response);
                    503:     const char * realm =  HTRequest_realm (request);
                    504: 
                    505:     if (request && challenge && realm) {
                    506:         BOOL proxy = 0;
                    507:        char * value = NULL;
                    508:        char * token = NULL;
                    509:        char * auth_info = NULL;
                    510:        
2.50      kahan     511:        HTDigest *digest;
                    512:        char *url;
                    513: 
2.52      kahan     514:        /*
                    515:        ** try to find the magic string in the challenge 
                    516:        */
2.56      frystyk   517:        HTTRACE(AUTH_TRACE, "Digest Update.. Processing authentication-info\n");
2.52      kahan     518:        if ((auth_info = HTAssocList_findObject(challenge, DIGEST_AI)))
                    519:            proxy = 0;
                    520:        else if ((auth_info = HTAssocList_findObject(challenge, 
                    521:                                                     PROXY_DIGEST_AI)))
                    522:            proxy = 1;
                    523:        else {
2.56      frystyk   524:            HTTRACE(AUTH_TRACE, "Digest Update.. Didn't find any authentication-info\n");
2.52      kahan     525:            return HT_OK;
                    526:        }
                    527:     
2.50      kahan     528:        /* 
                    529:        ** find the digest credentials 
                    530:        */
                    531:        if (proxy) {
                    532:            url = HTRequest_proxy(request);
                    533:            digest = (HTDigest *) HTAA_updateNode (proxy, DIGEST_AUTH, realm,
                    534:                                                   url, NULL);
                    535:        } else {
                    536:            url = HTAnchor_address((HTAnchor *)
                    537:                                   HTRequest_anchor(request));
                    538:            digest = (HTDigest *) HTAA_updateNode (proxy, DIGEST_AUTH, realm, 
                    539:                                                   url, NULL);
2.57    ! kahan     540:            HT_FREE(url);
2.50      kahan     541:        }
                    542:        if (!digest) {
2.56      frystyk   543:            HTTRACE(AUTH_TRACE, "Digest Update.. Error: received authentication-info without having a local digest\n"); 
2.50      kahan     544:            return HT_ERROR;
                    545:        }
                    546: 
                    547:        /*
                    548:        **  Search through the set of parameters in the Authentication-info
                    549:        **  header.
                    550:        */
                    551:        while ((token = HTNextField(&auth_info))) {
                    552:            if (!strcasecomp(token, "nextnonce")) {
                    553:                if ((value = HTNextField(&auth_info))) {
                    554:                    HT_FREE (digest->nonce);
                    555:                    StrAllocCopy(digest->nonce, value);
                    556:                } else if (!strcasecomp(token, "qop")) {
                    557:                    value = HTNextField(&auth_info);
                    558:                    /* split, process  the qop, report errors */
                    559:                } else if (!strcasecomp(token, "rspauth")) {
                    560:                    value = HTNextField(&auth_info);
                    561:                    /* process rspauth */
                    562:                } else if (!strcasecomp(token, "cnonce")) {
                    563:                    value = HTNextField (&auth_info);
                    564:                    if (value && strcmp (digest->cnonce, value)) {
                    565:                        /* print an alert?, bad cnonce? */
                    566:                    }   
                    567:                } else if (!strcasecomp(token, "nc")) {
                    568:                    value = HTNextField(&auth_info);
                    569:                    /* compare and printo some error? */
                    570:                }
                    571:            }   
                    572:        }
                    573:     }
2.52      kahan     574:     return HT_OK;
2.50      kahan     575: }
                    576:     
                    577: /*
                    578: **    Simple function to add a parameter/value pair to a string
                    579: **
                    580: */
                    581: 
                    582: PRIVATE BOOL add_param (char ** dest, char *param, char * value, BOOL quoted)
                    583: {
                    584:     char *tmp = *dest;
                    585: 
                    586:     if (!param || *param == '\0' || !value || *value == '\0')
                    587:        return NO;
                    588: 
                    589:     /* if there was a previous parameter, we add the next one in the
                    590:        following line */
                    591:     if (tmp) 
                    592:        StrAllocCat(tmp, ",");
                    593: 
                    594:     /* copy the new parameter and value */
                    595:     StrAllocCat(tmp, param);
                    596:     StrAllocCat(tmp, "=");
                    597:     if (quoted) {
                    598:     StrAllocCat(tmp, "\"");
                    599:     StrAllocCat(tmp, value);
                    600:     StrAllocCat(tmp, "\"");
                    601:     } else
                    602:        StrAllocCat(tmp, value);
                    603:     *dest = tmp;
                    604: 
                    605:     return YES;
                    606: }
                    607: 
                    608: /*
                    609: **  Code derived from draft-ietf-http-authentication-03 starts here
                    610: */
                    611: 
                    612: PRIVATE void CvtHex (HASH Bin, HASHHEX Hex)
                    613: {
                    614:     unsigned short i;
                    615:     unsigned char j;
                    616: 
                    617:     for (i = 0; i < HASHLEN; i++) {
                    618:        j = (Bin[i] >> 4) & 0xf;
                    619:        if (j <= 9)
                    620:            Hex[i*2] = (j + '0');
                    621:        else
                    622:            Hex[i*2] = (j + 'a' - 10);
                    623:        j = Bin[i] & 0xf;
                    624:        if (j <= 9)
                    625:            Hex[i*2+1] = (j + '0');
                    626:        else
                    627:            Hex[i*2+1] = (j + 'a' - 10);
                    628:   }
                    629:     Hex[HASHHEXLEN] = '\0';
                    630: }
                    631: 
                    632: /* calculate H(A1) as per spec */
                    633: PRIVATE void DigestCalcHA1 (int algorithm, char * pszAlg, char * pszUserName,
                    634:                            char * pszRealm, char * pszPassword,
                    635:                            char * pszNonce, char * pszCNonce,
                    636:                            HASHHEX SessionKey)
                    637: {
                    638:     HTDigestContext MdCtx;
                    639:     HASH HA1;
                    640: 
                    641:     HTDigest_init (&MdCtx, algorithm);
                    642:     HTDigest_update (&MdCtx, pszUserName, strlen(pszUserName));
                    643:     HTDigest_update (&MdCtx, ":", 1);
                    644:     HTDigest_update (&MdCtx, pszRealm, strlen(pszRealm));
                    645:     HTDigest_update (&MdCtx, ":", 1);
                    646:     HTDigest_update (&MdCtx, pszPassword, strlen(pszPassword));
                    647:     HTDigest_final (HA1, &MdCtx);
2.51      frystyk   648:     if (strcasecomp (pszAlg, "md5-sess") == 0) {
2.50      kahan     649:        HTDigest_init (&MdCtx, algorithm);
                    650:        HTDigest_update (&MdCtx, HA1, strlen (HA1));
                    651:        HTDigest_update (&MdCtx, ":", 1);
                    652:        HTDigest_update (&MdCtx, pszNonce, strlen(pszNonce));
                    653:        HTDigest_update (&MdCtx, ":", 1);
                    654:        HTDigest_update (&MdCtx, pszCNonce, strlen(pszCNonce));
                    655:        HTDigest_final (HA1, &MdCtx);
                    656:     }
                    657:     CvtHex (HA1, SessionKey);
2.44      frystyk   658: }
                    659: 
2.50      kahan     660: /* calculate request-digest/response-digest as per HTTP Digest spec */
                    661: PRIVATE void DigestCalcResponse (
                    662:     int    algorithm,      /* message digest algorithm */
                    663:     HASHHEX HA1,           /* H(A1) */
                    664:     char * pszNonce,       /* nonce from server */
                    665:     char * pszNonceCount,  /* 8 hex digits */
                    666:     char * pszCNonce,      /* client nonce */
                    667:     char * pszQop,         /* qop-value: "", "auth", "auth-int" */
                    668:     char * pszMethod,      /* method from the request */
                    669:     char * pszDigestUri,   /* requested URL */
                    670:     char * HEntity,        /* H(entity body) if qop="auth-int" */
                    671:     char * Response        /* request-digest or response-digest */
                    672:     )
                    673: {
                    674:     HTDigestContext MdCtx;
                    675:     HASH HA2;
                    676:     HASH RespHash;
                    677:     HASHHEX HA2Hex;
                    678: 
                    679:     /* calculate H(A2) */
                    680: 
                    681:     HTDigest_init (&MdCtx, algorithm);
                    682:     HTDigest_update (&MdCtx, pszMethod, strlen(pszMethod));
                    683:     HTDigest_update (&MdCtx, ":", 1);
                    684:     HTDigest_update (&MdCtx, pszDigestUri, strlen(pszDigestUri));
2.51      frystyk   685:     if (pszQop && strcasecomp (pszQop, "auth-int") == 0) {
2.50      kahan     686:        HTDigest_update (&MdCtx, ":", 1);
                    687:        HTDigest_update (&MdCtx, HEntity, HASHHEXLEN);
                    688:     }
                    689:     HTDigest_final (HA2, &MdCtx);
                    690:     CvtHex (HA2, HA2Hex);
                    691: 
                    692:     /* calculate response */
                    693:     HTDigest_init (&MdCtx, algorithm);
                    694:     HTDigest_update (&MdCtx, HA1, HASHHEXLEN);
                    695:     HTDigest_update (&MdCtx, ":", 1);
                    696:     HTDigest_update (&MdCtx, pszNonce, strlen(pszNonce));
                    697:     HTDigest_update (&MdCtx, ":", 1);
                    698:     if (pszQop && *pszQop) {
                    699:        HTDigest_update (&MdCtx, pszNonceCount, strlen(pszNonceCount));
                    700:        HTDigest_update (&MdCtx, ":", 1);
                    701:        HTDigest_update (&MdCtx, pszCNonce, strlen(pszCNonce));
                    702:        HTDigest_update (&MdCtx, ":", 1);
                    703:        HTDigest_update (&MdCtx, pszQop, strlen(pszQop));
                    704:        HTDigest_update (&MdCtx, ":", 1);
                    705:     }
                    706:     HTDigest_update (&MdCtx, HA2Hex, HASHHEXLEN);
                    707:     HTDigest_final (RespHash, &MdCtx);
                    708:     CvtHex (RespHash, Response);
                    709: }      
                    710: 
                    711: /*
                    712: **  Code derived from draft-ietf-http-authentication-03 ends here
                    713: */
                    714: 
2.44      frystyk   715: /*
                    716: **     Make digest authentication scheme credentials and register this
                    717: **     information in the request object as credentials. They will then
2.50      kahan     718: **     be included in the request header. An example is
                    719: **
                    720: **                 "Digest nonce:cnonce:blahblahblhah:digest-response"
                    721: **
2.44      frystyk   722: **     The function can both create normal and proxy credentials
                    723: **     Returns HT_OK or HT_ERROR
                    724: */
2.50      kahan     725: 
2.44      frystyk   726: PRIVATE BOOL digest_credentials (HTRequest * request, HTDigest * digest)
                    727: {
2.50      kahan     728:     if (request && digest && digest->realm)
                    729:     {
                    730:         char * realm = (char *) digest->realm;
                    731:        char * uri;
                    732:        char * method = (char *) HTMethod_name (HTRequest_method (request));
                    733:        char * cleartext = NULL;
                    734:        char nc[9];
                    735:        HASHHEX HA1;
                    736:         HASHHEX HA2;
                    737:        HASHHEX response;
2.44      frystyk   738: 
2.50      kahan     739:        /* @@ maybe optimize all my reallocs by preallocating the memory */
2.44      frystyk   740: 
2.50      kahan     741:        if (digest->proxy)
                    742:            uri = HTRequest_proxy(request);
2.57    ! kahan     743:        else {
        !           744:             char * tmp;
        !           745:             /* we get the absolute URL */
        !           746:             tmp = HTAnchor_address( (HTAnchor*)HTRequest_anchor(request));
        !           747:             /* and then remove what makes it absolute, to be backwards
        !           748:                compatible */
        !           749:             uri = HTParse (tmp, "", PARSE_PATH | PARSE_PUNCTUATION);
        !           750:             HT_FREE(tmp);
        !           751:        }
2.50      kahan     752: 
                    753:        /* increment the nonce counter */
                    754:        digest->nc++;
                    755:        sprintf (nc, "%08lx", digest->nc);
                    756:        add_param (&cleartext, "username", digest->uid, YES);
                    757:        add_param (&cleartext, "realm", realm, YES);
                    758:        add_param (&cleartext, "nonce", digest->nonce, YES);
                    759:        add_param (&cleartext, "uri", uri, YES);
                    760:        /* @@@  no support for auth-int yet */
                    761:        if (digest->qop) {
                    762:            add_param (&cleartext, "qop", "auth", NO);
                    763:            add_param (&cleartext, "nc", nc, NO);
                    764:            add_param (&cleartext, "cnonce", digest->cnonce, YES);
                    765:        }
                    766:        /* compute the response digest */
                    767:        /* @@@ md5 hard coded, change it to something from the answer, 
                    768:           md5-sess, etc */
                    769:        DigestCalcHA1 (digest->algorithm, "md5", digest->uid, realm, digest->pw, digest->nonce,
                    770:                       digest->cnonce, HA1);
                    771:        DigestCalcResponse (digest->algorithm, HA1, digest->nonce, nc, digest->cnonce,
                    772:                            digest->qop, method, uri, HA2, response);
                    773:        add_param (&cleartext, "response", response, NO);
                    774:        add_param (&cleartext, "opaque", digest->opaque, NO);
2.44      frystyk   775: 
                    776:        /* Create the credentials and assign them to the request object */
                    777:        {
2.50      kahan     778:            int cr_len = strlen ("Digest") + strlen (cleartext) + 3;
2.44      frystyk   779:            char * cookie = (char *) HT_MALLOC(cr_len+1);
                    780:            if (!cookie) HT_OUTOFMEM("digest_credentials");
                    781:            strcpy(cookie, "Digest ");
2.50      kahan     782:            strcat (cookie, cleartext);
2.56      frystyk   783:            HTTRACE(AUTH_TRACE, "Digest Cookie `%s\'\n" _ cookie);
2.44      frystyk   784: 
                    785:            /* Check whether it is proxy or normal credentials */
                    786:            if (digest->proxy)
2.50      kahan     787:                HTRequest_addCredentials(request, "Proxy-Authorization",
                    788:                                         cookie);
2.44      frystyk   789:            else
                    790:                HTRequest_addCredentials(request, "Authorization", cookie);
                    791: 
                    792:            HT_FREE(cookie);
                    793:        }
2.57    ! kahan     794:        if (!digest->proxy)
        !           795:          HT_FREE(uri);
2.44      frystyk   796:        HT_FREE(cleartext);
                    797:        return HT_OK;
                    798:     }
                    799:     return HT_ERROR;
                    800: }
                    801: 
                    802: /*     HTDigest_generate
                    803: **     ----------------
                    804: **     This function generates "digest" credentials for the challenge found in
                    805: **     the authentication information base for this request. The result is
                    806: **     stored as an association list in the request object.
                    807: **     This is a callback function for the AA handler.
                    808: */
2.45      frystyk   809: PUBLIC int HTDigest_generate (HTRequest * request, void * context, int mode)
2.44      frystyk   810: { 
                    811:     HTDigest * digest = (HTDigest *) context;
2.45      frystyk   812:     BOOL proxy = mode==HT_NO_PROXY_ACCESS ? YES : NO;
2.44      frystyk   813:     if (request) {
                    814:        const char * realm = HTRequest_realm(request);
2.46      frystyk   815: 
                    816:        /*
                    817:        **  If we were asked to explicitly ask the user again
                    818:        */
                    819:        if (mode == HT_REAUTH || mode == HT_PROXY_REAUTH)
                    820:            digest->retry = YES;
2.44      frystyk   821: 
                    822:        /*
                    823:        ** If we don't have a digest context then add a new one to the tree.
                    824:        ** We use different trees for normal and proxy authentication
                    825:        */
                    826:        if (!digest) {
2.50      kahan     827:            digest = HTDigest_new();
2.44      frystyk   828:            if (proxy) {
                    829:                char * url = HTRequest_proxy(request);
                    830:                digest->proxy = YES;
                    831:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest);
                    832:            } else {
                    833:                char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
                    834:                HTAA_updateNode(proxy, DIGEST_AUTH, realm, url, digest);
                    835:                HT_FREE(url);
                    836:            }
                    837:        }
                    838: 
                    839:        /*
                    840:        ** If we have a set of credentials (or the user provides a new set)
                    841:        ** then store it in the request object as the credentials
                    842:        */
2.50      kahan     843:        if ((digest->retry && 
2.44      frystyk   844:             prompt_digest_user(request, realm, digest) == HT_OK) ||
                    845:            (!digest->retry && digest->uid)) {
2.50      kahan     846:        /* @@@ here we should generate a new cnonce value */
                    847:            digest->cnonce = "012345678";
2.44      frystyk   848:            digest->retry = NO;
                    849:            return digest_credentials(request, digest);
2.50      kahan     850:        } else {
                    851:            char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
                    852:            if (proxy)
                    853:                HTAA_deleteNode(proxy, DIGEST_AUTH, realm, url);
                    854:            else
                    855:                HTAA_deleteNode(proxy, DIGEST_AUTH, realm, url);
                    856:            HT_FREE(url);
2.44      frystyk   857:            return HT_ERROR;
2.50      kahan     858:        }
2.44      frystyk   859:     }
                    860:     return HT_OK;
                    861: }
                    862: 
                    863: /*     HTDigest_parse
                    864: **     -------------
                    865: **     This function parses the contents of a "digest" challenge 
                    866: **     and stores the challenge in our authentication information datebase.
                    867: **     We also store the realm in the request object which will help finding
                    868: **     the right set of credentials to generate.
                    869: **     The function is a callback function for the AA handler.
                    870: */
2.45      frystyk   871: PUBLIC int HTDigest_parse (HTRequest * request, HTResponse * response,
                    872:                           void * context, int status)
2.44      frystyk   873: {
2.45      frystyk   874:     HTAssocList * challenge = HTResponse_challenge(response);
2.44      frystyk   875:     HTDigest * digest = NULL;    
                    876:     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
                    877:     if (request && challenge) {
                    878:        char * p = HTAssocList_findObject(challenge, DIGEST_AUTH);
                    879:        char * realm =  HTNextField(&p);
2.50      kahan     880:        char * rm    =  HTNextField(&p);
                    881:        char * value = NULL;
2.44      frystyk   882:        char * token = NULL;
                    883:        char * uris = NULL;
                    884: 
                    885:        /*
2.50      kahan     886:        ** If valid challenge then make a template for the resource and
                    887:        ** store this information in our authentication URL Tree
2.44      frystyk   888:        */
2.50      kahan     889:        if (realm && !strcasecomp(realm, "realm") && rm) {
2.56      frystyk   890:            HTTRACE(AUTH_TRACE, "Digest Parse. Realm `%s\' found\n" _ rm);
2.50      kahan     891:            HTRequest_setRealm(request, rm);
                    892: 
                    893:            /*
                    894:            **  If we are in proxy mode then add the proxy - not the final URL
                    895:            */
                    896:            if (proxy) {
                    897:                char * url = HTRequest_proxy(request);
2.56      frystyk   898:                HTTRACE(AUTH_TRACE, "Digest Parse. Proxy authentication\n");
2.50      kahan     899:                digest = (HTDigest *) HTAA_updateNode(proxy, DIGEST_AUTH, rm,
                    900:                                                      url, NULL);
                    901:                /* if the previous authentication failed, then try again */
                    902:                if (HTRequest_AAretrys (request) > 1 
                    903:                    && status == HT_NO_ACCESS && digest)
                    904:                  digest->retry = YES;
                    905:            } else {
                    906:                char * url = HTAnchor_address((HTAnchor *)
                    907:                                              HTRequest_anchor(request));
                    908:                char * tmplate = make_template(url);
                    909:                digest = (HTDigest *) HTAA_updateNode(proxy, DIGEST_AUTH, rm,
                    910:                                                      tmplate, NULL);
                    911:                /* if the previous authentication failed, then try again */
                    912:                if (HTRequest_AAretrys (request) > 1 
                    913:                    && status == HT_NO_ACCESS && digest)
                    914:                  digest->retry = YES;
                    915:                HT_FREE(tmplate);
                    916:                HT_FREE(url);
                    917:            }
                    918:        } else {
2.56      frystyk   919:            HTTRACE(AUTH_TRACE, "Digest Parse. Missing or incomplete realm\n");
2.50      kahan     920:            return HT_ERROR;
2.44      frystyk   921:        }
2.50      kahan     922: 
                    923: 
                    924:        /* if we get here it's because there's no digest */
                    925:        /* we parse the digest parameters from the challenge */
                    926: 
                    927:        if (digest) {
                    928:            /* it's an old digest, so we clean all in it except for the
                    929:               uid and the password, hoping that the server send back
                    930:               that data */
                    931:            HTDigest_reset (digest);
                    932:        } else {
                    933:            /* it's a brand new digest */
2.44      frystyk   934:            digest = HTDigest_new();
2.50      kahan     935:            StrAllocCopy (digest->realm, rm);
                    936:        }
2.44      frystyk   937: 
                    938:        /*
                    939:        **  Search through the set of parameters in the digest header.
                    940:        **  If valid challenge then make a template for the resource and
                    941:        **  store this information in our authentication URL Tree
                    942:        */
                    943:        while ((token = HTNextField(&p))) {
                    944:            if (!strcasecomp(token, "domain")) {
                    945:                if ((value = HTNextField(&p)))
                    946:                    uris = value;
2.50      kahan     947:            } else if (!strcasecomp(token, "nonce")) {
2.44      frystyk   948:                if ((value = HTNextField(&p)))
2.50      kahan     949:                    StrAllocCopy(digest->nonce, value);
2.44      frystyk   950:            } else if (!strcasecomp(token, "opaque")) {
                    951:                if ((value = HTNextField(&p)))
                    952:                    StrAllocCopy(digest->opaque, value);
2.50      kahan     953:            } else if (!strcasecomp(token, "qop")) {
                    954:                /* split the qop */
                    955:                if ((value = HTNextField(&p)))
                    956:                    StrAllocCopy(digest->qop, value);
2.44      frystyk   957:            } else if (!strcasecomp(token, "stale")) {
2.50      kahan     958:                if ((value = HTNextField(&p)) && !strcasecomp(value, "true")) {
                    959:                    /* only true if we already had a digest with uid and pw info */
                    960:                    if (digest->uid && digest->pw) {
                    961:                        digest->stale = YES;            
                    962:                        digest->retry = NO;
                    963:                    }
                    964:                }
2.44      frystyk   965:            } else if (!strcasecomp(token, "algorithm")) {
2.50      kahan     966:                if ((value = HTNextField(&p)) && strcasecomp(value, "md5")) {
2.44      frystyk   967:                    /*
                    968:                    **  We only support MD5 for the moment
                    969:                    */
2.56      frystyk   970:                    HTTRACE(AUTH_TRACE, "Digest Parse Unknown algorithm `%s\'\n" _ value);
2.44      frystyk   971:                    HTDigest_delete(digest);
                    972:                    return HT_ERROR;
2.50      kahan     973:                } else
                    974:                    digest->algorithm = HTDaMD5;
                    975:            }
                    976:        }
                    977:        
                    978:        if (digest->stale)
                    979:            return HT_OK;
                    980:        else if (digest->uid || digest->pw) {
                    981:            /*
                    982:            ** For some reason there was no stale nonce header and the
                    983:            ** authentication failed so we have to ask the user if we should
                    984:            ** try again. It may be because the user typed the wrong user name
                    985:            ** and password
                    986:            */
                    987:            HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
                    988: 
                    989:            /*
                    990:            ** Do we have a method registered for prompting the user whether
                    991:            ** we should retry
                    992:            */
                    993:            if (prompt) {
                    994:                int code = proxy ?
                    995:                    HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
                    996:                if ((*prompt)(request, HT_A_CONFIRM, code,
                    997:                              NULL, NULL, NULL) != YES)
                    998:                    return HT_ERROR;
                    999:                return HT_OK;
2.44      frystyk  1000:            }
2.50      kahan    1001:            return HT_ERROR;
2.44      frystyk  1002:        }
                   1003: 
                   1004:        /*
2.50      kahan    1005:        ** It's the first time we go this way, so we check the domain field to 
                   1006:        ** create the digest node entries for each URI.
2.44      frystyk  1007:        */
                   1008:        if (!uris) {
                   1009:            if (proxy) {
2.50      kahan    1010:                /* we ignore the domain */
2.44      frystyk  1011:                char * location = HTRequest_proxy(request);
2.56      frystyk  1012:                HTTRACE(AUTH_TRACE, "Digest Parse Proxy authentication\n");
2.50      kahan    1013:                HTAA_updateNode(proxy, DIGEST_AUTH, rm, location, digest);
2.44      frystyk  1014:            } else {
                   1015:                char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
                   1016:                char * tmplate = make_template(url);
2.50      kahan    1017:                HTAA_updateNode(proxy, DIGEST_AUTH, rm, tmplate, digest);
2.44      frystyk  1018:                HT_FREE(url);
                   1019:                HT_FREE(tmplate);
                   1020:            }
                   1021:        } else {
2.50      kahan    1022:            char * base_url =
                   1023:                HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
                   1024:            char * domain_url;
                   1025:            char * full_url;
                   1026: 
                   1027:            while ((domain_url = HTNextField (&uris))) {
                   1028:                /* complete the URL if it's an absolute one */
                   1029:                full_url = HTParse (domain_url, base_url, PARSE_ALL);
                   1030:                digest->references++;
                   1031:                if (proxy) {
2.56      frystyk  1032:                    HTTRACE(AUTH_TRACE, "Digest Parse Proxy authentication\n");
2.50      kahan    1033:                    HTAA_updateNode(proxy, DIGEST_AUTH, rm, full_url, digest);
                   1034:                } else {
                   1035:                    char * tmplate = make_template(full_url);
                   1036:                    HTAA_updateNode (proxy, DIGEST_AUTH, rm, tmplate, digest);
                   1037:                    HT_FREE (tmplate);
                   1038:                }
                   1039:                HT_FREE (full_url);
2.44      frystyk  1040:            }
2.50      kahan    1041:            HT_FREE (base_url);
2.44      frystyk  1042:        }
                   1043:        return HT_OK;
2.50      kahan    1044:     }  
2.56      frystyk  1045:     HTTRACE(AUTH_TRACE, "Auth........ No challenges found\n");
2.44      frystyk  1046:     return HT_ERROR;
                   1047: }
2.50      kahan    1048: 
                   1049: 
                   1050: 
                   1051: 
                   1052: 
                   1053: 
                   1054: 
                   1055: 
                   1056: 
                   1057: 
                   1058: 
                   1059: 
                   1060: 
2.44      frystyk  1061: 

Webmaster