On Tue, Oct 27, 2020 at 12:02:18PM +0100, Matthias Pressfreund wrote: > True. Updated patch below. >
Thanks, I have been using the diff (from your GH account) since a few weeks. OK denis@ I will commit tonight if nobody stands against. > > > 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