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