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