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