NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

bin/52772: httpd should allow remapping of paths



>Number:         52772
>Category:       bin
>Synopsis:       httpd should allow remapping of paths
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Nov 29 11:35:00 +0000 2017
>Originator:     Martin Husemann
>Release:        NetBSD 8.99.7
>Organization:
The NetBSD Foundation, Inc.
>Environment:
System: NetBSD seven-days-to-the-wolves.aprisoft.de 8.99.7 NetBSD 8.99.7 (GENERIC) #177: Thu Nov 23 09:03:25 CET 2017 martin%seven-days-to-the-wolves.aprisoft.de@localhost:/work/src/sys/arch/amd64/compile/GENERIC amd64
Architecture: x86_64
Machine: amd64
>Description:

I have to deal with a very stupid consumer appliance with broken firmware.
It requests data from a server I run, and the configuration part of the
appliances user interface is broken, so users can not configure the url
for the service properly (but parts of it are hardcoded).

The appliance does also not properly follow redirects for this request.

It would be very usefull if bozohttpd could rewrite the requested paths
befor applying authorization. I considered doing a command line option
for each rewrite rule, but this does not scale well and it is hard to
do different remapping rules per virtual host.

So I ended up doing a simmple remap table ".bzremap" in a file in the
(virtual) slash dir of the host. It looks like:

/requested/path:/re/mapped/to/this.html

The file is completely mmaped(), assuming it should be pretty short.
If the number of remap rules is big, we should probably use a .cdb file
instead.

Comments and reviews welcome!

>How-To-Repeat:
n/A

>Fix:

Here is a patch implementing this feature.

Index: bozohttpd.8
===================================================================
RCS file: /cvsroot/src/libexec/httpd/bozohttpd.8,v
retrieving revision 1.68
diff -u -p -r1.68 bozohttpd.8
--- bozohttpd.8	28 Nov 2017 12:22:27 -0000	1.68
+++ bozohttpd.8	29 Nov 2017 11:23:02 -0000
@@ -489,6 +489,30 @@ will redirect to
 Otherwise provided schema will be used i.e. symbolic link to
 .Em ftp://NetBSD.org/
 will redirect to the provided URL.
+If a
+.Pa .bzremap
+file is found at the root of a (virtual) server, it is expected to contain
+rewrite mappings for URLs.
+.Pp
+These remappings are performed internally in the server before authentication
+happens and can be used to hide implementation details, like the CGI handler
+specific suffix for non cgi scripts in authorized directories.
+.Pp
+The map file consists of lines two paths separated by a colon, where the left
+side needs to exactly match a (sub) path of the request and will be replaced
+by the right side.
+.Pp
+The first match always wins.
+.Pp
+A
+.Pa .bzremap
+file could look like this:
+.Bd -literal
+/nic/update:/auth-dir/updipv4.pl
+.Ed
+.Pp
+The remap file shold be short, access to it is slow and needs to happen
+on each request.
 .Sh EXAMPLES
 To configure set of virtual hosts, one would use an
 .Xr inetd.conf 5
Index: bozohttpd.c
===================================================================
RCS file: /cvsroot/src/libexec/httpd/bozohttpd.c,v
retrieving revision 1.86
diff -u -p -r1.86 bozohttpd.c
--- bozohttpd.c	5 Feb 2017 01:55:03 -0000	1.86
+++ bozohttpd.c	29 Nov 2017 11:23:02 -0000
@@ -120,6 +120,9 @@
 #ifndef ABSREDIRECT_FILE
 #define ABSREDIRECT_FILE	".bzabsredirect"
 #endif
+#ifndef REMAP_FILE
+#define REMAP_FILE		".bzremap"
+#endif
 #ifndef PUBLIC_HTML
 #define PUBLIC_HTML		"public_html"
 #endif
@@ -1068,6 +1071,109 @@ head:
 #endif /* !NO_USER_SUPPORT */
 }
 
+static void
+check_mapping(bozo_httpreq_t *request)
+{
+	bozohttpd_t *httpd = request->hr_httpd;
+	char *file = request->hr_file, *newfile;
+	void *fmap;
+	const char *replace, *map_to, *p;
+	struct stat st;
+	int mapfile;
+	size_t avail, len, rlen, flen;
+
+	mapfile = open(REMAP_FILE, O_RDONLY, 0);
+	if (mapfile == -1) return;
+	debug((httpd, DEBUG_FAT, "remap file found"));
+	if (fstat(mapfile, &st) == -1) {
+		bozowarn(httpd, "could not stat " REMAP_FILE);
+		close(mapfile);
+		return;
+	}
+
+	fmap = mmap(NULL, st.st_size, PROT_READ, 0, mapfile, 0);
+	if (fmap == NULL) {
+		bozowarn(httpd, "could not mmap " REMAP_FILE ", error %d",
+		    errno);
+		close(mapfile);
+		return;
+	}
+	flen = strlen(file);
+	for (p = fmap, avail = st.st_size; avail; ) {
+		/*
+		 * We have lines like:
+		 *   /this/url:/replacement/that/url
+		 * If we find a matching left hand side, replace will point
+		 * to it nad len will be its length. map_to will point to
+		 * the right hand side and rlen wil be its length.
+		 * If we have no match, both pointers will be NULL.
+		 */
+
+		/* skip empty lines */
+		while ((*p == '\r' || *p == '\n') && avail) {
+			p++;
+			avail--;
+		}
+		replace = p;
+		while (*p != ':' && *p != '\r' && *p != '\n' && avail) {
+			p++;
+			avail--;
+		}
+		if (!avail || *p != ':') {
+			replace = NULL;
+			map_to = NULL;
+			break;
+		}
+		len = p-replace;
+		/*
+		 * flen < len: the left hand side is too long, can't be a
+		 *   match
+		 * flen == len: full string has to match
+		 * flen > len: make sure there is a path separator at 'len'
+		 * avail < 2: we are at eof, missing right hand side
+		 */
+		if (avail < 2 || flen < len || 
+		    (flen == len && memcmp(file, replace, len) != 0) ||
+		    (flen > len
+			 && (file[len] != '/' ||
+			     memcmp(file, replace, len) != 0))) {
+
+			/* non-match, skip to end of line and continue */
+			while (*p != '\r' && *p != '\n' && avail) {
+				p++;
+				avail--;
+			}
+			replace = NULL;
+			map_to = NULL;
+			continue;
+		}
+		p++;
+		avail--;
+
+		/* found a match, parse the target */
+		map_to = p;
+		while (*p != '\r' && *p != '\n' && avail) {
+			p++;
+			avail--;
+		}
+		rlen = p - map_to;
+		break;
+	}
+
+	if (replace && map_to) {
+		newfile = bozomalloc(httpd, strlen(file) + rlen - len + 1);
+		memcpy(newfile, map_to, rlen);
+		strcpy(newfile+rlen, file + len);
+		debug((httpd, DEBUG_NORMAL, "remapping found ``%s'' ",
+		    newfile));
+		free(request->hr_file);
+		request->hr_file = newfile;
+	}
+
+	munmap(fmap, st.st_size);
+	close(mapfile);
+}
+
 /*
  * deal with virtual host names; we do this:
  *	if we have a virtual path root (httpd->virtbase), and we are given a
@@ -1191,6 +1297,12 @@ use_slashdir:
 	if (chdir(s) < 0)
 		return bozo_http_error(httpd, 404, request,
 					"can't chdir to slashdir");
+
+	/*
+	 * is there a mapping for this request?
+	 */
+	check_mapping(request);
+
 	return 0;
 }
 



Home | Main Index | Thread Index | Old Index