diff options
Diffstat (limited to 'WWW/Library/Implementation/HTAAProt.c')
-rw-r--r-- | WWW/Library/Implementation/HTAAProt.c | 592 |
1 files changed, 592 insertions, 0 deletions
diff --git a/WWW/Library/Implementation/HTAAProt.c b/WWW/Library/Implementation/HTAAProt.c new file mode 100644 index 00000000..751b51fc --- /dev/null +++ b/WWW/Library/Implementation/HTAAProt.c @@ -0,0 +1,592 @@ + +/* MODULE HTAAProt.c +** PROTECTION FILE PARSING MODULE +** +** AUTHORS: +** AL Ari Luotonen luotonen@dxcern.cern.ch +** MD Mark Donszelmann duns@vxdeop.cern.ch +** +** HISTORY: +** 20 Oct 93 AL Now finds uid/gid for nobody/nogroup by name +** (doesn't use default 65534 right away). +** Also understands negative uids/gids. +** 14 Nov 93 MD Added VMS compatibility +** +** BUGS: +** +** +*/ + +#include "HTUtils.h" + +#include <string.h> +#ifndef VMS +#include <pwd.h> /* Unix password file routine: getpwnam() */ +#include <grp.h> /* Unix group file routine: getgrnam() */ +#endif /* not VMS */ + +#include "HTAAUtil.h" +#include "HTAAFile.h" +#include "HTLex.h" /* Lexical analysor */ +#include "HTAssoc.h" /* Association list */ +#include "HTAAProt.h" /* Implemented here */ + +#include "LYLeaks.h" + +/* +** Protection setup caching +*/ +typedef struct { + char * prot_filename; + HTAAProt * prot; +} HTAAProtCache; + +PRIVATE HTList * prot_cache = NULL; /* Protection setup cache. */ +PRIVATE HTAAProt *default_prot = NULL; /* Default protection. */ +PRIVATE HTAAProt *current_prot = NULL; /* Current protection mode */ + /* which is set up by callbacks */ + /* from the rule system when */ + /* a "protect" rule is matched. */ + + +/* PRIVATE isNumber() +** DOES A CHARACTER STRING REPRESENT A NUMBER +*/ +PRIVATE BOOL isNumber ARGS1(CONST char *, s) +{ + CONST char *cur = s; + + if (!s || !*s) return NO; + + if (*cur == '-') + cur++; /* Allow initial minus sign in a number */ + + while (*cur) { + if (*cur < '0' || *cur > '9') + return NO; + cur++; + } + return YES; +} + + +#ifdef VMS +/* PUBLIC HTAA_getUidName() +** GET THE USER ID NAME (VMS ONLY) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the user name +** Default is "" (nobody). +*/ +PUBLIC char * HTAA_getUidName NOARGS +{ + if (current_prot && current_prot->uid_name + && (0 != strcmp(current_prot->uid_name,"nobody")) ) + return(current_prot->uid_name); + else + return(""); +} + +/* PUBLIC HTAA_getFileName +** GET THE FILENAME (VMS ONLY) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the filename +*/ +PUBLIC char * HTAA_getFileName NOARGS +{ + if (current_prot && current_prot->filename) + return(current_prot->filename); + else + return(""); +} + +#else /* not VMS */ + +/* PUBLIC HTAA_getUid() +** GET THE USER ID TO CHANGE THE PROCESS UID TO +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the uid number to give to setuid() system call. +** Default is 65534 (nobody). +*/ +PUBLIC int HTAA_getUid NOARGS +{ + struct passwd *pw = NULL; + + if (current_prot && current_prot->uid_name) { + if (isNumber(current_prot->uid_name)) { + if (NULL != (pw = getpwuid(atoi(current_prot->uid_name)))) { + if (TRACE) fprintf(stderr, + "%s(%s) returned (%s:%s:%d:%d:...)\n", + "HTAA_getUid: getpwuid", + current_prot->uid_name, + pw->pw_name, pw->pw_passwd, + pw->pw_uid, pw->pw_gid); + return pw->pw_uid; + } + } + else { /* User name (not a number) */ + if (NULL != (pw = getpwnam(current_prot->uid_name))) { + if (TRACE) fprintf(stderr, "%s(\"%s\") %s (%s:%s:%d:%d:...)\n", + "HTAA_getUid: getpwnam", + current_prot->uid_name, "returned", + pw->pw_name, pw->pw_passwd, + pw->pw_uid, pw->pw_gid); + return pw->pw_uid; + } + } + } + /* + ** Ok, then let's get uid for nobody. + */ + if (NULL != (pw = getpwnam("nobody"))) { + if (TRACE) fprintf(stderr, "HTAA_getUid: Uid for `nobody' is %d\n", + pw->pw_uid); + return pw->pw_uid; + } + /* + ** Ok, then use default. + */ + return 65534; /* nobody */ +} + + +/* PUBLIC HTAA_getGid() +** GET THE GROUP ID TO CHANGE THE PROCESS GID TO +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns the uid number to give to setgid() system call. +** Default is 65534 (nogroup). +*/ +PUBLIC int HTAA_getGid NOARGS +{ + struct group *gr = NULL; + + if (current_prot && current_prot->gid_name) { + if (isNumber(current_prot->gid_name)) { + if (NULL != (gr = getgrgid(atoi(current_prot->gid_name)))) { + if (TRACE) fprintf(stderr, + "%s(%s) returned (%s:%s:%d:...)\n", + "HTAA_getGid: getgrgid", + current_prot->gid_name, + gr->gr_name, gr->gr_passwd, gr->gr_gid); + return gr->gr_gid; + } + } + else { /* Group name (not number) */ + if (NULL != (gr = getgrnam(current_prot->gid_name))) { + if (TRACE) fprintf(stderr, + "%s(\"%s\") returned (%s:%s:%d:...)\n", + "HTAA_getGid: getgrnam", + current_prot->gid_name, + gr->gr_name, gr->gr_passwd, gr->gr_gid); + return gr->gr_gid; + } + } + } + /* + ** Ok, then let's get gid for nogroup. + */ + if (NULL != (gr = getgrnam("nogroup"))) { + if (TRACE) fprintf(stderr, "HTAA_getGid: Gid for `nogroup' is %d\n", + gr->gr_gid); + return gr->gr_gid; + } + /* + ** Ok, then use default. + */ + return 65534; /* nogroup */ +} +#endif /* not VMS */ + + +/* PRIVATE HTAA_setIds() +** SET UID AND GID (AS NAMES OR NUMBERS) +** TO HTAAProt STRUCTURE +** ON ENTRY: +** prot destination. +** ids is a string like "james.www" or "1422.69" etc. +** giving uid and gid. +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAA_setIds ARGS2(HTAAProt *, prot, + CONST char *, ids) +{ + if (ids) { + char *local_copy = NULL; + char *point; + + StrAllocCopy(local_copy, ids); + point = strchr(local_copy, '.'); + if (point) { + *(point++) = (char)0; + StrAllocCopy(prot->gid_name, point); + } + else { + StrAllocCopy(prot->gid_name, "nogroup"); + } + StrAllocCopy(prot->uid_name, local_copy); + FREE(local_copy); + } + else { + StrAllocCopy(prot->uid_name, "nobody"); + StrAllocCopy(prot->gid_name, "nogroup"); + } +} + + +/* PRIVATE HTAA_parseProtFile() +** PARSE A PROTECTION SETUP FILE AND +** PUT THE RESULT IN A HTAAProt STRUCTURE +** ON ENTRY: +** prot destination structure. +** fp open protection file. +** +** ON EXIT: +** returns nothing. +*/ +PRIVATE void HTAA_parseProtFile ARGS2(HTAAProt *, prot, + FILE *, fp) +{ + if (prot && fp) { + LexItem lex_item; + char *fieldname = NULL; + + while (LEX_EOF != (lex_item = lex(fp))) { + + while (lex_item == LEX_REC_SEP) /* Ignore empty lines */ + lex_item = lex(fp); + + if (lex_item == LEX_EOF) /* End of file */ + break; + + if (lex_item == LEX_ALPH_STR) { /* Valid setup record */ + + StrAllocCopy(fieldname, HTlex_buffer); + + if (LEX_FIELD_SEP != (lex_item = lex(fp))) + unlex(lex_item); /* If someone wants to use colon */ + /* after field name it's ok, but */ + /* not required. Here we read it.*/ + + if (0==strncasecomp(fieldname, "Auth", 4)) { + lex_item = lex(fp); + while (lex_item == LEX_ALPH_STR) { + HTAAScheme scheme = HTAAScheme_enum(HTlex_buffer); + if (scheme != HTAA_UNKNOWN) { + if (!prot->valid_schemes) + prot->valid_schemes = HTList_new(); + HTList_addObject(prot->valid_schemes,(void*)scheme); + if (TRACE) fprintf(stderr, "%s %s `%s'\n", + "HTAA_parseProtFile: valid", + "authentication scheme:", + HTAAScheme_name(scheme)); + } + else if (TRACE) fprintf(stderr, "%s %s `%s'\n", + "HTAA_parseProtFile: unknown", + "authentication scheme:", + HTlex_buffer); + + if (LEX_ITEM_SEP != (lex_item = lex(fp))) + break; + /* + ** Here lex_item == LEX_ITEM_SEP; after item separator + ** it is ok to have one or more newlines (LEX_REC_SEP) + ** and they are ignored (continuation line). + */ + do { + lex_item = lex(fp); + } while (lex_item == LEX_REC_SEP); + } /* while items in list */ + } /* if "Authenticate" */ + + else if (0==strncasecomp(fieldname, "mask", 4)) { + prot->mask_group = HTAA_parseGroupDef(fp); + lex_item=LEX_REC_SEP; /*groupdef parser read this already*/ + if (TRACE) { + if (prot->mask_group) { + fprintf(stderr, + "HTAA_parseProtFile: Mask group:\n"); + HTAA_printGroupDef(prot->mask_group); + } else fprintf(stderr, "HTAA_parseProtFile: %s\n", + "Mask group syntax error"); + } + } /* if "Mask" */ + + else { /* Just a name-value pair, put it to assoclist */ + + if (LEX_ALPH_STR == (lex_item = lex(fp))) { + if (!prot->values) + prot->values = HTAssocList_new(); + HTAssocList_add(prot->values, fieldname, HTlex_buffer); + lex_item = lex(fp); /* Read record separator */ + if (TRACE) fprintf(stderr, + "%s `%s' bound to value `%s'\n", + "HTAA_parseProtFile: Name", + fieldname, HTlex_buffer); + } + } /* else name-value pair */ + + } /* if valid field */ + + if (lex_item != LEX_EOF && lex_item != LEX_REC_SEP) { + if (TRACE) fprintf(stderr, "%s %s %d (that line ignored)\n", + "HTAA_parseProtFile: Syntax error", + "in protection setup file at line", + HTlex_line); + do { + lex_item = lex(fp); + } while (lex_item != LEX_EOF && lex_item != LEX_REC_SEP); + } /* if syntax error */ + } /* while not end-of-file */ + FREE(fieldname); + } /* if valid parameters */ +} + + +/* PRIVATE HTAAProt_new() +** ALLOCATE A NEW HTAAProt STRUCTURE AND +** INITIALIZE IT FROM PROTECTION SETUP FILE +** ON ENTRY: +** cur_docname current filename after rule translations. +** prot_filename protection setup file name. +** If NULL, not an error. +** ids Uid and gid names or numbers, +** examples: +** james ( <=> james.nogroup) +** .www ( <=> nobody.www) +** james.www +** james.69 +** 1422.69 +** 1422.www +** +** May be NULL, defaults to nobody.nogroup. +** Should be NULL, if prot_file is NULL. +** +** ON EXIT: +** returns returns a new and initialized protection +** setup structure. +** If setup file is already read in (found +** in cache), only sets uid_name and gid +** fields, and returns that. +*/ +PRIVATE HTAAProt *HTAAProt_new ARGS3(CONST char *, cur_docname, + CONST char *, prot_filename, + CONST char *, ids) +{ + HTList *cur = prot_cache; + HTAAProtCache *cache_item = NULL; + HTAAProt *prot; + FILE *fp; + + if (!prot_cache) + prot_cache = HTList_new(); + + while (NULL != (cache_item = (HTAAProtCache*)HTList_nextObject(cur))) { + if (!strcmp(cache_item->prot_filename, prot_filename)) + break; + } + if (cache_item) { + prot = cache_item->prot; + if (TRACE) fprintf(stderr, "%s `%s' already in cache\n", + "HTAAProt_new: Protection file", prot_filename); + } else { + if (TRACE) fprintf(stderr, + "HTAAProt_new: Loading protection file `%s'\n", + prot_filename); + + if (!(prot = (HTAAProt*)calloc(1, sizeof(HTAAProt)))) + outofmem(__FILE__, "HTAAProt_new"); + + prot->template = NULL; + prot->filename = NULL; + prot->uid_name = NULL; + prot->gid_name = NULL; + prot->valid_schemes = HTList_new(); + prot->mask_group= NULL; /* Masking disabled by defaults */ + prot->values = HTAssocList_new(); + + if (prot_filename && NULL != (fp = fopen(prot_filename, "r"))) { + HTAA_parseProtFile(prot, fp); + fclose(fp); + if (!(cache_item = + (HTAAProtCache*)calloc(1, sizeof(HTAAProtCache)))) + outofmem(__FILE__, "HTAAProt_new"); + cache_item->prot = prot; + cache_item->prot_filename = NULL; + StrAllocCopy(cache_item->prot_filename, prot_filename); + HTList_addObject(prot_cache, (void*)cache_item); + } + else if (TRACE) fprintf(stderr, "HTAAProt_new: %s `%s'\n", + "Unable to open protection setup file", + (prot_filename ? prot_filename : "(null)")); + } + + if (cur_docname) + StrAllocCopy(prot->filename, cur_docname); + HTAA_setIds(prot, ids); + + return prot; +} + + +/* PUBLIC HTAA_setDefaultProtection() +** SET THE DEFAULT PROTECTION MODE +** (called by rule system when a +** "defprot" rule is matched) +** ON ENTRY: +** cur_docname is the current result of rule translations. +** prot_filename is the protection setup file (second argument +** for "defprot" rule, optional) +** ids contains user and group names separated by +** a dot, corresponding to the uid +** gid under which the server should run, +** default is "nobody.nogroup" (third argument +** for "defprot" rule, optional; can be given +** only if protection setup file is also given). +** +** ON EXIT: +** returns nothing. +** Sets the module-wide variable default_prot. +*/ +PUBLIC void HTAA_setDefaultProtection ARGS3(CONST char *, cur_docname, + CONST char *, prot_filename, + CONST char *, ids) +{ + default_prot = NULL; /* Not free()'d because this is in cache */ + + if (prot_filename) { + default_prot = HTAAProt_new(cur_docname, prot_filename, ids); + } else { + if (TRACE) fprintf(stderr, "%s %s\n", + "HTAA_setDefaultProtection: ERROR: Protection file", + "not specified (obligatory for DefProt rule)!!\n"); + } +} + + +/* PUBLIC HTAA_setCurrentProtection() +** SET THE CURRENT PROTECTION MODE +** (called by rule system when a +** "protect" rule is matched) +** ON ENTRY: +** cur_docname is the current result of rule translations. +** prot_filename is the protection setup file (second argument +** for "protect" rule, optional) +** ids contains user and group names separated by +** a dot, corresponding to the uid +** gid under which the server should run, +** default is "nobody.nogroup" (third argument +** for "protect" rule, optional; can be given +** only if protection setup file is also given). +** +** ON EXIT: +** returns nothing. +** Sets the module-wide variable current_prot. +*/ +PUBLIC void HTAA_setCurrentProtection ARGS3(CONST char *, cur_docname, + CONST char *, prot_filename, + CONST char *, ids) +{ + current_prot = NULL; /* Not free()'d because this is in cache */ + + if (prot_filename) { + current_prot = HTAAProt_new(cur_docname, prot_filename, ids); + } else { + if (default_prot) { + current_prot = default_prot; + HTAA_setIds(current_prot, ids); + if (TRACE) fprintf(stderr, "%s %s %s\n", + "HTAA_setCurrentProtection: Protection file", + "not specified for Protect rule", + "-- using default protection"); + } else { + if (TRACE) fprintf(stderr, "%s %s %s\n", + "HTAA_setCurrentProtection: ERROR: Protection", + "file not specified for Protect rule, and", + "default protection is not set!!"); + } + } +} + + +/* PUBLIC HTAA_getCurrentProtection() +** GET CURRENT PROTECTION SETUP STRUCTURE +** (this is set up by callbacks made from +** the rule system when matching "protect" +** (and "defprot") rules) +** ON ENTRY: +** HTTranslate() must have been called before calling +** this function. +** +** ON EXIT: +** returns a HTAAProt structure representing the +** protection setup of the HTTranslate()'d file. +** This must not be free()'d. +*/ +PUBLIC HTAAProt *HTAA_getCurrentProtection NOARGS +{ + return current_prot; +} + + +/* PUBLIC HTAA_getDefaultProtection() +** GET DEFAULT PROTECTION SETUP STRUCTURE +** AND SET IT TO CURRENT PROTECTION +** (this is set up by callbacks made from +** the rule system when matching "defprot" +** rules) +** ON ENTRY: +** HTTranslate() must have been called before calling +** this function. +** +** ON EXIT: +** returns a HTAAProt structure representing the +** default protection setup of the HTTranslate()'d +** file (if HTAA_getCurrentProtection() returned +** NULL, i.e. if there is no "protect" rule +** but ACL exists, and we need to know default +** protection settings). +** This must not be free()'d. +** IMPORTANT: +** As a side-effect this tells the protection system that +** the file is in fact protected and sets the current +** protection mode to default. +*/ +PUBLIC HTAAProt *HTAA_getDefaultProtection NOARGS +{ + if (!current_prot) { + current_prot = default_prot; + default_prot = NULL; + } + return current_prot; +} + + +/* SERVER INTERNAL HTAA_clearProtections() +** CLEAR DOCUMENT PROTECTION MODE +** (ALSO DEFAULT PROTECTION) +** (called by the rule system) +** ON ENTRY: +** No arguments. +** +** ON EXIT: +** returns nothing. +** Frees the memory used by protection information. +*/ +PUBLIC void HTAA_clearProtections NOARGS +{ + current_prot = NULL; /* These are not freed because */ + default_prot = NULL; /* they are actually in cache. */ +} |