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