Annotation of libwww/Library/src/HTAAUtil.c, revision 2.31

2.23      frystyk     1: /*
2.9       frystyk     2: **     COMMON PARTS OF ACCESS AUTHORIZATION MODULE
                      3: **     FOR BOTH SERVER AND BROWSER
                      4: **
2.13      frystyk     5: **     (c) COPYRIGHT MIT 1995.
2.9       frystyk     6: **     Please first read the full copyright statement in the file COPYRIGH.
2.31    ! frystyk     7: **     @(#) $Id: HTAAUtil.c,v 2.30 1998/05/04 19:36:06 frystyk Exp $
2.1       luotonen    8: **
2.19      frystyk     9: **     The authentication information is stored in a list of authentication
                     10: **     data bases, each uniquely identified by a hostname and a port number.
                     11: **     Each data base contains a set of templates which can be used to predict
                     12: **     what information to use in a hierarchical tree. All authentication
                     13: **     dependent information is stored as opaque data in a anode. Normally
                     14: **     a server application would only keep one auth base but if it wants
                     15: **     different protection setup as a function of different interfaces then
                     16: **     it can have one auth base representing each interface. For example a
                     17: **     server with interfaces "www.foo.com" and "internal.foo.com" can have
                     18: **     different protection setups for each interface.
2.1       luotonen   19: **
                     20: ** AUTHORS:
                     21: **     AL      Ari Luotonen    luotonen@dxcern.cern.ch
2.3       duns       22: **     MD      Mark Donszelmann    duns@vxdeop.cern.ch
2.19      frystyk    23: **     HFN     Henrik Frystyk
2.1       luotonen   24: **
                     25: ** HISTORY:
2.4       luotonen   26: **      8 Nov 93  MD   (VMS only) Added case insensitive comparison
                     27: **                     in HTAA_templateCaseMatch
2.1       luotonen   28: */
                     29: 
2.11      frystyk    30: /* Library include files */
2.30      frystyk    31: #include "wwwsys.h"
2.23      frystyk    32: #include "WWWUtil.h"
                     33: #include "WWWCore.h"
2.19      frystyk    34: #include "HTAAUtil.h"                                   /* Implemented here */
                     35: 
2.26      frystyk    36: #define AA_TREE                        "w3c-AA"              /* Name of the AA tree */
                     37: #define AA_PROXY_TREE          "w3c-proxy-AA"  /* Name of the proxy AA tree */
2.23      frystyk    38: #define DEFAULT_PORT            80                    /* Concentrate on HTTP */
                     39: 
                     40: struct _HTAAModule {
2.19      frystyk    41:     char *             scheme;
2.29      frystyk    42:     HTNetBefore *      before;
                     43:     HTNetAfter *       after;
2.23      frystyk    44:     HTUTree_gc *       gc;
                     45: };
                     46: 
                     47: typedef struct _HTAAElement {
                     48:     char *             scheme;
                     49:     void *             context;
                     50: } HTAAElement;
2.19      frystyk    51: 
                     52: PRIVATE HTList * HTSchemes;    /* List of registered authentication schemes */
                     53: 
                     54: /* ------------------------------------------------------------------------- */
2.23      frystyk    55: /*                      AUTHENTICATION MODULE MANAGEMENT                    */
2.19      frystyk    56: /* ------------------------------------------------------------------------- */
                     57: 
2.23      frystyk    58: PRIVATE BOOL delete_module (HTAAModule * module)
2.19      frystyk    59: {
2.23      frystyk    60:     if (module) {
                     61:        HT_FREE(module->scheme);
                     62:        HT_FREE(module);
                     63:        return YES;
2.19      frystyk    64:     }
                     65:     return NO;
                     66: }
2.1       luotonen   67: 
2.23      frystyk    68: PRIVATE HTAAModule * find_module (const char * scheme)
2.19      frystyk    69: {
2.23      frystyk    70:     if (!HTSchemes) HTSchemes = HTList_new();
                     71:     if (scheme) {
                     72:        HTList * cur = HTSchemes;
                     73:        HTAAModule * pres = NULL;
                     74:        while ((pres = (HTAAModule *) HTList_nextObject(cur)))
                     75:            if (!strcasecomp(pres->scheme, scheme)) return pres;
                     76:     } else
                     77:        if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
                     78:     return NULL;
2.19      frystyk    79: }
2.1       luotonen   80: 
2.23      frystyk    81: PUBLIC HTAAModule * HTAA_newModule (const char *       scheme,
2.29      frystyk    82:                                    HTNetBefore *       before,
                     83:                                    HTNetAfter *        after,
2.23      frystyk    84:                                    HTUTree_gc *        gc)
                     85: {
                     86:     if (scheme) {
                     87:        HTAAModule * pres = find_module(scheme);
                     88: 
                     89:        /* If found then update entry - else create a new one */
                     90:        if (!pres) {
                     91:            if (!(pres = (HTAAModule *) HT_CALLOC(1, sizeof(HTAAModule))))
                     92:                HT_OUTOFMEM("HTAA_newModule");
                     93:            StrAllocCopy(pres->scheme, scheme);
                     94:            pres->before = before;
                     95:            pres->after = after;
                     96:            pres->gc = gc;
                     97: 
                     98:            /* Add the new AA Module to the list */
                     99:            HTList_addObject(HTSchemes, (void *) pres);
                    100:            if (AUTH_TRACE) HTTrace("Auth Engine. Created module %p\n", pres);
                    101:        } else {
                    102:            if (AUTH_TRACE) HTTrace("Auth Engine. Found module %p\n", pres);
2.19      frystyk   103:        }
2.23      frystyk   104:        return pres;
                    105:     } else {
                    106:        if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
                    107:        return NULL;
2.19      frystyk   108:     }
                    109: }
2.1       luotonen  110: 
2.23      frystyk   111: PUBLIC HTAAModule * HTAA_findModule (const char * scheme)
2.19      frystyk   112: {
2.23      frystyk   113:     if (scheme) {
                    114:        HTAAModule * pres = find_module(scheme);
                    115:        if (AUTH_TRACE)
                    116:            HTTrace("Auth Engine. did %sfind %s\n", pres ? "" : "NOT ",scheme);
                    117:        return pres;
                    118:     } else {
                    119:        if (AUTH_TRACE) HTTrace("Auth Engine. Bad augument\n");
2.19      frystyk   120:     }
                    121:     return NULL;
                    122: }
2.1       luotonen  123: 
2.23      frystyk   124: PUBLIC BOOL HTAA_deleteModule (const char * scheme)
2.19      frystyk   125: {
2.23      frystyk   126:     if (scheme) {
                    127:        HTAAModule * pres = find_module(scheme);
                    128:        if (pres) {
                    129:            HTList_removeObject(HTSchemes, pres);
                    130:            if (AUTH_TRACE) HTTrace("Auth Engine. deleted %p\n", pres);
                    131:            delete_module(pres);
                    132:            return YES;
                    133:        }
2.1       luotonen  134:     }
2.19      frystyk   135:     return NO;
2.1       luotonen  136: }
                    137: 
2.23      frystyk   138: PUBLIC BOOL HTAA_deleteAllModules (void)
2.19      frystyk   139: {
2.23      frystyk   140:     if (HTSchemes) {
                    141:        HTList * cur = HTSchemes;
                    142:        HTAAModule * pres;
                    143:        while ((pres = (HTAAModule *) HTList_nextObject(cur)))
                    144:            delete_module(pres);
                    145:        HTList_delete(HTSchemes);
                    146:        HTSchemes = NULL;
2.19      frystyk   147:        return YES;
                    148:     }
                    149:     return NO;
                    150: }
2.1       luotonen  151: 
2.23      frystyk   152: /* ------------------------------------------------------------------------- */
                    153: /*                         HANDLE THE AA URL TREE                           */
                    154: /* ------------------------------------------------------------------------- */
                    155: 
2.19      frystyk   156: /*
2.23      frystyk   157: **     A AA element is a particular AA procotol associated with a
                    158: **     particular point in the URL tree. The scheme is the name of the
                    159: **     AA protocol known to be able to handle this context. This protocol
                    160: **     must have been registered as a AA module.
                    161: */
                    162: PRIVATE HTAAElement * HTAA_newElement (const char * scheme, void * context)
                    163: {
                    164:     if (scheme) {
                    165:        HTAAElement * me;
                    166:        if ((me = (HTAAElement *) HT_CALLOC(1, sizeof(HTAAElement))) == NULL)
                    167:            HT_OUTOFMEM("HTAAElement_new");
                    168:        StrAllocCopy(me->scheme, scheme);
                    169:        me->context = context;
                    170:        if (AUTH_TRACE) HTTrace("Auth Engine. Created element %p\n", me);
                    171:        return me;
2.19      frystyk   172:     }
                    173:     return NULL;
                    174: }
2.1       luotonen  175: 
2.24      frystyk   176: /*
2.27      frystyk   177: **     If the new context differs from the existing one then use the
                    178: **     new one, otherwise only override the old context if new
2.24      frystyk   179: **     one differs from NULL
                    180: */
2.23      frystyk   181: PRIVATE BOOL HTAA_updateElement (HTAAElement * element,
                    182:                                 const char * scheme, void * context)
2.19      frystyk   183: {
2.23      frystyk   184:     if (element && scheme) {
2.24      frystyk   185:        /*
2.27      frystyk   186:        ** If the old context differs from the new one then 
                    187:        ** call the gc provided by the caller
2.24      frystyk   188:        */
2.27      frystyk   189:        if (context && context != element->context) {
2.24      frystyk   190:            HTAAModule * module = HTAA_findModule(element->scheme);
                    191:            if (module && module->gc && element->context)
                    192:                (*module->gc)(element->context);
                    193:            /*
                    194:            **  Insert the new scheme
                    195:            */
                    196:            StrAllocCopy(element->scheme, scheme);
                    197:            element->context = context;
2.27      frystyk   198:        }
2.23      frystyk   199:        return YES;
2.19      frystyk   200:     }
                    201:     return NO;
                    202: }
2.1       luotonen  203: 
2.23      frystyk   204: PRIVATE int HTAA_deleteElement (void * context)
2.19      frystyk   205: {
2.23      frystyk   206:     HTAAElement * me = (HTAAElement *) context;
                    207:     if (me) {
                    208:        HTAAModule * module = HTAA_findModule(me->scheme);
2.1       luotonen  209: 
2.23      frystyk   210:        /* If module then call the gc of the Authentication Module */
                    211:        if (module && module->gc && me->context)
                    212:            (*module->gc)(me->context);
2.1       luotonen  213: 
2.23      frystyk   214:        if (AUTH_TRACE) HTTrace("Auth Engine. Deleted element %p\n", me);
                    215:        HT_FREE(me->scheme);
                    216:        HT_FREE(me);
2.19      frystyk   217:        return YES;
                    218:     }
                    219:     return NO;
                    220: }
2.1       luotonen  221: 
                    222: /*
2.23      frystyk   223: **     Find AA Element
                    224: **     ---------------
                    225: **     Seaches the set of authentication information bases for a match
                    226: **     In order to find an anode we do the following:
                    227: **
                    228: **             1) Find the right auth base
                    229: **             2) See if there is a realm match
                    230: **             3) See if there is a template match for URL
                    231: **
                    232: **     Return the node found else NULL which means that we don't have any
                    233: **     authentication information to hook on to this request or response
2.1       luotonen  234: */
2.26      frystyk   235: PRIVATE HTAAElement * HTAA_findElement (BOOL proxy_access,
                    236:                                        const char * realm, const char * url)
2.19      frystyk   237: {
2.23      frystyk   238:     HTUTree * tree;
                    239:     if (!url) {
                    240:        if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
                    241:        return NULL;
2.19      frystyk   242:     }
2.23      frystyk   243:     if (AUTH_TRACE) HTTrace("Auth Engine. Looking up `%s'\n", url);
2.19      frystyk   244: 
2.23      frystyk   245:     /* Find an existing URL Tree for this URL (if any) */
2.19      frystyk   246:     {
                    247:        char * host = HTParse(url, "", PARSE_HOST);
                    248:        char * colon = strchr(host, ':');
2.23      frystyk   249:        int port = DEFAULT_PORT;
2.19      frystyk   250:        if (colon ) {
                    251:            *(colon++) = '\0';                       /* Chop off port number */
                    252:            port = atoi(colon);
2.23      frystyk   253:        }       
2.26      frystyk   254:        tree = HTUTree_find(proxy_access ? AA_PROXY_TREE : AA_TREE, host,port);
2.23      frystyk   255:        HT_FREE(host);
                    256:        if (!tree) {
                    257:            if (AUTH_TRACE) HTTrace("Auth Engine. No information\n");
                    258:            return NULL;
2.19      frystyk   259:        }
                    260:     }
2.1       luotonen  261: 
2.23      frystyk   262:     /* Find a matching AA element (if any) */
2.19      frystyk   263:     {
2.28      frystyk   264:        char * path = HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION);
2.23      frystyk   265:        HTAAElement *element = (HTAAElement*)HTUTree_findNode(tree,realm,path);
                    266:        HT_FREE(path);
                    267:        return element;
2.19      frystyk   268:     }
2.23      frystyk   269:     return NULL;
2.19      frystyk   270: }
                    271: 
2.23      frystyk   272: /*     Add a AA context to the URL tree
                    273: **     --------------------------------
                    274: **     Each node in the AA URL tree is a list of the modules we must call
                    275: **     for this particular node.
                    276: */
2.26      frystyk   277: PUBLIC void * HTAA_updateNode (BOOL proxy_access, char const * scheme,
2.24      frystyk   278:                               const char * realm, const char * url,
                    279:                               void * context)
2.23      frystyk   280: {
                    281:     HTUTree * tree = NULL;
                    282:     HTAAModule * module = NULL;
                    283:     if (!scheme || !url) {
                    284:        if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
2.24      frystyk   285:        return NULL;
2.23      frystyk   286:     }
                    287:     if (AUTH_TRACE) HTTrace("Auth Engine. Adding info for `%s'\n", url);
                    288: 
                    289:     /* Find the AA module with this name */
                    290:     if ((module = HTAA_findModule(scheme)) == NULL) {
                    291:        if (AUTH_TRACE) HTTrace("Auth Engine. Module `%s\' not registered\n",
                    292:                               scheme ? scheme : "<null>");
2.24      frystyk   293:        return NULL;
2.19      frystyk   294:     }
                    295: 
2.23      frystyk   296:     /* Find an existing URL Tree or create a new one */
2.19      frystyk   297:     {
                    298:        char * host = HTParse(url, "", PARSE_HOST);
                    299:        char * colon = strchr(host, ':');
2.23      frystyk   300:        int port = DEFAULT_PORT;
2.19      frystyk   301:        if (colon ) {
                    302:            *(colon++) = '\0';                       /* Chop off port number */
                    303:            port = atoi(colon);
2.23      frystyk   304:        }
2.26      frystyk   305:        tree = HTUTree_new(proxy_access ? AA_PROXY_TREE : AA_TREE,
                    306:                           host, port, HTAA_deleteElement);
2.19      frystyk   307:        HT_FREE(host);
2.23      frystyk   308:        if (!tree) {
                    309:            if (AUTH_TRACE) HTTrace("Auth Engine. Can't create tree\n");
2.24      frystyk   310:            return NULL;
2.19      frystyk   311:        }
                    312:     }
                    313: 
2.23      frystyk   314:     /* Find a matching AA element or create a new one */
2.19      frystyk   315:     {
2.28      frystyk   316:        char * path = HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION);
2.23      frystyk   317:        HTAAElement * element = NULL;
                    318:        BOOL status;
                    319:        if ((element = (HTAAElement *) HTUTree_findNode(tree, realm, path)))
                    320:            status = HTAA_updateElement(element, scheme, context);
                    321:        else {
                    322:            element = HTAA_newElement(scheme, context);
                    323:            status = HTUTree_addNode(tree, realm, path, element);
                    324:        }
                    325:        HT_FREE(path);
2.24      frystyk   326:        return status==YES ? element->context : NULL;
2.31    ! frystyk   327:     }
        !           328: }
        !           329: 
        !           330: /*     Delete a AA context from the URL tree
        !           331: **     -------------------------------------
        !           332: **     Each node in the AA URL tree is a list of the modules we must call
        !           333: **     for this particular node.
        !           334: */
        !           335: PUBLIC BOOL HTAA_deleteNode (BOOL proxy_access, char const * scheme,
        !           336:                             const char * realm, const char * url)
        !           337: {
        !           338:     HTUTree * tree = NULL;
        !           339:     HTAAModule * module = NULL;
        !           340:     if (!scheme || !url) {
        !           341:        if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
        !           342:        return NO;
        !           343:     }
        !           344:     if (AUTH_TRACE) HTTrace("Auth Engine. Deleting info for `%s'\n", url);
        !           345: 
        !           346:     /* Find the AA module with this name */
        !           347:     if ((module = HTAA_findModule(scheme)) == NULL) {
        !           348:        if (AUTH_TRACE) HTTrace("Auth Engine. Module `%s\' not registered\n",
        !           349:                               scheme ? scheme : "<null>");
        !           350:        return NO;
        !           351:     }
        !           352: 
        !           353:     /* Find an existing URL Tree or create a new one */
        !           354:     {
        !           355:        char * host = HTParse(url, "", PARSE_HOST);
        !           356:        char * colon = strchr(host, ':');
        !           357:        int port = DEFAULT_PORT;
        !           358:        if (colon ) {
        !           359:            *(colon++) = '\0';                       /* Chop off port number */
        !           360:            port = atoi(colon);
        !           361:        }
        !           362:        tree = HTUTree_new(proxy_access ? AA_PROXY_TREE : AA_TREE,
        !           363:                           host, port, HTAA_deleteElement);
        !           364:        HT_FREE(host);
        !           365:        if (!tree) {
        !           366:            if (AUTH_TRACE) HTTrace("Auth Engine. Can't create tree\n");
        !           367:            return NO;
        !           368:        }
        !           369:     }
        !           370: 
        !           371:     /* Delete any existing node */
        !           372:     {
        !           373:        char * path = HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION);
        !           374:        BOOL status = HTUTree_deleteNode(tree, realm, path);
        !           375:        HT_FREE(path);
        !           376:        return status;
2.19      frystyk   377:     }
                    378: }
                    379: 
                    380: /* ------------------------------------------------------------------------- */
2.23      frystyk   381: /*                            AUTHENTICATION ENGINE                         */
2.19      frystyk   382: /* ------------------------------------------------------------------------- */
                    383: 
2.23      frystyk   384: /*     HTAA_beforeFilter
                    385: **     ------------------
2.24      frystyk   386: **     Make a lookup in the URL tree to find any context for this node,
                    387: **     If no context is found then we assume that we don't know anything about
                    388: **     this URL and hence we don't call any BEFORE filters at all.
2.23      frystyk   389: **     Return HT_OK or whatever callback returns
2.19      frystyk   390: */
2.29      frystyk   391: PUBLIC int HTAA_beforeFilter (HTRequest * request, void * param, int mode)
2.19      frystyk   392: {
2.25      frystyk   393:     char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
2.23      frystyk   394:     const char * realm = HTRequest_realm(request);
2.26      frystyk   395:     HTAAElement * element = HTAA_findElement(NO, realm, url); 
2.25      frystyk   396:     HT_FREE(url);
2.23      frystyk   397: 
2.26      frystyk   398:     /* If we have an element then call the before filter with this scheme */
2.23      frystyk   399:     if (element) {
                    400:        HTAAModule * module = HTAA_findModule(element->scheme);
                    401:        if (module) {
                    402:            if (AUTH_TRACE) HTTrace("Auth Engine. Found BEFORE filter %p\n",
2.29      frystyk   403:                                    module->before);
                    404:            return (*module->before)(request, element->context, mode);
2.19      frystyk   405:        }
                    406:     }
2.23      frystyk   407:     return HT_OK;
2.19      frystyk   408: }
                    409: 
2.23      frystyk   410: /*     HTAA_afterFilter
                    411: **     -----------------
2.24      frystyk   412: **     Call the AFTER filter that knows how to handle this scheme.
2.19      frystyk   413: **     Return YES or whatever callback returns
                    414: */
2.29      frystyk   415: PUBLIC int HTAA_afterFilter (HTRequest * request, HTResponse * response,
                    416:                             void * param, int status)
2.19      frystyk   417: {
2.29      frystyk   418:     const char * scheme = HTResponse_scheme(response);
2.24      frystyk   419:     HTAAModule * module = NULL;
2.27      frystyk   420:     if (AUTH_TRACE) HTTrace("Auth Engine. After filter status %d\n", status);
2.24      frystyk   421:     /*
                    422:     ** If we don't have a scheme then the server has made an error. We
                    423:     **  try to make up for it by creating our own "noop" realm and use basic.
                    424:     */
                    425:     if (!scheme) {
2.29      frystyk   426:        HTResponse_addChallenge(response, "basic", "realm LIBWWW-UNKNOWN");
2.24      frystyk   427:        scheme = "basic";
                    428:     }
                    429:     if ((module = HTAA_findModule(scheme)) != NULL) {
2.23      frystyk   430:        if (AUTH_TRACE)
                    431:            HTTrace("Auth Engine. Found AFTER filter %p\n", module->after);
2.29      frystyk   432:        HTRequest_deleteCredentialsAll(request);
                    433:        return (*module->after)(request, response, NULL, status);
2.19      frystyk   434:     }
2.24      frystyk   435:     return HT_ERROR;
2.26      frystyk   436: }
                    437: 
                    438: /*     HTAA_proxybeforeFilter
                    439: **     ----------------------
                    440: **     Make a lookup in the proxy URL tree to find any context for this node,
                    441: **     If no context is found then we assume that we don't know anything about
                    442: **     this URL and hence we don't call any BEFORE filters at all.
                    443: **     Return HT_OK or whatever callback returns
                    444: */
2.29      frystyk   445: PUBLIC int HTAA_proxyBeforeFilter (HTRequest * request, void * param, int mode)
2.26      frystyk   446: {
                    447:     char * url = HTRequest_proxy(request);
                    448: 
2.27      frystyk   449:     /*
                    450:     **  We may not have a proxy - for example if it has been disabled for this
                    451:     **  request or it isn't a proxied access method.
                    452:     */
                    453:     if (url) {
                    454:        const char * realm = HTRequest_realm(request);
                    455:        HTAAElement * element = HTAA_findElement(YES, realm, url); 
                    456: 
                    457:        /* If we have an element then call the before filter with the scheme */
                    458:        if (element) {
                    459:            HTAAModule * module = HTAA_findModule(element->scheme);
                    460:            if (module) {
                    461:                if (AUTH_TRACE)
                    462:                    HTTrace("Auth Engine. Found Proxy BEFORE filter %p with context %p\n",
                    463:                            module->before, element->context);
                    464:                return (*module->before)(request, element->context, HT_NO_PROXY_ACCESS);
                    465:            }
2.26      frystyk   466:        }
                    467:     }
                    468:     return HT_OK;
2.19      frystyk   469: }

Webmaster