Module Name: src Committed By: martin Date: Sun Apr 10 10:33:11 UTC 2016
Modified Files: src/libexec/httpd [netbsd-7]: CHANGES Makefile auth-bozo.c bozohttpd.8 bozohttpd.c bozohttpd.h cgi-bozo.c content-bozo.c daemon-bozo.c dir-index-bozo.c lua-bozo.c main.c printenv.lua ssl-bozo.c tilde-luzah-bozo.c src/libexec/httpd/testsuite [netbsd-7]: Makefile test-bigfile Log Message: Catch up to -current (via patch), requested by mspo in #1141: libexec/httpd/CHANGES up to 1.21 libexec/httpd/Makefile up to 1.26 libexec/httpd/auth-bozo.c up to 1.18 libexec/httpd/bozohttpd.8 up to 1.58 libexec/httpd/bozohttpd.c up to 1.79 libexec/httpd/bozohttpd.h up to 1.44 libexec/httpd/cgi-bozo.c up to 1.32 libexec/httpd/content-bozo.c up to 1.13 libexec/httpd/daemon-bozo.c up to 1.17 libexec/httpd/dir-index-bozo.c up to 1.25 libexec/httpd/lua-bozo.c up to 1.14 libexec/httpd/main.c up to 1.13 libexec/httpd/netbsd_queue.h up to 1.1 libexec/httpd/printenv.lua up to 1.3 libexec/httpd/ssl-bozo.c up to 1.22 libexec/httpd/tilde-luzah-bozo.c up to 1.14 libexec/httpd/testsuite/Makefile up to 1.5 libexec/httpd/testsuite/test-bigfile up to 1.2 Import 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 20150320: o fix redirection handling o support transport stream (.ts) and video object (.vob) files o directory listings show correct file sizes for large files To generate a diff of this commit: cvs rdiff -u -r1.19.2.1 -r1.19.2.2 src/libexec/httpd/CHANGES cvs rdiff -u -r1.22.2.1 -r1.22.2.2 src/libexec/httpd/Makefile cvs rdiff -u -r1.13.2.1 -r1.13.2.2 src/libexec/httpd/auth-bozo.c cvs rdiff -u -r1.46.4.4 -r1.46.4.5 src/libexec/httpd/bozohttpd.8 cvs rdiff -u -r1.56.2.4 -r1.56.2.5 src/libexec/httpd/bozohttpd.c cvs rdiff -u -r1.33.2.2 -r1.33.2.3 src/libexec/httpd/bozohttpd.h cvs rdiff -u -r1.25.2.2 -r1.25.2.3 src/libexec/httpd/cgi-bozo.c cvs rdiff -u -r1.10.2.2 -r1.10.2.3 src/libexec/httpd/content-bozo.c cvs rdiff -u -r1.16 -r1.16.4.1 src/libexec/httpd/daemon-bozo.c cvs rdiff -u -r1.19.4.1 -r1.19.4.2 src/libexec/httpd/dir-index-bozo.c cvs rdiff -u -r1.10.2.1 -r1.10.2.2 src/libexec/httpd/lua-bozo.c cvs rdiff -u -r1.8 -r1.8.2.1 src/libexec/httpd/main.c cvs rdiff -u -r1.2 -r1.2.18.1 src/libexec/httpd/printenv.lua cvs rdiff -u -r1.18 -r1.18.2.1 src/libexec/httpd/ssl-bozo.c cvs rdiff -u -r1.10 -r1.10.4.1 src/libexec/httpd/tilde-luzah-bozo.c cvs rdiff -u -r1.4 -r1.4.24.1 src/libexec/httpd/testsuite/Makefile cvs rdiff -u -r1.1.1.1 -r1.1.1.1.30.1 \ src/libexec/httpd/testsuite/test-bigfile Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/libexec/httpd/CHANGES diff -u src/libexec/httpd/CHANGES:1.19.2.1 src/libexec/httpd/CHANGES:1.19.2.2 --- src/libexec/httpd/CHANGES:1.19.2.1 Sun Apr 19 04:44:03 2015 +++ src/libexec/httpd/CHANGES Sun Apr 10 10:33:11 2016 @@ -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 Index: src/libexec/httpd/Makefile diff -u src/libexec/httpd/Makefile:1.22.2.1 src/libexec/httpd/Makefile:1.22.2.2 --- src/libexec/httpd/Makefile:1.22.2.1 Thu Apr 23 19:38:11 2015 +++ src/libexec/httpd/Makefile Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.22.2.1 2015/04/23 19:38:11 snj Exp $ +# $NetBSD: Makefile,v 1.22.2.2 2016/04/10 10:33:11 martin Exp $ # # $eterna: Makefile,v 1.30 2010/07/11 00:34:27 mrg Exp $ # @@ -15,6 +15,10 @@ # DO_HTPASSWD /* support .htpasswd files */ # NO_LUA_SUPPORT /* don't support Lua for dynamic content */ # +# other system specific defines: +# HAVE_NBUTIL_H /* netbsd compat is in <nbutil.h> +# (don't forget to also enable -lnbutil) +# # these are usually set via the "COPTS" variable, or some other method # for setting CFLAGS relevant to your make, eg # % make COPTS="-DDO_HTPASSWD" @@ -33,6 +37,17 @@ DPADD= ${LIBCRYPT} ${LIBLUA} ${LIBM} WARNS?= 4 +.if defined(.OS.MAKE) +OPSYS= ${.OS.MAKE} +.else +OPSYS:= ${:!uname -s!:S/-//g:S/\///g} +.endif + +.if ${OPSYS} == "QNX" +CPPFLAGS+= -DHAVE_NBUTIL_H +LDADD+= -lnbutil +.endif + .include <bsd.own.mk> .if ${MKCRYPTO} != "no" Index: src/libexec/httpd/auth-bozo.c diff -u src/libexec/httpd/auth-bozo.c:1.13.2.1 src/libexec/httpd/auth-bozo.c:1.13.2.2 --- src/libexec/httpd/auth-bozo.c:1.13.2.1 Mon Jan 12 10:02:29 2015 +++ src/libexec/httpd/auth-bozo.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: auth-bozo.c,v 1.13.2.1 2015/01/12 10:02:29 martin Exp $ */ +/* $NetBSD: auth-bozo.c,v 1.13.2.2 2016/04/10 10:33:11 martin Exp $ */ /* $eterna: auth-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $ */ @@ -72,10 +72,10 @@ bozo_auth_check(bozo_httpreq_t *request, if (bozo_check_special_files(request, basename)) return 1; } - request->hr_authrealm = bozostrdup(httpd, dir); + request->hr_authrealm = bozostrdup(httpd, request, dir); - if ((size_t)snprintf(authfile, sizeof(authfile), "%s/%s", dir, AUTH_FILE) >= - sizeof(authfile)) { + if ((size_t)snprintf(authfile, sizeof(authfile), "%s/%s", dir, + AUTH_FILE) >= sizeof(authfile)) { return bozo_http_error(httpd, 404, request, "authfile path too long"); } @@ -136,7 +136,8 @@ bozo_auth_cleanup(bozo_httpreq_t *reques } int -bozo_auth_check_headers(bozo_httpreq_t *request, char *val, char *str, ssize_t len) +bozo_auth_check_headers(bozo_httpreq_t *request, char *val, char *str, + ssize_t len) { bozohttpd_t *httpd = request->hr_httpd; @@ -159,8 +160,8 @@ bozo_auth_check_headers(bozo_httpreq_t * *pass++ = '\0'; free(request->hr_authuser); free(request->hr_authpass); - request->hr_authuser = bozostrdup(httpd, authbuf); - request->hr_authpass = bozostrdup(httpd, pass); + request->hr_authuser = bozostrdup(httpd, request, authbuf); + request->hr_authpass = bozostrdup(httpd, request, pass); debug((httpd, DEBUG_FAT, "decoded authorization `%s' as `%s':`%s'", str, request->hr_authuser, request->hr_authpass)); @@ -190,8 +191,8 @@ bozo_auth_check_401(bozo_httpreq_t *requ 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 Index: src/libexec/httpd/bozohttpd.8 diff -u src/libexec/httpd/bozohttpd.8:1.46.4.4 src/libexec/httpd/bozohttpd.8:1.46.4.5 --- src/libexec/httpd/bozohttpd.8:1.46.4.4 Sat May 9 08:50:42 2015 +++ src/libexec/httpd/bozohttpd.8 Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -.\" $NetBSD: bozohttpd.8,v 1.46.4.4 2015/05/09 08:50:42 snj Exp $ +.\" $NetBSD: bozohttpd.8,v 1.46.4.5 2016/04/10 10:33:11 martin Exp $ .\" .\" $eterna: bozohttpd.8,v 1.101 2011/11/18 01:25:11 mrg Exp $ .\" @@ -26,7 +26,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd May 1, 2015 +.Dd December 12, 2015 .Dt BOZOHTTPD 8 .Os .Sh NAME @@ -34,13 +34,14 @@ .Nd hyper text transfer protocol version 1.1 daemon .Sh SYNOPSIS .Nm -.Op Fl CIMPSZciptvx +.Op Fl EHVXefhnsu .Op Fl C Ar suffix cgihandler .Op Fl I Ar port .Op Fl L Ar prefix script .Op Fl M Ar suffix type encoding encoding11 .Op Fl P Ar pidfile .Op Fl S Ar server_software +.Op Fl U Ar username .Op Fl Z Ar cert privkey .Op Fl c Ar cgibin .Op Fl i Ar address @@ -48,6 +49,7 @@ .Op Fl t Ar chrootdir .Op Fl v Ar virtualroot .Op Fl x Ar index +.Op Fl z Ar ciphers .Ar slashdir .Op Ar myname .Sh DESCRIPTION @@ -111,9 +113,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 +227,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 +265,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 . @@ -303,6 +304,9 @@ Changes the default file read for direct .Dq index.html to .Ar index . +.It Fl z Ar ciphers +Sets the list of SSL ciphers (see +.Xr SSL_CTX_set_cipher_list 3 ) . .It Fl Z Ar certificate_path privatekey_path Sets the path to the server certificate file and the private key file in pem format. @@ -333,7 +337,8 @@ by default to process incoming TCP conne option), .Nm has little internal networking knowledge. -(Indeed, you can run it on the command line with little change of functionality.) +(Indeed, you can run it on the command line with little change of +functionality.) A typical .Xr inetd.conf 5 entry would be: @@ -425,7 +430,7 @@ It may require linking with the crypt li .Dq -lcrypt . .Ss SSL SUPPORT .Nm -has support for SSLv2, SSLv3, and TLSv1 protocols that is included by +has support for TLSv1.1 and TLSv1.2 protocols that are included by default. It requires linking with the crypto and ssl library, using .Dq -lcrypto -lssl . @@ -462,12 +467,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 @@ -597,8 +613,9 @@ provided many fixes and enhancements for .It .An Mateusz Kocielski .Aq Mt s...@netbsd.org -fixed memory leaks, information disclosure issues and added support -for using CGI handlers with directory indexing. +fixed memory leaks, various issues with userdir support, +information disclosure issues, added support for using CGI handlers +with directory indexing and provided various other fixes. .It .An Arnaud Lacombe .Aq Mt a...@netbsd.org @@ -612,7 +629,7 @@ provided man page fixes .Aq Mt j...@netbsd.org Added the .Fl P -option. +option (pidfile support) and provided some man page fixes. .It .An Luke Mewburn .Aq Mt lu...@netbsd.org @@ -665,9 +682,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) Index: src/libexec/httpd/bozohttpd.c diff -u src/libexec/httpd/bozohttpd.c:1.56.2.4 src/libexec/httpd/bozohttpd.c:1.56.2.5 --- src/libexec/httpd/bozohttpd.c:1.56.2.4 Sat May 9 08:50:42 2015 +++ src/libexec/httpd/bozohttpd.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: bozohttpd.c,v 1.56.2.4 2015/05/09 08:50:42 snj Exp $ */ +/* $NetBSD: bozohttpd.c,v 1.56.2.5 2016/04/10 10:33:11 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/20150501" +#define SERVER_SOFTWARE "bozohttpd/20151231" #endif #ifndef DIRECT_ACCESS_FILE #define DIRECT_ACCESS_FILE ".bzdirect" @@ -171,61 +171,59 @@ volatile sig_atomic_t alarmhit; * check there's enough space in the prefs and names arrays. */ static int -size_arrays(bozoprefs_t *bozoprefs, unsigned needed) +size_arrays(bozoprefs_t *bozoprefs, size_t needed) { char **temp; if (bozoprefs->size == 0) { /* only get here first time around */ - bozoprefs->size = needed; - if ((bozoprefs->name = calloc(sizeof(char *), needed)) == NULL) { - (void) fprintf(stderr, "size_arrays: bad alloc\n"); + bozoprefs->name = calloc(sizeof(char *), needed); + if (bozoprefs->name == NULL) return 0; - } - if ((bozoprefs->value = calloc(sizeof(char *), needed)) == NULL) { + bozoprefs->value = calloc(sizeof(char *), needed); + if (bozoprefs->value == NULL) { free(bozoprefs->name); - (void) fprintf(stderr, "size_arrays: bad alloc\n"); return 0; } - } else if (bozoprefs->c == bozoprefs->size) { + bozoprefs->size = needed; + } else if (bozoprefs->count == bozoprefs->size) { /* only uses 'needed' when filled array */ - bozoprefs->size += needed; temp = realloc(bozoprefs->name, sizeof(char *) * needed); - if (temp == NULL) { - (void) fprintf(stderr, "size_arrays: bad alloc\n"); + if (temp == NULL) return 0; - } bozoprefs->name = temp; temp = realloc(bozoprefs->value, sizeof(char *) * needed); - if (temp == NULL) { - (void) fprintf(stderr, "size_arrays: bad alloc\n"); + if (temp == NULL) return 0; - } bozoprefs->value = temp; + bozoprefs->size += needed; } return 1; } -static int +static ssize_t findvar(bozoprefs_t *bozoprefs, const char *name) { - unsigned i; + size_t i; - for (i = 0 ; i < bozoprefs->c && strcmp(bozoprefs->name[i], name) != 0; i++) - ; - return (i == bozoprefs->c) ? -1 : (int)i; + for (i = 0; i < bozoprefs->count; i++) + if (strcmp(bozoprefs->name[i], name) == 0) + return (ssize_t)i; + return -1; } int -bozo_set_pref(bozoprefs_t *bozoprefs, const char *name, const char *value) +bozo_set_pref(bozohttpd_t *httpd, bozoprefs_t *bozoprefs, + const char *name, const char *value) { - int i; + ssize_t i; if ((i = findvar(bozoprefs, name)) < 0) { /* add the element to the array */ - if (size_arrays(bozoprefs, bozoprefs->size + 15)) { - bozoprefs->name[i = bozoprefs->c++] = strdup(name); - } + if (!size_arrays(bozoprefs, bozoprefs->size + 15)) + return 0; + i = bozoprefs->count++; + bozoprefs->name[i] = bozostrdup(httpd, NULL, name); } else { /* replace the element in the array */ if (bozoprefs->value[i]) { @@ -233,8 +231,7 @@ bozo_set_pref(bozoprefs_t *bozoprefs, co bozoprefs->value[i] = NULL; } } - /* sanity checks for range of values go here */ - bozoprefs->value[i] = strdup(value); + bozoprefs->value[i] = bozostrdup(httpd, NULL, value); return 1; } @@ -244,10 +241,10 @@ bozo_set_pref(bozoprefs_t *bozoprefs, co char * bozo_get_pref(bozoprefs_t *bozoprefs, const char *name) { - int i; + ssize_t i; - return ((i = findvar(bozoprefs, name)) < 0) ? NULL : - bozoprefs->value[i]; + i = findvar(bozoprefs, name); + return i < 0 ? NULL : bozoprefs->value[i]; } char * @@ -309,9 +306,9 @@ parse_request(bozohttpd_t *httpd, char * } /* allocate private copies */ - *file = bozostrdup(httpd, *file); + *file = bozostrdup(httpd, NULL, *file); if (*query) - *query = bozostrdup(httpd, *query); + *query = bozostrdup(httpd, NULL, *query); debug((httpd, DEBUG_FAT, "url: method: \"%s\" file: \"%s\" query: \"%s\" proto: \"%s\"", @@ -341,6 +338,7 @@ bozo_clean_request(bozo_httpreq_t *reque 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)) { @@ -371,6 +369,7 @@ static bozoheaders_t * addmerge_header(bozo_httpreq_t *request, char *val, char *str, ssize_t len) { + struct bozohttpd_t *httpd = request->hr_httpd; struct bozoheaders *hdr; USE_ARG(len); @@ -384,22 +383,18 @@ addmerge_header(bozo_httpreq_t *request, /* yup, merge it in */ char *nval; - if (asprintf(&nval, "%s, %s", hdr->h_value, str) == -1) { - (void)bozo_http_error(request->hr_httpd, 500, NULL, - "memory allocation failure"); - return NULL; - } + bozoasprintf(httpd, &nval, "%s, %s", hdr->h_value, str); free(hdr->h_value); hdr->h_value = nval; } else { /* nope, create a new one */ - hdr = bozomalloc(request->hr_httpd, sizeof *hdr); - hdr->h_header = bozostrdup(request->hr_httpd, val); + hdr = bozomalloc(httpd, sizeof *hdr); + hdr->h_header = bozostrdup(httpd, request, val); if (str && *str) - hdr->h_value = bozostrdup(request->hr_httpd, str); + hdr->h_value = bozostrdup(httpd, request, str); else - hdr->h_value = bozostrdup(request->hr_httpd, " "); + hdr->h_value = bozostrdup(httpd, request, " "); SIMPLEQ_INSERT_TAIL(&request->hr_headers, hdr, h_next); request->hr_nheaders++; @@ -415,13 +410,14 @@ addmerge_header(bozo_httpreq_t *request, static int process_proto(bozo_httpreq_t *request, const char *proto) { + struct bozohttpd_t *httpd = request->hr_httpd; char majorstr[16], *minorstr; int majorint, minorint; if (proto == NULL) { got_proto_09: - request->hr_proto = request->hr_httpd->consts.http_09; - debug((request->hr_httpd, DEBUG_FAT, "request %s is http/0.9", + request->hr_proto = httpd->consts.http_09; + debug((httpd, DEBUG_FAT, "request %s is http/0.9", request->hr_file)); return 0; } @@ -445,25 +441,25 @@ got_proto_09: goto got_proto_09; case 1: if (minorint == 0) - request->hr_proto = request->hr_httpd->consts.http_10; + request->hr_proto = httpd->consts.http_10; else if (minorint == 1) - request->hr_proto = request->hr_httpd->consts.http_11; + request->hr_proto = httpd->consts.http_11; else break; - debug((request->hr_httpd, DEBUG_FAT, "request %s is %s", + debug((httpd, DEBUG_FAT, "request %s is %s", request->hr_file, request->hr_proto)); SIMPLEQ_INIT(&request->hr_headers); request->hr_nheaders = 0; return 0; } bad: - return bozo_http_error(request->hr_httpd, 404, NULL, "unknown prototype"); + return bozo_http_error(httpd, 404, NULL, "unknown prototype"); } /* * process each type of HTTP method, setting this HTTP requests - # method type. + * method type. */ static struct method_map { const char *name; @@ -485,9 +481,10 @@ static struct method_map { static int process_method(bozo_httpreq_t *request, const char *method) { + struct bozohttpd_t *httpd = request->hr_httpd; struct method_map *mmp; - if (request->hr_proto == request->hr_httpd->consts.http_11) + if (request->hr_proto == httpd->consts.http_11) request->hr_allow = "GET, HEAD, POST"; for (mmp = method_map; mmp->name; mmp++) @@ -497,7 +494,7 @@ process_method(bozo_httpreq_t *request, return 0; } - return bozo_http_error(request->hr_httpd, 404, request, "unknown method"); + return bozo_http_error(httpd, 404, request, "unknown method"); } /* @@ -560,9 +557,9 @@ bozo_read_request(bozohttpd_t *httpd) host = NULL; } if (host != NULL) - request->hr_remotehost = bozostrdup(request->hr_httpd, host); + request->hr_remotehost = bozostrdup(httpd, request, host); if (addr != NULL) - request->hr_remoteaddr = bozostrdup(request->hr_httpd, addr); + request->hr_remoteaddr = bozostrdup(httpd, request, addr); slen = sizeof(ss); /* @@ -578,15 +575,16 @@ bozo_read_request(bozohttpd_t *httpd) if (getsockname(0, (struct sockaddr *)(void *)&ss, &slen) < 0) port = NULL; else { - if (getnameinfo((struct sockaddr *)(void *)&ss, slen, NULL, 0, - bufport, sizeof bufport, NI_NUMERICSERV) == 0) + if (getnameinfo((struct sockaddr *)(void *)&ss, slen, + NULL, 0, bufport, sizeof bufport, + NI_NUMERICSERV) == 0) port = bufport; else port = NULL; } } if (port != NULL) - request->hr_serverport = bozostrdup(request->hr_httpd, port); + request->hr_serverport = bozostrdup(httpd, request, port); /* * setup a timer to make sure the request is not hung @@ -595,7 +593,7 @@ bozo_read_request(bozohttpd_t *httpd) sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGALRM); sa.sa_flags = 0; - sigaction(SIGALRM, &sa, NULL); /* XXX */ + sigaction(SIGALRM, &sa, NULL); alarm(MAX_WAIT_TIME); while ((str = bozodgetln(httpd, STDIN_FILENO, &len, bozo_read)) != NULL) { @@ -614,11 +612,11 @@ bozo_read_request(bozohttpd_t *httpd) "null method"); goto cleanup; } - - bozo_warn(httpd, "got request ``%s'' from host %s to port %s", - str, - host ? host : addr ? addr : "<local>", - port ? port : "<stdin>"); + bozowarn(httpd, + "got request ``%s'' from host %s to port %s", + str, + host ? host : addr ? addr : "<local>", + port ? port : "<stdin>"); /* we allocate return space in file and query only */ parse_request(httpd, str, &method, &file, &query, &proto); @@ -682,7 +680,8 @@ bozo_read_request(bozohttpd_t *httpd) else if (strcasecmp(hdr->h_header, "content-length") == 0) request->hr_content_length = hdr->h_value; else if (strcasecmp(hdr->h_header, "host") == 0) - request->hr_host = bozostrdup(httpd, hdr->h_value); + request->hr_host = bozostrdup(httpd, request, + hdr->h_value); /* RFC 2616 (HTTP/1.1): 14.20 */ else if (strcasecmp(hdr->h_header, "expect") == 0) { (void)bozo_http_error(httpd, 417, request, @@ -797,7 +796,7 @@ mmap_and_write_part(bozohttpd_t *httpd, addr = mmap(0, mappedsz, PROT_READ, MAP_SHARED, fd, mappedoffset); if (addr == (char *)-1) { - bozo_warn(httpd, "mmap failed: %s", strerror(errno)); + bozowarn(httpd, "mmap failed: %s", strerror(errno)); return -1; } mappedaddr = addr; @@ -808,7 +807,7 @@ mmap_and_write_part(bozohttpd_t *httpd, while (sz > BOZO_WRSZ) { if (bozo_write(httpd, STDOUT_FILENO, addr + wroffset, BOZO_WRSZ) != BOZO_WRSZ) { - bozo_warn(httpd, "write failed: %s", strerror(errno)); + bozowarn(httpd, "write failed: %s", strerror(errno)); goto out; } debug((httpd, DEBUG_OBESE, "wrote %d bytes", BOZO_WRSZ)); @@ -817,13 +816,13 @@ mmap_and_write_part(bozohttpd_t *httpd, } if (sz && (size_t)bozo_write(httpd, STDOUT_FILENO, addr + wroffset, sz) != sz) { - bozo_warn(httpd, "final write failed: %s", strerror(errno)); + bozowarn(httpd, "final write failed: %s", strerror(errno)); goto out; } debug((httpd, DEBUG_OBESE, "wrote %d bytes", (int)sz)); out: if (munmap(mappedaddr, mappedsz) < 0) { - bozo_warn(httpd, "munmap failed"); + bozowarn(httpd, "munmap failed"); return -1; } @@ -851,10 +850,11 @@ parse_http_date(const char *val, time_t /* * 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 +868,6 @@ bozo_escape_rfc3986(bozohttpd_t *httpd, 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,11 +890,18 @@ bozo_escape_rfc3986(bozohttpd_t *httpd, case ';': case '=': case '%': + case '"': + if (absolute) + goto leave_it; + case '\n': + case '\r': + case ' ': encode_it: - snprintf(d, 4, "%%%2X", *s++); + snprintf(d, 4, "%%%02X", *s++); d += 3; len += 3; break; + leave_it: default: *d++ = *s++; len++; @@ -912,115 +914,118 @@ bozo_escape_rfc3986(bozohttpd_t *httpd, } /* - * 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) +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 *scheme, *query, *quest; const char *hostname = BOZOHOST(httpd, request); - int query = 0; + int absproto = 0; /* absolute redirect provides own schema */ if (url == NULL) { - if (asprintf(&urlbuf, "/%s/", request->hr_file) < 0) - bozo_err(httpd, 1, "asprintf"); + bozoasprintf(httpd, &urlbuf, "/%s/", request->hr_file); url = urlbuf; } else urlbuf = NULL; - url = bozo_escape_rfc3986(request->hr_httpd, url); - if (request->hr_query && strlen(request->hr_query)) - query = 1; +#ifndef NO_USER_SUPPORT + if (request->hr_user && !absolute) { + bozoasprintf(httpd, &userbuf, "/~%s%s", request->hr_user, url); + url = userbuf; + } else + userbuf = NULL; +#endif /* !NO_USER_SUPPORT */ + + if (absolute) { + char *sep = NULL; + const char *s; - if (request->hr_serverport && strcmp(request->hr_serverport, "80") != 0) - snprintf(portbuf, sizeof(portbuf), ":%s", - request->hr_serverport); - else + /* + * 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) { + for (s = url; s != sep;) { + if (!isalnum((int)*s) && + *s != '+' && *s != '-' && *s != '.') + break; + if (++s == sep) { + absproto = 1; + } + } + } + } + + /* construct final redirection url */ + + scheme = absproto ? "" : httpd->sslinfo ? "https://" : "http://"; + + if (absolute) { + hostname = ""; 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)); + } else { + const char *defport = httpd->sslinfo ? "443" : "80"; + + if (request->hr_serverport && + strcmp(request->hr_serverport, defport) != 0) + snprintf(portbuf, sizeof(portbuf), ":%s", + request->hr_serverport); + else + portbuf[0] = '\0'; + } + + url = bozo_escape_rfc3986(httpd, url, absolute); + + if (request->hr_query && strlen(request->hr_query)) { + query = request->hr_query; + quest = "?"; + } else { + query = quest = ""; + } + + bozoasprintf(httpd, &finalurl, "%s%s%s%s%s%s", + scheme, hostname, portbuf, url, quest, query); + + bozowarn(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 */ } /* @@ -1037,9 +1042,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 */ @@ -1050,12 +1052,12 @@ check_virtual(bozo_httpreq_t *request) file += 7; /* RFC 2616 (HTTP/1.1), 5.2: URI takes precedence over Host: */ free(request->hr_host); - request->hr_host = bozostrdup(request->hr_httpd, file); + request->hr_host = bozostrdup(httpd, request, file); if ((s = strchr(request->hr_host, '/')) != NULL) *s = '\0'; s = strchr(file, '/'); free(request->hr_file); - request->hr_file = bozostrdup(request->hr_httpd, s ? s : "/"); + request->hr_file = bozostrdup(httpd, request, s ? s : "/"); debug((httpd, DEBUG_OBESE, "got host ``%s'' file is now ``%s''", request->hr_host, request->hr_file)); } else if (!request->hr_host) @@ -1069,6 +1071,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(httpd, request, + 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 @@ -1093,15 +1118,14 @@ check_virtual(bozo_httpreq_t *request) } debug((httpd, DEBUG_OBESE, "looking at dir``%s''", d->d_name)); - if (d->d_namlen == len && strcmp(d->d_name, - request->hr_host) == 0) { + if (strcmp(d->d_name, request->hr_host) == 0) { /* found it, punch it */ debug((httpd, DEBUG_OBESE, "found it punch it")); request->hr_virthostname = - bozostrdup(httpd, d->d_name); - if (asprintf(&s, "%s/%s", httpd->virtbase, - request->hr_virthostname) < 0) - bozo_err(httpd, 1, "asprintf"); + bozostrdup(httpd, request, d->d_name); + bozoasprintf(httpd, &s, "%s/%s", + httpd->virtbase, + request->hr_virthostname); break; } } @@ -1138,6 +1162,7 @@ use_slashdir: static int check_bzredirect(bozo_httpreq_t *request) { + bozohttpd_t *httpd = request->hr_httpd; struct stat sb; char dir[MAXPATHLEN], redir[MAXPATHLEN], redirpath[MAXPATHLEN + 1], path[MAXPATHLEN]; @@ -1150,27 +1175,31 @@ check_bzredirect(bozo_httpreq_t *request */ if((size_t)snprintf(dir, sizeof(dir), "%s", request->hr_file + 1) >= sizeof(dir)) { - bozo_http_error(request->hr_httpd, 404, request, + bozo_http_error(httpd, 404, request, "file path too long"); return -1; } - debug((request->hr_httpd, DEBUG_FAT, "check_bzredirect: dir %s", dir)); + debug((httpd, DEBUG_FAT, "check_bzredirect: 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 { + 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((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"); + bozo_http_error(httpd, 404, request, + "redirectfile path too long"); return -1; } if (lstat(redir, &sb) == 0) { @@ -1178,9 +1207,9 @@ 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, + bozo_http_error(httpd, 404, request, "redirectfile path too long"); return -1; } @@ -1188,16 +1217,14 @@ check_bzredirect(bozo_httpreq_t *request return 0; absolute = 1; } - debug((request->hr_httpd, DEBUG_FAT, - "check_bzredirect: calling readlink")); + debug((httpd, DEBUG_FAT, "check_bzredirect: calling readlink")); rv = readlink(redir, redirpath, sizeof redirpath - 1); if (rv == -1 || rv == 0) { - debug((request->hr_httpd, DEBUG_FAT, "readlink failed")); + debug((httpd, DEBUG_FAT, "readlink failed")); return 0; } redirpath[rv] = '\0'; - debug((request->hr_httpd, DEBUG_FAT, - "readlink returned \"%s\"", redirpath)); + debug((httpd, DEBUG_FAT, "readlink returned \"%s\"", redirpath)); /* check if we need authentication */ snprintf(path, sizeof(path), "%s/", dir); @@ -1205,19 +1232,17 @@ 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)) { - bozo_http_error(request->hr_httpd, 404, request, + 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(httpd, 404, request, "redirect path too long"); return -1; } - } + } else + finalredir = redirpath; - debug((request->hr_httpd, DEBUG_FAT, - "check_bzredirect: new redir %s", finalredir)); + debug((httpd, DEBUG_FAT, "check_bzredirect: new redir %s", finalredir)); handle_redirect(request, finalredir, absolute); return 1; } @@ -1297,7 +1322,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 @@ -1315,7 +1339,6 @@ transform_request(bozo_httpreq_t *reques bozohttpd_t *httpd = request->hr_httpd; char *file, *newfile = NULL; size_t len; - const char *hostname = BOZOHOST(httpd, request); file = NULL; *isindex = 0; @@ -1333,84 +1356,49 @@ transform_request(bozo_httpreq_t *reques goto bad_done; } - switch(check_bzredirect(request)) { - case -1: - goto bad_done; - case 1: - return 0; - } + /* omit additional slashes at the beginning */ + while (file[1] == '/') + file++; - 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; + bozoasprintf(httpd, &userredirecturl, "%s/", file); + 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; @@ -1420,10 +1408,10 @@ transform_request(bozo_httpreq_t *reques strcpy(newfile, file + 1); strcat(newfile, httpd->index_html); } else - newfile = bozostrdup(request->hr_httpd, file + 1); + newfile = bozostrdup(httpd, request, file + 1); } else if (len == 1) { debug((httpd, DEBUG_EXPLODING, "tf_req: len == 1")); - newfile = bozostrdup(request->hr_httpd, httpd->index_html); + newfile = bozostrdup(httpd, request, httpd->index_html); *isindex = 1; } else { /* len == 0 ? */ (void)bozo_http_error(httpd, 500, request, @@ -1437,15 +1425,14 @@ transform_request(bozo_httpreq_t *reques } /* - * 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"); @@ -1549,7 +1536,7 @@ bozo_process_request(bozo_httpreq_t *req fd = -1; encoding = NULL; if (can_gzip(request)) { - asprintf(&file, "%s.gz", request->hr_file); + bozoasprintf(httpd, &file, "%s.gz", request->hr_file); fd = open(file, O_RDONLY); if (fd >= 0) encoding = "gzip"; @@ -1563,7 +1550,7 @@ bozo_process_request(bozo_httpreq_t *req 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, @@ -1642,9 +1629,6 @@ bozo_process_request(bozo_httpreq_t *req 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 @@ -1726,7 +1710,7 @@ bozo_print_header(bozo_httpreq_t *reques 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); } @@ -1756,7 +1740,7 @@ debug__(bozohttpd_t *httpd, int level, c /* these are like warn() and err(), except for syslog not stderr */ void -bozo_warn(bozohttpd_t *httpd, const char *fmt, ...) +bozowarn(bozohttpd_t *httpd, const char *fmt, ...) { va_list ap; @@ -1771,7 +1755,7 @@ bozo_warn(bozohttpd_t *httpd, const char } void -bozo_err(bozohttpd_t *httpd, int code, const char *fmt, ...) +bozoerr(bozohttpd_t *httpd, int code, const char *fmt, ...) { va_list ap; @@ -1786,6 +1770,20 @@ bozo_err(bozohttpd_t *httpd, int code, c exit(code); } +void +bozoasprintf(bozohttpd_t *httpd, char **str, const char *fmt, ...) +{ + va_list ap; + int e; + + va_start(ap, fmt); + e = vasprintf(str, fmt, ap); + va_end(ap); + + if (e < 0) + bozoerr(httpd, EXIT_FAILURE, "asprintf"); +} + /* * this escapes HTML tags. returns allocated escaped * string if needed, or NULL on allocation failure or @@ -1906,7 +1904,7 @@ bozo_http_error(bozohttpd_t *httpd, int debug((httpd, DEBUG_FAT, "bozo_http_error %d: %s", code, msg)); if (header == NULL || reason == NULL) { - bozo_err(httpd, 1, + bozoerr(httpd, 1, "bozo_http_error() failed (short = %p, long = %p)", header, reason); return code; @@ -1920,26 +1918,47 @@ bozo_http_error(bozohttpd_t *httpd, int portbuf[0] = '\0'; if (request && request->hr_file) { - char *file = NULL; + char *file = NULL, *user = NULL, *user_escaped = NULL; + int file_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; + /* expand username to ~user/ */ + bozoasprintf(httpd, &user, "~%s/", user_escaped); + if (user_escaped != request->hr_user) + 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); + free(user); if (size >= (int)BUFSIZ) { - bozo_warn(httpd, + bozowarn(httpd, "bozo_http_error buffer too small, truncated"); size = (int)BUFSIZ; } + + if (file_alloc) + free(file); } else size = 0; @@ -2078,12 +2097,11 @@ bozorealloc(bozohttpd_t *httpd, void *pt void *p; p = realloc(ptr, size); - if (p == NULL) { - (void)bozo_http_error(httpd, 500, NULL, - "memory allocation failure"); - exit(1); - } - return (p); + if (p) + return p; + + (void)bozo_http_error(httpd, 500, NULL, "memory allocation failure"); + exit(EXIT_FAILURE); } void * @@ -2092,26 +2110,27 @@ bozomalloc(bozohttpd_t *httpd, size_t si void *p; p = malloc(size); - if (p == NULL) { - (void)bozo_http_error(httpd, 500, NULL, - "memory allocation failure"); - exit(1); - } - return (p); + if (p) + return p; + + (void)bozo_http_error(httpd, 500, NULL, "memory allocation failure"); + exit(EXIT_FAILURE); } char * -bozostrdup(bozohttpd_t *httpd, const char *str) +bozostrdup(bozohttpd_t *httpd, bozo_httpreq_t *request, const char *str) { char *p; p = strdup(str); - if (p == NULL) { - (void)bozo_http_error(httpd, 500, NULL, - "memory allocation failure"); - exit(1); - } - return (p); + if (p) + return p; + + if (!request) + bozoerr(httpd, EXIT_FAILURE, "strdup"); + + (void)bozo_http_error(httpd, 500, request, "memory allocation failure"); + exit(EXIT_FAILURE); } /* set default values in bozohttpd_t struct */ @@ -2144,15 +2163,16 @@ bozo_init_httpd(bozohttpd_t *httpd) /* set default values in bozoprefs_t struct */ int -bozo_init_prefs(bozoprefs_t *prefs) +bozo_init_prefs(bozohttpd_t *httpd, bozoprefs_t *prefs) { /* make sure everything is clean */ (void) memset(prefs, 0x0, sizeof(*prefs)); /* set up default values */ - bozo_set_pref(prefs, "server software", SERVER_SOFTWARE); - bozo_set_pref(prefs, "index.html", INDEX_HTML); - bozo_set_pref(prefs, "public_html", PUBLIC_HTML); + if (!bozo_set_pref(httpd, prefs, "server software", SERVER_SOFTWARE) || + !bozo_set_pref(httpd, prefs, "index.html", INDEX_HTML) || + !bozo_set_pref(httpd, prefs, "public_html", PUBLIC_HTML)) + return 0; return 1; } @@ -2161,7 +2181,7 @@ bozo_init_prefs(bozoprefs_t *prefs) int bozo_set_defaults(bozohttpd_t *httpd, bozoprefs_t *prefs) { - return bozo_init_httpd(httpd) && bozo_init_prefs(prefs); + return bozo_init_httpd(httpd) && bozo_init_prefs(httpd, prefs); } /* set the virtual host name, port and root */ @@ -2183,16 +2203,15 @@ bozo_setup(bozohttpd_t *httpd, bozoprefs if (vhost == NULL) { httpd->virthostname = bozomalloc(httpd, MAXHOSTNAMELEN+1); - /* XXX we do not check for FQDN here */ if (gethostname(httpd->virthostname, MAXHOSTNAMELEN+1) < 0) - bozo_err(httpd, 1, "gethostname"); + bozoerr(httpd, 1, "gethostname"); httpd->virthostname[MAXHOSTNAMELEN] = '\0'; } else { - httpd->virthostname = strdup(vhost); + httpd->virthostname = bozostrdup(httpd, NULL, vhost); } - httpd->slashdir = strdup(root); + httpd->slashdir = bozostrdup(httpd, NULL, root); if ((portnum = bozo_get_pref(prefs, "port number")) != NULL) { - httpd->bindport = strdup(portnum); + httpd->bindport = bozostrdup(httpd, NULL, portnum); } /* go over preferences now */ @@ -2200,16 +2219,12 @@ bozo_setup(bozohttpd_t *httpd, bozoprefs 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; } if ((cp = bozo_get_pref(prefs, "bind address")) != NULL) { - httpd->bindaddress = strdup(cp); + httpd->bindaddress = bozostrdup(httpd, NULL, cp); } if ((cp = bozo_get_pref(prefs, "background")) != NULL) { httpd->background = atoi(cp); @@ -2219,19 +2234,23 @@ bozo_setup(bozohttpd_t *httpd, bozoprefs httpd->foreground = 1; } if ((cp = bozo_get_pref(prefs, "pid file")) != NULL) { - httpd->pidfile = strdup(cp); + httpd->pidfile = bozostrdup(httpd, NULL, cp); } if ((cp = bozo_get_pref(prefs, "unknown slash")) != NULL && strcmp(cp, "true") == 0) { httpd->unknown_slash = 1; } if ((cp = bozo_get_pref(prefs, "virtual base")) != NULL) { - httpd->virtbase = strdup(cp); + httpd->virtbase = bozostrdup(httpd, NULL, cp); } if ((cp = bozo_get_pref(prefs, "enable users")) != NULL && 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; @@ -2245,11 +2264,12 @@ bozo_setup(bozohttpd_t *httpd, bozoprefs httpd->dir_indexing = 1; } if ((cp = bozo_get_pref(prefs, "public_html")) != NULL) { - httpd->public_html = strdup(cp); + httpd->public_html = bozostrdup(httpd, NULL, cp); } httpd->server_software = - strdup(bozo_get_pref(prefs, "server software")); - httpd->index_html = strdup(bozo_get_pref(prefs, "index.html")); + bozostrdup(httpd, NULL, bozo_get_pref(prefs, "server software")); + httpd->index_html = + bozostrdup(httpd, NULL, bozo_get_pref(prefs, "index.html")); /* * initialise ssl and daemon mode if necessary. @@ -2257,39 +2277,33 @@ bozo_setup(bozohttpd_t *httpd, bozoprefs bozo_ssl_init(httpd); bozo_daemon_init(httpd); - if ((username = bozo_get_pref(prefs, "username")) == NULL) { - if ((pw = getpwuid(uid = 0)) == NULL) - bozo_err(httpd, 1, "getpwuid(0): %s", strerror(errno)); - httpd->username = strdup(pw->pw_name); - } else { - httpd->username = strdup(username); - if ((pw = getpwnam(httpd->username)) == NULL) - bozo_err(httpd, 1, "getpwnam(%s): %s", httpd->username, - strerror(errno)); + username = bozo_get_pref(prefs, "username"); + if (username != NULL) { + if ((pw = getpwnam(username)) == NULL) + bozoerr(httpd, 1, "getpwnam(%s): %s", username, + strerror(errno)); if (initgroups(pw->pw_name, pw->pw_gid) == -1) - bozo_err(httpd, 1, "initgroups: %s", strerror(errno)); + bozoerr(httpd, 1, "initgroups: %s", strerror(errno)); if (setgid(pw->pw_gid) == -1) - bozo_err(httpd, 1, "setgid(%u): %s", pw->pw_gid, - strerror(errno)); + bozoerr(httpd, 1, "setgid(%u): %s", pw->pw_gid, + strerror(errno)); uid = pw->pw_uid; } /* * handle chroot. */ if ((chrootdir = bozo_get_pref(prefs, "chroot dir")) != NULL) { - httpd->rootdir = strdup(chrootdir); + httpd->rootdir = bozostrdup(httpd, NULL, chrootdir); if (chdir(httpd->rootdir) == -1) - bozo_err(httpd, 1, "chdir(%s): %s", httpd->rootdir, + bozoerr(httpd, 1, "chdir(%s): %s", httpd->rootdir, strerror(errno)); if (chroot(httpd->rootdir) == -1) - bozo_err(httpd, 1, "chroot(%s): %s", httpd->rootdir, + bozoerr(httpd, 1, "chroot(%s): %s", httpd->rootdir, strerror(errno)); } - if (username != NULL) - if (setuid(uid) == -1) - bozo_err(httpd, 1, "setuid(%d): %s", uid, - strerror(errno)); + if (username != NULL && setuid(uid) == -1) + bozoerr(httpd, 1, "setuid(%d): %s", uid, strerror(errno)); /* * prevent info leakage between different compartments. Index: src/libexec/httpd/bozohttpd.h diff -u src/libexec/httpd/bozohttpd.h:1.33.2.2 src/libexec/httpd/bozohttpd.h:1.33.2.3 --- src/libexec/httpd/bozohttpd.h:1.33.2.2 Sat May 9 08:50:42 2015 +++ src/libexec/httpd/bozohttpd.h Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: bozohttpd.h,v 1.33.2.2 2015/05/09 08:50:42 snj Exp $ */ +/* $NetBSD: bozohttpd.h,v 1.33.2.3 2016/04/10 10:33:11 martin Exp $ */ /* $eterna: bozohttpd.h,v 1.39 2011/11/18 09:21:15 mrg Exp $ */ @@ -41,6 +41,11 @@ #endif #include <stdio.h> +/* QNX provides a lot of NetBSD things in nbutil.h */ +#ifdef HAVE_NBUTIL_H +#include <nbutil.h> +#endif + /* lots of "const" but gets free()'ed etc at times, sigh */ /* headers */ @@ -85,11 +90,9 @@ typedef struct bozo_consts_t { /* this structure encapsulates all the bozo flags and control vars */ typedef struct bozohttpd_t { char *rootdir; /* root directory */ - char *username; /* username to switch to */ 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 */ @@ -104,6 +107,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 */ @@ -146,6 +150,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; @@ -176,8 +183,8 @@ typedef struct bozo_httpreq_t { /* structure to hold string based (name, value) pairs with preferences */ typedef struct bozoprefs_t { - unsigned size; /* size of the two arrays */ - unsigned c; /* # of entries in arrays */ + size_t size; /* size of the two arrays */ + size_t count; /* # of entries in arrays */ char **name; /* names of each entry */ char **value; /* values for the name entries */ } bozoprefs_t; @@ -210,34 +217,42 @@ void debug__(bozohttpd_t *, int, const c #define debug(x) #endif /* NO_DEBUG */ -void bozo_warn(bozohttpd_t *, const char *, ...) - BOZO_PRINTFLIKE(2, 3); -void bozo_err(bozohttpd_t *, int, const char *, ...) - BOZO_PRINTFLIKE(3, 4) - BOZO_DEAD; 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); +void bozo_print_header(bozo_httpreq_t *, struct stat *, const char *, + const char *); +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)); +/* these are similar to libc functions, no underscore here */ +void bozowarn(bozohttpd_t *, const char *, ...) + BOZO_PRINTFLIKE(2, 3); +void bozoerr(bozohttpd_t *, int, const char *, ...) + BOZO_PRINTFLIKE(3, 4) + BOZO_DEAD; +void bozoasprintf(bozohttpd_t *, char **, const char *, ...) + BOZO_PRINTFLIKE(3, 4); +char *bozodgetln(bozohttpd_t *, int, ssize_t *, ssize_t (*)(bozohttpd_t *, + int, void *, size_t)); char *bozostrnsep(char **, const char *, ssize_t *); - void *bozomalloc(bozohttpd_t *, size_t); void *bozorealloc(bozohttpd_t *, void *, size_t); -char *bozostrdup(bozohttpd_t *, const char *); +char *bozostrdup(bozohttpd_t *, bozo_httpreq_t *, const char *); + +#define bozo_noop do { /* nothing */ } while (/*CONSTCOND*/0) /* ssl-bozo.c */ #ifdef NO_SSL_SUPPORT -#define bozo_ssl_set_opts(w, x, y) do { /* nothing */ } while (0) -#define bozo_ssl_init(x) do { /* nothing */ } while (0) +#define bozo_ssl_set_opts(w, x, y) bozo_noop +#define bozo_ssl_set_ciphers(w, x, y) bozo_noop +#define bozo_ssl_init(x) bozo_noop #define bozo_ssl_accept(x) (0) -#define bozo_ssl_destroy(x) do { /* nothing */ } while (0) +#define bozo_ssl_destroy(x) bozo_noop #else void bozo_ssl_set_opts(bozohttpd_t *, const char *, const char *); +void bozo_ssl_set_ciphers(bozohttpd_t *, const char *); void bozo_ssl_init(bozohttpd_t *); int bozo_ssl_accept(bozohttpd_t *); void bozo_ssl_destroy(bozohttpd_t *); @@ -255,13 +270,13 @@ void bozo_auth_check_401(bozo_httpreq_t void bozo_auth_cgi_setenv(bozo_httpreq_t *, char ***); int bozo_auth_cgi_count(bozo_httpreq_t *); #else -#define bozo_auth_init(x) do { /* nothing */ } while (0) +#define bozo_auth_init(x) bozo_noop #define bozo_auth_check(x, y) 0 -#define bozo_auth_cleanup(x) do { /* nothing */ } while (0) +#define bozo_auth_cleanup(x) bozo_noop #define bozo_auth_check_headers(y, z, a, b) 0 #define bozo_auth_check_special_files(x, y) 0 -#define bozo_auth_check_401(x, y) do { /* nothing */ } while (0) -#define bozo_auth_cgi_setenv(x, y) do { /* nothing */ } while (0) +#define bozo_auth_check_401(x, y) bozo_noop +#define bozo_auth_cgi_setenv(x, y) bozo_noop #define bozo_auth_cgi_count(x) 0 #endif /* DO_HTPASSWD */ @@ -288,9 +303,9 @@ int bozo_process_lua(bozo_httpreq_t *); /* daemon-bozo.c */ #ifdef NO_DAEMON_MODE -#define bozo_daemon_init(x) do { /* nothing */ } while (0) +#define bozo_daemon_init(x) bozo_noop #define bozo_daemon_fork(x) 0 -#define bozo_daemon_closefds(x) do { /* nothing */ } while (0) +#define bozo_daemon_closefds(x) bozo_noop #else void bozo_daemon_init(bozohttpd_t *); int bozo_daemon_fork(bozohttpd_t *); @@ -300,9 +315,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 */ @@ -320,7 +337,8 @@ const char *bozo_content_encoding(bozo_h bozo_content_map_t *bozo_match_content_map(bozohttpd_t *, const char *, int); bozo_content_map_t *bozo_get_content_map(bozohttpd_t *, const char *); #ifndef NO_DYNAMIC_CONTENT -void bozo_add_content_map_mime(bozohttpd_t *, const char *, const char *, const char *, const char *); +void bozo_add_content_map_mime(bozohttpd_t *, const char *, const char *, + const char *, const char *); #endif /* I/O */ @@ -331,7 +349,7 @@ int bozo_flush(bozohttpd_t *, FILE *); /* misc */ int bozo_init_httpd(bozohttpd_t *); -int bozo_init_prefs(bozoprefs_t *); +int bozo_init_prefs(bozohttpd_t *, bozoprefs_t *); int bozo_set_defaults(bozohttpd_t *, bozoprefs_t *); int bozo_setup(bozohttpd_t *, bozoprefs_t *, const char *, const char *); bozo_httpreq_t *bozo_read_request(bozohttpd_t *); @@ -339,7 +357,7 @@ void bozo_process_request(bozo_httpreq_t void bozo_clean_request(bozo_httpreq_t *); /* variables */ -int bozo_set_pref(bozoprefs_t *, const char *, const char *); +int bozo_set_pref(bozohttpd_t *, bozoprefs_t *, const char *, const char *); char *bozo_get_pref(bozoprefs_t *, const char *); #endif /* BOZOHTTOPD_H_ */ Index: src/libexec/httpd/cgi-bozo.c diff -u src/libexec/httpd/cgi-bozo.c:1.25.2.2 src/libexec/httpd/cgi-bozo.c:1.25.2.3 --- src/libexec/httpd/cgi-bozo.c:1.25.2.2 Sat May 9 08:50:42 2015 +++ src/libexec/httpd/cgi-bozo.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: cgi-bozo.c,v 1.25.2.2 2015/05/09 08:50:42 snj Exp $ */ +/* $NetBSD: cgi-bozo.c,v 1.25.2.3 2016/04/10 10:33:11 martin Exp $ */ /* $eterna: cgi-bozo.c,v 1.40 2011/11/18 09:21:15 mrg Exp $ */ @@ -75,22 +75,23 @@ content_cgihandler(bozohttpd_t *httpd, b } static int -parse_header(bozohttpd_t *httpd, const char *str, ssize_t len, char **hdr_str, - char **hdr_val) +parse_header(bozo_httpreq_t *request, const char *str, ssize_t len, + char **hdr_str, char **hdr_val) { + struct bozohttpd_t *httpd = request->hr_httpd; char *name, *value; /* if the string passed is zero-length bail out */ if (*str == '\0') return -1; - value = bozostrdup(httpd, str); + value = bozostrdup(httpd, request, str); /* locate the ':' separator in the header/value */ name = bozostrnsep(&value, ":", &len); if (NULL == name || -1 == len) { - free(name); + free(value); return -1; } @@ -127,7 +128,7 @@ finish_cgi_output(bozohttpd_t *httpd, bo (str = bozodgetln(httpd, in, &len, bozo_read)) != NULL) { char *hdr_name, *hdr_value; - if (parse_header(httpd, str, len, &hdr_name, &hdr_value)) + if (parse_header(request, str, len, &hdr_name, &hdr_value)) break; /* @@ -194,7 +195,7 @@ finish_cgi_output(bozohttpd_t *httpd, bo rbytes -= wbytes; bp += wbytes; } else - bozo_err(httpd, 1, + bozoerr(httpd, 1, "cgi output write failed: %s", strerror(errno)); } @@ -214,7 +215,7 @@ append_index_html(bozohttpd_t *httpd, ch void bozo_cgi_setbin(bozohttpd_t *httpd, const char *path) { - httpd->cgibin = strdup(path); + httpd->cgibin = bozostrdup(httpd, NULL, path); debug((httpd, DEBUG_OBESE, "cgibin (cgi-bin directory) is %s", httpd->cgibin)); } @@ -247,8 +248,7 @@ bozo_process_cgi(bozo_httpreq_t *request char date[40]; bozoheaders_t *headp; const char *type, *clen, *info, *cgihandler; - char *query, *s, *t, *path, *env, *file, *url; - char command[MAXPATHLEN]; + char *query, *s, *t, *path, *env, *command, *file, *url; char **envp, **curenvp, *argv[4]; char *uri; size_t len; @@ -260,31 +260,36 @@ 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 uri = request->hr_file; if (uri[0] == '/') - file = bozostrdup(httpd, uri); + file = bozostrdup(httpd, request, uri); else - asprintf(&file, "/%s", uri); - if (file == NULL) - return 0; + bozoasprintf(httpd, &file, "/%s", uri); if (request->hr_query && strlen(request->hr_query)) - query = bozostrdup(httpd, request->hr_query); + query = bozostrdup(httpd, request, request->hr_query); else query = NULL; - asprintf(&url, "%s%s%s", file, query ? "?" : "", query ? query : ""); - if (url == NULL) - goto out; + bozoasprintf(httpd, &url, "%s%s%s", + file, + query ? "?" : "", + query ? query : ""); debug((httpd, DEBUG_NORMAL, "bozo_process_cgi: url `%s'", url)); path = NULL; envp = NULL; cgihandler = NULL; + command = NULL; info = NULL; len = strlen(url); @@ -309,15 +314,14 @@ bozo_process_cgi(bozo_httpreq_t *request ix = 0; if (cgihandler) { - snprintf(command, sizeof(command), "%s", file + 1); - path = bozostrdup(httpd, cgihandler); + command = file + 1; + path = bozostrdup(httpd, request, cgihandler); argv[ix++] = path; /* argv[] = [ path, command, query, NULL ] */ } else { - snprintf(command, sizeof(command), "%s", - file + CGIBIN_PREFIX_LEN + 1); + command = file + CGIBIN_PREFIX_LEN + 1; if ((s = strchr(command, '/')) != NULL) { - info = bozostrdup(httpd, s); + info = bozostrdup(httpd, request, s); *s = '\0'; } path = bozomalloc(httpd, @@ -414,21 +418,18 @@ bozo_process_cgi(bozo_httpreq_t *request bozo_setenv(httpd, "REMOTE_ADDR", request->hr_remoteaddr, curenvp++); /* - * XXX Apache does this when invoking content handlers, and PHP - * XXX 5.3 requires it as a "security" measure. + * Apache does this when invoking content handlers, and PHP + * 5.3 requires it as a "security" measure. */ if (cgihandler) bozo_setenv(httpd, "REDIRECT_STATUS", "200", curenvp++); bozo_auth_cgi_setenv(request, &curenvp); - free(file); - free(url); - debug((httpd, DEBUG_FAT, "bozo_process_cgi: going exec %s, %s %s %s", path, argv[0], strornull(argv[1]), strornull(argv[2]))); if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sv) == -1) - bozo_err(httpd, 1, "child socketpair failed: %s", + bozoerr(httpd, 1, "child socketpair failed: %s", strerror(errno)); /* @@ -439,7 +440,7 @@ bozo_process_cgi(bozo_httpreq_t *request */ switch (fork()) { case -1: /* eep, failure */ - bozo_err(httpd, 1, "child fork failed: %s", strerror(errno)); + bozoerr(httpd, 1, "child fork failed: %s", strerror(errno)); /*NOTREACHED*/ case 0: close(sv[0]); @@ -451,19 +452,23 @@ bozo_process_cgi(bozo_httpreq_t *request bozo_daemon_closefds(httpd); if (-1 == execve(path, argv, envp)) - bozo_err(httpd, 1, "child exec failed: %s: %s", + bozoerr(httpd, 1, "child exec failed: %s: %s", path, strerror(errno)); /* NOT REACHED */ - bozo_err(httpd, 1, "child execve returned?!"); + bozoerr(httpd, 1, "child execve returned?!"); } + free(query); + free(file); + free(url); + close(sv[1]); /* parent: read from stdin (bozo_read()) write to sv[0] */ /* child: read from sv[0] (bozo_write()) write to stdout */ pid = fork(); if (pid == -1) - bozo_err(httpd, 1, "io child fork failed: %s", strerror(errno)); + bozoerr(httpd, 1, "io child fork failed: %s", strerror(errno)); else if (pid == 0) { /* child reader/writer */ close(STDIN_FILENO); @@ -487,7 +492,7 @@ bozo_process_cgi(bozo_httpreq_t *request rbytes -= wbytes; bp += wbytes; } else - bozo_err(httpd, 1, "write failed: %s", + bozoerr(httpd, 1, "write failed: %s", strerror(errno)); } } @@ -504,7 +509,8 @@ bozo_process_cgi(bozo_httpreq_t *request #ifndef NO_DYNAMIC_CONTENT /* cgi maps are simple ".postfix /path/to/prog" */ void -bozo_add_content_map_cgi(bozohttpd_t *httpd, const char *arg, const char *cgihandler) +bozo_add_content_map_cgi(bozohttpd_t *httpd, const char *arg, + const char *cgihandler) { bozo_content_map_t *map; Index: src/libexec/httpd/content-bozo.c diff -u src/libexec/httpd/content-bozo.c:1.10.2.2 src/libexec/httpd/content-bozo.c:1.10.2.3 --- src/libexec/httpd/content-bozo.c:1.10.2.2 Sat May 9 08:50:42 2015 +++ src/libexec/httpd/content-bozo.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: content-bozo.c,v 1.10.2.2 2015/05/09 08:50:42 snj Exp $ */ +/* $NetBSD: content-bozo.c,v 1.10.2.3 2016/04/10 10:33:11 martin Exp $ */ /* $eterna: content-bozo.c,v 1.17 2011/11/18 09:21:15 mrg Exp $ */ @@ -258,7 +258,7 @@ bozo_get_content_map(bozohttpd_t *httpd, httpd->dynamic_content_map, (httpd->dynamic_content_map_size + 1) * sizeof *map); if (httpd->dynamic_content_map == NULL) - bozo_err(httpd, 1, "out of memory allocating content map"); + bozoerr(httpd, 1, "out of memory allocating content map"); map = &httpd->dynamic_content_map[httpd->dynamic_content_map_size]; map->name = map->type = map->encoding = map->encoding11 = map->cgihandler = NULL; Index: src/libexec/httpd/daemon-bozo.c diff -u src/libexec/httpd/daemon-bozo.c:1.16 src/libexec/httpd/daemon-bozo.c:1.16.4.1 --- src/libexec/httpd/daemon-bozo.c:1.16 Thu Jan 2 08:21:38 2014 +++ src/libexec/httpd/daemon-bozo.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: daemon-bozo.c,v 1.16 2014/01/02 08:21:38 mrg Exp $ */ +/* $NetBSD: daemon-bozo.c,v 1.16.4.1 2016/04/10 10:33:11 martin Exp $ */ /* $eterna: daemon-bozo.c,v 1.24 2011/11/18 09:21:15 mrg Exp $ */ @@ -105,10 +105,10 @@ create_pidfile(bozohttpd_t *httpd) return; if (atexit(remove_pidfile) == -1) - bozo_err(httpd, 1, "Failed to install pidfile handler"); + bozoerr(httpd, 1, "Failed to install pidfile handler"); if ((file = fopen(httpd->pidfile, "w")) == NULL) - bozo_err(httpd, 1, "Failed to create pidfile '%s'", + bozoerr(httpd, 1, "Failed to create pidfile '%s'", httpd->pidfile); (void)fprintf(file, "%d\n", getpid()); (void)fclose(file); @@ -138,7 +138,7 @@ bozo_daemon_init(bozohttpd_t *httpd) h.ai_flags = AI_PASSIVE; e = getaddrinfo(httpd->bindaddress, portnum, &h, &r0); if (e) - bozo_err(httpd, 1, "getaddrinfo([%s]:%s): %s", + bozoerr(httpd, 1, "getaddrinfo([%s]:%s): %s", httpd->bindaddress ? httpd->bindaddress : "*", portnum, gai_strerror(e)); for (r = r0; r != NULL; r = r->ai_next) @@ -151,7 +151,7 @@ bozo_daemon_init(bozohttpd_t *httpd) continue; if (setsockopt(httpd->sock[i], SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) - bozo_warn(httpd, "setsockopt SO_REUSEADDR: %s", + bozowarn(httpd, "setsockopt SO_REUSEADDR: %s", strerror(errno)); if (bind(httpd->sock[i], r->ai_addr, r->ai_addrlen) == -1) continue; @@ -163,7 +163,7 @@ bozo_daemon_init(bozohttpd_t *httpd) i++; } if (i == 0) - bozo_err(httpd, 1, "could not find any addresses to bind"); + bozoerr(httpd, 1, "could not find any addresses to bind"); httpd->nsock = i; freeaddrinfo(r0); @@ -172,7 +172,7 @@ bozo_daemon_init(bozohttpd_t *httpd) create_pidfile(httpd); - bozo_warn(httpd, "started in daemon mode as `%s' port `%s' root `%s'", + bozowarn(httpd, "started in daemon mode as `%s' port `%s' root `%s'", httpd->virthostname, portnum, httpd->slashdir); signal(SIGHUP, controlled_exit); @@ -209,13 +209,13 @@ daemon_poll_err(bozohttpd_t *httpd, int if ((httpd->fds[idx].revents & (POLLNVAL|POLLERR|POLLHUP)) == 0) return 0; - bozo_warn(httpd, "poll on fd %d pid %d revents %d: %s", + bozowarn(httpd, "poll on fd %d pid %d revents %d: %s", httpd->fds[idx].fd, getpid(), httpd->fds[idx].revents, strerror(errno)); - bozo_warn(httpd, "nsock = %d", httpd->nsock); + bozowarn(httpd, "nsock = %d", httpd->nsock); close(httpd->sock[idx]); httpd->nsock--; - bozo_warn(httpd, "nsock now = %d", httpd->nsock); + bozowarn(httpd, "nsock now = %d", httpd->nsock); /* no sockets left */ if (httpd->nsock == 0) exit(0); @@ -271,7 +271,7 @@ again: /* fail on programmer errors */ if (errno == EFAULT || errno == EINVAL) - bozo_err(httpd, 1, "poll: %s", + bozoerr(httpd, 1, "poll: %s", strerror(errno)); /* sleep on some temporary kernel failures */ @@ -294,7 +294,7 @@ again: if (fd == -1) { if (errno == EFAULT || errno == EINVAL) - bozo_err(httpd, 1, "accept: %s", + bozoerr(httpd, 1, "accept: %s", strerror(errno)); if (errno == ENOMEM || @@ -317,7 +317,7 @@ again: switch (fork()) { case -1: /* eep, failure */ - bozo_warn(httpd, "fork() failed, sleeping for " + bozowarn(httpd, "fork() failed, sleeping for " "10 seconds: %s", strerror(errno)); close(fd); sleep(10); Index: src/libexec/httpd/dir-index-bozo.c diff -u src/libexec/httpd/dir-index-bozo.c:1.19.4.1 src/libexec/httpd/dir-index-bozo.c:1.19.4.2 --- src/libexec/httpd/dir-index-bozo.c:1.19.4.1 Mon Jan 12 10:02:29 2015 +++ src/libexec/httpd/dir-index-bozo.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: dir-index-bozo.c,v 1.19.4.1 2015/01/12 10:02:29 martin Exp $ */ +/* $NetBSD: dir-index-bozo.c,v 1.19.4.2 2016/04/10 10:33:11 martin Exp $ */ /* $eterna: dir-index-bozo.c,v 1.20 2011/11/18 09:21:15 mrg Exp $ */ @@ -57,7 +57,7 @@ directory_hr(bozohttpd_t *httpd) * output a directory index. return 1 if it actually did something.. */ int -bozo_dir_index(bozo_httpreq_t *request, const char *dirname, int isindex) +bozo_dir_index(bozo_httpreq_t *request, const char *dirpath, int isindex) { bozohttpd_t *httpd = request->hr_httpd; struct stat sb; @@ -66,23 +66,23 @@ bozo_dir_index(bozo_httpreq_t *request, 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) return 0; - if (strlen(dirname) <= strlen(httpd->index_html)) - dirname = "."; + if (strlen(dirpath) <= strlen(httpd->index_html)) + dirpath = "."; else { - file = bozostrdup(httpd, dirname); + file = bozostrdup(httpd, request, dirpath); file[strlen(file) - strlen(httpd->index_html)] = '\0'; - dirname = file; + dirpath = file; } - debug((httpd, DEBUG_FAT, "bozo_dir_index: dirname ``%s''", dirname)); - if (stat(dirname, &sb) < 0 || - (dp = opendir(dirname)) == NULL) { + debug((httpd, DEBUG_FAT, "bozo_dir_index: dirpath ``%s''", dirpath)); + if (stat(dirpath, &sb) < 0 || + (dp = opendir(dirpath)) == NULL) { if (errno == EPERM) (void)bozo_http_error(httpd, 403, request, "no permission to open directory"); @@ -108,11 +108,21 @@ bozo_dir_index(bozo_httpreq_t *request, goto done; } +#ifndef NO_USER_SUPPORT + if (request->hr_user) { + bozoasprintf(httpd, &printname, "~%s/%s", + request->hr_user, request->hr_file); + } else + printname = bozostrdup(httpd, request, request->hr_file); +#else + printname = bozostrdup(httpd, request, 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 @@ -123,7 +133,7 @@ bozo_dir_index(bozo_httpreq_t *request, directory_hr(httpd); bozo_printf(httpd, "<pre>"); - for (j = k = scandir(dirname, &de, NULL, alphasort), deo = de; + for (j = k = scandir(dirpath, &de, NULL, alphasort), deo = de; j--; de++) { int nostat = 0; char *name = (*de)->d_name; @@ -134,13 +144,13 @@ bozo_dir_index(bozo_httpreq_t *request, httpd->hide_dots && name[0] == '.')) continue; - snprintf(buf, sizeof buf, "%s/%s", dirname, name); + snprintf(buf, sizeof buf, "%s/%s", dirpath, name); if (stat(buf, &sb)) nostat = 1; 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 +216,7 @@ bozo_dir_index(bozo_httpreq_t *request, done: free(file); + free(printname); return 1; } #endif /* NO_DIRINDEX_SUPPORT */ Index: src/libexec/httpd/lua-bozo.c diff -u src/libexec/httpd/lua-bozo.c:1.10.2.1 src/libexec/httpd/lua-bozo.c:1.10.2.2 --- src/libexec/httpd/lua-bozo.c:1.10.2.1 Mon Jan 12 10:02:29 2015 +++ src/libexec/httpd/lua-bozo.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: lua-bozo.c,v 1.10.2.1 2015/01/12 10:02:29 martin Exp $ */ +/* $NetBSD: lua-bozo.c,v 1.10.2.2 2016/04/10 10:33:11 martin Exp $ */ /* * Copyright (c) 2013 Marc Balmer <m...@msys.ch> @@ -123,7 +123,7 @@ lua_register_handler(lua_State *L) handler = bozomalloc(httpd, sizeof(lua_handler_t)); - handler->name = bozostrdup(httpd, lua_tostring(L, 1)); + handler->name = bozostrdup(httpd, NULL, lua_tostring(L, 1)); handler->ref = luaL_ref(L, LUA_REGISTRYINDEX); SIMPLEQ_INSERT_TAIL(&map->handlers, handler, h_next); httpd->process_lua = 1; @@ -184,19 +184,19 @@ bozo_add_lua_map(bozohttpd_t *httpd, con lua_state_map_t *map; map = bozomalloc(httpd, sizeof(lua_state_map_t)); - map->prefix = bozostrdup(httpd, prefix); + map->prefix = bozostrdup(httpd, NULL, prefix); if (*script == '/') - map->script = bozostrdup(httpd, script); + map->script = bozostrdup(httpd, NULL, script); else { char cwd[MAXPATHLEN], *path; getcwd(cwd, sizeof(cwd) - 1); - asprintf(&path, "%s/%s", cwd, script); + bozoasprintf(httpd, &path, "%s/%s", cwd, script); map->script = path; } map->L = luaL_newstate(); if (map->L == NULL) - bozo_err(httpd, 1, "can't create Lua state"); + bozoerr(httpd, 1, "can't create Lua state"); SIMPLEQ_INIT(&map->handlers); #if LUA_VERSION_NUM >= 502 @@ -225,10 +225,10 @@ bozo_add_lua_map(bozohttpd_t *httpd, con lua_settable(map->L, LUA_REGISTRYINDEX); if (luaL_loadfile(map->L, script)) - bozo_err(httpd, 1, "failed to load script %s: %s", script, + bozoerr(httpd, 1, "failed to load script %s: %s", script, lua_tostring(map->L, -1)); if (lua_pcall(map->L, 0, 0, 0)) - bozo_err(httpd, 1, "failed to execute script %s: %s", script, + bozoerr(httpd, 1, "failed to execute script %s: %s", script, lua_tostring(map->L, -1)); SIMPLEQ_INSERT_TAIL(&httpd->lua_states, map, s_next); } @@ -311,44 +311,41 @@ bozo_process_lua(bozo_httpreq_t *request if (!httpd->process_lua) return 0; + info = NULL; + query = NULL; + prefix = NULL; uri = request->hr_oldfile ? request->hr_oldfile : request->hr_file; if (*uri == '/') { - file = bozostrdup(httpd, uri); - prefix = bozostrdup(httpd, &uri[1]); + file = bozostrdup(httpd, request, uri); + if (file == NULL) + goto out; + prefix = bozostrdup(httpd, request, &uri[1]); } else { - prefix = bozostrdup(httpd, uri); - asprintf(&file, "/%s", uri); - } - if (file == NULL) { - free(prefix); - return 0; + if (asprintf(&file, "/%s", uri) < 0) + goto out; + prefix = bozostrdup(httpd, request, uri); } + if (prefix == NULL) + goto out; - if (request->hr_query && strlen(request->hr_query)) - query = bozostrdup(httpd, request->hr_query); - else - query = NULL; + if (request->hr_query && request->hr_query[0]) + query = bozostrdup(httpd, request, request->hr_query); p = strchr(prefix, '/'); - if (p == NULL){ - free(prefix); - return 0; - } + if (p == NULL) + goto out; *p++ = '\0'; handler = p; - if (!*handler) { - free(prefix); - return 0; - } + if (!*handler) + goto out; p = strchr(handler, '/'); if (p != NULL) *p++ = '\0'; - info = NULL; command = file + 1; if ((s = strchr(command, '/')) != NULL) { - info = bozostrdup(httpd, s); + info = bozostrdup(httpd, request, s); *s = '\0'; } Index: src/libexec/httpd/main.c diff -u src/libexec/httpd/main.c:1.8 src/libexec/httpd/main.c:1.8.2.1 --- src/libexec/httpd/main.c:1.8 Wed Jul 16 07:41:43 2014 +++ src/libexec/httpd/main.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.8 2014/07/16 07:41:43 mrg Exp $ */ +/* $NetBSD: main.c,v 1.8.2.1 2016/04/10 10:33:11 martin 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 */ @@ -58,65 +58,67 @@ BOZO_DEAD static void usage(bozohttpd_t *httpd, char *progname) { - bozo_warn(httpd, "usage: %s [options] slashdir [virtualhostname]", + bozowarn(httpd, "usage: %s [options] slashdir [virtualhostname]", progname); - bozo_warn(httpd, "options:"); + bozowarn(httpd, "options:"); #ifndef NO_DEBUG - bozo_warn(httpd, " -d\t\t\tenable debug support"); + bozowarn(httpd, " -d\t\t\tenable debug support"); +#endif + bozowarn(httpd, " -s\t\t\talways log to stderr"); +#ifndef NO_DYNAMIC_CONTENT + bozowarn(httpd, " -M arg t c c11\tadd this mime extenstion"); #endif - bozo_warn(httpd, " -s\t\t\talways log to stderr"); #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]"); + bozowarn(httpd, " -u\t\t\tenable ~user/public_html support"); + bozowarn(httpd, " -p dir\t\tchange `public_html' directory name"); +#ifndef NO_CGIBIN_SUPPORT + bozowarn(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 - bozo_warn(httpd, " -C arg prog\t\tadd this CGI handler"); + bozowarn(httpd, " -C arg prog\t\tadd this CGI handler"); #endif - bozo_warn(httpd, + bozowarn(httpd, " -c cgibin\t\tenable cgi-bin support in this directory"); #endif #ifndef NO_LUA_SUPPORT - bozo_warn(httpd, " -L arg script\tadd this Lua script"); + bozowarn(httpd, " -L arg script\tadd this Lua script"); #endif - bozo_warn(httpd, " -I port\t\tbind or use on this port"); + bozowarn(httpd, " -I port\t\tbind or use on this port"); #ifndef NO_DAEMON_MODE - bozo_warn(httpd, " -b\t\t\tbackground and go into daemon mode"); - bozo_warn(httpd, " -f\t\t\tkeep daemon mode in the foreground"); - bozo_warn(httpd, + bozowarn(httpd, " -b\t\t\tbackground and go into daemon mode"); + bozowarn(httpd, " -f\t\t\tkeep daemon mode in the foreground"); + bozowarn(httpd, " -i address\t\tbind on this address (daemon mode only)"); - bozo_warn(httpd, " -P pidfile\t\tpath to the pid file to create"); + bozowarn(httpd, " -P pidfile\t\tpath to the pid file to create"); #endif - bozo_warn(httpd, " -S version\t\tset server version string"); - bozo_warn(httpd, " -t dir\t\tchroot to `dir'"); - bozo_warn(httpd, " -U username\t\tchange user to `user'"); - bozo_warn(httpd, + bozowarn(httpd, " -S version\t\tset server version string"); + bozowarn(httpd, " -t dir\t\tchroot to `dir'"); + bozowarn(httpd, " -U username\t\tchange user to `user'"); + bozowarn(httpd, " -e\t\t\tdon't clean the environment (-t and -U only)"); - bozo_warn(httpd, + bozowarn(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, + bozowarn(httpd, " -X\t\t\tenable automatic directory index support"); - bozo_warn(httpd, + bozowarn(httpd, " -H\t\t\thide files starting with a period (.)" " in index mode"); #endif - bozo_warn(httpd, + bozowarn(httpd, " -x index\t\tchange default `index.html' file name"); #ifndef NO_SSL_SUPPORT - bozo_warn(httpd, + bozowarn(httpd, + " -z ciphers\t\tspecify SSL ciphers"); + bozowarn(httpd, " -Z cert privkey\tspecify path to server certificate" " and private key file\n" "\t\t\tin pem format and enable bozohttpd in SSL mode"); #endif /* NO_SSL_SUPPORT */ - bozo_err(httpd, 1, "%s failed to start", progname); + bozoerr(httpd, 1, "%s failed to start", progname); } int @@ -126,6 +128,7 @@ main(int argc, char **argv) bozohttpd_t httpd; bozoprefs_t prefs; char *progname; + const char *val; int c; (void) memset(&httpd, 0x0, sizeof(httpd)); @@ -140,13 +143,17 @@ 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 - bozo_err(&httpd, 1, + bozoerr(&httpd, 1, "Lua support is not enabled"); /* NOTREACHED */ #else @@ -159,7 +166,7 @@ main(int argc, char **argv) #endif /* NO_LUA_SUPPORT */ case 'M': #ifdef NO_DYNAMIC_CONTENT - bozo_err(&httpd, 1, + bozoerr(&httpd, 1, "dynamic mime content support is not enabled"); /* NOTREACHED */ #else @@ -173,23 +180,20 @@ main(int argc, char **argv) #endif /* NO_DYNAMIC_CONTENT */ case 'n': - bozo_set_pref(&prefs, "numeric", "true"); - break; - - case 'r': - bozo_set_pref(&prefs, "trusted referal", "true"); + bozo_set_pref(&httpd, &prefs, "numeric", "true"); break; case 's': - bozo_set_pref(&prefs, "log to stderr", "true"); + bozo_set_pref(&httpd, &prefs, "log to stderr", "true"); break; case 'S': - bozo_set_pref(&prefs, "server software", optarg); + bozo_set_pref(&httpd, &prefs, "server software", + optarg); break; case 'Z': #ifdef NO_SSL_SUPPORT - bozo_err(&httpd, 1, "ssl support is not enabled"); + bozoerr(&httpd, 1, "ssl support is not enabled"); /* NOT REACHED */ #else /* make sure there's two arguments */ @@ -198,24 +202,34 @@ main(int argc, char **argv) bozo_ssl_set_opts(&httpd, optarg, argv[optind++]); break; #endif /* NO_SSL_SUPPORT */ + + case 'z': +#ifdef NO_SSL_SUPPORT + bozoerr(&httpd, 1, "ssl support is not enabled"); + /* NOT REACHED */ +#else + bozo_ssl_set_ciphers(&httpd, optarg); + break; +#endif /* NO_SSL_SUPPORT */ + case 'U': - bozo_set_pref(&prefs, "username", optarg); + bozo_set_pref(&httpd, &prefs, "username", optarg); break; case 'V': - bozo_set_pref(&prefs, "unknown slash", "true"); + bozo_set_pref(&httpd, &prefs, "unknown slash", "true"); break; case 'v': - bozo_set_pref(&prefs, "virtual base", optarg); + bozo_set_pref(&httpd, &prefs, "virtual base", optarg); break; case 'x': - bozo_set_pref(&prefs, "index.html", optarg); + bozo_set_pref(&httpd, &prefs, "index.html", optarg); break; case 'I': - bozo_set_pref(&prefs, "port number", optarg); + bozo_set_pref(&httpd, &prefs, "port number", optarg); break; #ifdef NO_DAEMON_MODE @@ -224,7 +238,7 @@ main(int argc, char **argv) case 'f': case 'i': case 'P': - bozo_err(&httpd, 1, "Daemon mode is not enabled"); + bozoerr(&httpd, 1, "Daemon mode is not enabled"); /* NOTREACHED */ #else case 'b': @@ -233,34 +247,33 @@ main(int argc, char **argv) * background == 2 (aka, -b -b) means to * only process 1 per kid */ - if (bozo_get_pref(&prefs, "background") == NULL) { - bozo_set_pref(&prefs, "background", "1"); - } else { - bozo_set_pref(&prefs, "background", "2"); - } + val = bozo_get_pref(&prefs, "background") == NULL ? + "1" : "2"; + bozo_set_pref(&httpd, &prefs, "background", val); break; case 'e': - bozo_set_pref(&prefs, "dirty environment", "true"); + bozo_set_pref(&httpd, &prefs, "dirty environment", + "true"); break; case 'f': - bozo_set_pref(&prefs, "foreground", "true"); + bozo_set_pref(&httpd, &prefs, "foreground", "true"); break; case 'i': - bozo_set_pref(&prefs, "bind address", optarg); + bozo_set_pref(&httpd, &prefs, "bind address", optarg); break; case 'P': - bozo_set_pref(&prefs, "pid file", optarg); + bozo_set_pref(&httpd, &prefs, "pid file", optarg); break; #endif /* NO_DAEMON_MODE */ #ifdef NO_CGIBIN_SUPPORT case 'c': case 'C': - bozo_err(&httpd, 1, "CGI is not enabled"); + bozoerr(&httpd, 1, "CGI is not enabled"); /* NOTREACHED */ #else case 'c': @@ -269,7 +282,7 @@ main(int argc, char **argv) case 'C': # ifdef NO_DYNAMIC_CONTENT - bozo_err(&httpd, 1, + bozoerr(&httpd, 1, "dynamic CGI handler support is not enabled"); /* NOTREACHED */ # else @@ -286,42 +299,54 @@ main(int argc, char **argv) httpd.debug++; #ifdef NO_DEBUG if (httpd.debug == 1) - bozo_warn(&httpd, "Debugging is not enabled"); + bozowarn(&httpd, "Debugging is not enabled"); #endif /* NO_DEBUG */ break; case 't': - bozo_set_pref(&prefs, "chroot dir", optarg); + bozo_set_pref(&httpd, &prefs, "chroot dir", optarg); break; #ifdef NO_USER_SUPPORT case 'p': case 'u': - bozo_err(&httpd, 1, "User support is not enabled"); + case 'E': + bozoerr(&httpd, 1, "User support is not enabled"); /* NOTREACHED */ #else case 'p': - bozo_set_pref(&prefs, "public_html", optarg); + bozo_set_pref(&httpd, &prefs, "public_html", optarg); break; case 'u': - bozo_set_pref(&prefs, "enable users", "true"); + bozo_set_pref(&httpd, &prefs, "enable users", "true"); + break; +#ifndef NO_CGIBIN_SUPPORT + case 'E': + bozo_set_pref(&httpd, &prefs, "enable user cgibin", + "true"); break; +#else + case 'E': + bozoerr(&httpd, 1, "CGI is not enabled"); + /* NOTREACHED */ +#endif /* NO_CGIBIN_SPPORT */ #endif /* NO_USER_SUPPORT */ #ifdef NO_DIRINDEX_SUPPORT case 'H': case 'X': - bozo_err(&httpd, 1, + bozoerr(&httpd, 1, "directory indexing is not enabled"); /* NOTREACHED */ #else case 'H': - bozo_set_pref(&prefs, "hide dots", "true"); + bozo_set_pref(&httpd, &prefs, "hide dots", "true"); break; case 'X': - bozo_set_pref(&prefs, "directory indexing", "true"); + bozo_set_pref(&httpd, &prefs, "directory indexing", + "true"); break; #endif /* NO_DIRINDEX_SUPPORT */ Index: src/libexec/httpd/printenv.lua diff -u src/libexec/httpd/printenv.lua:1.2 src/libexec/httpd/printenv.lua:1.2.18.1 --- src/libexec/httpd/printenv.lua:1.2 Thu Jan 2 08:21:38 2014 +++ src/libexec/httpd/printenv.lua Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ --- $NetBSD: printenv.lua,v 1.2 2014/01/02 08:21:38 mrg Exp $ +-- $NetBSD: printenv.lua,v 1.2.18.1 2016/04/10 10:33:11 martin Exp $ -- this small Lua script demonstrates the use of Lua in (bozo)httpd -- it will simply output the "environment" @@ -8,6 +8,10 @@ -- the same value on each invocation. You can not keep state between -- two calls. +-- You can test this example by running the following command: +-- /usr/libexec/httpd -b -f -I 8080 -L test printenv.lua . +-- and then navigate to: http://127.0.0.1:8080/test/printenv + local httpd = require 'httpd' function printenv(env, headers, query) @@ -15,12 +19,14 @@ function printenv(env, headers, query) -- we get the "environment" in the env table, the values are more -- or less the same as the variable for a CGI program - if count == nil then - count = 1 - end - - -- output a header - print([[ + -- output headers using httpd.write() + -- httpd.write() will not append newlines + httpd.write("HTTP/1.1 200 Ok\r\n") + httpd.write("Content-Type: text/html\r\n\r\n") + + -- output html using httpd.print() + -- you can also use print() and io.write() but they will not work with SSL + httpd.print([[ <html> <head> <title>Bozotic Lua Environment</title> @@ -29,54 +35,58 @@ function printenv(env, headers, query) <h1>Bozotic Lua Environment</h1> ]]) - print('module version: ' .. httpd._VERSION .. '<br>') + httpd.print('module version: ' .. httpd._VERSION .. '<br>') - print('<h2>Server Environment</h2>') + httpd.print('<h2>Server Environment</h2>') -- print the list of "environment" variables for k, v in pairs(env) do - print(k .. '=' .. v .. '<br/>') + httpd.print(k .. '=' .. v .. '<br/>') end - print('<h2>Request Headers</h2>') + httpd.print('<h2>Request Headers</h2>') for k, v in pairs(headers) do - print(k .. '=' .. v .. '<br/>') + httpd.print(k .. '=' .. v .. '<br/>') end if query ~= nil then - print('<h2>Query Variables</h2>') + httpd.print('<h2>Query Variables</h2>') for k, v in pairs(query) do - print(k .. '=' .. v .. '<br/>') + httpd.print(k .. '=' .. v .. '<br/>') end end - print('<h2>Form Test</h2>') + httpd.print('<h2>Form Test</h2>') - print([[ - <form method="POST" action="/rest/form?sender=me"> + httpd.print([[ + <form method="POST" action="form?sender=me"> <input type="text" name="a_value"> <input type="submit"> </form> ]]) -- output a footer - print([[ + httpd.print([[ </body> </html> ]]) end function form(env, header, query) + + httpd.write("HTTP/1.1 200 Ok\r\n") + httpd.write("Content-Type: text/html\r\n\r\n") + if query ~= nil then - print('<h2>Form Variables</h2>') + httpd.print('<h2>Form Variables</h2>') if env.CONTENT_TYPE ~= nil then - print('Content-type: ' .. env.CONTENT_TYPE .. '<br>') + httpd.print('Content-type: ' .. env.CONTENT_TYPE .. '<br>') end for k, v in pairs(query) do - print(k .. '=' .. v .. '<br/>') + httpd.print(k .. '=' .. v .. '<br/>') end else - print('No values') + httpd.print('No values') end end Index: src/libexec/httpd/ssl-bozo.c diff -u src/libexec/httpd/ssl-bozo.c:1.18 src/libexec/httpd/ssl-bozo.c:1.18.2.1 --- src/libexec/httpd/ssl-bozo.c:1.18 Thu Jul 17 06:27:52 2014 +++ src/libexec/httpd/ssl-bozo.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: ssl-bozo.c,v 1.18 2014/07/17 06:27:52 mrg Exp $ */ +/* $NetBSD: ssl-bozo.c,v 1.18.2.1 2016/04/10 10:33:11 martin Exp $ */ /* $eterna: ssl-bozo.c,v 1.15 2011/11/18 09:21:15 mrg Exp $ */ @@ -48,6 +48,25 @@ #define USE_ARG(x) /*LINTED*/(void)&(x) #endif +#ifndef BOZO_SSL_CIPHERS +#define BOZO_SSL_CIPHERS \ + "AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:" \ + "AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:" \ + "AES:" \ + "-SHA:" \ + "!aNULL:!eNULL:" \ + "!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:" \ + "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:" \ + "!KRB5-DES-CBC3-SHA" +#endif + +#ifndef BOZO_SSL_OPTIONS +#define BOZO_SSL_OPTIONS \ + (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1) +#endif + + /* this structure encapsulates the ssl info */ + /* this structure encapsulates the ssl info */ typedef struct sslinfo_t { SSL_CTX *ssl_context; @@ -55,6 +74,7 @@ typedef struct sslinfo_t { SSL *bozossl; char *certificate_file; char *privatekey_file; + char *ciphers; } sslinfo_t; /* @@ -83,7 +103,7 @@ bozo_clear_ssl_queue(bozohttpd_t *httpd) } /* - * bozo_ssl_warn works just like bozo_warn, plus the SSL error queue + * bozo_ssl_warn works just like bozowarn, plus the SSL error queue */ BOZO_PRINTFLIKE(2, 3) static void bozo_ssl_warn(bozohttpd_t *httpd, const char *fmt, ...) @@ -103,7 +123,7 @@ bozo_ssl_warn(bozohttpd_t *httpd, const /* - * bozo_ssl_err works just like bozo_err, plus the SSL error queue + * bozo_ssl_err works just like bozoerr, plus the SSL error queue */ BOZO_PRINTFLIKE(3, 4) BOZO_DEAD static void bozo_ssl_err(bozohttpd_t *httpd, int code, const char *fmt, ...) @@ -187,6 +207,7 @@ void bozo_ssl_init(bozohttpd_t *httpd) { sslinfo_t *sslinfo = httpd->sslinfo; + long options; if (sslinfo == NULL || !sslinfo->certificate_file) return; @@ -200,6 +221,18 @@ bozo_ssl_init(bozohttpd_t *httpd) bozo_ssl_err(httpd, EXIT_FAILURE, "SSL context creation failed"); + options = SSL_CTX_set_options(sslinfo->ssl_context, + BOZO_SSL_OPTIONS); + if ((options & BOZO_SSL_OPTIONS) != BOZO_SSL_OPTIONS) + bozo_ssl_err(httpd, EXIT_FAILURE, + "Error setting ssl options requested %#lx, got %#lx", + BOZO_SSL_OPTIONS, options); + + if (!SSL_CTX_set_cipher_list(sslinfo->ssl_context, + sslinfo->ciphers ? sslinfo->ciphers : BOZO_SSL_CIPHERS)) + bozo_ssl_err(httpd, EXIT_FAILURE, + "Error setting cipher list '%s'", sslinfo->ciphers); + if (1 != SSL_CTX_use_certificate_chain_file(sslinfo->ssl_context, sslinfo->certificate_file)) bozo_ssl_err(httpd, EXIT_FAILURE, @@ -231,7 +264,7 @@ bozo_ssl_accept(bozohttpd_t *httpd) sslinfo->bozossl = SSL_new(sslinfo->ssl_context); if (sslinfo->bozossl == NULL) - bozo_err(httpd, 1, "SSL_new failed"); + bozoerr(httpd, 1, "SSL_new failed"); SSL_set_rfd(sslinfo->bozossl, 0); SSL_set_wfd(sslinfo->bozossl, 1); @@ -251,24 +284,40 @@ bozo_ssl_destroy(bozohttpd_t *httpd) SSL_free(sslinfo->bozossl); } +static sslinfo_t * +bozo_get_sslinfo(bozohttpd_t *httpd) +{ + sslinfo_t *sslinfo; + if (httpd->sslinfo) + return httpd->sslinfo; + sslinfo = bozomalloc(httpd, sizeof(*sslinfo)); + if (sslinfo == NULL) + bozoerr(httpd, 1, "sslinfo allocation failed"); + memset(sslinfo, 0, sizeof(*sslinfo)); + return httpd->sslinfo = sslinfo; +} + void bozo_ssl_set_opts(bozohttpd_t *httpd, const char *cert, const char *priv) { - sslinfo_t *sslinfo = httpd->sslinfo; + sslinfo_t *sslinfo = bozo_get_sslinfo(httpd); - if (sslinfo == NULL) { - sslinfo = bozomalloc(httpd, sizeof(*sslinfo)); - if (sslinfo == NULL) - bozo_err(httpd, 1, "sslinfo allocation failed"); - httpd->sslinfo = sslinfo; - } - sslinfo->certificate_file = strdup(cert); - sslinfo->privatekey_file = strdup(priv); + sslinfo->certificate_file = bozostrdup(httpd, NULL, cert); + sslinfo->privatekey_file = bozostrdup(httpd, NULL, priv); debug((httpd, DEBUG_NORMAL, "using cert/priv files: %s & %s", - sslinfo->certificate_file, - sslinfo->privatekey_file)); + sslinfo->certificate_file, + sslinfo->privatekey_file)); if (!httpd->bindport) - httpd->bindport = strdup("https"); + httpd->bindport = bozostrdup(httpd, NULL, "https"); +} + +void +bozo_ssl_set_ciphers(bozohttpd_t *httpd, const char *ciphers) +{ + sslinfo_t *sslinfo = bozo_get_sslinfo(httpd); + + sslinfo->ciphers = bozostrdup(httpd, NULL, ciphers); + debug((httpd, DEBUG_NORMAL, "using ciphers: %s", sslinfo->ciphers)); } #endif /* NO_SSL_SUPPORT */ Index: src/libexec/httpd/tilde-luzah-bozo.c diff -u src/libexec/httpd/tilde-luzah-bozo.c:1.10 src/libexec/httpd/tilde-luzah-bozo.c:1.10.4.1 --- src/libexec/httpd/tilde-luzah-bozo.c:1.10 Thu Jan 2 08:21:38 2014 +++ src/libexec/httpd/tilde-luzah-bozo.c Sun Apr 10 10:33:11 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: tilde-luzah-bozo.c,v 1.10 2014/01/02 08:21:38 mrg Exp $ */ +/* $NetBSD: tilde-luzah-bozo.c,v 1.10.4.1 2016/04/10 10:33:11 martin Exp $ */ /* $eterna: tilde-luzah-bozo.c,v 1.16 2011/11/18 09:21:15 mrg Exp $ */ @@ -36,6 +36,7 @@ #include <sys/param.h> +#include <assert.h> #include <errno.h> #include <pwd.h> #include <stdlib.h> @@ -55,27 +56,40 @@ * 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; + char *s, *file = NULL, *user; struct passwd *pw; - *isindex = 0; + /* find username */ + user = strchr(request->hr_file + 1, '~'); - if ((s = strchr(request->hr_file + 2, '/')) != NULL) { + /* this shouldn't happen, but "better paranoid than sorry" */ + assert(user != NULL); + + user++; + + if ((s = strchr(user, '/')) != NULL) { *s++ = '\0'; - c = s[strlen(s)-1]; - *isindex = (c == '/' || c == '\0'); } debug((httpd, DEBUG_OBESE, "looking for user %s", - request->hr_file + 2)); - pw = getpwnam(request->hr_file + 2); + user)); + pw = getpwnam(user); + request->hr_user = bozostrdup(httpd, request, 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; } @@ -85,40 +99,25 @@ bozo_user_transform(bozo_httpreq_t *requ pw->pw_uid, pw->pw_gid)); if (chdir(pw->pw_dir) < 0) { - bozo_warn(httpd, "chdir1 error: %s: %s", pw->pw_dir, + bozowarn(httpd, "chdir1 error: %s: %s", pw->pw_dir, strerror(errno)); (void)bozo_http_error(httpd, 404, request, "can't chdir to homedir"); return 0; } if (chdir(httpd->public_html) < 0) { - bozo_warn(httpd, "chdir2 error: %s: %s", httpd->public_html, + bozowarn(httpd, "chdir2 error: %s: %s", httpd->public_html, strerror(errno)); (void)bozo_http_error(httpd, 404, request, "can't chdir to public_html"); return 0; } if (s == NULL || *s == '\0') { - file = bozostrdup(httpd, httpd->index_html); + file = bozostrdup(httpd, request, "/"); } 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); Index: src/libexec/httpd/testsuite/Makefile diff -u src/libexec/httpd/testsuite/Makefile:1.4 src/libexec/httpd/testsuite/Makefile:1.4.24.1 --- src/libexec/httpd/testsuite/Makefile:1.4 Sat May 23 02:26:03 2009 +++ src/libexec/httpd/testsuite/Makefile Sun Apr 10 10:33:11 2016 @@ -6,7 +6,7 @@ BIGFILETESTS= partial4000 partial8000 BOZOHTTPD?= ../bozohttpd BOZOHTTPD?= ../debug/bozohttpd-debug WGET?= wget - +DATA?= $(.CURDIR)/data all: clean: @@ -19,14 +19,14 @@ check: check-simple check-bigfile check-simple: .for a in $(SIMPLETESTS) echo "Running test $a" - $(BOZOHTTPD) ./data < $(.CURDIR)/$a.in > tmp.$a.out || true + $(BOZOHTTPD) "$(DATA)" < $(.CURDIR)/$a.in > tmp.$a.out || true $(.CURDIR)/html_cmp $(.CURDIR)/$a.out tmp.$a.out .endfor check-bigfile: .for a in $(BIGFILETESTS) echo "Running test $a" - $(.CURDIR)/test-bigfile "$a" "${BOZOHTTPD}" "${WGET}" "./data" + $(.CURDIR)/test-bigfile "$a" "${BOZOHTTPD}" "${WGET}" "$(DATA)" .endfor .include <bsd.obj.mk> Index: src/libexec/httpd/testsuite/test-bigfile diff -u src/libexec/httpd/testsuite/test-bigfile:1.1.1.1 src/libexec/httpd/testsuite/test-bigfile:1.1.1.1.30.1 --- src/libexec/httpd/testsuite/test-bigfile:1.1.1.1 Sat May 23 02:21:19 2009 +++ src/libexec/httpd/testsuite/test-bigfile Sun Apr 10 10:33:11 2016 @@ -8,7 +8,7 @@ datadir="$4" bozotestport=11111 # copy beginning file -cp ./data/bigfile.${test} ./bigfile +cp ${datadir}/bigfile.${test} ./bigfile # fire up bozohttpd ${bozohttpd} -b -b -I ${bozotestport} -n -s -f ${datadir} & @@ -18,7 +18,7 @@ ${wget} -c http://localhost:${bozotestpo kill -9 $bozopid -if cmp ./bigfile ./data/bigfile; then +if cmp ./bigfile ${datadir}/bigfile; then rm -f ./bigfile exit 0 else