Sophie

Sophie

distrib > Mageia > 5 > i586 > media > core-updates-src > by-pkgid > deecb6b6a05b8293e284be1ad9b5f073 > files > 9

xymon-4.3.17-5.1.mga5.src.rpm

--- a/lib/cgi.c
+++ b/lib/cgi.c
@@ -252,6 +252,71 @@ cgidata_t *cgi_request(void)
 	return head;
 }
 
+char *csp_header(const char *str)
+{
+	char *csppol = NULL;
+	char *returnstr = NULL;
+
+	if (getenv("XYMON_NOCSPHEADER")) return NULL;
+	
+	if      (strncmp(str, "enadis", 6) == 0) csppol = strdup("script-src 'self' 'unsafe-inline'; connect-src 'self'; form-action 'self'; sandbox allow-forms allow-scripts;");
+	else if (strncmp(str, "useradm", 7) == 0) csppol = strdup("script-src 'self'; connect-src 'self'; form-action 'self';");
+	else if (strncmp(str, "chpasswd", 8) == 0) csppol = strdup("script-src 'self'; connect-src 'self'; form-action 'self';");
+	else if (strncmp(str, "ackinfo", 7) == 0) csppol = strdup("script-src 'self'; connect-src 'self'; form-action 'self';");
+	else if (strncmp(str, "acknowledge", 11) == 0) csppol = strdup("script-src 'self'; connect-src 'self'; form-action 'self';");
+	else if (strncmp(str, "criticaleditor", 14) == 0) csppol = strdup("script-src 'self'; connect-src 'self'; form-action 'self';");
+	else if (strncmp(str, "svcstatus", 9) == 0) csppol = strdup("script-src 'self'; connect-src 'self'; form-action 'self'; sandbox allow-forms;");
+	else if (strncmp(str, "historylog", 10) == 0) csppol = strdup("script-src 'self'; connect-src 'self'; form-action 'self'; sandbox allow-forms;");
+	else {
+		errprintf(" csp_header: page %s not listed, no CSP returned\n", str);
+	}
+	if ((!csppol) || (*csppol == '\0')) return NULL;
+	returnstr = (char *)malloc(3 * strlen(csppol) + 512);
+	snprintf(returnstr, (3 * strlen(csppol) + 512), "Content-Security-Policy: %s\nX-Content-Security-Policy: %s\nX-Webkit-CSP: %s\n", csppol, csppol, csppol);
+	dbgprintf("CSP return is %s", returnstr);
+	return returnstr;
+}
+
+int cgi_refererok(char *expected)
+{
+	static char cgi_checkstr[1024];
+	int isok = 0;
+	char *p, *httphost;
+
+	p = getenv("HTTP_REFERER");
+	dbgprintf(" - checking if referer is OK (http_referer: %s, http_host: %s, xymonwebhost: %s, checkstr: %s\n", textornull(p), textornull(getenv("HTTP_HOST")),  textornull(xgetenv("XYMONWEBHOST")), textornull(expected));
+	if (!p) return 0;
+
+	/* If passed NULL, just check that there _is_ a REFERER */
+	if (!expected) return 1;
+
+	httphost = getenv("HTTP_HOST");
+	if (!httphost) {
+		if (strcmp(xgetenv("XYMONWEBHOST"), "http://localhost") != 0) {
+			/* If XYMONWEBHOST is set by the admin, use that */
+			snprintf(cgi_checkstr, sizeof(cgi_checkstr), "%s%s", getenv("XYMONWEBHOST"), expected);
+			if (strncmp(p, cgi_checkstr, strlen(cgi_checkstr)) == 0) isok = 1;
+		}
+		else {
+			errprintf("Disallowed request due to missing HTTP_HOST variable\n");
+			return 0;
+		}
+	}
+	else {
+		/* skip the protocol specifier, which HTTP_REFERER has but HTTP_HOST doesn't */
+		p += (strncasecmp(p, "https://", 8) == 0) ? 8 : (strncasecmp(p, "http://", 7) == 0) ? 7 : 0;
+
+		if (*p == '\0') { errprintf("Disallowed request due to unexpected referer '%s'\n", getenv("HTTP_REFERER")); return 0; }
+
+		snprintf(cgi_checkstr, sizeof(cgi_checkstr), "%s%s", httphost, expected);
+		if (strncmp(p, cgi_checkstr, strlen(cgi_checkstr)) == 0) isok = 1;
+	}
+	
+	if (!isok) errprintf("Disallowed request due to unexpected referer '%s', wanted '%s' (originally '%s')\n", p, cgi_checkstr, expected);
+
+	return isok;
+}
+
 char *get_cookie(char *cookiename)
 {
 	static char *ckdata = NULL;
--- a/lib/cgi.h
+++ b/lib/cgi.h
@@ -23,6 +23,8 @@ extern enum cgi_method_t cgi_method;
 
 extern char *cgi_error(void);
 extern cgidata_t *cgi_request(void);
+extern char *csp_header(const char *pagename); 
+extern int cgi_refererok(char *expected); 
 extern char *get_cookie(char *cookiename);
 
 #endif
--- a/web/criticaleditor.c
+++ b/web/criticaleditor.c
@@ -389,6 +389,18 @@ int main(int argc, char *argv[])
 	}
 
 	redirect_cgilog("criticaleditor");
+
+        /* We only want to accept posts from certain pages */
+	{
+		char cgisource[1024]; char *p;
+		p = csp_header("criticaleditor"); if (p) fprintf(stdout, "%s", p);
+		snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "criticaleditor");
+		if (!cgi_refererok(cgisource)) {
+			fprintf(stdout, "Location: %s.sh?\n\n", cgisource);
+			return 0;
+		}
+	}
+
 	parse_query();
 	load_critconfig(configfn);
 
--- a/web/acknowledge.c
+++ b/web/acknowledge.c
@@ -359,6 +359,18 @@ int main(int argc, char *argv[])
 		strbuffer_t *response = newstrbuffer(0);
 		int count = 0;
 
+
+		/* We only want to accept posts from certain pages */
+		{ 
+			char cgisource[1024]; char *p;
+			p = csp_header("acknowledge"); if (p) fprintf(stdout, "%s", p);
+			snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "acknowledge");
+			if (!cgi_refererok(cgisource)) {
+				fprintf(stdout, "Location: %s.sh?\n\n", cgisource);
+				return 0;
+			}
+		}
+
 		parse_query();
 		if (getenv("REMOTE_USER")) {
 			char *remaddr = getenv("REMOTE_ADDR");
--- a/web/useradm.c
+++ b/web/useradm.c
@@ -75,6 +75,14 @@ int parse_query(void)
 		cwalk = cwalk->next;
 	}
 
+	/* We only want to accept posts from certain pages */
+	if (returnval != ACT_NONE) {
+		char cgisource[1024]; char *p;
+		p = csp_header("useradm"); if (p) fprintf(stdout, "%s", p);
+		snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "useradm");
+		if (!cgi_refererok(cgisource)) { fprintf(stdout, "Location: %s.sh?\n\n", cgisource); return 0; }
+	}
+
 	return returnval;
 }
 
--- a/web/enadis.c
+++ b/web/enadis.c
@@ -68,6 +68,23 @@ void parse_cgi(void)
 	postdata = cgi_request();
 	if (cgi_method == CGI_GET) return;
 
+
+	/* We only want to accept posts from certain pages: svcstatus (for info), and ourselves */
+	/* At some point in the future, moving info lookups to their own page would be a good idea */
+	{
+		char cgisource[1024]; char *p;
+		p = csp_header("enadis"); if (p) fprintf(stdout, "%s", p);
+		snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "enadis");
+		if (!cgi_refererok(cgisource)) {
+			snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("CGIBINURL"), "svcstatus");
+			if (!cgi_refererok(cgisource)) {
+				dbgprintf("Not coming from self or svcstatus; abort\n");
+				return;	/* Just display, don't do anything */
+			}
+		}
+	}
+
+
 	if (!postdata) {
 		errormsg(cgi_error());
 	}
--- a/web/ackinfo.c
+++ b/web/ackinfo.c
@@ -92,6 +92,18 @@ int main(int argc, char *argv[])
 	}
 
 	redirect_cgilog("ackinfo");
+
+	/* We only want to accept posts from certain pages */
+	{
+	    char cgisource[1024]; char *p;
+	    p = csp_header("ackinfo"); if (p) fprintf(stdout, "%s", p);
+	    snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "criticalview");
+	    if (!cgi_refererok(cgisource)) {
+		fprintf(stdout, "Location: %s.sh?\n\n", cgisource);
+		return 0;
+	    }
+	}
+
 	parse_query();
 
 	if (hostname && *hostname && testname && *testname && ((level == 0) || (validity>0)) && ackmsg && *ackmsg) {
--- a/web/svcstatus.c
+++ b/web/svcstatus.c
@@ -748,6 +748,8 @@ int main(int argc, char *argv[])
 	}
 
 	redirect_cgilog("svcstatus");
+	fprintf(stdout, "%s", csp_header("svcstatus"));
+	fprintf(stdout, "Refresh: 30\n");
 
 	*errortxt = '\0';
 	hostname = service = tstamp = NULL;