diff options
Diffstat (limited to 'WWW/Library/Implementation/HTRules.c')
-rw-r--r-- | WWW/Library/Implementation/HTRules.c | 704 |
1 files changed, 704 insertions, 0 deletions
diff --git a/WWW/Library/Implementation/HTRules.c b/WWW/Library/Implementation/HTRules.c new file mode 100644 index 0000000..91ac93d --- /dev/null +++ b/WWW/Library/Implementation/HTRules.c @@ -0,0 +1,704 @@ +/* + * $LynxId: HTRules.c,v 1.47 2017/07/02 19:45:22 tom Exp $ + * + * Configuration manager for Hypertext Daemon HTRules.c + * ========================================== + * + * + * History: + * 3 Jun 91 Written TBL + * 10 Aug 91 Authorisation added after Daniel Martin (pass, fail) + * Rule order in file changed + * Comments allowed with # on 1st char of rule line + * 17 Jun 92 Bug fix: pass and fail failed if didn't contain '*' TBL + * 1 Sep 93 Bug fix: no memory check - Nathan Torkington + * BYTE_ADDRESSING removed - Arthur Secret + * 11 Sep 93 MD Changed %i into %d in debug printf. + * VMS does not recognize %i. + * Bug Fix: in case of PASS, only one parameter to printf. + * 19 Sep 93 AL Added Access Authorization stuff. + * 1 Nov 93 AL Added htbin. + * 25 May 99 KW Added redirect for lynx. + * + */ + +#include <HTUtils.h> + +/* (c) CERN WorldWideWeb project 1990,91. See Copyright.html for details */ +#include <HTRules.h> + +#include <HTFile.h> +#include <LYLeaks.h> +#include <HTAAProt.h> + +#define LINE_LENGTH 256 + +typedef struct _rule { + struct _rule *next; + HTRuleOp op; + char *pattern; + char *equiv; + char *condition_op; /* as strings - may be inefficient, */ + char *condition; /* but this is not for a server - kw */ +} rule; + +#ifndef NO_RULES + +#include <HTTP.h> /* for redirecting_url, indirectly HTPermitRedir - kw */ +#include <LYGlobalDefs.h> /* for LYUserSpecifiedURL - kw */ +#include <LYStrings.h> /* for LYscanFloat */ +#include <LYUtils.h> /* for LYFixCursesOn - kw */ +#include <HTAlert.h> + +/* Global variables + * ---------------- + */ +char *HTBinDir = NULL; /* Physical /htbin directory path. */ + + /* In future this should not be global. */ +char *HTSearchScript = NULL; /* Search script name. */ + +/* Module-wide variables + * --------------------- + */ + +static rule *rules = 0; /* Pointer to first on list */ + +#ifndef PUT_ON_HEAD +static rule *rule_tail = 0; /* Pointer to last on list */ +#endif + +/* Add rule to the list HTAddRule() + * -------------------- + * + * On entry, + * pattern points to 0-terminated string containing a single "*" + * equiv points to the equivalent string with * for the + * place where the text matched by * goes. + * On exit, + * returns 0 if success, -1 if error. + */ + +int HTAddRule(HTRuleOp op, const char *pattern, + const char *equiv, + const char *cond_op, + const char *cond) +{ /* BYTE_ADDRESSING removed and memory check - AS - 1 Sep 93 */ + rule *temp; + char *pPattern = NULL; + + temp = typecalloc(rule); + if (temp == NULL) + outofmem(__FILE__, "HTAddRule"); + + if (equiv) { /* Two operands */ + char *pEquiv = NULL; + + StrAllocCopy(pEquiv, equiv); + temp->equiv = pEquiv; + } else { + temp->equiv = 0; + } + if (cond_op) { + StrAllocCopy(temp->condition_op, cond_op); + StrAllocCopy(temp->condition, cond); + } + StrAllocCopy(pPattern, pattern); + temp->pattern = pPattern; + temp->op = op; + + if (equiv) { + CTRACE((tfp, "Rule: For `%s' op %d `%s'", pattern, (int) op, equiv)); + } else { + CTRACE((tfp, "Rule: For `%s' op %d", pattern, (int) op)); + } + if (cond_op) { + CTRACE((tfp, "\t%s %s\n", cond_op, NONNULL(cond))); + } else { + CTRACE((tfp, "\n")); + } + + if (!rules) { +#ifdef LY_FIND_LEAKS + atexit(HTClearRules); +#endif + } +#ifdef PUT_ON_HEAD + temp->next = rules; + rules = temp; +#else + temp->next = 0; + if (rule_tail) + rule_tail->next = temp; + else + rules = temp; + rule_tail = temp; +#endif + + return 0; +} + +/* Clear all rules HTClearRules() + * --------------- + * + * On exit, + * There are no rules + * + * See also + * HTAddRule() + */ +void HTClearRules(void) +{ + while (rules) { + rule *temp = rules; + + rules = temp->next; + FREE(temp->pattern); + FREE(temp->equiv); + FREE(temp->condition_op); + FREE(temp->condition); + FREE(temp); + } +#ifndef PUT_ON_HEAD + rule_tail = 0; +#endif +} + +static BOOL rule_cond_ok(rule * r) +{ + BOOL result; + + if (!r->condition_op) + return YES; + if (strcmp(r->condition_op, "if") && strcmp(r->condition_op, "unless")) { + CTRACE((tfp, "....... rule ignored, unrecognized `%s'!\n", + r->condition_op)); + return NO; + } + if (!strcmp(r->condition, "redirected")) + result = (BOOL) (redirection_attempts > 0); + else if (!strcmp(r->condition, "userspec")) + result = LYUserSpecifiedURL; + else { + CTRACE((tfp, "....... rule ignored, unrecognized `%s %s'!\n", + r->condition_op, NONNULL(r->condition))); + return NO; + } + if (!strcmp(r->condition_op, "if")) + return result; + else + return (BOOL) (!result); + +} + +/* Translate by rules HTTranslate() + * ------------------ + * + * The most recently defined rules are applied first. + * + * On entry, + * required points to a string whose equivalent value is needed + * On exit, + * returns the address of the equivalent string allocated from + * the heap which the CALLER MUST FREE. If no translation + * occurred, then it is a copy of the original. + * NEW FEATURES: + * When a "protect" or "defprot" rule is matched, + * a call to HTAA_setCurrentProtection() or + * HTAA_setDefaultProtection() is made to notify + * the Access Authorization module that the file is + * protected, and so it knows how to handle it. + * -- AL + */ +char *HTTranslate(const char *required) +{ + rule *r; + char *current = NULL; + char *msgtmp = NULL; + const char *pMsg; + int proxy_none_flag = 0; + int permitredir_flag = 0; + + StrAllocCopy(current, required); + + HTAA_clearProtections(); /* Reset from previous call -- AL */ + + for (r = rules; r; r = r->next) { + char *p = r->pattern; + int m = 0; /* Number of characters matched against wildcard */ + const char *q = current; + + for (; *p && *q; p++, q++) { /* Find first mismatch */ + if (*p != *q) + break; + } + + if (*p == '*') { /* Match up to wildcard */ + m = (int) strlen(q) - (int) strlen(p + 1); /* Amount to match to wildcard */ + if (m < 0) + continue; /* tail is too short to match */ + if (0 != strcmp(q + m, p + 1)) + continue; /* Tail mismatch */ + } else + /* Not wildcard */ if (*p != *q) + continue; /* plain mismatch: go to next rule */ + + if (!rule_cond_ok(r)) /* check condition, next rule if false - kw */ + continue; + + switch (r->op) { /* Perform operation */ + + case HT_DefProt: + case HT_Protect: +#ifdef ACCESS_AUTH + { + char *local_copy = NULL; + char *p2; + char *eff_ids = NULL; + char *prot_file = NULL; + + CTRACE((tfp, "HTRule: `%s' matched %s %s: `%s'\n", + current, + (r->op == HT_Protect ? "Protect" : "DefProt"), + "rule, setup", + (r->equiv ? r->equiv : + (r->op == HT_Protect ? "DEFAULT" : "NULL!!")))); + + if (r->equiv) { + StrAllocCopy(local_copy, r->equiv); + p2 = local_copy; + prot_file = HTNextField(&p2); + eff_ids = HTNextField(&p2); + } + + if (r->op == HT_Protect) + HTAA_setCurrentProtection(current, prot_file, eff_ids); + else + HTAA_setDefaultProtection(current, prot_file, eff_ids); + + FREE(local_copy); + + /* continue translating rules */ + } +#endif /* ACCESS_AUTH */ + break; + + case HT_UserMsg: /* Produce message immediately */ + LYFixCursesOn("show rule message:"); + HTUserMsg2((r->equiv ? r->equiv : "Rule: %s"), current); + break; + case HT_InfoMsg: /* Produce messages immediately */ + case HT_Progress: + case HT_Alert: + LYFixCursesOn("show rule message:"); /* and fall through */ + /* FALLTHRU */ + case HT_AlwaysAlert: + pMsg = r->equiv ? r->equiv : + (r->op == HT_AlwaysAlert) ? "%s" : "Rule: %s"; + if (StrChr(pMsg, '%')) { + HTSprintf0(&msgtmp, pMsg, current); + pMsg = msgtmp; + } + switch (r->op) { /* Actually produce message */ + case HT_InfoMsg: + HTInfoMsg(pMsg); + break; + case HT_Progress: + HTProgress(pMsg); + break; + case HT_Alert: + HTAlert(pMsg); + break; + case HT_AlwaysAlert: + HTAlwaysAlert("Rule alert:", pMsg); + break; + default: + break; + } + FREE(msgtmp); + break; + + case HT_PermitRedir: /* Set special flag */ + permitredir_flag = 1; + CTRACE((tfp, "HTRule: Mark for redirection permitted\n")); + break; + + case HT_Pass: /* Authorised */ + if (!r->equiv) { + if (proxy_none_flag) { + char *temp = NULL; + + StrAllocCopy(temp, "NoProxy="); + StrAllocCat(temp, current); + FREE(current); + current = temp; + } + CTRACE((tfp, "HTRule: Pass `%s'\n", current)); + return current; + } + /* FALLTHRU */ + + case HT_Map: + case HT_Redirect: + case HT_RedirectPerm: + if (*p == *q) { /* End of both strings, no wildcard */ + CTRACE((tfp, "For `%s' using `%s'\n", current, r->equiv)); + StrAllocCopy(current, r->equiv); /* use entire translation */ + } else { + char *ins = StrChr(r->equiv, '*'); /* Insertion point */ + + if (ins) { /* Consistent rule!!! */ + char *temp = NULL; + + HTSprintf0(&temp, "%.*s%.*s%s", + (int) (ins - r->equiv), + r->equiv, + m, + q, + ins + 1); + CTRACE((tfp, "For `%s' using `%s'\n", + current, temp)); + FREE(current); + current = temp; /* Use this */ + + } else { /* No insertion point */ + char *temp = NULL; + + StrAllocCopy(temp, r->equiv); + CTRACE((tfp, "For `%s' using `%s'\n", + current, temp)); + FREE(current); + current = temp; /* Use this */ + } /* If no insertion point exists */ + } + if (r->op == HT_Pass) { + if (proxy_none_flag) { + char *temp = NULL; + + StrAllocCopy(temp, "NoProxy="); + StrAllocCat(temp, current); + FREE(current); + current = temp; + } + CTRACE((tfp, "HTRule: ...and pass `%s'\n", + current)); + return current; + } else if (r->op == HT_Redirect) { + CTRACE((tfp, "HTRule: ...and redirect to `%s'\n", + current)); + redirecting_url = current; + HTPermitRedir = (BOOL) (permitredir_flag == 1); + return (char *) 0; + } else if (r->op == HT_RedirectPerm) { + CTRACE((tfp, "HTRule: ...and redirect like 301 to `%s'\n", + current)); + redirecting_url = current; + permanent_redirection = TRUE; + HTPermitRedir = (BOOL) (permitredir_flag == 1); + return (char *) 0; + } + break; + + case HT_UseProxy: + if (r->equiv && 0 == strcasecomp(r->equiv, "none")) { + CTRACE((tfp, "For `%s' will not use proxy\n", current)); + proxy_none_flag = 1; + } else if (proxy_none_flag) { + CTRACE((tfp, "For `%s' proxy server ignored: %s\n", + current, + NONNULL(r->equiv))); + } else { + char *temp = NULL; + + StrAllocCopy(temp, "Proxied="); + StrAllocCat(temp, r->equiv); + StrAllocCat(temp, current); + CTRACE((tfp, "HTRule: proxy server found: %s\n", + NONNULL(r->equiv))); + FREE(current); + return temp; + } + break; + + case HT_Invalid: + case HT_Fail: /* Unauthorised */ + CTRACE((tfp, "HTRule: *** FAIL `%s'\n", current)); + FREE(current); + return (char *) 0; + } /* if tail matches ... switch operation */ + + } /* loop over rules */ + + if (proxy_none_flag) { + char *temp = NULL; + + StrAllocCopy(temp, "NoProxy="); + StrAllocCat(temp, current); + FREE(current); + return temp; + } + + return current; +} + +/* Load one line of configuration + * ------------------------------ + * + * Call this, for example, to load a X resource with config info. + * + * returns 0 OK, < 0 syntax error. + */ +int HTSetConfiguration(char *config) +{ + HTRuleOp op; + char *line = NULL; + char *pointer = NULL; + char *word1; + const char *word2; + const char *word3; + const char *cond_op = NULL; + const char *cond = NULL; + float quality, secs, secs_per_byte; + long maxbytes; + int status; + + StrAllocCopy(line, config); + if (line != NULL) { + char *p = line; + + /* Chop off comments */ + while ((p = StrChr(p, '#'))) { + if (p == line || isspace(UCH(*(p - 1)))) { + *p = 0; + break; + } else { + p++; + } + } + } + pointer = line; + word1 = HTNextField(&pointer); + if (!word1) { + FREE(line); + return 0; + }; /* Comment only or blank */ + + word2 = HTNextField(&pointer); + + if (0 == strcasecomp(word1, "defprot") || + 0 == strcasecomp(word1, "protect")) + word3 = pointer; /* The rest of the line to be parsed by AA module */ + else + word3 = HTNextField(&pointer); /* Just the next word */ + + if (!word2) { + fprintf(stderr, "HTRule: %s %s\n", RULE_NEEDS_DATA, line); + FREE(line); + return -2; /*syntax error */ + } + + if (0 == strcasecomp(word1, "suffix")) { + char *encoding = HTNextField(&pointer); + + status = 0; + if (pointer) + status = LYscanFloat(pointer, &quality); + + HTSetSuffix(word2, word3, + encoding ? encoding : "binary", + status >= 1 ? quality : (float) 1.0); + + } else if (0 == strcasecomp(word1, "presentation")) { + status = 0; + if (pointer) { + const char *temp = pointer; + + if (LYscanFloat2(&temp, &quality)) { + status = 1; + if (LYscanFloat2(&temp, &secs)) { + status = 2; + if (LYscanFloat2(&temp, &secs_per_byte)) { + status = 3; + if (sscanf(temp, "%ld", &maxbytes)) { + status = 4; + } + } + } + } + } + + HTSetPresentation(word2, word3, NULL, + status >= 1 ? quality : 1.0, + status >= 2 ? secs : 0.0, + status >= 3 ? secs_per_byte : 0.0, + status >= 4 ? maxbytes : 0, + mediaCFG); + + } else if (0 == strncasecomp(word1, "htbin", 5) || + 0 == strncasecomp(word1, "bindir", 6)) { + StrAllocCopy(HTBinDir, word2); /* Physical /htbin location */ + + } else if (0 == strncasecomp(word1, "search", 6)) { + StrAllocCopy(HTSearchScript, word2); /* Search script name */ + + } else { + op = 0 == strcasecomp(word1, "map") ? HT_Map + : 0 == strcasecomp(word1, "pass") ? HT_Pass + : 0 == strcasecomp(word1, "fail") ? HT_Fail + : 0 == strcasecomp(word1, "redirect") ? HT_Redirect + : 0 == strncasecomp(word1, "redirectperm", 12) ? HT_RedirectPerm + : 0 == strcasecomp(word1, "redirecttemp") ? HT_Redirect + : 0 == strcasecomp(word1, "permitredirection") ? HT_PermitRedir + : 0 == strcasecomp(word1, "useproxy") ? HT_UseProxy + : 0 == strcasecomp(word1, "alert") ? HT_Alert + : 0 == strcasecomp(word1, "alwaysalert") ? HT_AlwaysAlert + : 0 == strcasecomp(word1, "progress") ? HT_Progress + : 0 == strcasecomp(word1, "usermsg") ? HT_UserMsg + : 0 == strcasecomp(word1, "infomsg") ? HT_InfoMsg + : 0 == strcasecomp(word1, "defprot") ? HT_DefProt + : 0 == strcasecomp(word1, "protect") ? HT_Protect + : HT_Invalid; + if (op == HT_Invalid) { + fprintf(stderr, "HTRule: %s '%s'\n", RULE_INCORRECT, config); + } else { + switch (op) { + case HT_Fail: /* never a or other 2nd parameter */ + case HT_PermitRedir: + cond_op = word3; + if (cond_op && *cond_op) { + word3 = NULL; + cond = HTNextField(&pointer); + } + break; + + case HT_Pass: /* possibly a URL2 */ + if (word3 && (!strcasecomp(word3, "if") || + !strcasecomp(word3, "unless"))) { + cond_op = word3; + word3 = NULL; + cond = HTNextField(&pointer); + break; + } + /* else fall through */ + case HT_Map: /* always a URL2 (or other 2nd parameter) */ + case HT_Redirect: + case HT_RedirectPerm: + case HT_UseProxy: + cond_op = HTNextField(&pointer); + /* check for extra status word in "Redirect" */ + if (op == HT_Redirect && 0 == strcasecomp(word1, "redirect") && + cond_op && + strcasecomp(cond_op, "if") && + strcasecomp(cond_op, "unless")) { + if (0 == strcmp(word2, "301") || + 0 == strcasecomp(word2, "permanent")) { + op = HT_RedirectPerm; + } else if (!(0 == strcmp(word2, "302") || + 0 == strcmp(word2, "303") || + 0 == strcasecomp(word2, "temp") || + 0 == strcasecomp(word2, "seeother"))) { + CTRACE((tfp, "Rule: Ignoring `%s' in Redirect\n", word2)); + } + word2 = word3; + word3 = cond_op; /* cond_op isn't condition op after all */ + cond_op = HTNextField(&pointer); + } + if (cond_op && *cond_op) + cond = HTNextField(&pointer); + break; + + case HT_Progress: + case HT_InfoMsg: + case HT_UserMsg: + case HT_Alert: + case HT_AlwaysAlert: + cond_op = HTNextField(&pointer); + if (cond_op && *cond_op) + cond = HTNextField(&pointer); + if (word3) { /* Fix string with too may %s - kw */ + const char *cp = word3; + char *cp1, *cp2; + + while ((cp1 = StrChr(cp, '%'))) { + if (cp1[1] == '\0') { + *cp1 = '\0'; + break; + } else if (cp1[1] == '%') { + cp = cp1 + 2; + continue; + } else + while ((cp2 = StrChr(cp1 + 2, '%'))) { + if (cp2[1] == '\0') { + *cp2 = '\0'; + break; + } else if (cp2[1] == '%') { + cp1 = cp2; + } else { + *cp2 = '?'; /* replace bad % */ + cp1 = cp2; + } + } + break; + } + } + break; + + default: + break; + } + if (cond_op && cond && *cond && !strcasecomp(cond_op, "unless")) { + cond_op = "unless"; + } else if (cond_op && cond && *cond && + !strcasecomp(cond_op, "if")) { + cond_op = "if"; + } else if (cond_op || cond) { + fprintf(stderr, "HTRule: %s '%s'\n", RULE_INCORRECT, config); + FREE(line); /* syntax error, condition is a mess - kw */ + return -2; /* NB unrecognized cond passes here - kw */ + } + if (cond && !strncasecomp(cond, "redirected", (int) strlen(cond))) { + cond = "redirected"; /* recognized, canonical case - kw */ + } else if (cond && strlen(cond) >= 8 && + !strncasecomp(cond, "userspecified", (int) strlen(cond))) { + cond = "userspec"; /* also allow abbreviation - kw */ + } + HTAddRule(op, word2, word3, cond_op, cond); + } + } + FREE(line); + return 0; +} + +/* Load the rules from a file HTLoadRules() + * -------------------------- + * + * On entry, + * Rules can be in any state + * On exit, + * Any existing rules will have been kept. + * Any new rules will have been loaded. + * Returns 0 if no error, 0 if error! + * + * Bugs: + * The strings may not contain spaces. + */ + +int HTLoadRules(const char *filename) +{ + FILE *fp = fopen(filename, TXT_R); + char line[LINE_LENGTH + 1]; + + if (!fp) { + CTRACE((tfp, "HTRules: Can't open rules file %s\n", filename)); + return -1; /* File open error */ + } + for (;;) { + if (!fgets(line, LINE_LENGTH + 1, fp)) + break; /* EOF or error */ + (void) HTSetConfiguration(line); + } + fclose(fp); + return 0; /* No error or syntax errors ignored */ +} + +#endif /* NO_RULES */ |