diff options
author | denis <denis@cvs.openbsd.org> | 2020-10-29 12:30:53 +0000 |
---|---|---|
committer | denis <denis@cvs.openbsd.org> | 2020-10-29 12:30:53 +0000 |
commit | 6d09daa5ac294d34d1052ecaeec57d8d30b8013b (patch) | |
tree | d64e9add17b75494bae591d776138e74bc024b6d | |
parent | 3cb394795d5880ab9c3f2020b479edaf15c284bb (diff) |
Add location (found|not found) option to test for resource path existence.
Diff by Matthias Pressfreund <mpfr @ fn de>. Thanks.
-rw-r--r-- | usr.sbin/httpd/httpd.conf.5 | 13 | ||||
-rw-r--r-- | usr.sbin/httpd/httpd.h | 8 | ||||
-rw-r--r-- | usr.sbin/httpd/parse.y | 48 | ||||
-rw-r--r-- | usr.sbin/httpd/server_http.c | 44 |
4 files changed, 92 insertions, 21 deletions
diff --git a/usr.sbin/httpd/httpd.conf.5 b/usr.sbin/httpd/httpd.conf.5 index 59de37fc2b4..e3b45f3fc44 100644 --- a/usr.sbin/httpd/httpd.conf.5 +++ b/usr.sbin/httpd/httpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: httpd.conf.5,v 1.113 2020/09/05 11:49:38 tb Exp $ +.\" $OpenBSD: httpd.conf.5,v 1.114 2020/10/29 12:30:52 denis Exp $ .\" .\" Copyright (c) 2014, 2015 Reyk Floeter <reyk@openbsd.org> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: September 5 2020 $ +.Dd $Mdocdate: October 29 2020 $ .Dt HTTPD.CONF 5 .Os .Sh NAME @@ -399,11 +399,16 @@ of the host's domain should be considered HSTS hosts. .It Ic listen on Ar address Oo Ic tls Oc Ic port Ar number Set the listen address and port. This statement can be specified multiple times. -.It Ic location Ar path Brq ... +.It Ic location Oo Oo Ic not Oc Ic found Oc Ar path Brq ... Specify server configuration rules for a specific location. The .Ar path argument will be matched against the request path with shell globbing rules. +Optionally, it is also possible to match for +.Ic found +(i.e. accessible) or +.Ic not found +request paths only. In case of multiple location statements in the same context, the first matching location statement will be put into effect, while all later ones will be ignored. @@ -419,7 +424,7 @@ except .Ic tcp and .Ic tls . -.It Ic location match Ar path Brq ... +.It Ic location Oo Oo Ic not Oc Ic found Oc Ic match Ar path Brq ... Like the .Ic location option, diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index 373b8053f95..4b57e8d3381 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.152 2020/08/29 07:53:48 florian Exp $ */ +/* $OpenBSD: httpd.h,v 1.153 2020/10/29 12:30:52 denis Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org> @@ -391,13 +391,16 @@ SPLAY_HEAD(client_tree, client); #define SRVFLAG_DEFAULT_TYPE 0x00800000 #define SRVFLAG_PATH_REWRITE 0x01000000 #define SRVFLAG_NO_PATH_REWRITE 0x02000000 +#define SRVFLAG_LOCATION_FOUND 0x40000000 +#define SRVFLAG_LOCATION_NOT_FOUND 0x80000000 #define SRVFLAG_BITS \ "\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX" \ "\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG" \ "\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG" \ "\21AUTH\22NO_AUTH\23BLOCK\24NO_BLOCK\25LOCATION_MATCH" \ - "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE\31PATH\32NO_PATH" + "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE\31PATH\32NO_PATH" \ + "\37LOCATION_FOUND\40LOCATION_NOT_FOUND" #define TCPFLAG_NODELAY 0x01 #define TCPFLAG_NNODELAY 0x02 @@ -690,6 +693,7 @@ const char * server_root_strip(const char *, int); struct server_config * server_getlocation(struct client *, const char *); +int server_locationaccesstest(struct server_config *, const char *); const char * server_http_host(struct sockaddr_storage *, char *, size_t); char *server_http_parsehost(char *, char *, size_t, int *); diff --git a/usr.sbin/httpd/parse.y b/usr.sbin/httpd/parse.y index b09d168035d..f499e127e0f 100644 --- a/usr.sbin/httpd/parse.y +++ b/usr.sbin/httpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.119 2020/10/26 19:31:22 denis Exp $ */ +/* $OpenBSD: parse.y,v 1.120 2020/10/29 12:30:52 denis Exp $ */ /* * Copyright (c) 2020 Matthias Pressfreund <mpfr@fn.de> @@ -143,12 +143,12 @@ typedef struct { %token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TICKET %token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST %token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE -%token CA CLIENT CRL OPTIONAL PARAM FORWARDED +%token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT %token <v.string> STRING %token <v.number> NUMBER %type <v.port> port %type <v.string> fcgiport -%type <v.number> opttls optmatch +%type <v.number> opttls optmatch optfound %type <v.tv> timeout %type <v.string> numberstring optstring %type <v.auth> authopts @@ -514,39 +514,39 @@ serveroptsl : LISTEN ON STRING opttls port { | fastcgi | authenticate | filter - | LOCATION optmatch STRING { + | LOCATION optfound optmatch STRING { struct server *s; struct sockaddr_un *sun; if (srv->srv_conf.ss.ss_family == AF_UNSPEC) { yyerror("listen address not specified"); - free($3); + free($4); YYERROR; } if (parentsrv != NULL) { - yyerror("location %s inside location", $3); - free($3); + yyerror("location %s inside location", $4); + free($4); YYERROR; } if (!loadcfg) { - free($3); + free($4); YYACCEPT; } if ((s = calloc(1, sizeof (*s))) == NULL) fatal("out of memory"); - if (strlcpy(s->srv_conf.location, $3, + if (strlcpy(s->srv_conf.location, $4, sizeof(s->srv_conf.location)) >= sizeof(s->srv_conf.location)) { yyerror("server location truncated"); - free($3); + free($4); free(s); YYERROR; } - free($3); + free($4); if (strlcpy(s->srv_conf.name, srv->srv_conf.name, sizeof(s->srv_conf.name)) >= @@ -566,7 +566,18 @@ serveroptsl : LISTEN ON STRING opttls port { /* A location entry uses the parent id */ s->srv_conf.parent_id = srv->srv_conf.id; s->srv_conf.flags = SRVFLAG_LOCATION; - if ($2) + if ($2 == 1) { + s->srv_conf.flags &= + ~SRVFLAG_LOCATION_NOT_FOUND; + s->srv_conf.flags |= + SRVFLAG_LOCATION_FOUND; + } else if ($2 == -1) { + s->srv_conf.flags &= + ~SRVFLAG_LOCATION_FOUND; + s->srv_conf.flags |= + SRVFLAG_LOCATION_NOT_FOUND; + } + if ($3) s->srv_conf.flags |= SRVFLAG_LOCATION_MATCH; s->srv_s = -1; memcpy(&s->srv_conf.ss, &srv->srv_conf.ss, @@ -586,12 +597,18 @@ serveroptsl : LISTEN ON STRING opttls port { SPLAY_INIT(&srv->srv_clients); } '{' optnl serveropts_l '}' { struct server *s = NULL; + uint32_t f; + + f = SRVFLAG_LOCATION_FOUND | + SRVFLAG_LOCATION_NOT_FOUND; TAILQ_FOREACH(s, conf->sc_servers, srv_entry) { /* Compare locations of same parent server */ if ((s->srv_conf.flags & SRVFLAG_LOCATION) && s->srv_conf.parent_id == srv_conf->parent_id && + (s->srv_conf.flags & f) == + (srv_conf->flags & f) && strcmp(s->srv_conf.location, srv_conf->location) == 0) break; @@ -629,6 +646,11 @@ serveroptsl : LISTEN ON STRING opttls port { } ; +optfound : /* empty */ { $$ = 0; } + | FOUND { $$ = 1; } + | NOT FOUND { $$ = -1; } + ; + hsts : HSTS '{' optnl hstsflags_l '}' | HSTS hstsflags | HSTS @@ -1377,6 +1399,7 @@ lookup(char *s) { "error", ERR }, { "fastcgi", FCGI }, { "forwarded", FORWARDED }, + { "found", FOUND }, { "hsts", HSTS }, { "include", INCLUDE }, { "index", INDEX }, @@ -1392,6 +1415,7 @@ lookup(char *s) { "max-age", MAXAGE }, { "no", NO }, { "nodelay", NODELAY }, + { "not", NOT }, { "ocsp", OCSP }, { "on", ON }, { "optional", OPTIONAL }, diff --git a/usr.sbin/httpd/server_http.c b/usr.sbin/httpd/server_http.c index 35194009efc..d9bc71f67a7 100644 --- a/usr.sbin/httpd/server_http.c +++ b/usr.sbin/httpd/server_http.c @@ -1,6 +1,7 @@ -/* $OpenBSD: server_http.c,v 1.141 2020/09/12 07:34:17 yasuoka Exp $ */ +/* $OpenBSD: server_http.c,v 1.142 2020/10/29 12:30:52 denis Exp $ */ /* + * Copyright (c) 2020 Matthias Pressfreund <mpfr@fn.de> * Copyright (c) 2006 - 2018 Reyk Floeter <reyk@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -20,6 +21,7 @@ #include <sys/queue.h> #include <sys/socket.h> #include <sys/tree.h> +#include <sys/stat.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -36,6 +38,7 @@ #include <event.h> #include <ctype.h> #include <vis.h> +#include <fcntl.h> #include "httpd.h" #include "http.h" @@ -1317,7 +1320,11 @@ server_response(struct httpd *httpd, struct client *clt) goto fail; /* Now search for the location */ - srv_conf = server_getlocation(clt, desc->http_path); + if ((srv_conf = server_getlocation(clt, + desc->http_path)) == NULL) { + server_abort_http(clt, 500, desc->http_path); + return (-1); + } /* Optional rewrite */ if (srv_conf->flags & SRVFLAG_PATH_REWRITE) { @@ -1353,7 +1360,11 @@ server_response(struct httpd *httpd, struct client *clt) goto fail; /* Now search for the updated location */ - srv_conf = server_getlocation(clt, desc->http_path_alias); + if ((srv_conf = server_getlocation(clt, + desc->http_path_alias)) == NULL) { + server_abort_http(clt, 500, desc->http_path_alias); + return (-1); + } } if (clt->clt_toread > 0 && (size_t)clt->clt_toread > @@ -1419,6 +1430,12 @@ server_getlocation(struct client *clt, const char *path) path, FNM_CASEFOLD); } if (ret == 0 && errstr == NULL) { + if ((ret = server_locationaccesstest(location, + path)) == -1) + return (NULL); + + if (ret) + continue; /* Replace host configuration */ clt->clt_srv_conf = srv_conf = location; break; @@ -1430,6 +1447,27 @@ server_getlocation(struct client *clt, const char *path) } int +server_locationaccesstest(struct server_config *srv_conf, const char *path) +{ + int rootfd, ret; + struct stat sb; + + if (((SRVFLAG_LOCATION_FOUND | SRVFLAG_LOCATION_NOT_FOUND) & + srv_conf->flags) == 0) + return (0); + + if ((rootfd = open(srv_conf->root, O_RDONLY)) == -1) + return (-1); + + path = server_root_strip(path, srv_conf->strip) + 1; + if ((ret = faccessat(rootfd, path, R_OK, 0)) != -1) + ret = fstatat(rootfd, path, &sb, 0); + close(rootfd); + return ((ret == -1 && SRVFLAG_LOCATION_FOUND & srv_conf->flags) || + (ret == 0 && SRVFLAG_LOCATION_NOT_FOUND & srv_conf->flags)); +} + +int server_response_http(struct client *clt, unsigned int code, struct media_type *media, off_t size, time_t mtime) { |