True. Updated patch below.
On 2020-10-27 11:29, Denis Fondras wrote: > Thanks Matthias, > > comment below. > > On Tue, Oct 27, 2020 at 08:37:39AM +0100, Matthias Pressfreund wrote: >> Index: usr.sbin/httpd/httpd.conf.5 >> =================================================================== >> RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v >> retrieving revision 1.113 >> diff -u -p -u -p -r1.113 httpd.conf.5 >> --- usr.sbin/httpd/httpd.conf.5 5 Sep 2020 11:49:38 -0000 1.113 >> +++ usr.sbin/httpd/httpd.conf.5 27 Oct 2020 05:59:05 -0000 >> @@ -1,5 +1,6 @@ >> .\" $OpenBSD: httpd.conf.5,v 1.113 2020/09/05 11:49:38 tb Exp $ >> .\" >> +.\" Copyright (c) 2020 Matthias Pressfreund <m...@fn.de> >> .\" Copyright (c) 2014, 2015 Reyk Floeter <r...@openbsd.org> >> .\" >> .\" Permission to use, copy, modify, and distribute this software for any >> @@ -14,7 +15,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 27 2020 $ >> .Dt HTTPD.CONF 5 >> .Os >> .Sh NAME >> @@ -399,11 +400,16 @@ of the host's domain should be considere >> .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 >> +.Ar found >> +(i.e. accessible) or >> +.Ar not found > > .Ic seems best suited here. > Index: usr.sbin/httpd/httpd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v retrieving revision 1.113 diff -u -p -u -p -r1.113 httpd.conf.5 --- usr.sbin/httpd/httpd.conf.5 5 Sep 2020 11:49:38 -0000 1.113 +++ usr.sbin/httpd/httpd.conf.5 27 Oct 2020 10:59:35 -0000 @@ -1,5 +1,6 @@ .\" $OpenBSD: httpd.conf.5,v 1.113 2020/09/05 11:49:38 tb Exp $ .\" +.\" Copyright (c) 2020 Matthias Pressfreund <m...@fn.de> .\" Copyright (c) 2014, 2015 Reyk Floeter <r...@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -14,7 +15,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 27 2020 $ .Dt HTTPD.CONF 5 .Os .Sh NAME @@ -399,11 +400,16 @@ of the host's domain should be considere .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 +425,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, Index: usr.sbin/httpd/httpd.h =================================================================== RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v retrieving revision 1.152 diff -u -p -u -p -r1.152 httpd.h --- usr.sbin/httpd/httpd.h 29 Aug 2020 07:53:48 -0000 1.152 +++ usr.sbin/httpd/httpd.h 27 Oct 2020 05:59:05 -0000 @@ -1,6 +1,7 @@ /* $OpenBSD: httpd.h,v 1.152 2020/08/29 07:53:48 florian Exp $ */ /* + * Copyright (c) 2020 Matthias Pressfreund <m...@fn.de> * Copyright (c) 2006 - 2015 Reyk Floeter <r...@openbsd.org> * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <p...@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henn...@openbsd.org> @@ -391,13 +392,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 +694,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 *); Index: usr.sbin/httpd/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/httpd/parse.y,v retrieving revision 1.119 diff -u -p -u -p -r1.119 parse.y --- usr.sbin/httpd/parse.y 26 Oct 2020 19:31:22 -0000 1.119 +++ usr.sbin/httpd/parse.y 27 Oct 2020 05:59:05 -0000 @@ -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 po | 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 po /* 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 po 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 po } ; +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 }, Index: usr.sbin/httpd/server_http.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v retrieving revision 1.141 diff -u -p -u -p -r1.141 server_http.c --- usr.sbin/httpd/server_http.c 12 Sep 2020 07:34:17 -0000 1.141 +++ usr.sbin/httpd/server_http.c 27 Oct 2020 05:59:05 -0000 @@ -1,6 +1,7 @@ /* $OpenBSD: server_http.c,v 1.141 2020/09/12 07:34:17 yasuoka Exp $ */ /* + * Copyright (c) 2020 Matthias Pressfreund <m...@fn.de> * Copyright (c) 2006 - 2018 Reyk Floeter <r...@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, str 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, str 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, c 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; @@ -1427,6 +1444,27 @@ server_getlocation(struct client *clt, c } return (srv_conf); +} + +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