Annotation of libwww/Library/src/HTAAUtil.c, revision 2.33
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.32 kahan 7: ** @(#) $Id: HTAAUtil.c,v 1.3 1998/10/08 18:13:49 cvs 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
81: if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
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);
106: if (AUTH_TRACE) HTTrace("Auth Engine. Created module %p\n", pres);
107: } else {
108: if (AUTH_TRACE) HTTrace("Auth Engine. Found module %p\n", pres);
2.19 frystyk 109: }
2.23 frystyk 110: return pres;
111: } else {
112: if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
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);
121: if (AUTH_TRACE)
122: HTTrace("Auth Engine. did %sfind %s\n", pres ? "" : "NOT ",scheme);
123: return pres;
124: } else {
125: if (AUTH_TRACE) HTTrace("Auth Engine. Bad augument\n");
2.19 frystyk 126: }
127: return NULL;
128: }
2.1 luotonen 129:
2.23 frystyk 130: PUBLIC BOOL HTAA_deleteModule (const char * scheme)
2.19 frystyk 131: {
2.23 frystyk 132: if (scheme) {
133: HTAAModule * pres = find_module(scheme);
134: if (pres) {
135: HTList_removeObject(HTSchemes, pres);
136: if (AUTH_TRACE) HTTrace("Auth Engine. deleted %p\n", pres);
137: delete_module(pres);
138: return YES;
139: }
2.1 luotonen 140: }
2.19 frystyk 141: return NO;
2.1 luotonen 142: }
143:
2.23 frystyk 144: PUBLIC BOOL HTAA_deleteAllModules (void)
2.19 frystyk 145: {
2.23 frystyk 146: if (HTSchemes) {
147: HTList * cur = HTSchemes;
148: HTAAModule * pres;
149: while ((pres = (HTAAModule *) HTList_nextObject(cur)))
150: delete_module(pres);
151: HTList_delete(HTSchemes);
152: HTSchemes = NULL;
2.19 frystyk 153: return YES;
154: }
155: return NO;
156: }
2.1 luotonen 157:
2.23 frystyk 158: /* ------------------------------------------------------------------------- */
159: /* HANDLE THE AA URL TREE */
160: /* ------------------------------------------------------------------------- */
161:
2.19 frystyk 162: /*
2.23 frystyk 163: ** A AA element is a particular AA procotol associated with a
164: ** particular point in the URL tree. The scheme is the name of the
165: ** AA protocol known to be able to handle this context. This protocol
166: ** must have been registered as a AA module.
167: */
168: PRIVATE HTAAElement * HTAA_newElement (const char * scheme, void * context)
169: {
170: if (scheme) {
171: HTAAElement * me;
172: if ((me = (HTAAElement *) HT_CALLOC(1, sizeof(HTAAElement))) == NULL)
173: HT_OUTOFMEM("HTAAElement_new");
174: StrAllocCopy(me->scheme, scheme);
175: me->context = context;
176: if (AUTH_TRACE) HTTrace("Auth Engine. Created element %p\n", me);
177: return me;
2.19 frystyk 178: }
179: return NULL;
180: }
2.1 luotonen 181:
2.24 frystyk 182: /*
2.27 frystyk 183: ** If the new context differs from the existing one then use the
184: ** new one, otherwise only override the old context if new
2.24 frystyk 185: ** one differs from NULL
186: */
2.23 frystyk 187: PRIVATE BOOL HTAA_updateElement (HTAAElement * element,
188: const char * scheme, void * context)
2.19 frystyk 189: {
2.23 frystyk 190: if (element && scheme) {
2.24 frystyk 191: /*
2.27 frystyk 192: ** If the old context differs from the new one then
193: ** call the gc provided by the caller
2.24 frystyk 194: */
2.27 frystyk 195: if (context && context != element->context) {
2.24 frystyk 196: HTAAModule * module = HTAA_findModule(element->scheme);
197: if (module && module->gc && element->context)
198: (*module->gc)(element->context);
199: /*
200: ** Insert the new scheme
201: */
202: StrAllocCopy(element->scheme, scheme);
203: element->context = context;
2.27 frystyk 204: }
2.23 frystyk 205: return YES;
2.19 frystyk 206: }
207: return NO;
208: }
2.1 luotonen 209:
2.23 frystyk 210: PRIVATE int HTAA_deleteElement (void * context)
2.19 frystyk 211: {
2.23 frystyk 212: HTAAElement * me = (HTAAElement *) context;
213: if (me) {
214: HTAAModule * module = HTAA_findModule(me->scheme);
2.1 luotonen 215:
2.23 frystyk 216: /* If module then call the gc of the Authentication Module */
217: if (module && module->gc && me->context)
218: (*module->gc)(me->context);
2.1 luotonen 219:
2.23 frystyk 220: if (AUTH_TRACE) HTTrace("Auth Engine. Deleted element %p\n", me);
221: HT_FREE(me->scheme);
222: HT_FREE(me);
2.19 frystyk 223: return YES;
224: }
225: return NO;
226: }
2.1 luotonen 227:
228: /*
2.23 frystyk 229: ** Find AA Element
230: ** ---------------
231: ** Seaches the set of authentication information bases for a match
232: ** In order to find an anode we do the following:
233: **
234: ** 1) Find the right auth base
235: ** 2) See if there is a realm match
236: ** 3) See if there is a template match for URL
237: **
238: ** Return the node found else NULL which means that we don't have any
239: ** authentication information to hook on to this request or response
2.1 luotonen 240: */
2.26 frystyk 241: PRIVATE HTAAElement * HTAA_findElement (BOOL proxy_access,
242: const char * realm, const char * url)
2.19 frystyk 243: {
2.23 frystyk 244: HTUTree * tree;
245: if (!url) {
246: if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
247: return NULL;
2.19 frystyk 248: }
2.23 frystyk 249: if (AUTH_TRACE) HTTrace("Auth Engine. Looking up `%s'\n", url);
2.19 frystyk 250:
2.23 frystyk 251: /* Find an existing URL Tree for this URL (if any) */
2.19 frystyk 252: {
253: char * host = HTParse(url, "", PARSE_HOST);
254: char * colon = strchr(host, ':');
2.23 frystyk 255: int port = DEFAULT_PORT;
2.19 frystyk 256: if (colon ) {
257: *(colon++) = '\0'; /* Chop off port number */
258: port = atoi(colon);
2.23 frystyk 259: }
2.26 frystyk 260: tree = HTUTree_find(proxy_access ? AA_PROXY_TREE : AA_TREE, host,port);
2.23 frystyk 261: HT_FREE(host);
262: if (!tree) {
263: if (AUTH_TRACE) HTTrace("Auth Engine. No information\n");
264: return NULL;
2.19 frystyk 265: }
266: }
2.1 luotonen 267:
2.23 frystyk 268: /* Find a matching AA element (if any) */
2.19 frystyk 269: {
2.28 frystyk 270: char * path = HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION);
2.23 frystyk 271: HTAAElement *element = (HTAAElement*)HTUTree_findNode(tree,realm,path);
272: HT_FREE(path);
273: return element;
2.19 frystyk 274: }
2.23 frystyk 275: return NULL;
2.19 frystyk 276: }
277:
2.23 frystyk 278: /* Add a AA context to the URL tree
279: ** --------------------------------
280: ** Each node in the AA URL tree is a list of the modules we must call
281: ** for this particular node.
282: */
2.26 frystyk 283: PUBLIC void * HTAA_updateNode (BOOL proxy_access, char const * scheme,
2.24 frystyk 284: const char * realm, const char * url,
285: void * context)
2.23 frystyk 286: {
287: HTUTree * tree = NULL;
288: HTAAModule * module = NULL;
289: if (!scheme || !url) {
290: if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
2.24 frystyk 291: return NULL;
2.23 frystyk 292: }
293: if (AUTH_TRACE) HTTrace("Auth Engine. Adding info for `%s'\n", url);
294:
295: /* Find the AA module with this name */
296: if ((module = HTAA_findModule(scheme)) == NULL) {
297: if (AUTH_TRACE) HTTrace("Auth Engine. Module `%s\' not registered\n",
298: scheme ? scheme : "<null>");
2.24 frystyk 299: return NULL;
2.19 frystyk 300: }
301:
2.23 frystyk 302: /* Find an existing URL Tree or create a new one */
2.19 frystyk 303: {
304: char * host = HTParse(url, "", PARSE_HOST);
305: char * colon = strchr(host, ':');
2.23 frystyk 306: int port = DEFAULT_PORT;
2.19 frystyk 307: if (colon ) {
308: *(colon++) = '\0'; /* Chop off port number */
309: port = atoi(colon);
2.23 frystyk 310: }
2.26 frystyk 311: tree = HTUTree_new(proxy_access ? AA_PROXY_TREE : AA_TREE,
312: host, port, HTAA_deleteElement);
2.19 frystyk 313: HT_FREE(host);
2.23 frystyk 314: if (!tree) {
315: if (AUTH_TRACE) HTTrace("Auth Engine. Can't create tree\n");
2.24 frystyk 316: return NULL;
2.19 frystyk 317: }
318: }
319:
2.23 frystyk 320: /* Find a matching AA element or create a new one */
2.19 frystyk 321: {
2.28 frystyk 322: char * path = HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION);
2.23 frystyk 323: HTAAElement * element = NULL;
324: BOOL status;
325: if ((element = (HTAAElement *) HTUTree_findNode(tree, realm, path)))
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) {
348: if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
349: return NO;
350: }
351: if (AUTH_TRACE) HTTrace("Auth Engine. Deleting info for `%s'\n", url);
352:
353: /* Find the AA module with this name */
354: if ((module = HTAA_findModule(scheme)) == NULL) {
355: if (AUTH_TRACE) HTTrace("Auth Engine. Module `%s\' not registered\n",
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) {
373: if (AUTH_TRACE) HTTrace("Auth Engine. Can't create tree\n");
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) {
409: if (AUTH_TRACE) HTTrace("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.27 frystyk 427: if (AUTH_TRACE) HTTrace("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.23 frystyk 437: if (AUTH_TRACE)
2.33 ! kahan 438: HTTrace("Auth Engine. Found AFTER filter %p\n", module->after);
2.29 frystyk 439: HTRequest_deleteCredentialsAll(request);
2.32 kahan 440: HTRequest_addAARetry (request);
2.29 frystyk 441: return (*module->after)(request, response, NULL, status);
2.19 frystyk 442: }
2.24 frystyk 443: return HT_ERROR;
2.26 frystyk 444: }
2.33 ! kahan 445:
! 446: /* HTAA_UpdateFilter
! 447: ** -----------------
! 448: ** Call the Update filter that knows how to handle this scheme.
! 449: ** Return YES or whatever callback returns
! 450: */
! 451: PUBLIC int HTAA_updateFilter (HTRequest * request, HTResponse * response,
! 452: void * param, int status)
! 453: {
! 454: const char * scheme = HTResponse_scheme(response);
! 455: HTAAModule * module = NULL;
! 456: if (AUTH_TRACE) HTTrace("Auth Engine. Update filter status %d\n", status);
! 457: /*
! 458: ** If we don't have a scheme then the server has made an error. We
! 459: ** try to make up for it by creating our own "noop" realm and use basic.
! 460: */
! 461: if (!scheme) {
! 462: HTResponse_addChallenge(response, "basic", "realm LIBWWW-UNKNOWN");
! 463: scheme = "basic";
! 464: }
! 465: if ((module = HTAA_findModule(scheme)) != NULL) {
! 466: /* we don't call this module systematically, as it could hamper
! 467: the execution of Basic authentication requests for nothing */
! 468: if (module->update) {
! 469: if (AUTH_TRACE)
! 470: HTTrace("Auth Engine. Found Update filter %p\n", module->update);
! 471: HTRequest_deleteCredentialsAll(request);
! 472: return (*module->update)(request, response, NULL, status);
! 473: }
! 474: return HT_OK;
! 475: }
! 476: return HT_ERROR;
! 477: }
! 478:
2.26 frystyk 479:
480: /* HTAA_proxybeforeFilter
481: ** ----------------------
482: ** Make a lookup in the proxy URL tree to find any context for this node,
483: ** If no context is found then we assume that we don't know anything about
484: ** this URL and hence we don't call any BEFORE filters at all.
485: ** Return HT_OK or whatever callback returns
486: */
2.29 frystyk 487: PUBLIC int HTAA_proxyBeforeFilter (HTRequest * request, void * param, int mode)
2.26 frystyk 488: {
489: char * url = HTRequest_proxy(request);
490:
2.27 frystyk 491: /*
492: ** We may not have a proxy - for example if it has been disabled for this
493: ** request or it isn't a proxied access method.
494: */
495: if (url) {
496: const char * realm = HTRequest_realm(request);
497: HTAAElement * element = HTAA_findElement(YES, realm, url);
498:
499: /* If we have an element then call the before filter with the scheme */
500: if (element) {
501: HTAAModule * module = HTAA_findModule(element->scheme);
502: if (module) {
503: if (AUTH_TRACE)
504: HTTrace("Auth Engine. Found Proxy BEFORE filter %p with context %p\n",
505: module->before, element->context);
506: return (*module->before)(request, element->context, HT_NO_PROXY_ACCESS);
507: }
2.26 frystyk 508: }
509: }
510: return HT_OK;
2.19 frystyk 511: }
Webmaster