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

Reply via email to