summaryrefslogtreecommitdiffstats
path: root/usr.sbin/httpd
diff options
context:
space:
mode:
authorreyk <reyk@openbsd.org>2014-08-08 18:29:42 +0000
committerreyk <reyk@openbsd.org>2014-08-08 18:29:42 +0000
commitde6550b143b4867d7b323aa57e845c3161977b02 (patch)
tree296da00097870cfecbc82075e68abaceddd79640 /usr.sbin/httpd
parentNo events were added for DNS UDP so it stopped working after the first (diff)
downloadwireguard-openbsd-de6550b143b4867d7b323aa57e845c3161977b02.tar.xz
wireguard-openbsd-de6550b143b4867d7b323aa57e845c3161977b02.zip
When opening directories, re-match the location after the index file
has been appended. This allows to use a fastcgi target as the default index, for example index.php. OK florian@
Diffstat (limited to 'usr.sbin/httpd')
-rw-r--r--usr.sbin/httpd/http.h5
-rw-r--r--usr.sbin/httpd/httpd.h4
-rw-r--r--usr.sbin/httpd/server_fcgi.c5
-rw-r--r--usr.sbin/httpd/server_file.c121
-rw-r--r--usr.sbin/httpd/server_http.c33
5 files changed, 119 insertions, 49 deletions
diff --git a/usr.sbin/httpd/http.h b/usr.sbin/httpd/http.h
index 44f22ba7006..1918525be5a 100644
--- a/usr.sbin/httpd/http.h
+++ b/usr.sbin/httpd/http.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: http.h,v 1.5 2014/08/03 21:33:27 reyk Exp $ */
+/* $OpenBSD: http.h,v 1.6 2014/08/08 18:29:42 reyk Exp $ */
/*
* Copyright (c) 2012 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -156,6 +156,9 @@ struct http_descriptor {
int http_chunked;
char *http_version;
+ /* Rewritten path remains NULL if not used */
+ char *http_path_alias;
+
/* A tree of headers and attached lists for repeated headers. */
struct kv *http_lastheader;
struct kvtree http_headers;
diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h
index 74d6904e206..1a8042840c0 100644
--- a/usr.sbin/httpd/httpd.h
+++ b/usr.sbin/httpd/httpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.h,v 1.51 2014/08/06 18:21:14 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.52 2014/08/08 18:29:42 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -516,6 +516,8 @@ int server_response_http(struct client *, u_int, struct media_type *,
void server_reset_http(struct client *);
void server_close_http(struct client *);
int server_response(struct httpd *, struct client *);
+struct server_config *
+ server_getlocation(struct client *, const char *);
const char *
server_http_host(struct sockaddr_storage *, char *, size_t);
void server_http_date(char *, size_t);
diff --git a/usr.sbin/httpd/server_fcgi.c b/usr.sbin/httpd/server_fcgi.c
index 6850dd0a30f..4cf4aa40551 100644
--- a/usr.sbin/httpd/server_fcgi.c
+++ b/usr.sbin/httpd/server_fcgi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_fcgi.c,v 1.29 2014/08/07 12:43:22 florian Exp $ */
+/* $OpenBSD: server_fcgi.c,v 1.30 2014/08/08 18:29:42 reyk Exp $ */
/*
* Copyright (c) 2014 Florian Obser <florian@openbsd.org>
@@ -190,7 +190,8 @@ server_fcgi(struct httpd *env, struct client *clt)
h->content_len = param.total_len = 0;
if (asprintf(&script, "%s%s", srv_conf->root,
- desc->http_path) == -1 ||
+ desc->http_path_alias != NULL ?
+ desc->http_path_alias : desc->http_path) == -1 ||
(scriptlen = path_info(script)) == -1) {
errstr = "failed to get script name";
goto fail;
diff --git a/usr.sbin/httpd/server_file.c b/usr.sbin/httpd/server_file.c
index 65ecb0100b8..1b35037ed85 100644
--- a/usr.sbin/httpd/server_file.c
+++ b/usr.sbin/httpd/server_file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_file.c,v 1.31 2014/08/06 11:24:12 reyk Exp $ */
+/* $OpenBSD: server_file.c,v 1.32 2014/08/08 18:29:42 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -46,30 +46,25 @@
#include "httpd.h"
#include "http.h"
-int server_file_access(struct client *, char *, size_t,
+int server_file_access(struct httpd *, struct client *, char *,
+ size_t, struct stat *);
+int server_file_request(struct httpd *, struct client *, char *,
struct stat *);
int server_file_index(struct httpd *, struct client *);
+int server_file_method(struct client *);
int
-server_file_access(struct client *clt, char *path, size_t len,
- struct stat *st)
+server_file_access(struct httpd *env, struct client *clt,
+ char *path, size_t len, struct stat *st)
{
struct http_descriptor *desc = clt->clt_desc;
struct server_config *srv_conf = clt->clt_srv_conf;
struct stat stb;
char *newpath;
+ int ret;
errno = 0;
- switch (desc->http_method) {
- case HTTP_METHOD_GET:
- case HTTP_METHOD_HEAD:
- break;
- default:
- /* Other methods are not allowed */
- return (405);
- }
-
if (access(path, R_OK) == -1) {
goto fail;
} else if (stat(path, st) == -1) {
@@ -81,7 +76,7 @@ server_file_access(struct client *clt, char *path, size_t len,
goto fail;
}
- if (!len) {
+ if (desc->http_path_alias != NULL) {
/* Recursion - the index "file" is a directory? */
errno = EINVAL;
goto fail;
@@ -93,21 +88,31 @@ server_file_access(struct client *clt, char *path, size_t len,
srv_conf->flags & SRVFLAG_SSL ? "s" : "",
desc->http_host, desc->http_path) == -1)
return (500);
- free(desc->http_path);
- desc->http_path = newpath;
+ /* Path alias will be used for the redirection */
+ desc->http_path_alias = newpath;
/* Indicate that the file has been moved */
return (301);
}
- /* Otherwise append the default index file */
+ /* Append the default index file to the location */
+ if (asprintf(&newpath, "%s%s", desc->http_path,
+ srv_conf->index) == -1)
+ return (500);
+ desc->http_path_alias = newpath;
+ if (server_getlocation(clt, newpath) != srv_conf) {
+ /* The location has changed */
+ return (server_file(env, clt));
+ }
+
+ /* Otherwise append the default index file to the path */
if (strlcat(path, srv_conf->index, len) >= len) {
errno = EACCES;
goto fail;
}
- /* Check again but set len to 0 to avoid recursion */
- if (server_file_access(clt, path, 0, &stb) == 404) {
+ ret = server_file_access(env, clt, path, len, &stb);
+ if (ret == 404) {
/*
* Index file not found; fail if auto-indexing is
* not enabled, otherwise return success but
@@ -118,17 +123,17 @@ server_file_access(struct client *clt, char *path, size_t len,
errno = EACCES;
goto fail;
}
- } else {
- /* return updated stat from index file */
- memcpy(st, &stb, sizeof(*st));
+
+ return (server_file_index(env, clt));
}
+ return (ret);
} else if (!S_ISREG(st->st_mode)) {
/* Don't follow symlinks and ignore special files */
errno = EACCES;
goto fail;
}
- return (0);
+ return (server_file_request(env, clt, path, st));
fail:
switch (errno) {
@@ -148,29 +153,69 @@ server_file(struct httpd *env, struct client *clt)
{
struct http_descriptor *desc = clt->clt_desc;
struct server_config *srv_conf = clt->clt_srv_conf;
- struct media_type *media;
- const char *errstr = NULL;
- int fd = -1, ret, code = 500;
char path[MAXPATHLEN];
+ const char *errstr = NULL;
+ int ret = 500;
struct stat st;
+ if (srv_conf->flags & SRVFLAG_FCGI)
+ return (server_fcgi(env, clt));
+
/* Request path is already canonicalized */
if ((size_t)snprintf(path, sizeof(path), "%s%s",
- srv_conf->root, desc->http_path) >= sizeof(path)) {
+ srv_conf->root,
+ desc->http_path_alias != NULL ?
+ desc->http_path_alias : desc->http_path) >= sizeof(path)) {
errstr = desc->http_path;
goto abort;
}
/* Returns HTTP status code on error */
- if ((ret = server_file_access(clt, path, sizeof(path), &st)) != 0) {
- code = ret;
- errstr = desc->http_path;
+ if ((ret = server_file_access(env, clt, path, sizeof(path),
+ &st)) > 0) {
+ errstr = desc->http_path_alias != NULL ?
+ desc->http_path_alias : desc->http_path;
goto abort;
}
- if (S_ISDIR(st.st_mode)) {
- /* List directory index */
- return (server_file_index(env, clt));
+ return (ret);
+
+ abort:
+ if (errstr == NULL)
+ errstr = strerror(errno);
+ server_abort_http(clt, ret, errstr);
+ return (-1);
+}
+
+int
+server_file_method(struct client *clt)
+{
+ struct http_descriptor *desc = clt->clt_desc;
+
+ switch (desc->http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_HEAD:
+ return (0);
+ default:
+ /* Other methods are not allowed */
+ errno = EACCES;
+ return (405);
+ }
+ /* NOTREACHED */
+}
+
+int
+server_file_request(struct httpd *env, struct client *clt, char *path,
+ struct stat *st)
+{
+ struct server_config *srv_conf = clt->clt_srv_conf;
+ struct media_type *media;
+ const char *errstr = NULL;
+ int fd = -1, ret, code = 500;
+
+ if ((ret = server_file_method(clt)) != 0) {
+ code = ret;
+ goto abort;
}
/* Now open the file, should be readable or we have another problem */
@@ -178,7 +223,7 @@ server_file(struct httpd *env, struct client *clt)
goto abort;
media = media_find(env->sc_mediatypes, path);
- ret = server_response_http(clt, 200, media, st.st_size);
+ ret = server_response_http(clt, 200, media, st->st_size);
switch (ret) {
case -1:
goto fail;
@@ -233,6 +278,7 @@ server_file_index(struct httpd *env, struct client *clt)
struct server_config *srv_conf = clt->clt_srv_conf;
struct dirent **namelist, *dp;
int namesize, i, ret, fd = -1, namewidth, skip;
+ int code = 500;
struct evbuffer *evb = NULL;
struct media_type *media;
const char *style;
@@ -240,6 +286,11 @@ server_file_index(struct httpd *env, struct client *clt)
struct tm tm;
time_t t;
+ if ((ret = server_file_method(clt)) != 0) {
+ code = ret;
+ goto abort;
+ }
+
/* Request path is already canonicalized */
if ((size_t)snprintf(path, sizeof(path), "%s%s",
srv_conf->root, desc->http_path) >= sizeof(path))
@@ -356,7 +407,7 @@ server_file_index(struct httpd *env, struct client *clt)
close(fd);
if (evb != NULL)
evbuffer_free(evb);
- server_abort_http(clt, 500, desc->http_path);
+ server_abort_http(clt, code, desc->http_path);
return (-1);
}
diff --git a/usr.sbin/httpd/server_http.c b/usr.sbin/httpd/server_http.c
index 3ef58e5e902..9e09428a628 100644
--- a/usr.sbin/httpd/server_http.c
+++ b/usr.sbin/httpd/server_http.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_http.c,v 1.43 2014/08/08 15:46:01 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.44 2014/08/08 18:29:42 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -100,6 +100,10 @@ server_httpdesc_free(struct http_descriptor *desc)
free(desc->http_path);
desc->http_path = NULL;
}
+ if (desc->http_path_alias != NULL) {
+ free(desc->http_path_alias);
+ desc->http_path_alias = NULL;
+ }
if (desc->http_query != NULL) {
free(desc->http_query);
desc->http_query = NULL;
@@ -680,7 +684,7 @@ server_response(struct httpd *httpd, struct client *clt)
char hostname[MAXHOSTNAMELEN];
struct http_descriptor *desc = clt->clt_desc;
struct server *srv = clt->clt_srv;
- struct server_config *srv_conf = &srv->srv_conf, *location;
+ struct server_config *srv_conf = &srv->srv_conf;
struct kv *kv, key, *host;
/* Canonicalize the request path */
@@ -756,23 +760,32 @@ server_response(struct httpd *httpd, struct client *clt)
goto fail;
/* Now search for the location */
+ srv_conf = server_getlocation(clt, desc->http_path);
+
+ return (server_file(httpd, clt));
+ fail:
+ server_abort_http(clt, 400, "bad request");
+ return (-1);
+}
+
+struct server_config *
+server_getlocation(struct client *clt, const char *path)
+{
+ struct server *srv = clt->clt_srv;
+ struct server_config *srv_conf = clt->clt_srv_conf, *location;
+
+ /* Now search for the location */
TAILQ_FOREACH(location, &srv->srv_hosts, entry) {
if ((location->flags & SRVFLAG_LOCATION) &&
location->id == srv_conf->id &&
- fnmatch(location->location, desc->http_path,
- FNM_CASEFOLD) == 0) {
+ fnmatch(location->location, path, FNM_CASEFOLD) == 0) {
/* Replace host configuration */
clt->clt_srv_conf = srv_conf = location;
break;
}
}
- if (srv_conf->flags & SRVFLAG_FCGI)
- return (server_fcgi(httpd, clt));
- return (server_file(httpd, clt));
- fail:
- server_abort_http(clt, 400, "bad request");
- return (-1);
+ return (srv_conf);
}
int