Source-Changes-HG archive

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

[src/trunk]: src/libexec/httpd Add support for remapping requested paths via ...



details:   https://anonhg.NetBSD.org/src/rev/7a5a7ab53d4d
branches:  trunk
changeset: 364083:7a5a7ab53d4d
user:      martin <martin%NetBSD.org@localhost>
date:      Fri Aug 24 11:41:16 2018 +0000

description:
Add support for remapping requested paths via a .bzredirect file.
Fixes PR 52772. Ok: mrg@

diffstat:

 libexec/httpd/bozohttpd.8             |   35 ++++++-
 libexec/httpd/bozohttpd.c             |  171 +++++++++++++++++++++++++++++++++-
 libexec/httpd/testsuite/Makefile      |    2 +-
 libexec/httpd/testsuite/data/.bzremap |    2 +
 libexec/httpd/testsuite/t12.in        |    2 +
 libexec/httpd/testsuite/t12.out       |   11 ++
 libexec/httpd/testsuite/t13.in        |    2 +
 libexec/httpd/testsuite/t13.out       |   11 ++
 8 files changed, 231 insertions(+), 5 deletions(-)

diffs (truncated from 335 to 300 lines):

diff -r fdb14c252e52 -r 7a5a7ab53d4d libexec/httpd/bozohttpd.8
--- a/libexec/httpd/bozohttpd.8 Fri Aug 24 10:04:41 2018 +0000
+++ b/libexec/httpd/bozohttpd.8 Fri Aug 24 11:41:16 2018 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: bozohttpd.8,v 1.68 2017/11/28 12:22:27 wiz Exp $
+.\"    $NetBSD: bozohttpd.8,v 1.69 2018/08/24 11:41:16 martin Exp $
 .\"
 .\"    $eterna: bozohttpd.8,v 1.101 2011/11/18 01:25:11 mrg Exp $
 .\"
@@ -489,6 +489,37 @@
 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 should be short, access to it is slow and needs to happen
+on each request.
+If a request path needs to include a colon 
+.Pq Li \&:
+character, it can be escaped
+with a backslash
+.Pq Li \e
+The right hand side of the colon is always used verbatim, no escape sequences
+are interpreted.
 .Sh EXAMPLES
 To configure set of virtual hosts, one would use an
 .Xr inetd.conf 5
@@ -554,7 +585,7 @@
 and regular code audits.
 This manual documents
 .Nm
-version 20170201.
+version 20180824.
 .Sh AUTHORS
 .An -nosplit
 .Nm
diff -r fdb14c252e52 -r 7a5a7ab53d4d libexec/httpd/bozohttpd.c
--- a/libexec/httpd/bozohttpd.c Fri Aug 24 10:04:41 2018 +0000
+++ b/libexec/httpd/bozohttpd.c Fri Aug 24 11:41:16 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: bozohttpd.c,v 1.87 2018/01/28 13:37:39 maya Exp $      */
+/*     $NetBSD: bozohttpd.c,v 1.88 2018/08/24 11:41:16 martin Exp $    */
 
 /*     $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $      */
 
@@ -109,7 +109,7 @@
 #define INDEX_HTML             "index.html"
 #endif
 #ifndef SERVER_SOFTWARE
-#define SERVER_SOFTWARE                "bozohttpd/20170201"
+#define SERVER_SOFTWARE                "bozohttpd/20180824"
 #endif
 #ifndef DIRECT_ACCESS_FILE
 #define DIRECT_ACCESS_FILE     ".bzdirect"
@@ -120,6 +120,15 @@
 #ifndef ABSREDIRECT_FILE
 #define ABSREDIRECT_FILE       ".bzabsredirect"
 #endif
+#ifndef REMAP_FILE
+#define REMAP_FILE             ".bzremap"
+#endif
+
+/*
+ * When you add some .bz* file, make sure to also check it in
+ * bozo_check_special_files()
+ */
+
 #ifndef PUBLIC_HTML
 #define PUBLIC_HTML            "public_html"
 #endif
@@ -149,6 +158,7 @@
 #include <signal.h>
 #include <stdarg.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <string.h>
 #include <syslog.h>
 #include <time.h>
@@ -1069,6 +1079,154 @@
 }
 
 /*
+ * Like strncmp(), but s_esc may contain characters escaped by \.
+ * The len argument does not include the backslashes used for escaping,
+ * that is: it gives the raw len, after unescaping the string.
+ */
+static int
+esccmp(const char *s_plain, const char *s_esc, size_t len)
+{
+       bool esc = false;
+
+       while (len) {
+               if (!esc && *s_esc == '\\') {
+                       esc = true;
+                       s_esc++;
+                       continue;
+               }
+               esc = false;
+               if (*s_plain == 0 || *s_esc == 0 || *s_plain != *s_esc)
+                       return *s_esc - *s_plain;
+               s_esc++;
+               s_plain++; 
+               len--;
+       }
+       return 0;
+}
+
+/*
+ * Check if the request refers to a uri that is mapped via a .bzremap.
+ * We have  /requested/path:/re/mapped/to/this.html lines in there,
+ * and the : separator may be use in the left hand side escaped with
+ * \ to encode a path containig a : character.
+ */
+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, reqlen, num_esc = 0;
+       bool escaped = false;
+
+       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 ", errno: %d",
+                   errno);
+               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;
+       }
+       reqlen = 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 and 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;
+               escaped = false;
+               while (avail) {
+                       if (*p == '\r' || *p == '\n')
+                               break;
+                       if (!escaped && *p == ':')
+                               break;
+                       if (escaped) {
+                               escaped = false;
+                               num_esc++;
+                       } else if (*p == '\\') {
+                               escaped = true;
+                       }
+                       p++;
+                       avail--;
+               }
+               if (!avail || *p != ':') {
+                       replace = NULL;
+                       map_to = NULL;
+                       break;
+               }
+               len = p - replace - num_esc;
+               /*
+                * reqlen < len: the left hand side is too long, can't be a
+                *   match
+                * reqlen == len: full string has to match
+                * reqlen > len: make sure there is a path separator at 'len'
+                * avail < 2: we are at eof, missing right hand side
+                */
+               if (avail < 2 || reqlen < len || 
+                   (reqlen == len && esccmp(file, replace, len) != 0) ||
+                   (reqlen > len && (file[len] != '/' ||
+                                       esccmp(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
  *     virtual host spec (Host: ho.st or http://ho.st/), see if this
@@ -1191,6 +1349,12 @@
        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;
 }
 
@@ -1707,6 +1871,9 @@
        if (strcmp(name, ABSREDIRECT_FILE) == 0)
                return bozo_http_error(httpd, 403, request,
                    "no permission to open redirect file");
+       if (strcmp(name, REMAP_FILE) == 0)
+               return bozo_http_error(httpd, 403, request,
+                   "no permission to open redirect file");
        return bozo_auth_check_special_files(request, name);
 }
 
diff -r fdb14c252e52 -r 7a5a7ab53d4d libexec/httpd/testsuite/Makefile
--- a/libexec/httpd/testsuite/Makefile  Fri Aug 24 10:04:41 2018 +0000
+++ b/libexec/httpd/testsuite/Makefile  Fri Aug 24 11:41:16 2018 +0000
@@ -1,6 +1,6 @@
 #      $eterna: Makefile,v 1.14 2009/05/22 21:51:39 mrg Exp $
 
-SIMPLETESTS=   t1 t2 t3 t4 t5 t6 t7 t8 t9 t10
+SIMPLETESTS=   t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t12 t13
 CGITESTS=      t11
 BIGFILETESTS=  partial4000 partial8000
 
diff -r fdb14c252e52 -r 7a5a7ab53d4d libexec/httpd/testsuite/data/.bzremap
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/libexec/httpd/testsuite/data/.bzremap     Fri Aug 24 11:41:16 2018 +0000
@@ -0,0 +1,2 @@
+/nic/update:/auth-dir/updipv4.pl
+/update\:all:/auth-dir/updall.pl
diff -r fdb14c252e52 -r 7a5a7ab53d4d libexec/httpd/testsuite/t12.in
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/libexec/httpd/testsuite/t12.in    Fri Aug 24 11:41:16 2018 +0000
@@ -0,0 +1,2 @@
+get /nic/update HTTP/1.1
+Host:
diff -r fdb14c252e52 -r 7a5a7ab53d4d libexec/httpd/testsuite/t12.out



Home | Main Index | Thread Index | Old Index