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

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.42    ! frystyk     6: **     @(#) $Id: HTAABrow.c,v 2.41 1996/08/08 16:40:51 frystyk Exp $
2.1       luotonen    7: **
2.32      frystyk     8: **     Contains code for parsing challenges and creating credentials for 
2.36      frystyk     9: **     basic authentication schemes. See also the HTAAUtil module
2.32      frystyk    10: **     for how to handle other authentication schemes. You don't have to use
                     11: **     this code at all.
2.1       luotonen   12: **
                     13: ** AUTHORS:
                     14: **     AL      Ari Luotonen    luotonen@dxcern.cern.ch
2.32      frystyk    15: **     HFN     Henrik Frystyk
2.1       luotonen   16: **
                     17: ** HISTORY:
2.5       luotonen   18: **     Oct 17  AL      Made corrections suggested by marca:
                     19: **                     Added  if (!realm->username) return NULL;
                     20: **                     Changed some ""s to NULLs.
2.33      frystyk    21: **                     Now doing HT_CALLOC() to init uuencode source;
2.5       luotonen   22: **                     otherwise HTUU_encode() reads uninitialized memory
                     23: **                     every now and then (not a real bug but not pretty).
                     24: **                     Corrected the formula for uuencode destination size.
2.32      frystyk    25: **     Feb 96 HFN      Rewritten to make it scheme independent and based on
                     26: **                     callback functions and an info structure
2.1       luotonen   27: */
                     28: 
2.17      frystyk    29: /* Library include files */
2.27      frystyk    30: #include "WWWLib.h"
                     31: #include "HTAAUtil.h"
                     32: #include "HTAABrow.h"                                   /* Implemented here */
2.1       luotonen   33: 
2.36      frystyk    34: #define BASIC_AUTH     "basic"
                     35: 
2.32      frystyk    36: typedef struct _HTBasic {                /* Basic challenge and credentials */
                     37:     char *     uid;
                     38:     char *     pw;
2.38      frystyk    39:     BOOL       retry;                      /* Should we ask the user again? */
2.40      frystyk    40:     BOOL       proxy;                               /* Proxy authentication */
2.32      frystyk    41: } HTBasic;
                     42: 
2.36      frystyk    43: /* ------------------------------------------------------------------------- */
                     44: 
                     45: PRIVATE HTBasic * HTBasic_new()
                     46: {
                     47:     HTBasic * me = NULL;
                     48:     if ((me = (HTBasic *) HT_CALLOC(1, sizeof(HTBasic))) == NULL)
                     49:        HT_OUTOFMEM("HTBasic_new");
2.38      frystyk    50:     me->retry = YES;                          /* Ask the first time through */
2.36      frystyk    51:     return me;
                     52: }
2.7       luotonen   53: 
2.36      frystyk    54: /*     HTBasic_delete
                     55: **     --------------
                     56: **     Deletes a "basic" information object
                     57: */
                     58: PUBLIC int HTBasic_delete (void * context)
                     59: {
                     60:     HTBasic * basic = (HTBasic *) context;
                     61:     if (basic) {
                     62:        HT_FREE(basic->uid);
                     63:        HT_FREE(basic->pw);
                     64:        HT_FREE(basic);
                     65:        return YES;
                     66:     }
                     67:     return NO;
                     68: }
2.1       luotonen   69: 
2.32      frystyk    70: /*
                     71: **     Create a protection template for the files
                     72: **     in the same directory as the given file
                     73: **     Returns a template matching docname, and other files in that directory.
                     74: **
                     75: **             E.g.  /foo/bar/x.html  =>  /foo/bar/ *
                     76: **                                                 ^
                     77: **                             Space only to prevent it from
                     78: **                             being a comment marker here,
                     79: **                             there really isn't any space.
2.1       luotonen   80: */
2.33      frystyk    81: PRIVATE char * make_template (const char * docname)
2.1       luotonen   82: {
2.39      frystyk    83:     char * tmplate = NULL;
2.32      frystyk    84:     if (docname) {
2.39      frystyk    85:        char * host = HTParse(docname, "", PARSE_ACCESS|PARSE_HOST|PARSE_PUNCTUATION);
                     86:        char * path = HTParse(docname, "", PARSE_PATH|PARSE_PUNCTUATION);
                     87:        char * slash = strrchr(path, '/');
                     88:        if (slash) {
                     89:            if (*(slash+1)) {           
                     90:                strcpy(slash, "*");
                     91:                StrAllocCat(host, path);
                     92:            } else
                     93:                StrAllocCat(host, "*");
                     94:        }
                     95:        HT_FREE(path);
                     96:        tmplate = host;
                     97:     } else
                     98:        StrAllocCopy(tmplate, "*");
2.32      frystyk    99:     if (AUTH_TRACE)
                    100:        HTTrace("Template.... Made template `%s' for file `%s'\n",
2.39      frystyk   101:                tmplate, docname ? docname : "<null>");
2.32      frystyk   102:     return tmplate;
2.1       luotonen  103: }
                    104: 
2.32      frystyk   105: /*
                    106: **     Make basic authentication scheme credentials and register this
                    107: **     information in the request object as credentials. They will then
                    108: **     be included in the request header. An example is 
                    109: **
                    110: **             "Basic AkRDIhEF8sdEgs72F73bfaS=="
                    111: **
2.40      frystyk   112: **     The function can both create normal and proxy credentials
2.36      frystyk   113: **     Returns HT_OK or HT_ERROR
2.32      frystyk   114: */
2.36      frystyk   115: PRIVATE BOOL basic_credentials (HTRequest * request, HTBasic * basic)
2.32      frystyk   116: {
                    117:     if (request && basic) {
                    118:        char * cleartext = NULL;
                    119:        char * cipher = NULL;
                    120:        int cl_len = strlen(basic->uid ? basic->uid : "") +
2.42    ! frystyk   121:            strlen(basic->pw ? basic->pw : "") + 5;
2.37      frystyk   122:        int ci_len = 4 * (((cl_len+2)/3) + 1);
                    123:        if ((cleartext = (char *) HT_CALLOC(1, cl_len)) == NULL)
2.32      frystyk   124:            HT_OUTOFMEM("basic_credentials");
                    125:        *cleartext = '\0';
                    126:        if (basic->uid) strcpy(cleartext, basic->uid);
                    127:        strcat(cleartext, ":");
                    128:        if (basic->pw) strcat(cleartext, basic->pw);
2.37      frystyk   129:        if ((cipher = (char *) HT_CALLOC(1, ci_len + 3)) == NULL)
2.32      frystyk   130:            HT_OUTOFMEM("basic_credentials");
2.37      frystyk   131:        HTUU_encode((unsigned char *) cleartext, strlen(cleartext), cipher);
2.1       luotonen  132: 
2.32      frystyk   133:        /* Create the credentials and assign them to the request object */
                    134:        {
2.37      frystyk   135:            int cr_len = strlen("basic") + ci_len + 3;
2.32      frystyk   136:            char * cookie = (char *) HT_MALLOC(cr_len+1);
                    137:            if (!cookie) HT_OUTOFMEM("basic_credentials");
                    138:            strcpy(cookie, "Basic ");
                    139:            strcat(cookie, cipher);
2.37      frystyk   140:            if (AUTH_TRACE) HTTrace("Basic Cookie `%s\'\n", cookie);
2.40      frystyk   141: 
                    142:            /* Check whether it is proxy or normal credentials */
                    143:            if (basic->proxy)
                    144:                HTRequest_addCredentials(request, "Proxy-Authorization", cookie);
                    145:            else
                    146:                HTRequest_addCredentials(request, "Authorization", cookie);
                    147: 
2.32      frystyk   148:            HT_FREE(cookie);
2.1       luotonen  149:        }
2.32      frystyk   150:        HT_FREE(cleartext);
                    151:        HT_FREE(cipher);
2.36      frystyk   152:        return HT_OK;
2.32      frystyk   153:     }
2.36      frystyk   154:     return HT_ERROR;
2.1       luotonen  155: }
                    156: 
2.32      frystyk   157: /*
                    158: **     Prompt the user for username and password.
                    159: **     Returns YES if user name was typed in, else NO
2.1       luotonen  160: */
2.36      frystyk   161: PRIVATE int prompt_user (HTRequest * request, const char * realm,
                    162:                         HTBasic * basic)
2.1       luotonen  163: {
2.32      frystyk   164:     HTAlertCallback * cbf = HTAlert_find(HT_A_USER_PW);
                    165:     if (request && cbf) {
2.40      frystyk   166:        HTAlertPar * reply = HTAlert_newReply();
2.41      frystyk   167:        int msg = basic->proxy ? HT_MSG_PROXY_UID : HT_MSG_UID;
                    168:        BOOL res = (*cbf)(request, HT_A_USER_PW, msg,
2.36      frystyk   169:                          basic->uid, (char *) realm, reply);
2.32      frystyk   170:        if (res) {
2.36      frystyk   171:            HT_FREE(basic->uid);
                    172:            HT_FREE(basic->pw);
                    173:            basic->uid = HTAlert_replyMessage(reply);
                    174:            basic->pw = HTAlert_replySecret(reply);
2.32      frystyk   175:        }
                    176:        HTAlert_deleteReply(reply);
2.36      frystyk   177:        return res ? HT_OK : HT_ERROR;
2.1       luotonen  178:     }
2.36      frystyk   179:     return HT_OK;
2.1       luotonen  180: }
                    181: 
2.32      frystyk   182: /*     HTBasic_generate
                    183: **     ----------------
                    184: **     This function generates "basic" credentials for the challenge found in
                    185: **     the authentication information base for this request. The result is
                    186: **     stored as an association list in the request object.
                    187: **     This is a callback function for the AA handler.
                    188: */
2.36      frystyk   189: PUBLIC int HTBasic_generate (HTRequest * request, void * context, int status)
2.32      frystyk   190: { 
2.36      frystyk   191:     HTBasic * basic = (HTBasic *) context;
2.42    ! frystyk   192:     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
2.36      frystyk   193:     if (request) {
                    194:        const char * realm = HTRequest_realm(request);
                    195: 
2.40      frystyk   196:        /*
                    197:        ** If we don't have a basic context then add a new one to the tree.
2.42    ! frystyk   198:        ** We use different trees for normal and proxy authentication
2.40      frystyk   199:        */
2.36      frystyk   200:        if (!basic) {
2.42    ! frystyk   201:            if (proxy) {
        !           202:                char * url = HTRequest_proxy(request);
        !           203:                basic = HTBasic_new();
        !           204:                basic->proxy = YES;
        !           205:                HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
        !           206:            } else {
        !           207:                char * url = HTAnchor_address((HTAnchor*)HTRequest_anchor(request));
        !           208:                basic = HTBasic_new();
        !           209:                HTAA_updateNode(proxy, BASIC_AUTH, realm, url, basic);
        !           210:                HT_FREE(url);
        !           211:            }
2.36      frystyk   212:        }
                    213: 
2.32      frystyk   214:        /*
2.36      frystyk   215:        ** If we have a set of credentials (or the user provides a new set)
                    216:        ** then store it in the request object as the credentials
2.32      frystyk   217:        */
2.39      frystyk   218:        if ((basic->retry && prompt_user(request, realm, basic) == HT_OK) ||
                    219:            (!basic->retry && basic->uid)) {
2.38      frystyk   220:            basic->retry = NO;
2.36      frystyk   221:            return basic_credentials(request, basic);
2.38      frystyk   222:        } else
2.37      frystyk   223:            return HT_ERROR;
2.1       luotonen  224:     }
2.36      frystyk   225:     return HT_OK;
2.1       luotonen  226: }
                    227: 
2.32      frystyk   228: /*     HTBasic_parse
                    229: **     -------------
                    230: **     This function parses the contents of a "basic" challenge 
                    231: **     and stores the challenge in our authentication information datebase.
                    232: **     We also store the realm in the request object which will help finding
                    233: **     the right set of credentials to generate.
                    234: **     The function is a callback function for the AA handler.
                    235: */
2.36      frystyk   236: PUBLIC int HTBasic_parse (HTRequest * request, void * context, int status)
2.32      frystyk   237: {
2.36      frystyk   238:     HTAssocList * challenge = HTRequest_challenge(request);
2.38      frystyk   239:     HTBasic * basic = NULL;
2.40      frystyk   240:     BOOL proxy = status==HT_NO_PROXY_ACCESS ? YES : NO;
2.36      frystyk   241:     if (request && challenge) {
                    242:        char * p = HTAssocList_findObject(challenge, BASIC_AUTH);
                    243:        char * realm = HTNextField(&p);
                    244:        char * rm = HTNextField(&p);
2.38      frystyk   245: 
2.32      frystyk   246:        /*
2.36      frystyk   247:        ** If valid challenge then make a template for the resource and
                    248:        ** store this information in our authentication URL Tree
2.32      frystyk   249:        */
2.36      frystyk   250:        if (realm && !strcasecomp(realm, "realm") && rm) {
                    251:            if (AUTH_TRACE) HTTrace("Basic Parse. Realm `%s\' found\n", rm);
                    252:            HTRequest_setRealm(request, rm);
2.40      frystyk   253: 
                    254:            /*
                    255:            **  If we are in proxy mode then add the proxy - not the final URL
                    256:            */
                    257:            if (proxy) {
                    258:                char * url = HTRequest_proxy(request);
2.42    ! frystyk   259:                if (AUTH_TRACE) HTTrace("Basic Parse. Proxy authentication\n");
2.40      frystyk   260:                basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
                    261:                                                    url, NULL);
                    262:            } else {
                    263:                char * url = HTAnchor_address((HTAnchor *)
                    264:                                              HTRequest_anchor(request));
                    265:                char * tmplate = make_template(url);
                    266:                basic = (HTBasic *) HTAA_updateNode(proxy, BASIC_AUTH, rm,
                    267:                                                    tmplate, NULL);
                    268:                HT_FREE(url);
                    269:                HT_FREE(tmplate);
                    270:            }
2.1       luotonen  271:        }
2.38      frystyk   272: 
                    273:        /*
                    274:        ** For some reason the authentication failed so we have to ask the user
                    275:        ** if we should try again. It may be because the user typed the wrong
                    276:        ** user name and password
                    277:        */
                    278:        if (basic) {
                    279:            HTAlertCallback * prompt = HTAlert_find(HT_A_CONFIRM);
2.40      frystyk   280: 
                    281:            /*
2.42    ! frystyk   282:            ** Do we haev a method registered for prompting the user whether
        !           283:            ** we should retry
2.40      frystyk   284:            */
2.38      frystyk   285:            if (prompt) {
2.40      frystyk   286:                int code = proxy ?
                    287:                    HT_MSG_RETRY_PROXY_AUTH : HT_MSG_RETRY_AUTHENTICATION;
                    288:                if ((*prompt)(request, HT_A_CONFIRM, code,
2.38      frystyk   289:                              NULL, NULL, NULL) != YES)
                    290:                    return HT_ERROR;
                    291:                basic->retry = YES;
                    292:            }
                    293:        }
2.36      frystyk   294:        return HT_OK;
2.1       luotonen  295:     }
2.36      frystyk   296:     if (AUTH_TRACE) HTTrace("Auth........ No challenges found\n");
2.38      frystyk   297:     return HT_ERROR;
2.7       luotonen  298: }

Webmaster