Annotation of libwww/Library/src/HTAAUtil.c, revision 2.34
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.34 ! kahan 7: ** @(#) $Id: HTAAUtil.c,v 2.33 1999/01/27 08:52:02 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
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;
2.34 ! kahan 325: if ((element = (HTAAElement *) HTUTree_findNode(tree, realm, path))
! 326: && element->scheme && !strcasecomp (element->scheme, scheme))
2.23 frystyk 327: status = HTAA_updateElement(element, scheme, context);
328: else {
2.32 kahan 329: /* create the new element */
330: element = HTAA_newElement(scheme, context);
331: status = HTUTree_addNode(tree, realm, path, element);
2.23 frystyk 332: }
333: HT_FREE(path);
2.24 frystyk 334: return status==YES ? element->context : NULL;
2.31 frystyk 335: }
336: }
337:
338: /* Delete a AA context from the URL tree
339: ** -------------------------------------
340: ** Each node in the AA URL tree is a list of the modules we must call
341: ** for this particular node.
342: */
343: PUBLIC BOOL HTAA_deleteNode (BOOL proxy_access, char const * scheme,
344: const char * realm, const char * url)
345: {
346: HTUTree * tree = NULL;
347: HTAAModule * module = NULL;
348: if (!scheme || !url) {
349: if (AUTH_TRACE) HTTrace("Auth Engine. Bad argument\n");
350: return NO;
351: }
352: if (AUTH_TRACE) HTTrace("Auth Engine. Deleting info for `%s'\n", url);
353:
354: /* Find the AA module with this name */
355: if ((module = HTAA_findModule(scheme)) == NULL) {
356: if (AUTH_TRACE) HTTrace("Auth Engine. Module `%s\' not registered\n",
357: scheme ? scheme : "<null>");
358: return NO;
359: }
360:
361: /* Find an existing URL Tree or create a new one */
362: {
363: char * host = HTParse(url, "", PARSE_HOST);
364: char * colon = strchr(host, ':');
365: int port = DEFAULT_PORT;
366: if (colon ) {
367: *(colon++) = '\0'; /* Chop off port number */
368: port = atoi(colon);
369: }
370: tree = HTUTree_new(proxy_access ? AA_PROXY_TREE : AA_TREE,
371: host, port, HTAA_deleteElement);
372: HT_FREE(host);
373: if (!tree) {
374: if (AUTH_TRACE) HTTrace("Auth Engine. Can't create tree\n");
375: return NO;
376: }
377: }
378:
379: /* Delete any existing node */
380: {
381: char * path = HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION);
382: BOOL status = HTUTree_deleteNode(tree, realm, path);
383: HT_FREE(path);
384: return status;
2.19 frystyk 385: }
386: }
387:
388: /* ------------------------------------------------------------------------- */
2.23 frystyk 389: /* AUTHENTICATION ENGINE */
2.19 frystyk 390: /* ------------------------------------------------------------------------- */
391:
2.23 frystyk 392: /* HTAA_beforeFilter
393: ** ------------------
2.24 frystyk 394: ** Make a lookup in the URL tree to find any context for this node,
395: ** If no context is found then we assume that we don't know anything about
396: ** this URL and hence we don't call any BEFORE filters at all.
2.23 frystyk 397: ** Return HT_OK or whatever callback returns
2.19 frystyk 398: */
2.29 frystyk 399: PUBLIC int HTAA_beforeFilter (HTRequest * request, void * param, int mode)
2.19 frystyk 400: {
2.25 frystyk 401: char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
2.23 frystyk 402: const char * realm = HTRequest_realm(request);
2.26 frystyk 403: HTAAElement * element = HTAA_findElement(NO, realm, url);
2.25 frystyk 404: HT_FREE(url);
2.23 frystyk 405:
2.26 frystyk 406: /* If we have an element then call the before filter with this scheme */
2.23 frystyk 407: if (element) {
408: HTAAModule * module = HTAA_findModule(element->scheme);
409: if (module) {
410: if (AUTH_TRACE) HTTrace("Auth Engine. Found BEFORE filter %p\n",
2.29 frystyk 411: module->before);
412: return (*module->before)(request, element->context, mode);
2.19 frystyk 413: }
414: }
2.23 frystyk 415: return HT_OK;
2.19 frystyk 416: }
417:
2.23 frystyk 418: /* HTAA_afterFilter
419: ** -----------------
2.24 frystyk 420: ** Call the AFTER filter that knows how to handle this scheme.
2.19 frystyk 421: ** Return YES or whatever callback returns
422: */
2.29 frystyk 423: PUBLIC int HTAA_afterFilter (HTRequest * request, HTResponse * response,
424: void * param, int status)
2.19 frystyk 425: {
2.29 frystyk 426: const char * scheme = HTResponse_scheme(response);
2.24 frystyk 427: HTAAModule * module = NULL;
2.27 frystyk 428: if (AUTH_TRACE) HTTrace("Auth Engine. After filter status %d\n", status);
2.24 frystyk 429: /*
430: ** If we don't have a scheme then the server has made an error. We
431: ** try to make up for it by creating our own "noop" realm and use basic.
432: */
433: if (!scheme) {
2.29 frystyk 434: HTResponse_addChallenge(response, "basic", "realm LIBWWW-UNKNOWN");
2.24 frystyk 435: scheme = "basic";
436: }
437: if ((module = HTAA_findModule(scheme)) != NULL) {
2.23 frystyk 438: if (AUTH_TRACE)
2.33 kahan 439: HTTrace("Auth Engine. Found AFTER filter %p\n", module->after);
2.29 frystyk 440: HTRequest_deleteCredentialsAll(request);
2.32 kahan 441: HTRequest_addAARetry (request);
2.29 frystyk 442: return (*module->after)(request, response, NULL, status);
2.19 frystyk 443: }
2.24 frystyk 444: return HT_ERROR;
2.26 frystyk 445: }
2.33 kahan 446:
447: /* HTAA_UpdateFilter
448: ** -----------------
449: ** Call the Update filter that knows how to handle this scheme.
450: ** Return YES or whatever callback returns
451: */
452: PUBLIC int HTAA_updateFilter (HTRequest * request, HTResponse * response,
453: void * param, int status)
454: {
455: const char * scheme = HTResponse_scheme(response);
456: HTAAModule * module = NULL;
457: if (AUTH_TRACE) HTTrace("Auth Engine. Update filter status %d\n", status);
458: /*
459: ** If we don't have a scheme then the server has made an error. We
460: ** try to make up for it by creating our own "noop" realm and use basic.
461: */
462: if (!scheme) {
463: HTResponse_addChallenge(response, "basic", "realm LIBWWW-UNKNOWN");
464: scheme = "basic";
465: }
466: if ((module = HTAA_findModule(scheme)) != NULL) {
467: /* we don't call this module systematically, as it could hamper
468: the execution of Basic authentication requests for nothing */
469: if (module->update) {
470: if (AUTH_TRACE)
471: HTTrace("Auth Engine. Found Update filter %p\n", module->update);
472: HTRequest_deleteCredentialsAll(request);
473: return (*module->update)(request, response, NULL, status);
474: }
475: return HT_OK;
476: }
477: return HT_ERROR;
478: }
479:
2.26 frystyk 480:
481: /* HTAA_proxybeforeFilter
482: ** ----------------------
483: ** Make a lookup in the proxy URL tree to find any context for this node,
484: ** If no context is found then we assume that we don't know anything about
485: ** this URL and hence we don't call any BEFORE filters at all.
486: ** Return HT_OK or whatever callback returns
487: */
2.29 frystyk 488: PUBLIC int HTAA_proxyBeforeFilter (HTRequest * request, void * param, int mode)
2.26 frystyk 489: {
490: char * url = HTRequest_proxy(request);
491:
2.27 frystyk 492: /*
493: ** We may not have a proxy - for example if it has been disabled for this
494: ** request or it isn't a proxied access method.
495: */
496: if (url) {
497: const char * realm = HTRequest_realm(request);
498: HTAAElement * element = HTAA_findElement(YES, realm, url);
499:
500: /* If we have an element then call the before filter with the scheme */
501: if (element) {
502: HTAAModule * module = HTAA_findModule(element->scheme);
503: if (module) {
504: if (AUTH_TRACE)
505: HTTrace("Auth Engine. Found Proxy BEFORE filter %p with context %p\n",
506: module->before, element->context);
507: return (*module->before)(request, element->context, HT_NO_PROXY_ACCESS);
508: }
2.26 frystyk 509: }
510: }
511: return HT_OK;
2.19 frystyk 512: }
Webmaster