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

2.9       frystyk     1: /*                                                                  HTAAUtil.c
                      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.22    ! frystyk     7: **     @(#) $Id: HTAAUtil.c,v 2.21 1996/04/12 17:45:27 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.20      frystyk    31: #include "sysdep.h"
2.1       luotonen   32: #include "HTUtils.h"
2.11      frystyk    33: #include "HTString.h"
2.19      frystyk    34: #include "HTParse.h"
                     35: #include "HTReqMan.h"
                     36: #include "HTAssoc.h"
                     37: #include "HTAAUtil.h"                                   /* Implemented here */
                     38: 
                     39: typedef struct _HTAuthScheme {
                     40:     char *             scheme;
                     41:     HTAuthParCallback *        parser;
                     42:     HTAuthGenCallback *        generator;
                     43:     HTAuthGcCallback * gc;
                     44: } HTAuthScheme;
                     45: 
                     46: PRIVATE HTList * HTSchemes;    /* List of registered authentication schemes */
                     47: 
                     48: typedef struct _HTABase {                /* Server Authentication info base */
                     49:     char *     host;
                     50:     int                port;
                     51:     HTList *   templates;                /* List of templates for this base */
                     52:     HTList *   nodes;                        /* List of nodes for this base */
                     53: } HTABase;
                     54: 
                     55: typedef struct _HTANode {                /* Authentication scheme specifics */
                     56:     char *     realm;
                     57:     char *     scheme;
                     58:     void *     data;
                     59: } HTANode;
                     60: 
                     61: typedef struct _HTATemplate {                   /* Hierarchical information */
                     62:     char *     tmplate;
                     63:     HTANode *  node;
                     64: } HTATemplate;
                     65: 
                     66: PRIVATE HTList * AuthBases = NULL;           /* Current authentication base */
                     67: 
                     68: /* ------------------------------------------------------------------------- */
                     69: /*                          AUTHENTICATION SCHEMES                          */
                     70: /* ------------------------------------------------------------------------- */
                     71: 
                     72: /*     HTAuthCall_add
                     73: **     --------------
                     74: **     Register a callback functions that is to be called when we want to
                     75: **     parse challenges and to generate credentials - or the other way round.
                     76: **     If you are a server then you want to do the latter and if you are a 
                     77: **     client then you want to do the former.
                     78: */
2.20      frystyk    79: PUBLIC BOOL HTAuthCall_add (const char *       scheme,
2.19      frystyk    80:                            HTAuthParCallback * parser,
                     81:                            HTAuthGenCallback * generator,
                     82:                            HTAuthGcCallback *  gc)
                     83: {
                     84:     if (scheme && parser && generator && gc) {
                     85:        HTAuthScheme * me;
                     86:        if (AUTH_TRACE)
                     87:            HTTrace("Auth add.... %s with parser %p and generator %p\n",
                     88:                    scheme, (void *) parser, (void *) generator);
                     89:        if ((me = (HTAuthScheme *) HT_CALLOC(1, sizeof(HTAuthScheme))) == NULL)
                     90:            HT_OUTOFMEM("HTAuthCall_add");
                     91:        StrAllocCopy(me->scheme, scheme);
                     92:        me->parser = parser;
                     93:        me->generator = generator;
                     94:        me->gc = gc;
                     95:        if (!HTSchemes) HTSchemes = HTList_new();       
                     96:        return HTList_addObject(HTSchemes, (void *) me);
                     97:     }
                     98:     return NO;
                     99: }
2.1       luotonen  100: 
2.19      frystyk   101: /*     HTAuthCall_delete
                    102: **     -------------------
                    103: **     Unregister a authentication scheme from the list
                    104: **     Return YES if OK, else NO
                    105: */
2.20      frystyk   106: PUBLIC BOOL HTAuthCall_delete (const char * scheme)
2.19      frystyk   107: {
                    108:     HTList * cur = HTSchemes;
                    109:     if (scheme && cur) {
                    110:        HTAuthScheme * pres;
                    111:        while ((pres = (HTAuthScheme *) HTList_nextObject(cur))) {
                    112:            if (!strcmp(scheme, pres->scheme)) {
                    113:                HTList_removeObject(HTSchemes, (void *) pres);
                    114:                HT_FREE(pres->scheme);
                    115:                HT_FREE(pres);
                    116:                return YES;
                    117:            }
                    118:        }
                    119:     }
                    120:     return NO;
                    121: }
2.1       luotonen  122: 
2.19      frystyk   123: /*     HTAuthCall_deleteAll
                    124: **     ----------------------
                    125: **     Unregisters all call back functions
                    126: **     Returns YES if OK, else NO
2.1       luotonen  127: */
2.19      frystyk   128: PUBLIC BOOL HTAuthCall_deleteAll (void)
2.1       luotonen  129: {
2.19      frystyk   130:     HTList * cur = HTSchemes;
                    131:     if (AUTH_TRACE) HTTrace("Auth delete. all schemes\n");
                    132:     if (cur) {
                    133:        HTAuthScheme * pres;
                    134:        while ((pres = (HTAuthScheme *) HTList_nextObject(cur))) {
                    135:            HT_FREE(pres->scheme);
                    136:            HT_FREE(pres);
                    137:        }
                    138:        HTList_delete(HTSchemes);
                    139:        HTSchemes = NULL;
                    140:        return YES;
                    141:     }
                    142:     return NO;
                    143: }
2.1       luotonen  144: 
2.19      frystyk   145: /* ------------------------------------------------------------------------- */
                    146: /*                    AUTHENTICATION INFORMATION DATA BASE                  */
                    147: /* ------------------------------------------------------------------------- */
                    148: 
                    149: /*     This module maintains an authentication information database
                    150: **     which contains informations for generate either credentials or
                    151: **     challenges. The database is symmetric for both server and client
                    152: **     applications and the implementation can be changed independent of the 
2.22    ! frystyk   153: **     API so if you fell like using a fancy database toolkit then feel free
2.19      frystyk   154: **     to go right ahead :-)
                    155: */
                    156: 
                    157: /*
                    158: **     Create a new anode
                    159: **     Returns new object or NULL if error
                    160: */
2.20      frystyk   161: PRIVATE HTANode * HTANode_new (HTABase * base, const char * realm,
                    162:                               const char * scheme, void * data)
2.19      frystyk   163: {
                    164:     if (base && realm && scheme) {
                    165:        HTANode * me;
                    166:        if ((me = (HTANode *) HT_CALLOC(1, sizeof(HTANode))) == NULL)
                    167:            HT_OUTOFMEM("HTANode_new");
                    168:        StrAllocCopy(me->realm, realm);
                    169:        StrAllocCopy(me->scheme, scheme);
                    170:        me->data = data;
                    171:        HTList_addObject(base->nodes, (void *) me);
                    172:        return me;
                    173:     }
                    174:     return NULL;
                    175: }
2.1       luotonen  176: 
2.19      frystyk   177: /*
                    178: **     Delete a node. We call the scheme gc callback to handle the opaque
                    179: **     data object.
                    180: */
                    181: PRIVATE BOOL HTANode_delete (HTABase * base, HTANode * me)
                    182: {
                    183:     if (base && me) {
                    184:        HTAuth_cleanup(me->scheme, me->data);
                    185:        HT_FREE(me->realm);
                    186:        HT_FREE(me->scheme);
                    187:        HTList_removeObject(base->nodes, (void *) me);
                    188:        HT_FREE(me);
                    189:        return YES;
2.1       luotonen  190:     }
2.19      frystyk   191:     return NO;
2.1       luotonen  192: }
                    193: 
2.19      frystyk   194: /*
                    195: **     Search an authentication base for a matching anode.
                    196: **     Return the anode object found or NULL if none
                    197: */
2.20      frystyk   198: PRIVATE HTANode * HTANode_find (HTABase * base, const char * realm)
2.19      frystyk   199: {    
                    200:     if (base && base->nodes && realm) {
                    201:        HTList * cur = base->nodes;
                    202:        HTANode * pres;
                    203:        while ((pres = (HTANode *) HTList_nextObject(cur))) {
                    204:            if (!strcmp(pres->realm, realm)) return pres;
                    205:        }
                    206:     }
                    207:     return NULL;
                    208: }
2.1       luotonen  209: 
2.19      frystyk   210: /*
                    211: **     Create a new template and add to authentication base
                    212: **     Returns new object or NULL if error
                    213: */
                    214: PRIVATE HTATemplate * HTATemplate_new (HTABase * base, char * tmplate,
                    215:                                       HTANode * node)
                    216: {
                    217:     if (base && tmplate && node) {
                    218:        HTATemplate * me;
                    219:        if ((me = (HTATemplate *) HT_CALLOC(1, sizeof(HTATemplate))) == NULL)
                    220:            HT_OUTOFMEM("HTATemplate_new");
                    221:        me->node = node;
                    222:        me->tmplate = tmplate;
                    223:        HTList_addObject(base->templates, (void *) me);
                    224:        return me;
2.1       luotonen  225:     }
2.19      frystyk   226:     return NULL;
2.1       luotonen  227: }
                    228: 
2.19      frystyk   229: /*
                    230: **     Delete a template
                    231: */
                    232: PRIVATE BOOL HTATemplate_delete (HTABase * base, HTATemplate * me)
                    233: {
                    234:     if (base && me) {
                    235:        HT_FREE(me->tmplate);
                    236:        HTList_removeObject(base->templates, (void *) me);
                    237:        HT_FREE(me);
                    238:        return YES;
                    239:     }
                    240:     return NO;
                    241: }
2.1       luotonen  242: 
2.19      frystyk   243: /*
                    244: **     Search an authentication base for a matching template.
                    245: **     Return the template object found or NULL if none
                    246: */
2.20      frystyk   247: PRIVATE HTATemplate * HTATemplate_find (HTABase * base, const char *docname)
2.19      frystyk   248: {
                    249:     if (base && base->templates && docname) {
                    250:        HTList * cur = base->templates;
                    251:        HTATemplate * pres;
                    252:        while ((pres = (HTATemplate *) HTList_nextObject(cur))) {
                    253:            if (HTStrMatch(pres->tmplate, docname)) {
                    254:                if (AUTH_TRACE)
                    255:                    HTTrace("Template.... `%s' matched `%s'\n",
                    256:                            docname, pres->tmplate);
                    257:                return pres;
                    258:            }
                    259:        }
                    260:     }
                    261:     return NULL;
                    262: }
2.1       luotonen  263: 
2.19      frystyk   264: /*
                    265: **     Search an authentication base for a HTATemplate object in order to
                    266: **     update it with a new HTANode. We do this whenever we replace a anode
                    267: **     Return YES if OK, else NO
                    268: */
                    269: PRIVATE BOOL HTATemplate_update (HTABase * base, HTANode * old, HTANode *me)
                    270: {
                    271:     if (base && old && me) {
                    272:        HTList * cur = base->templates;
                    273:        HTATemplate * pres;
                    274:        while ((pres = (HTATemplate *) HTList_nextObject(cur))) {
                    275:            if (pres->node == old) {
                    276:                pres->node = me;
                    277:                if (AUTH_TRACE) HTTrace("Template.... updating %p\n", pres);
                    278:                return YES;
                    279:            }
                    280:        }
                    281:     }
                    282:     return NO;
                    283: }
2.1       luotonen  284: 
2.19      frystyk   285: /*
                    286: **     Create a new authentication base
                    287: **     Returns new object or NULL if error
                    288: */
2.20      frystyk   289: PRIVATE HTABase * HTABase_new (const char * host, int port)
2.19      frystyk   290: {
                    291:     if (host) {
                    292:        HTABase * me;
                    293:        if ((me = (HTABase *) HT_CALLOC(1, sizeof(HTABase))) == NULL)
                    294:            HT_OUTOFMEM("HTABase_new");
                    295:        StrAllocCopy(me->host, host);
                    296:        me->port = (port > 0 ? port : 80);
                    297:        me->templates = HTList_new();
                    298:        me->nodes = HTList_new();
                    299:        HTList_addObject(AuthBases, (void *) me);
                    300:        if (AUTH_TRACE) HTTrace("Auth Base... %p created\n", me);
                    301:        return me;
                    302:     }
                    303:     return NULL;
2.1       luotonen  304: }
                    305: 
2.19      frystyk   306: /*
                    307: **     Delete a complete server tree and everything within it.
                    308: */
                    309: PRIVATE BOOL HTABase_delete (HTABase * base)
                    310: {
                    311:     if (base) {
                    312:        HTList * cur;
                    313: 
                    314:        /* Free all templates */
                    315:        if ((cur = base->templates)) {
                    316:            HTATemplate * pres;
                    317:            while ((pres = (HTATemplate *) HTList_lastObject(cur)))
                    318:                HTATemplate_delete(base, pres);
                    319:            HTList_delete(base->templates);
                    320:        }
2.1       luotonen  321: 
2.19      frystyk   322:        /* Free all nodes */
                    323:        if ((cur = base->nodes)) {
                    324:            HTANode * pres;
                    325:            while ((pres = (HTANode *) HTList_lastObject(cur)))
                    326:                HTANode_delete(base, pres);
                    327:            HTList_delete(base->nodes);     
                    328:        }
2.1       luotonen  329: 
2.19      frystyk   330:        HT_FREE(base->host);
                    331:        HT_FREE(base);
                    332:        return YES;
                    333:     }
                    334:     return NO;
                    335: }
2.1       luotonen  336: 
                    337: /*
2.19      frystyk   338: **     Find a authentication base. Return NULL if not found
2.1       luotonen  339: */
2.20      frystyk   340: PRIVATE HTABase * HTABase_find (const char * host, int port)
2.19      frystyk   341: {
                    342:     HTList * cur = AuthBases;
                    343:     if (port <= 0) port = 80;
                    344:     if (host && cur) {
                    345:        HTABase * pres;
                    346:        while ((pres = (HTABase *) HTList_nextObject(cur))) {
                    347:            if (pres->port==port && !strcmp(pres->host, host)) return pres;
                    348:        }
                    349:     }
                    350:     return NULL;
                    351: }
2.1       luotonen  352: 
2.19      frystyk   353: /* ------------------------------------------------------------------------- */
                    354: /*                HANDLING THE AUTHENTICATION INFORMATION BASE              */
                    355: /* ------------------------------------------------------------------------- */
                    356: 
                    357: /*     HTAuthInfo_add
                    358: **     --------------
                    359: **     Add an access authentication information node to the database. If
                    360: **     the entry is already found then it is replaced with the new one.
                    361: **     The template must follow normal URI syntax but can include a wildcard
                    362: **     Return YES if added (or replaced), else NO
2.1       luotonen  363: */
2.20      frystyk   364: PUBLIC BOOL HTAuthInfo_add (const char * scheme, char * url,
2.19      frystyk   365:                            char * realm, void * data)
                    366: {
                    367:     HTABase * base;
                    368:     HTANode * anode;
                    369:     if (!scheme || !url || !realm || !data) return NO;
                    370:     if (AUTH_TRACE) HTTrace("Auth base... adding info for `%s'\n", url);
                    371:     if (!AuthBases) AuthBases = HTList_new();
                    372: 
                    373:     /* Find an existing authentication base or create new */
                    374:     {
                    375:        char * host = HTParse(url, "", PARSE_HOST);
                    376:        char * colon = strchr(host, ':');
                    377:        int port = 80;
                    378:        if (colon ) {
                    379:            *(colon++) = '\0';                       /* Chop off port number */
                    380:            port = atoi(colon);
                    381:        }
                    382:        if ((base = HTABase_find(host, port)) == NULL)
                    383:            base = HTABase_new(host, port);
                    384:        HT_FREE(host);
                    385:        if (!base) return NO;                  /* Couldn't create a new base */
                    386:     }
2.1       luotonen  387: 
2.19      frystyk   388:     /*
                    389:     ** Find a matching anode or create a new one. If we find an existing one
                    390:     ** we also update the template pointing to the anode. Otherwise we create
                    391:     ** a new template as well.
                    392:     */
                    393:     {
                    394:        HTANode * old = HTANode_find(base, realm);
                    395:        anode = HTANode_new(base, realm, scheme, data);
                    396:        if (old) {
                    397:            HTATemplate_update(base, old, anode);
                    398:            HTANode_delete(base, old);
                    399:        } else {
                    400:            char * docname = HTParse(url, "", PARSE_PATH);
                    401:            HTATemplate_new(base, docname, anode);
                    402:        }
                    403:     }
                    404:     return anode ? YES : NO;
                    405: }
                    406: 
                    407: /*     HTAuthInfo_deleteAll
                    408: **     --------------------
                    409: **     Remove the Database
                    410: */
                    411: PUBLIC BOOL HTAuthInfo_deleteAll (void)
                    412: {
                    413:     if (AuthBases) {
                    414:        HTList * cur = AuthBases;
                    415:        HTABase * pres;
                    416:        while ((pres = (HTABase *) HTList_nextObject(cur)))
                    417:            HTABase_delete(pres);
                    418:        HTList_delete(AuthBases);
                    419:        AuthBases = NULL;
                    420:        return YES;
                    421:     }
                    422:     return NO;
                    423: }
2.1       luotonen  424: 
2.19      frystyk   425: /*     AuthInfo_find
                    426: **     -------------
                    427: **     Seaches the set of authentication information bases for a match
                    428: **     In order to find an anode we do the following:
                    429: **
                    430: **             1) Find the right auth base
                    431: **             2) See if there is a realm match
                    432: **             3) See if there is a template match for URL
2.1       luotonen  433: **
2.19      frystyk   434: **     Return the node found else NULL which means that we don't have any
                    435: **     authentication information to hook on to this request or response
                    436: */
                    437: PRIVATE HTANode * HTAuthInfo_find (char * url, char * realm)
                    438: {
                    439:     HTABase * base;
                    440:     HTATemplate * tmplate;
                    441:     HTANode * anode;
                    442:     if (AUTH_TRACE)
                    443:        HTTrace("Auth base... looking for info on `%s'\n", url);
                    444: 
                    445:     /* Find an existing authentication base */
                    446:     {
                    447:        char * host = HTParse(url, "", PARSE_HOST);
                    448:        char * colon = strchr(host, ':');
                    449:        int port = 80;
                    450:        if (colon ) {
                    451:            *(colon++) = '\0';                       /* Chop off port number */
                    452:            port = atoi(colon);
                    453:        }       
                    454:        base = HTABase_find(host, port);
                    455:        HT_FREE(host);
                    456:        if (base == NULL) return NULL;                     /* Base not found */
                    457:     }
                    458: 
                    459:     /* Do we have a realm to look for? */
                    460:     if (realm) {
                    461:        if ((anode = HTANode_find(base, realm)) != NULL) {
                    462:            if (AUTH_TRACE)
                    463:                HTTrace("Auth info... found matching realm `%s\'\n", realm);
                    464:            return anode;
                    465:        }
                    466:     }
                    467: 
                    468:     /* If no realm or realm not found then look for template */
                    469:     {
                    470:        char * docname = HTParse(url, "", PARSE_PATH);
                    471:        if ((tmplate = HTATemplate_find(base, docname)) != NULL)
                    472:            anode = tmplate->node;
                    473:        HT_FREE(docname);
                    474:        return anode;
                    475:     }
                    476:     return NULL;                                                /* No match */
                    477: }
                    478: 
                    479: /* ------------------------------------------------------------------------- */
                    480: /*                PARSE AND GENERATE CHELLENGES AND CREDENTIALS             */
                    481: /* ------------------------------------------------------------------------- */
                    482: 
                    483: /*     HTAuth_parse
                    484: **     ------------
                    485: **     This function looks for a authentication scheme that matches what we
                    486: **     have in the request object and calls the parser callback function.
                    487: **     Case is not significant.
                    488: **     Return YES or whatever callback returns
                    489: */
                    490: PUBLIC BOOL HTAuth_parse (HTRequest * request)
                    491: {
                    492:     HTList * cur = HTSchemes;
                    493:     if (request && request->scheme && request->challenge && cur) {
                    494:        HTAuthScheme * pres;
                    495:        while ((pres = (HTAuthScheme *) HTList_nextObject(cur))) {
                    496:            if (!strcasecomp(request->scheme, pres->scheme)) {
                    497:                if (AUTH_TRACE)
                    498:                    HTTrace("Auth Calling Parser %p\n", pres->parser);
                    499:                return (*(pres->parser))(request, pres->scheme);
2.1       luotonen  500:            }
2.19      frystyk   501:        }
                    502:     }
                    503:     if (AUTH_TRACE)HTTrace("Auth Parse.. No challenge or credentials found\n");
                    504:     return YES;
                    505: }
                    506: 
                    507: /*     HTAuth_generate
                    508: **     ---------------
                    509: **     This function looks for a any authentication scheme that protects 
                    510: **     this resource and calls the generator callback in order to make a
                    511: **     challenge or setup credentials depending on whether we are a server
                    512: **     or a client.
                    513: **     Return YES or whatever callback returns
                    514: */
                    515: PUBLIC BOOL HTAuth_generate (HTRequest * request)
                    516: {
                    517:     HTList * cur = HTSchemes;
                    518:     if (request && cur) {
                    519:        char * url = HTAnchor_physical(request->anchor);
                    520:        HTANode * node = HTAuthInfo_find(url, request->realm);
                    521:        if (node && node->data) {
                    522:            HTAuthScheme * pres;
                    523:            while ((pres = (HTAuthScheme *) HTList_nextObject(cur))) {
                    524:                if (!strcasecomp(node->scheme, pres->scheme)) {
                    525:                    if (AUTH_TRACE)
                    526:                        HTTrace("Auth Calling Generator %p\n",pres->generator);
                    527:                    return (*(pres->generator))(request, node->scheme,
                    528:                                                node->realm, node->data);
                    529:                }
2.1       luotonen  530:            }
                    531:        }
2.19      frystyk   532:     }
                    533:     if (AUTH_TRACE)HTTrace("Auth Gen.... No challenge or credentials found\n");
                    534:     return YES;
2.1       luotonen  535: }
2.6       frystyk   536: 
2.19      frystyk   537: /*     HTAuth_cleanup
                    538: **     --------------
                    539: **     This function looks for a authentication scheme that matches what we
                    540: **     have in the request object and calls the cleanup callback function.
                    541: **     Case is not significant. If the scheme is not registered then
                    542: **     Return YES if callback found else NO
                    543: */
2.20      frystyk   544: PUBLIC BOOL HTAuth_cleanup (const char * scheme, void * data)
2.19      frystyk   545: {
                    546:     HTList * cur = HTSchemes;
                    547:     if (scheme && cur && data) {
                    548:        HTAuthScheme * pres;
                    549:        while ((pres = (HTAuthScheme *) HTList_nextObject(cur))) {
                    550:            if (!strcasecomp(scheme, pres->scheme)) {
                    551:                if (AUTH_TRACE) HTTrace("Auth Calling gc %p\n", pres->gc);
                    552:                (*(pres->gc))(scheme, data);
                    553:                return YES;
                    554:            }
                    555:        }
                    556:     }
                    557:     return NO;
                    558: }
2.1       luotonen  559: 

Webmaster