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