about summary refs log tree commit diff stats
path: root/WWW/Library/Implementation/HTRules.c
diff options
context:
space:
mode:
Diffstat (limited to 'WWW/Library/Implementation/HTRules.c')
-rw-r--r--WWW/Library/Implementation/HTRules.c705
1 files changed, 705 insertions, 0 deletions
diff --git a/WWW/Library/Implementation/HTRules.c b/WWW/Library/Implementation/HTRules.c
new file mode 100644
index 00000000..35b36719
--- /dev/null
+++ b/WWW/Library/Implementation/HTRules.c
@@ -0,0 +1,705 @@
+/*
+ * $LynxId: HTRules.c,v 1.42 2010/06/17 21:33:35 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");
+
+    assert(temp != NULL);
+
+    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 */
+	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;
+	    }
+	    /* Else fall through ...to map and pass */
+
+	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 = line;
+    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);
+    {
+	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 */