summaryrefslogtreecommitdiff
path: root/libexec/httpd
diff options
context:
space:
mode:
authorshm <shm@NetBSD.org>2015-10-28 09:20:15 +0000
committershm <shm@NetBSD.org>2015-10-28 09:20:15 +0000
commit56a69ad5cb70c5597b194c1c331407dfdab19644 (patch)
treeebc7035bdb2306903345f1b3026e76c5b2c117f8 /libexec/httpd
parentdb9d0c6c291e16dcf47577769569c34517053a75 (diff)
* add CGI support for ~user translation (-E switch)
* add redirects to ~user translation * fix bugs around ~user translation * add schema detection for absolute redirects * fixed few memory leaks * bunch of minor tweaks * removed -r support * smarter redirects OK mrg@
Diffstat (limited to 'libexec/httpd')
-rw-r--r--libexec/httpd/CHANGES10
-rw-r--r--libexec/httpd/auth-bozo.c5
-rw-r--r--libexec/httpd/bozohttpd.839
-rw-r--r--libexec/httpd/bozohttpd.c389
-rw-r--r--libexec/httpd/bozohttpd.h15
-rw-r--r--libexec/httpd/cgi-bozo.c9
-rw-r--r--libexec/httpd/dir-index-bozo.c22
-rwxr-xr-xlibexec/httpd/lua/bozo.lua5
-rw-r--r--libexec/httpd/main.c36
-rw-r--r--libexec/httpd/tilde-luzah-bozo.c46
10 files changed, 322 insertions, 254 deletions
diff --git a/libexec/httpd/CHANGES b/libexec/httpd/CHANGES
index 8eb0da78bf1..2f11017e51e 100644
--- a/libexec/httpd/CHANGES
+++ b/libexec/httpd/CHANGES
@@ -1,5 +1,15 @@
$eterna: CHANGES,v 1.78 2011/11/18 01:25:11 mrg Exp $
+changes in bozohttpd 20151028:
+ o add CGI support for ~user translation (-E switch)
+ o add redirects to ~user translation
+ o fix bugs around ~user translation
+ o add schema detection for absolute redirects
+ o fixed few memory leaks
+ o bunch of minor tweaks
+ o removed -r support
+ o smarter redirects
+
changes in bozohttpd 20150320:
o fix redirection handling
o support transport stream (.ts) and video object (.vob) files
diff --git a/libexec/httpd/auth-bozo.c b/libexec/httpd/auth-bozo.c
index 4a8dd666ea9..d0440dea6b9 100644
--- a/libexec/httpd/auth-bozo.c
+++ b/libexec/httpd/auth-bozo.c
@@ -1,4 +1,4 @@
-/* $NetBSD: auth-bozo.c,v 1.16 2014/12/26 19:52:00 mrg Exp $ */
+/* $NetBSD: auth-bozo.c,v 1.17 2015/10/28 09:20:15 shm Exp $ */
/* $eterna: auth-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $ */
@@ -190,8 +190,7 @@ bozo_auth_check_401(bozo_httpreq_t *request, int code)
if (code == 401)
bozo_printf(httpd,
"WWW-Authenticate: Basic realm=\"%s\"\r\n",
- (request && request->hr_authrealm) ?
- request->hr_authrealm : "default realm");
+ request->hr_authrealm ? request->hr_authrealm : "default realm");
}
#ifndef NO_CGIBIN_SUPPORT
diff --git a/libexec/httpd/bozohttpd.8 b/libexec/httpd/bozohttpd.8
index 876ff6bb32e..74b99b245c9 100644
--- a/libexec/httpd/bozohttpd.8
+++ b/libexec/httpd/bozohttpd.8
@@ -1,4 +1,4 @@
-.\" $NetBSD: bozohttpd.8,v 1.53 2015/08/13 12:30:08 wiz Exp $
+.\" $NetBSD: bozohttpd.8,v 1.54 2015/10/28 09:20:15 shm Exp $
.\"
.\" $eterna: bozohttpd.8,v 1.101 2011/11/18 01:25:11 mrg Exp $
.\"
@@ -111,9 +111,11 @@ is a valid CGI program in the
directory.
In other words, all CGI URL's must begin with
.Em \%/cgi-bin/ .
-Note that the CGI/1.1 interface is not available with
+Note that the CGI/1.1 interface is available with
.Em ~user
-translation.
+translation using
+.Fl E
+switch.
.It Fl e
Causes
.Nm
@@ -223,15 +225,6 @@ translations from
.Dq public_html
to
.Ar pubdir .
-.It Fl r
-Forces pages besides the
-.Dq index.html
-(see the
-.Fl X
-option) page to require that the Referrer: header be present and
-refer to this web server, otherwise a redirect to the
-.Dq index.html
-page will be returned instead.
.It Fl S Ar server_software
Sets the internal server version to
.Ar server_software .
@@ -270,6 +263,12 @@ into the directory
(but see the
.Fl p
option above).
+.It Fl E
+Enables CGI/1.1 interface for
+.Em ~user
+translation.
+Note that enabling this support implies that users can run
+commands as web server user, this may have security implications.
.It Fl V
Sets the default virtual host directory to
.Ar slashdir .
@@ -462,12 +461,23 @@ symbolic link is found,
.Nm
will perform a smart redirect to the target of this symlink.
The target is assumed to live on the same server.
+If target starts with slash then absolute redirection is performed,
+otherwise it's handled as relative.
If a
.Pa .bzabsredirect
symbolic link is found,
.Nm
will redirect to the absolute url pointed to by this symlink.
This is useful to redirect to different servers.
+Two forms of redirection are supported - symbolic link without schema will use
+.Em http://
+as default i.e. link to
+.Em NetBSD.org
+will redirect to
+.Em http://NetBSD.org/
+Otherwise provided schema will be used i.e. symbolic link to
+.Em ftp://NetBSD.org/
+will redirect to provided the URL.
.Sh EXAMPLES
To configure set of virtual hosts, one would use an
.Xr inetd.conf 5
@@ -613,7 +623,7 @@ provided man page fixes
.Aq Mt jmmv@NetBSD.org
Added the
.Fl P
-option.
+option (pidfile support) and provided some man page fixes.
.It
.An Luke Mewburn
.Aq Mt lukem@NetBSD.org
@@ -666,9 +676,6 @@ provided http authorisation fixes
provided chroot and change-to-user support, and other various fixes
.It
Coyote Point provided various CGI fixes.
-.It
-.An Julio Merino
-added pidfile support and provided some man page fixes.
.El
.Pp
There are probably others I have forgotten (let me know if you care)
diff --git a/libexec/httpd/bozohttpd.c b/libexec/httpd/bozohttpd.c
index ac99fba8bd1..5b060f3aefa 100644
--- a/libexec/httpd/bozohttpd.c
+++ b/libexec/httpd/bozohttpd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: bozohttpd.c,v 1.66 2015/07/16 12:19:23 shm Exp $ */
+/* $NetBSD: bozohttpd.c,v 1.67 2015/10/28 09:20:15 shm Exp $ */
/* $eterna: bozohttpd.c,v 1.178 2011/11/18 09:21:15 mrg Exp $ */
@@ -341,6 +341,7 @@ bozo_clean_request(bozo_httpreq_t *request)
free(request->hr_oldfile);
free(request->hr_query);
free(request->hr_host);
+ bozo_user_free(request->hr_user);
bozo_auth_cleanup(request);
for (hdr = SIMPLEQ_FIRST(&request->hr_headers); hdr;
hdr = SIMPLEQ_NEXT(hdr, h_next)) {
@@ -851,10 +852,11 @@ parse_http_date(const char *val, time_t *timestamp)
/*
* given an url, encode it ala rfc 3986. ie, escape ? and friends.
* note that this function returns a static buffer, and thus needs
- * to be updated for any sort of parallel processing.
+ * to be updated for any sort of parallel processing. escape only
+ * chosen characters for absolute redirects
*/
char *
-bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url)
+bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url, int absolute)
{
static char *buf;
static size_t buflen = 0;
@@ -868,11 +870,6 @@ bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url)
buf = bozorealloc(httpd, buf, buflen);
}
- if (url == NULL) {
- buf[0] = 0;
- return buf;
- }
-
for (len = 0, s = url, d = buf; *s;) {
if (*s & 0x80)
goto encode_it;
@@ -895,15 +892,18 @@ bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url)
case ';':
case '=':
case '%':
+ case '"':
+ if (absolute)
+ goto leave_it;
case '\n':
case '\r':
case ' ':
- case '"':
encode_it:
snprintf(d, 4, "%%%02X", *s++);
d += 3;
len += 3;
break;
+ leave_it:
default:
*d++ = *s++;
len++;
@@ -916,56 +916,24 @@ bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url)
}
/*
- * checks to see if this request has a valid .bzdirect file. returns
- * 0 on failure and 1 on success.
- */
-static int
-check_direct_access(bozo_httpreq_t *request)
-{
- FILE *fp;
- struct stat sb;
- char dir[MAXPATHLEN], dirfile[MAXPATHLEN], *basename;
-
- snprintf(dir, sizeof(dir), "%s", request->hr_file + 1);
- debug((request->hr_httpd, DEBUG_FAT, "check_direct_access: dir %s", dir));
- basename = strrchr(dir, '/');
-
- if ((!basename || basename[1] != '\0') &&
- lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode))
- /* nothing */;
- else if (basename == NULL)
- strcpy(dir, ".");
- else {
- *basename++ = '\0';
- bozo_check_special_files(request, basename);
- }
-
- if ((size_t)snprintf(dirfile, sizeof(dirfile), "%s/%s", dir,
- DIRECT_ACCESS_FILE) >= sizeof(dirfile)) {
- bozo_http_error(request->hr_httpd, 404, request,
- "directfile path too long");
- return 0;
- }
- if (stat(dirfile, &sb) < 0 ||
- (fp = fopen(dirfile, "r")) == NULL)
- return 0;
- fclose(fp);
- return 1;
-}
-
-/*
- * do automatic redirection -- if there are query parameters for the URL
- * we will tack these on to the new (redirected) URL.
+ * do automatic redirection -- if there are query parameters or userdir for
+ * the URL we will tack these on to the new (redirected) URL.
*/
static void
handle_redirect(bozo_httpreq_t *request,
const char *url, int absolute)
{
bozohttpd_t *httpd = request->hr_httpd;
- char *urlbuf;
+ char *finalurl, *urlbuf;
+#ifndef NO_USER_SUPPORT
+ char *userbuf;
+#endif /* !NO_USER_SUPPORT */
char portbuf[20];
const char *hostname = BOZOHOST(httpd, request);
+ size_t finalurl_len;
int query = 0;
+ int absproto = 0; /* absolute redirect provides own schema
+ * eg. https:// */
if (url == NULL) {
if (asprintf(&urlbuf, "/%s/", request->hr_file) < 0)
@@ -973,7 +941,46 @@ handle_redirect(bozo_httpreq_t *request,
url = urlbuf;
} else
urlbuf = NULL;
- url = bozo_escape_rfc3986(request->hr_httpd, url);
+
+#ifndef NO_USER_SUPPORT
+ if (request->hr_user && !absolute) {
+ if (asprintf(&userbuf, "/~%s%s", request->hr_user, url) < 0)
+ bozo_err(httpd, 1, "asprintf");
+ url = userbuf;
+ } else
+ userbuf = NULL;
+#endif /* !NO_USER_SUPPORT */
+
+ if (absolute) {
+ char *sep = NULL;
+ const char *s;
+
+ /*
+ * absolute redirect may specify own protocol i.e. to redirect to
+ * another schema like https:// or ftp://. Details: RFC 3986, section
+ * 3.
+ */
+
+ /* 1. check if url contains :// */
+ sep = strstr(url, "://");
+
+ /*
+ * RFC 3986, section 3.1:
+ * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ */
+ if (sep != NULL) {
+ for (s = url; s != sep;) {
+ if (!isalnum((int)*s) && *s != '+' && *s != '-' &&
+ *s != '.')
+ break;
+ if (++s == sep) {
+ absproto = 1;
+ }
+ }
+ }
+ }
+
+ url = bozo_escape_rfc3986(request->hr_httpd, url, absolute);
if (request->hr_query && strlen(request->hr_query))
query = 1;
@@ -983,48 +990,62 @@ handle_redirect(bozo_httpreq_t *request,
request->hr_serverport);
else
portbuf[0] = '\0';
- if (absolute)
- bozo_warn(httpd, "redirecting %s", url);
- else
- bozo_warn(httpd, "redirecting %s%s%s", hostname, portbuf, url);
- debug((httpd, DEBUG_FAT, "redirecting %s", url));
+
+ /* construct final redirection url */
+ finalurl_len = strlen(url) + 1;
+ if (!absproto) {
+ /* add default schema */
+ if (httpd->sslinfo)
+ finalurl_len += sizeof("https://") - 1;
+ else
+ finalurl_len += sizeof("http://") - 1;
+ }
+ if (absolute == 0)
+ finalurl_len += strlen(hostname)+strlen(portbuf);
+ if (query)
+ finalurl_len += strlen(request->hr_query) + 1; /* byte more for ? */
+ finalurl = bozomalloc(httpd, finalurl_len);
+ strcpy(finalurl, "");
+ if (!absproto) {
+ /* add default schema */
+ if (httpd->sslinfo)
+ strlcat(finalurl, "https://", finalurl_len);
+ else
+ strlcat(finalurl, "http://", finalurl_len);
+ }
+ if (absolute == 0) {
+ strlcat(finalurl, hostname, finalurl_len);
+ strlcat(finalurl, portbuf, finalurl_len);
+ }
+ strlcat(finalurl, url, finalurl_len);
+ if (query) {
+ strlcat(finalurl, "?", finalurl_len);
+ strlcat(finalurl, request->hr_query, finalurl_len);
+ }
+
+ bozo_warn(httpd, "redirecting %s", finalurl);
+ debug((httpd, DEBUG_FAT, "redirecting %s", finalurl));
+
bozo_printf(httpd, "%s 301 Document Moved\r\n", request->hr_proto);
if (request->hr_proto != httpd->consts.http_09)
bozo_print_header(request, NULL, "text/html", NULL);
- if (request->hr_proto != httpd->consts.http_09) {
- bozo_printf(httpd, "Location: http://");
- if (absolute == 0)
- bozo_printf(httpd, "%s%s", hostname, portbuf);
- if (query) {
- bozo_printf(httpd, "%s?%s\r\n", url, request->hr_query);
- } else {
- bozo_printf(httpd, "%s\r\n", url);
- }
- }
+ if (request->hr_proto != httpd->consts.http_09)
+ bozo_printf(httpd, "Location: %s\r\n", finalurl);
bozo_printf(httpd, "\r\n");
if (request->hr_method == HTTP_HEAD)
goto head;
bozo_printf(httpd, "<html><head><title>Document Moved</title></head>\n");
bozo_printf(httpd, "<body><h1>Document Moved</h1>\n");
- bozo_printf(httpd, "This document had moved <a href=\"http://");
- if (query) {
- if (absolute)
- bozo_printf(httpd, "%s?%s", url, request->hr_query);
- else
- bozo_printf(httpd, "%s%s%s?%s", hostname,
- portbuf, url, request->hr_query);
- } else {
- if (absolute)
- bozo_printf(httpd, "%s", url);
- else
- bozo_printf(httpd, "%s%s%s", hostname,
- portbuf, url);
- }
- bozo_printf(httpd, "\">here</a>\n");
+ bozo_printf(httpd, "This document had moved <a href=\"%s\">here</a>\n",
+ finalurl);
bozo_printf(httpd, "</body></html>\n");
head:
bozo_flush(httpd, stdout);
free(urlbuf);
+ free(finalurl);
+#ifndef NO_USER_SUPPORT
+ free(userbuf);
+#endif /* !NO_USER_SUPPORT */
}
/*
@@ -1041,9 +1062,6 @@ check_virtual(bozo_httpreq_t *request)
char *file = request->hr_file, *s;
size_t len;
- if (!httpd->virtbase)
- goto use_slashdir;
-
/*
* convert http://virtual.host/ to request->hr_host
*/
@@ -1073,6 +1091,29 @@ check_virtual(bozo_httpreq_t *request)
request->hr_host[len - 3] = '\0';
len = strlen(request->hr_host);
}
+
+ if (!httpd->virtbase) {
+
+ /*
+ * if we don't use vhost support, then set virthostname if
+ * user supplied Host header. It will be used for possible
+ * redirections
+ */
+
+ if (request->hr_host) {
+ s = strrchr(request->hr_host, ':');
+ if (s != NULL)
+ /* truncate Host: as we want to copy it without port part */
+ *s = '\0';
+ request->hr_virthostname = bozostrdup(request->hr_httpd,
+ request->hr_host);
+ if (s != NULL)
+ /* fix Host: again, if we truncated it */
+ *s = ':';
+ }
+
+ goto use_slashdir;
+ }
/*
* ok, we have a virtual host, use opendir(3) to find a case
@@ -1161,16 +1202,20 @@ check_bzredirect(bozo_httpreq_t *request)
basename = strrchr(dir, '/');
if ((!basename || basename[1] != '\0') &&
- lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode))
- /* nothing */;
- else if (basename == NULL)
- strcpy(dir, ".");
- else {
+ lstat(dir, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ strcpy(path, dir);
+ } else if (basename == NULL) {
+ strcpy(path, ".");
+ strcpy(dir, "");
+ } else {
*basename++ = '\0';
bozo_check_special_files(request, basename);
+ strcpy(path, dir);
}
- if ((size_t)snprintf(redir, sizeof(redir), "%s/%s", dir,
+ debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: path %s", path));
+
+ if ((size_t)snprintf(redir, sizeof(redir), "%s/%s", path,
REDIRECT_FILE) >= sizeof(redir)) {
bozo_http_error(request->hr_httpd, 404, request,
"redirectfile path too long");
@@ -1181,7 +1226,7 @@ check_bzredirect(bozo_httpreq_t *request)
return 0;
absolute = 0;
} else {
- if((size_t)snprintf(redir, sizeof(redir), "%s/%s", dir,
+ if((size_t)snprintf(redir, sizeof(redir), "%s/%s", path,
ABSREDIRECT_FILE) >= sizeof(redir)) {
bozo_http_error(request->hr_httpd, 404, request,
"redirectfile path too long");
@@ -1208,16 +1253,15 @@ check_bzredirect(bozo_httpreq_t *request)
return 1;
/* now we have the link pointer, redirect to the real place */
- if (absolute)
- finalredir = redirpath;
- else {
- if ((size_t)snprintf(finalredir = redir, sizeof(redir), "/%s/%s",
- dir, redirpath) >= sizeof(redir)) {
+ if (!absolute && redirpath[0] != '/') {
+ if ((size_t)snprintf(finalredir = redir, sizeof(redir), "%s%s/%s",
+ (strlen(dir) > 0 ? "/" : ""), dir, redirpath) >= sizeof(redir)) {
bozo_http_error(request->hr_httpd, 404, request,
"redirect path too long");
return -1;
}
- }
+ } else
+ finalredir = redirpath;
debug((request->hr_httpd, DEBUG_FAT,
"check_bzredirect: new redir %s", finalredir));
@@ -1300,7 +1344,6 @@ fix_url_percent(bozo_httpreq_t *request)
* transform_request does this:
* - ``expand'' %20 crapola
* - punt if it doesn't start with /
- * - check httpd->untrustedref / referrer
* - look for "http://myname/" and deal with it.
* - maybe call bozo_process_cgi()
* - check for ~user and call bozo_user_transform() if so
@@ -1318,7 +1361,6 @@ transform_request(bozo_httpreq_t *request, int *isindex)
bozohttpd_t *httpd = request->hr_httpd;
char *file, *newfile = NULL;
size_t len;
- const char *hostname = BOZOHOST(httpd, request);
file = NULL;
*isindex = 0;
@@ -1340,84 +1382,46 @@ transform_request(bozo_httpreq_t *request, int *isindex)
while (file[1] == '/')
file++;
- switch(check_bzredirect(request)) {
- case -1:
- goto bad_done;
- case 1:
- return 0;
- }
-
- if (httpd->untrustedref) {
- int to_indexhtml = 0;
-
-#define TOP_PAGE(x) (strcmp((x), "/") == 0 || \
- strcmp((x) + 1, httpd->index_html) == 0 || \
- strcmp((x) + 1, "favicon.ico") == 0)
-
- debug((httpd, DEBUG_EXPLODING, "checking httpd->untrustedref"));
- /*
- * first check that this path isn't allowed via .bzdirect file,
- * and then check referrer; make sure that people come via the
- * real name... otherwise if we aren't looking at / or
- * /index.html, redirect... we also special case favicon.ico.
- */
- if (check_direct_access(request))
- /* nothing */;
- else if (request->hr_referrer) {
- const char *r = request->hr_referrer;
-
- debug((httpd, DEBUG_FAT,
- "checking referrer \"%s\" vs virthostname %s",
- r, hostname));
- if (strncmp(r, "http://", 7) != 0 ||
- (strncasecmp(r + 7, hostname,
- strlen(hostname)) != 0 &&
- !TOP_PAGE(file)))
- to_indexhtml = 1;
- } else {
- const char *h = request->hr_host;
-
- debug((httpd, DEBUG_FAT, "url has no referrer at all"));
- /* if there's no referrer, let / or /index.html past */
- if (!TOP_PAGE(file) ||
- (h && strncasecmp(h, hostname,
- strlen(hostname)) != 0))
- to_indexhtml = 1;
- }
-
- if (to_indexhtml) {
- char *slashindexhtml;
-
- if (asprintf(&slashindexhtml, "/%s",
- httpd->index_html) < 0)
- bozo_err(httpd, 1, "asprintf");
- debug((httpd, DEBUG_FAT,
- "httpd->untrustedref: redirecting %s to %s",
- file, slashindexhtml));
- handle_redirect(request, slashindexhtml, 0);
- free(slashindexhtml);
- return 0;
- }
- }
+ /* fix file provided by user as it's used in other handlers */
+ request->hr_file = file;
len = strlen(file);
- if (/*CONSTCOND*/0) {
+
#ifndef NO_USER_SUPPORT
- } else if (len > 1 && httpd->enable_users && file[1] == '~') {
+ /* first of all expand user path */
+ if (len > 1 && httpd->enable_users && file[1] == '~') {
if (file[2] == '\0') {
(void)bozo_http_error(httpd, 404, request,
"missing username");
goto bad_done;
}
if (strchr(file + 2, '/') == NULL) {
- handle_redirect(request, NULL, 0);
+ char *userredirecturl;
+ if (asprintf(&userredirecturl, "%s/", file) < 0)
+ bozo_err(httpd, 1, "asprintf");
+ handle_redirect(request, userredirecturl, 0);
+ free(userredirecturl);
return 0;
}
debug((httpd, DEBUG_FAT, "calling bozo_user_transform"));
- return bozo_user_transform(request, isindex);
+ if (!bozo_user_transform(request))
+ return 0;
+
+ file = request->hr_file;
+ len = strlen(file);
+ }
#endif /* NO_USER_SUPPORT */
- } else if (len > 1) {
+
+
+ switch (check_bzredirect(request)) {
+ case -1:
+ goto bad_done;
+ case 1:
+ return 0;
+ }
+
+ if (len > 1) {
debug((httpd, DEBUG_FAT, "file[len-1] == %c", file[len-1]));
if (file[len-1] == '/') { /* append index.html */
*isindex = 1;
@@ -1444,15 +1448,14 @@ transform_request(bozo_httpreq_t *request, int *isindex)
}
/*
- * look for "http://myname/" and deal with it as necessary.
- */
-
- /*
* stop traversing outside our domain
*
* XXX true security only comes from our parent using chroot(2)
* before execve(2)'ing us. or our own built in chroot(2) support.
*/
+
+ debug((httpd, DEBUG_FAT, "newfile: %s", newfile));
+
if (*newfile == '/' || strcmp(newfile, "..") == 0 ||
strstr(newfile, "/..") || strstr(newfile, "../")) {
(void)bozo_http_error(httpd, 403, request, "illegal request");
@@ -1570,7 +1573,7 @@ bozo_process_request(bozo_httpreq_t *request)
if (fd < 0) {
debug((httpd, DEBUG_FAT, "open failed: %s", strerror(errno)));
- switch(errno) {
+ switch (errno) {
case EPERM:
case EACCES:
(void)bozo_http_error(httpd, 403, request,
@@ -1649,9 +1652,6 @@ bozo_process_request(bozo_httpreq_t *request)
while (szleft) {
size_t sz;
- /* This should take care of the first unaligned chunk */
- if ((cur_byte_pos & (httpd->page_size - 1)) != 0)
- sz = (size_t)(cur_byte_pos & ~httpd->page_size);
if ((off_t)httpd->mmapsz < szleft)
sz = httpd->mmapsz;
else
@@ -1733,7 +1733,7 @@ bozo_print_header(bozo_httpreq_t *request,
len = sbp->st_size;
bozo_printf(httpd, "Content-Length: %qd\r\n", (long long)len);
}
- if (request && request->hr_proto == httpd->consts.http_11)
+ if (request->hr_proto == httpd->consts.http_11)
bozo_printf(httpd, "Connection: close\r\n");
bozo_flush(httpd, stdout);
}
@@ -1927,26 +1927,53 @@ bozo_http_error(bozohttpd_t *httpd, int code, bozo_httpreq_t *request,
portbuf[0] = '\0';
if (request && request->hr_file) {
- char *file = NULL;
+ char *file = NULL, *user = NULL, *user_escaped = NULL;
+ int file_alloc = 0, user_alloc = 0;
const char *hostname = BOZOHOST(httpd, request);
/* bozo_escape_html() failure here is just too bad. */
file = bozo_escape_html(NULL, request->hr_file);
- if (file == NULL)
+ if (file == NULL)
file = request->hr_file;
+ else
+ file_alloc = 1;
+
+#ifndef NO_USER_SUPPORT
+ if (request->hr_user != NULL) {
+ user_escaped = bozo_escape_html(NULL, request->hr_user);
+ if (user_escaped == NULL)
+ user_escaped = request->hr_user;
+ else
+ user_alloc = 1;
+ /* expand username to ~user/ */
+ user = alloca(strlen(user_escaped) + 3);
+ if (user != NULL) {
+ strcpy(user, "~");
+ strcat(user, user_escaped);
+ strcat(user, "/");
+ }
+ if (user_alloc == 1)
+ free(user_escaped);
+ }
+#endif /* !NO_USER_SUPPORT */
+
size = snprintf(httpd->errorbuf, BUFSIZ,
"<html><head><title>%s</title></head>\n"
"<body><h1>%s</h1>\n"
- "%s: <pre>%s</pre>\n"
+ "%s%s: <pre>%s</pre>\n"
"<hr><address><a href=\"http://%s%s/\">%s%s</a></address>\n"
"</body></html>\n",
- header, header, file, reason,
- hostname, portbuf, hostname, portbuf);
+ header, header,
+ user ? user : "", file,
+ reason, hostname, portbuf, hostname, portbuf);
if (size >= (int)BUFSIZ) {
bozo_warn(httpd,
"bozo_http_error buffer too small, truncated");
size = (int)BUFSIZ;
}
+
+ if (file_alloc)
+ free(file);
} else
size = 0;
@@ -2207,10 +2234,6 @@ bozo_setup(bozohttpd_t *httpd, bozoprefs_t *prefs, const char *vhost,
strcmp(cp, "true") == 0) {
httpd->numeric = 1;
}
- if ((cp = bozo_get_pref(prefs, "trusted referal")) != NULL &&
- strcmp(cp, "true") == 0) {
- httpd->untrustedref = 1;
- }
if ((cp = bozo_get_pref(prefs, "log to stderr")) != NULL &&
strcmp(cp, "true") == 0) {
httpd->logstderr = 1;
@@ -2239,6 +2262,10 @@ bozo_setup(bozohttpd_t *httpd, bozoprefs_t *prefs, const char *vhost,
strcmp(cp, "true") == 0) {
httpd->enable_users = 1;
}
+ if ((cp = bozo_get_pref(prefs, "enable user cgibin")) != NULL &&
+ strcmp(cp, "true") == 0) {
+ httpd->enable_cgi_users = 1;
+ }
if ((cp = bozo_get_pref(prefs, "dirty environment")) != NULL &&
strcmp(cp, "true") == 0) {
dirtyenv = 1;
diff --git a/libexec/httpd/bozohttpd.h b/libexec/httpd/bozohttpd.h
index bab47882846..3839429a955 100644
--- a/libexec/httpd/bozohttpd.h
+++ b/libexec/httpd/bozohttpd.h
@@ -1,4 +1,4 @@
-/* $NetBSD: bozohttpd.h,v 1.37 2015/10/25 19:06:49 mrg Exp $ */
+/* $NetBSD: bozohttpd.h,v 1.38 2015/10/28 09:20:15 shm Exp $ */
/* $eterna: bozohttpd.h,v 1.39 2011/11/18 09:21:15 mrg Exp $ */
@@ -94,7 +94,6 @@ typedef struct bozohttpd_t {
int numeric; /* avoid gethostby*() */
char *virtbase; /* virtual directory base */
int unknown_slash; /* unknown vhosts go to normal slashdir */
- int untrustedref; /* make sure referrer = me unless url = / */
int logstderr; /* log to stderr (even if not tty) */
int background; /* drop into daemon mode */
int foreground; /* keep daemon mode in foreground */
@@ -109,6 +108,7 @@ typedef struct bozohttpd_t {
const char *index_html; /* our home page */
const char *public_html; /* ~user/public_html page */
int enable_users; /* enable public_html */
+ int enable_cgi_users; /* use the cgi handler */
int *sock; /* bound sockets */
int nsock; /* number of above */
struct pollfd *fds; /* current poll fd set */
@@ -151,6 +151,9 @@ typedef struct bozo_httpreq_t {
char *hr_query;
char *hr_host; /* HTTP/1.1 Host: or virtual hostname,
possibly including a port number */
+#ifndef NO_USER_SUPPORT
+ char *hr_user; /* username if we hit userdir request */
+#endif /* !NO_USER_SUPPORT */
const char *hr_proto;
const char *hr_content_type;
const char *hr_content_length;
@@ -225,7 +228,7 @@ int bozo_http_error(bozohttpd_t *, int, bozo_httpreq_t *, const char *);
int bozo_check_special_files(bozo_httpreq_t *, const char *);
char *bozo_http_date(char *, size_t);
void bozo_print_header(bozo_httpreq_t *, struct stat *, const char *, const char *);
-char *bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url);
+char *bozo_escape_rfc3986(bozohttpd_t *httpd, const char *url, int absolute);
char *bozo_escape_html(bozohttpd_t *httpd, const char *url);
char *bozodgetln(bozohttpd_t *, int, ssize_t *, ssize_t (*)(bozohttpd_t *, int, void *, size_t));
@@ -305,9 +308,11 @@ void bozo_daemon_closefds(bozohttpd_t *);
/* tilde-luzah-bozo.c */
#ifdef NO_USER_SUPPORT
-#define bozo_user_transform(a, c) 0
+#define bozo_user_transform(x) 0
+#define bozo_user_free(x) 0
#else
-int bozo_user_transform(bozo_httpreq_t *, int *);
+int bozo_user_transform(bozo_httpreq_t *);
+#define bozo_user_free(x) free(x)
#endif /* NO_USER_SUPPORT */
diff --git a/libexec/httpd/cgi-bozo.c b/libexec/httpd/cgi-bozo.c
index e0bcc8ca70d..8ab52d38c7f 100644
--- a/libexec/httpd/cgi-bozo.c
+++ b/libexec/httpd/cgi-bozo.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cgi-bozo.c,v 1.27 2015/05/02 11:35:48 mrg Exp $ */
+/* $NetBSD: cgi-bozo.c,v 1.28 2015/10/28 09:20:15 shm Exp $ */
/* $eterna: cgi-bozo.c,v 1.40 2011/11/18 09:21:15 mrg Exp $ */
@@ -90,7 +90,7 @@ parse_header(bozohttpd_t *httpd, const char *str, ssize_t len, char **hdr_str,
name = bozostrnsep(&value, ":", &len);
if (NULL == name || -1 == len) {
- free(name);
+ free(value);
return -1;
}
@@ -260,6 +260,11 @@ bozo_process_cgi(bozo_httpreq_t *request)
if (!httpd->cgibin && !httpd->process_cgi)
return 0;
+#ifndef NO_USER_SUPPORT
+ if (request->hr_user && !httpd->enable_cgi_users)
+ return 0;
+#endif /* !NO_USER_SUPPORT */
+
if (request->hr_oldfile && strcmp(request->hr_oldfile, "/") != 0)
uri = request->hr_oldfile;
else
diff --git a/libexec/httpd/dir-index-bozo.c b/libexec/httpd/dir-index-bozo.c
index 49989bfc828..c4e5ae63ce1 100644
--- a/libexec/httpd/dir-index-bozo.c
+++ b/libexec/httpd/dir-index-bozo.c
@@ -1,4 +1,4 @@
-/* $NetBSD: dir-index-bozo.c,v 1.21 2015/08/27 17:12:18 mrg Exp $ */
+/* $NetBSD: dir-index-bozo.c,v 1.22 2015/10/28 09:20:15 shm Exp $ */
/* $eterna: dir-index-bozo.c,v 1.20 2011/11/18 09:21:15 mrg Exp $ */
@@ -66,7 +66,7 @@ bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex)
DIR *dp;
char buf[MAXPATHLEN];
char spacebuf[48];
- char *file = NULL;
+ char *file = NULL, *printname = NULL;
int l, k, j, i;
if (!isindex || !httpd->dir_indexing)
@@ -108,11 +108,22 @@ bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex)
goto done;
}
+#ifndef NO_USER_SUPPORT
+ if (request->hr_user) {
+ if (asprintf(&printname, "~%s/%s", request->hr_user,
+ request->hr_file) < 0)
+ bozo_err(httpd, 1, "asprintf");
+ } else
+ printname = bozostrdup(httpd, request->hr_file);
+#else
+ printname = bozostrdup(httpd, request->hr_file);
+#endif /* !NO_USER_SUPPORT */
+
bozo_printf(httpd,
"<html><head><title>Index of %s</title></head>\r\n",
- request->hr_file);
+ printname);
bozo_printf(httpd, "<body><h1>Index of %s</h1>\r\n",
- request->hr_file);
+ printname);
bozo_printf(httpd, "<pre>\r\n");
#define NAMELEN 40
#define LMODLEN 19
@@ -140,7 +151,7 @@ bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex)
l = 0;
- urlname = bozo_escape_rfc3986(httpd, name);
+ urlname = bozo_escape_rfc3986(httpd, name, 0);
htmlname = bozo_escape_html(httpd, name);
if (htmlname == NULL)
htmlname = name;
@@ -206,6 +217,7 @@ bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex)
done:
free(file);
+ free(printname);
return 1;
}
#endif /* NO_DIRINDEX_SUPPORT */
diff --git a/libexec/httpd/lua/bozo.lua b/libexec/httpd/lua/bozo.lua
index 9a30c9f1fc6..567bbeb9147 100755
--- a/libexec/httpd/lua/bozo.lua
+++ b/libexec/httpd/lua/bozo.lua
@@ -35,6 +35,7 @@ dofile "optparse.lua"
opt = OptionParser{usage="%prog [options] root [vhost]", version="20091105"}
opt.add_option{"-C", "--cgimap", action="store", dest="cgimap", help="--cgimap 's t'"}
+opt.add_option{"-E", "--enable-user-cgibin", action="store_true", dest="enableusercgibin", help="--enable-user-cgibin"}
opt.add_option{"-H", "--hide-dots", action="store_true", dest="hidedots", help="--hide-dots"}
opt.add_option{"-I", "--portnum", action="store", dest="portnum", help="--portnum number"}
opt.add_option{"-M", "--dynamicmime", action="store", dest="dynmime", help="--dynamicmime 'suffix type a b'"}
@@ -50,7 +51,6 @@ opt.add_option{"-f", "--foreground", action="store_true", dest="foreground", hel
opt.add_option{"-i", "--bindaddr", action="store", dest="bindaddress", help="--bindaddr address"}
opt.add_option{"-n", "--numeric", action="store_true", dest="numeric", help="--numeric"}
opt.add_option{"-p", "--public-html", action="store", dest="public_html", help="--public-html dir"}
-opt.add_option{"-r", "--trusted-referal", action="store_true", dest="trustedref", help="trusted referal"}
opt.add_option{"-s", "--logtostderr", action="store_true", dest="logstderr", help="log to stderr"}
opt.add_option{"-t", "--chroot", action="store", dest="chroot", help="--chroot dir"}
opt.add_option{"-u", "--enable-users", action="store_true", dest="enableusers", help="--enable-users"}
@@ -141,6 +141,9 @@ end
if options.hidedots then
bozohttpd.set_pref(prefs, "hide dots", "true")
end
+if options.enableusercgibin then
+ bozohttpd.set_pref(prefs, "enable user cgibin", "true")
+end
if options.dirindex then
bozohttpd.set_pref(prefs, "directory indexing", "true")
end
diff --git a/libexec/httpd/main.c b/libexec/httpd/main.c
index 348628bf6a2..6c645d4e995 100644
--- a/libexec/httpd/main.c
+++ b/libexec/httpd/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.8 2014/07/16 07:41:43 mrg Exp $ */
+/* $NetBSD: main.c,v 1.9 2015/10/28 09:20:15 shm Exp $ */
/* $eterna: main.c,v 1.6 2011/11/18 09:21:15 mrg Exp $ */
/* from: eterna: bozohttpd.c,v 1.159 2009/05/23 02:14:30 mrg Exp */
@@ -65,12 +65,15 @@ usage(bozohttpd_t *httpd, char *progname)
bozo_warn(httpd, " -d\t\t\tenable debug support");
#endif
bozo_warn(httpd, " -s\t\t\talways log to stderr");
+#ifndef NO_DYNAMIC_CONTENT
+ bozo_warn(httpd, " -M arg t c c11\tadd this mime extenstion");
+#endif
#ifndef NO_USER_SUPPORT
bozo_warn(httpd, " -u\t\t\tenable ~user/public_html support");
- bozo_warn(httpd, " -p dir\t\tchange `public_html' directory name]");
+ bozo_warn(httpd, " -p dir\t\tchange `public_html' directory name");
+#ifndef NO_CGIBIN_SUPPORT
+ bozo_warn(httpd, " -E\t\t\tenable CGI support for user dirs");
#endif
-#ifndef NO_DYNAMIC_CONTENT
- bozo_warn(httpd, " -M arg t c c11\tadd this mime extenstion");
#endif
#ifndef NO_CGIBIN_SUPPORT
#ifndef NO_DYNAMIC_CONTENT
@@ -98,9 +101,6 @@ usage(bozohttpd_t *httpd, char *progname)
bozo_warn(httpd,
" -v virtualroot\tenable virtual host support "
"in this directory");
- bozo_warn(httpd,
- " -r\t\t\tmake sure sub-pages come from "
- "this host via referrer");
#ifndef NO_DIRINDEX_SUPPORT
bozo_warn(httpd,
" -X\t\t\tenable automatic directory index support");
@@ -140,9 +140,13 @@ main(int argc, char **argv)
bozo_set_defaults(&httpd, &prefs);
+ /*
+ * -r option was removed, do not reuse it for a while
+ */
+
while ((c = getopt(argc, argv,
- "C:HI:L:M:P:S:U:VXZ:bc:defhi:np:rst:uv:x:z:")) != -1) {
- switch(c) {
+ "C:EHI:L:M:P:S:U:VXZ:bc:defhi:np:st:uv:x:z:")) != -1) {
+ switch (c) {
case 'L':
#ifdef NO_LUA_SUPPORT
@@ -176,10 +180,6 @@ main(int argc, char **argv)
bozo_set_pref(&prefs, "numeric", "true");
break;
- case 'r':
- bozo_set_pref(&prefs, "trusted referal", "true");
- break;
-
case 's':
bozo_set_pref(&prefs, "log to stderr", "true");
break;
@@ -297,6 +297,7 @@ main(int argc, char **argv)
#ifdef NO_USER_SUPPORT
case 'p':
case 'u':
+ case 'E':
bozo_err(&httpd, 1, "User support is not enabled");
/* NOTREACHED */
#else
@@ -307,6 +308,15 @@ main(int argc, char **argv)
case 'u':
bozo_set_pref(&prefs, "enable users", "true");
break;
+#ifndef NO_CGIBIN_SUPPORT
+ case 'E':
+ bozo_set_pref(&prefs, "enable user cgibin", "true");
+ break;
+#else
+ case 'E':
+ bozo_err(&httpd, 1, "CGI is not enabled");
+ /* NOTREACHED */
+#endif /* NO_CGIBIN_SPPORT */
#endif /* NO_USER_SUPPORT */
#ifdef NO_DIRINDEX_SUPPORT
diff --git a/libexec/httpd/tilde-luzah-bozo.c b/libexec/httpd/tilde-luzah-bozo.c
index f7fd0c7bd56..8e968336f67 100644
--- a/libexec/httpd/tilde-luzah-bozo.c
+++ b/libexec/httpd/tilde-luzah-bozo.c
@@ -1,4 +1,4 @@
-/* $NetBSD: tilde-luzah-bozo.c,v 1.11 2015/07/16 12:19:23 shm Exp $ */
+/* $NetBSD: tilde-luzah-bozo.c,v 1.12 2015/10/28 09:20:15 shm Exp $ */
/* $eterna: tilde-luzah-bozo.c,v 1.16 2011/11/18 09:21:15 mrg Exp $ */
@@ -56,16 +56,14 @@
* enabled.
*/
int
-bozo_user_transform(bozo_httpreq_t *request, int *isindex)
+bozo_user_transform(bozo_httpreq_t *request)
{
bozohttpd_t *httpd = request->hr_httpd;
- char c, *s, *file = NULL, *user;
+ char *s, *file = NULL, *user;
struct passwd *pw;
- *isindex = 0;
-
/* find username */
- user = strchr(request->hr_file + 2, '~');
+ user = strchr(request->hr_file + 1, '~');
/* this shouldn't happen, but "better paranoid than sorry" */
assert(user != NULL);
@@ -74,17 +72,24 @@ bozo_user_transform(bozo_httpreq_t *request, int *isindex)
if ((s = strchr(user, '/')) != NULL) {
*s++ = '\0';
- c = s[strlen(s)-1];
- *isindex = (c == '/' || c == '\0');
}
debug((httpd, DEBUG_OBESE, "looking for user %s",
user));
pw = getpwnam(user);
+ request->hr_user = bozostrdup(httpd, user);
+
/* fix this up immediately */
- if (s)
+ if (s) {
s[-1] = '/';
+ /* omit additional slashes at the beginning */
+ while (*s == '/')
+ s++;
+ }
+
if (pw == NULL) {
+ free(request->hr_user);
+ request->hr_user = NULL;
(void)bozo_http_error(httpd, 404, request, "no such user");
return 0;
}
@@ -108,26 +113,11 @@ bozo_user_transform(bozo_httpreq_t *request, int *isindex)
return 0;
}
if (s == NULL || *s == '\0') {
- file = bozostrdup(httpd, httpd->index_html);
+ file = bozostrdup(httpd, "/");
} else {
- file = bozomalloc(httpd, strlen(s) +
- (*isindex ? strlen(httpd->index_html) + 1 : 1));
- strcpy(file, s);
- if (*isindex)
- strcat(file, httpd->index_html);
- }
-
- /* see transform_request() */
- if (*file == '/' || strcmp(file, "..") == 0 ||
- strstr(file, "/..") || strstr(file, "../")) {
- (void)bozo_http_error(httpd, 403, request, "illegal request");
- free(file);
- return 0;
- }
-
- if (bozo_auth_check(request, file)) {
- free(file);
- return 0;
+ file = bozomalloc(httpd, strlen(s) + 2);
+ strcpy(file, "/");
+ strcat(file, s);
}
free(request->hr_file);