Skip to content

Commit

Permalink
Add location (found|not found) option to test for resource path exist…
Browse files Browse the repository at this point in the history
…ence.

Diff by Matthias Pressfreund <mpfr @ fn de>. Thanks.
  • Loading branch information
denis committed Oct 29, 2020
1 parent 1938344 commit e96b74b
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 21 deletions.
13 changes: 9 additions & 4 deletions usr.sbin/httpd/httpd.conf.5
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
.\"
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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,
Expand Down
8 changes: 6 additions & 2 deletions usr.sbin/httpd/httpd.h
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 *);
Expand Down
48 changes: 36 additions & 12 deletions usr.sbin/httpd/parse.y
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)) >=
Expand All @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1377,6 +1399,7 @@ lookup(char *s)
{ "error", ERR },
{ "fastcgi", FCGI },
{ "forwarded", FORWARDED },
{ "found", FOUND },
{ "hsts", HSTS },
{ "include", INCLUDE },
{ "index", INDEX },
Expand All @@ -1392,6 +1415,7 @@ lookup(char *s)
{ "max-age", MAXAGE },
{ "no", NO },
{ "nodelay", NODELAY },
{ "not", NOT },
{ "ocsp", OCSP },
{ "on", ON },
{ "optional", OPTIONAL },
Expand Down
44 changes: 41 additions & 3 deletions usr.sbin/httpd/server_http.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
* Copyright (c) 2006 - 2018 Reyk Floeter <[email protected]>
*
* Permission to use, copy, modify, and distribute this software for any
Expand All @@ -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>
Expand All @@ -36,6 +38,7 @@
#include <event.h>
#include <ctype.h>
#include <vis.h>
#include <fcntl.h>

#include "httpd.h"
#include "http.h"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 >
Expand Down Expand Up @@ -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;
Expand All @@ -1429,6 +1446,27 @@ server_getlocation(struct client *clt, const char *path)
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
server_response_http(struct client *clt, unsigned int code,
struct media_type *media, off_t size, time_t mtime)
Expand Down

0 comments on commit e96b74b

Please sign in to comment.