Annotation of libwww/Library/src/HTAAUtil.c, revision 2.2
2.1 luotonen 1:
2.2 ! luotonen 2: /* MODULE HTAAUtil.c
2.1 luotonen 3: ** COMMON PARTS OF ACCESS AUTHORIZATION MODULE
4: ** FOR BOTH SERVER AND BROWSER
5: **
6: ** IMPORTANT:
7: ** Routines in this module use dynamic allocation, but free
8: ** automatically all the memory reserved by them.
9: **
10: ** Therefore the caller never has to (and never should)
11: ** free() any object returned by these functions.
12: **
13: ** Therefore also all the strings returned by this package
14: ** are only valid until the next call to the same function
15: ** is made. This approach is selected, because of the nature
16: ** of access authorization: no string returned by the package
17: ** needs to be valid longer than until the next call.
18: **
19: ** This also makes it easy to plug the AA package in:
20: ** you don't have to ponder whether to free() something
21: ** here or is it done somewhere else (because it is always
22: ** done somewhere else).
23: **
24: ** The strings that the package needs to store are copied
25: ** so the original strings given as parameters to AA
26: ** functions may be freed or modified with no side effects.
27: **
28: ** The AA package does not free() anything else than what
29: ** it has itself allocated.
30: **
31: ** AA (Access Authorization) package means modules which
32: ** names start with HTAA.
33: **
34: ** AUTHORS:
35: ** AL Ari Luotonen luotonen@dxcern.cern.ch
36: **
37: ** HISTORY:
38: **
39: **
40: ** BUGS:
41: **
42: **
43: */
44:
45: #include <string.h>
46: #include "HTUtils.h"
47: #include "tcp.h" /* NETREAD() etc. */
48: #include "HTAAUtil.h" /* Implemented here */
49: #include "HTAssoc.h" /* Assoc list */
50:
51:
52: /* PUBLIC HTAAScheme_enum()
53: ** TRANSLATE SCHEME NAME INTO
54: ** A SCHEME ENUMERATION
55: **
56: ** ON ENTRY:
57: ** name is a string representing the scheme name.
58: **
59: ** ON EXIT:
60: ** returns the enumerated constant for that scheme.
61: */
62: PUBLIC HTAAScheme HTAAScheme_enum ARGS1(CONST char*, name)
63: {
64: static char *upcased = NULL;
65: char *cur;
66:
67: if (!name) return HTAA_UNKNOWN;
68:
69: StrAllocCopy(upcased, name);
70: cur = upcased;
71: while (*cur) {
72: *cur = TOUPPER(*cur);
73: cur++;
74: }
75:
76: if (!strncmp(upcased, "NONE", 4))
77: return HTAA_NONE;
78: else if (!strncmp(upcased, "BASIC", 5))
79: return HTAA_BASIC;
80: else if (!strncmp(upcased, "PUBKEY", 6))
81: return HTAA_PUBKEY;
82: else if (!strncmp(upcased, "KERBEROSV4", 10))
83: return HTAA_KERBEROS_V4;
84: else if (!strncmp(upcased, "KERBEROSV5", 10))
85: return HTAA_KERBEROS_V5;
86: else
87: return HTAA_UNKNOWN;
88: }
89:
90:
91: /* PUBLIC HTAAScheme_name()
92: ** GET THE NAME OF A GIVEN SCHEME
93: ** ON ENTRY:
94: ** scheme is one of the scheme enum values:
95: ** HTAA_NONE, HTAA_BASIC, HTAA_PUBKEY, ...
96: **
97: ** ON EXIT:
98: ** returns the name of the scheme, i.e.
99: ** "None", "Basic", "Pubkey", ...
100: */
101: PUBLIC char *HTAAScheme_name ARGS1(HTAAScheme, scheme)
102: {
103: switch (scheme) {
104: case HTAA_NONE: return "None"; break;
105: case HTAA_BASIC: return "Basic"; break;
106: case HTAA_PUBKEY: return "Pubkey"; break;
107: case HTAA_KERBEROS_V4: return "KerberosV4"; break;
108: case HTAA_KERBEROS_V5: return "KerberosV5"; break;
109: case HTAA_UNKNOWN: return "UNKNOWN"; break;
110: default: return "THIS-IS-A-BUG";
111: }
112: }
113:
114:
115: /* PUBLIC HTAAMethod_enum()
116: ** TRANSLATE METHOD NAME INTO AN ENUMERATED VALUE
117: ** ON ENTRY:
118: ** name is the method name to translate.
119: **
120: ** ON EXIT:
121: ** returns HTAAMethod enumerated value corresponding
122: ** to the given name.
123: */
124: PUBLIC HTAAMethod HTAAMethod_enum ARGS1(CONST char *, name)
125: {
126: char tmp[MAX_METHODNAME_LEN+1];
127: CONST char *src = name;
128: char *dest = tmp;
129:
130: if (!name) return METHOD_UNKNOWN;
131:
132: while (*src) {
133: *dest = TOUPPER(*src);
134: dest++;
135: src++;
136: }
137: *dest = 0;
138:
139: if (0==strcmp(tmp, "GET"))
140: return METHOD_GET;
141: else if (0==strcmp(tmp, "PUT"))
142: return METHOD_PUT;
143: else
144: return METHOD_UNKNOWN;
145: }
146:
147:
148: /* PUBLIC HTAAMethod_name()
149: ** GET THE NAME OF A GIVEN METHOD
150: ** ON ENTRY:
151: ** method is one of the method enum values:
152: ** METHOD_GET, METHOD_PUT, ...
153: **
154: ** ON EXIT:
155: ** returns the name of the scheme, i.e.
156: ** "GET", "PUT", ...
157: */
158: PUBLIC char *HTAAMethod_name ARGS1(HTAAMethod, method)
159: {
160: switch (method) {
161: case METHOD_GET: return "GET"; break;
162: case METHOD_PUT: return "PUT"; break;
163: case METHOD_UNKNOWN: return "UNKNOWN"; break;
164: default: return "THIS-IS-A-BUG";
165: }
166: }
167:
168:
169: /* PUBLIC HTAAMethod_inList()
170: ** IS A METHOD IN A LIST OF METHOD NAMES
171: ** ON ENTRY:
172: ** method is the method to look for.
173: ** list is a list of method names.
174: **
175: ** ON EXIT:
176: ** returns YES, if method was found.
177: ** NO, if not found.
178: */
179: PUBLIC BOOL HTAAMethod_inList ARGS2(HTAAMethod, method,
180: HTList *, list)
181: {
182: HTList *cur = list;
183: char *item;
184:
185: while (NULL != (item = (char*)HTList_nextObject(cur))) {
186: if (TRACE) fprintf(stderr, " %s", item);
187: if (method == HTAAMethod_enum(item))
188: return YES;
189: }
190:
191: return NO; /* Not found */
192: }
193:
194:
195:
196: /* PUBLIC HTAA_templateMatch()
197: ** STRING COMPARISON FUNCTION FOR FILE NAMES
198: ** WITH ONE WILDCARD * IN THE TEMPLATE
199: ** NOTE:
200: ** This is essentially the same code as in HTRules.c, but it
201: ** cannot be used because it is embedded in between other code.
202: ** (In fact, HTRules.c should use this routine, but then this
203: ** routine would have to be more sophisticated... why is life
204: ** sometimes so hard...)
205: **
206: ** ON ENTRY:
207: ** template is a template string to match the file name
208: ** agaist, may contain a single wildcard
209: ** character * which matches zero or more
210: ** arbitrary characters.
211: ** filename is the filename (or pathname) to be matched
212: ** agaist the template.
213: **
214: ** ON EXIT:
215: ** returns YES, if filename matches the template.
216: ** NO, otherwise.
217: */
218: PUBLIC BOOL HTAA_templateMatch ARGS2(CONST char *, template,
219: CONST char *, filename)
220: {
221: CONST char *p = template;
222: CONST char *q = filename;
223: int m;
224:
225: for( ; *p && *q && *p == *q; p++, q++) /* Find first mismatch */
226: ; /* do nothing else */
227:
228: if (!*p && !*q) return YES; /* Equally long equal strings */
229: else if ('*' == *p) { /* Wildcard */
230: p++; /* Skip wildcard character */
231: m = strlen(q) - strlen(p); /* Amount to match to wildcard */
232: if (m < 0) return NO; /* No match, filename too short */
233: else { /* Skip the matched characters and compare */
234: if (strcmp(p, q+m)) return NO; /* Tail mismatch */
235: else return YES; /* Tail match */
236: }
237: } /* if wildcard */
238: else return NO; /* Length or character mismatch */
239: }
240:
241:
242: /* PUBLIC HTAA_makeProtectionTemplate()
243: ** CREATE A PROTECTION TEMPLATE FOR THE FILES
244: ** IN THE SAME DIRECTORY AS THE GIVEN FILE
245: ** (Used by server if there is no fancier way for
246: ** it to tell the client, and by browser if server
247: ** didn't send WWW-ProtectionTemplate: field)
248: ** ON ENTRY:
249: ** docname is the document pathname (from URL).
250: **
251: ** ON EXIT:
252: ** returns a template matching docname, and other files
253: ** files in that directory.
254: **
255: ** E.g. /foo/bar/x.html => /foo/bar/ *
256: ** ^
257: ** Space only to prevent it from
258: ** being a comment marker here,
259: ** there really isn't any space.
260: */
261: PUBLIC char *HTAA_makeProtectionTemplate ARGS1(CONST char *, docname)
262: {
263: char *template = NULL;
264: char *slash = NULL;
265:
266: if (docname) {
267: StrAllocCopy(template, docname);
268: slash = strrchr(template, '/');
269: if (slash) slash++;
270: else slash = template;
2.2 ! luotonen 271: *slash = (char)0;
2.1 luotonen 272: StrAllocCat(template, "*");
273: }
274: else StrAllocCopy(template, "*");
275:
276: if (TRACE) fprintf(stderr,
277: "make_template: made template `%s' for file `%s'\n",
278: template, docname);
279:
280: return template;
281: }
282:
283:
284:
285:
286: /*
287: ** Skip leading whitespace from *s forward
288: */
289: #define SKIPWS(s) while (*s==' ' || *s=='\t') s++;
290:
291: /*
292: ** Kill trailing whitespace starting from *(s-1) backwords
293: */
2.2 ! luotonen 294: #define KILLWS(s) {char *c=s-1; while (*c==' ' || *c=='\t') *(c--)=(char)0;}
2.1 luotonen 295:
296:
297: /* PUBLIC HTAA_parseArgList()
298: ** PARSE AN ARGUMENT LIST GIVEN IN A HEADER FIELD
299: ** ON ENTRY:
300: ** str is a comma-separated list:
301: **
302: ** item, item, item
303: ** where
304: ** item ::= value
305: ** | name=value
306: ** | name="value"
307: **
308: ** Leading and trailing whitespace is ignored
309: ** everywhere except inside quotes, so the following
310: ** examples are equal:
311: **
312: ** name=value,foo=bar
313: ** name="value",foo="bar"
314: ** name = value , foo = bar
315: ** name = "value" , foo = "bar"
316: **
317: ** ON EXIT:
318: ** returns a list of name-value pairs (actually HTAssocList*).
319: ** For items with no name, just value, the name is
320: ** the number of order number of that item. E.g.
321: ** "1" for the first, etc.
322: */
323: PUBLIC HTAssocList *HTAA_parseArgList ARGS1(char *, str)
324: {
325: HTAssocList *assoc_list = HTAssocList_new();
326: char *cur = NULL;
327: char *name = NULL;
328: int index = 0;
329:
330: if (!str) return assoc_list;
331:
332: while (*str) {
333: SKIPWS(str); /* Skip leading whitespace */
334: cur = str;
335: index++;
336:
337: while (*cur && *cur != '=' && *cur != ',')
338: cur++; /* Find end of name (or lonely value without a name) */
339: KILLWS(cur); /* Kill trailing whitespace */
340:
341: if (*cur == '=') { /* Name followed by a value */
2.2 ! luotonen 342: *(cur++) = (char)0; /* Terminate name */
2.1 luotonen 343: StrAllocCopy(name, str);
344: SKIPWS(cur); /* Skip WS leading the value */
345: str = cur;
346: if (*str == '"') { /* Quoted value */
347: str++;
348: cur = str;
349: while (*cur && *cur != '"') cur++;
350: if (*cur == '"')
2.2 ! luotonen 351: *(cur++) = (char)0; /* Terminate value */
2.1 luotonen 352: /* else it is lacking terminating quote */
353: SKIPWS(cur); /* Skip WS leading comma */
354: if (*cur == ',') cur++; /* Skip separating colon */
355: }
356: else { /* Unquoted value */
357: while (*cur && *cur != ',') cur++;
358: KILLWS(cur); /* Kill trailing whitespace */
359: if (*cur == ',')
2.2 ! luotonen 360: *(cur++) = (char)0;
2.1 luotonen 361: /* else *cur already NULL */
362: }
363: }
364: else { /* No name, just a value */
365: if (*cur == ',')
2.2 ! luotonen 366: *(cur++) = (char)0; /* Terminate value */
2.1 luotonen 367: /* else last value on line (already terminated by NULL) */
368: StrAllocCopy(name, "nnn"); /* Room for item order number */
369: sprintf(name, "%d", index); /* Item order number for name */
370: }
371: HTAssocList_add(assoc_list, name, str);
372: str = cur;
373: } /* while *str */
374:
375: return assoc_list;
376: }
377:
378:
379:
380: /************** HEADER LINE READER -- DOES UNFOLDING *************************/
381:
382: #define BUFFER_SIZE 1024
383:
384: PRIVATE char buffer[BUFFER_SIZE + 1];
385: PRIVATE char *start_pointer = buffer;
386: PRIVATE char *end_pointer = buffer;
387: PRIVATE int in_soc = -1;
388:
389: /* PUBLIC HTAA_setupReader()
390: ** SET UP HEADER LINE READER, i.e. give
391: ** the already-read-but-not-yet-processed
392: ** buffer of text to be read before more
393: ** is read from the socket.
394: ** ON ENTRY:
395: ** start_of_headers is a pointer to a buffer containing
396: ** the beginning of the header lines
397: ** (rest will be read from a socket).
398: ** length is the number of valid characters in
399: ** 'start_of_headers' buffer.
400: ** soc is the socket to use when start_of_headers
401: ** buffer is used up.
402: ** ON EXIT:
403: ** returns nothing.
404: ** Subsequent calls to HTAA_getUnfoldedLine()
405: ** will use this buffer first and then
406: ** proceed to read from socket.
407: */
408: PUBLIC void HTAA_setupReader ARGS3(char *, start_of_headers,
409: int, length,
410: int, soc)
411: {
412: start_pointer = buffer;
413: if (start_of_headers) {
414: strncpy(buffer, start_of_headers, length);
2.2 ! luotonen 415: buffer[length] = (char)0;
2.1 luotonen 416: end_pointer = buffer + length;
417: }
418: else {
2.2 ! luotonen 419: *start_pointer = (char)0;
2.1 luotonen 420: end_pointer = start_pointer;
421: }
422: in_soc = soc;
423: }
424:
425:
426: /* PUBLIC HTAA_getUnfoldedLine()
427: ** READ AN UNFOLDED HEADER LINE FROM SOCKET
428: ** ON ENTRY:
429: ** HTAA_setupReader must absolutely be called before
430: ** this function to set up internal buffer.
431: **
432: ** ON EXIT:
433: ** returns a newly-allocated character string representing
434: ** the read line. The line is unfolded, i.e.
435: ** lines that begin with whitespace are appended
436: ** to current line. E.g.
437: **
438: ** Field-Name: Blaa-Blaa
439: ** This-Is-A-Continuation-Line
440: ** Here-Is_Another
441: **
442: ** is seen by the caller as:
443: **
444: ** Field-Name: Blaa-Blaa This-Is-A-Continuation-Line Here-Is_Another
445: **
446: */
447: PUBLIC char *HTAA_getUnfoldedLine NOARGS
448: {
449: char *line = NULL;
450: char *cur;
451: int count;
452: BOOL peek_for_folding = NO;
453:
454: if (in_soc < 0) {
455: fprintf(stderr, "%s %s\n",
456: "HTAA_getUnfoldedLine: buffer not initialized",
457: "with function HTAA_setupReader()");
458: return NULL;
459: }
460:
461: for(;;) {
462:
463: /* Reading from socket */
464:
465: if (start_pointer >= end_pointer) {/*Read the next block and continue*/
466: count = NETREAD(in_soc, buffer, BUFFER_SIZE);
467: if (count <= 0) {
468: in_soc = -1;
469: return line;
470: }
471: start_pointer = buffer;
472: end_pointer = buffer + count;
2.2 ! luotonen 473: *end_pointer = (char)0;
2.1 luotonen 474: #ifdef NOT_ASCII
475: cur = start_pointer;
476: while (cur < end_pointer) {
477: *cur = TOASCII(*cur);
478: cur++;
479: }
480: #endif /*NOT_ASCII*/
481: }
482: cur = start_pointer;
483:
484:
485: /* Unfolding */
486:
487: if (peek_for_folding) {
488: if (*cur != ' ' && *cur != '\t')
489: return line; /* Ok, no continuation line */
490: else /* So this is a continuation line, continue */
491: peek_for_folding = NO;
492: }
493:
494:
495: /* Finding end-of-line */
496:
497: while (cur < end_pointer && *cur != '\n') /* Find the end-of-line */
498: cur++; /* (or end-of-buffer). */
499:
500:
501: /* Terminating line */
502:
503: if (cur < end_pointer) { /* So *cur==LF, terminate line */
2.2 ! luotonen 504: *cur = (char)0; /* Overwrite LF */
2.1 luotonen 505: if (*(cur-1) == '\r')
2.2 ! luotonen 506: *(cur-1) = (char)0; /* Overwrite CR */
2.1 luotonen 507: peek_for_folding = YES; /* Check for a continuation line */
508: }
509:
510:
511: /* Copying the result */
512:
513: if (line)
514: StrAllocCat(line, start_pointer); /* Append */
515: else
516: StrAllocCopy(line, start_pointer); /* A new line */
517:
518: start_pointer = cur+1; /* Skip the read line */
519:
520: } /* forever */
521: }
522:
523:
524:
525:
Webmaster