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