summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2015-02-23 18:43:19 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2015-02-23 18:43:19 +0000
commit2a732b5ee8b6f6ba4012fbd23b247661dcf64643 (patch)
tree80960047bf584cffddfa7e16ab3a5e10ca89bb3f /usr.sbin
parent47a2d5d0615cf84871f46dd70e2187128f0b2144 (diff)
Allow to specify CGI variables as macros in redirection strings, eg.
block return 301 "http://www.example.com/$REQUEST_URI" OK tedu@ florian@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/httpd/httpd.c35
-rw-r--r--usr.sbin/httpd/httpd.conf.529
-rw-r--r--usr.sbin/httpd/httpd.h3
-rw-r--r--usr.sbin/httpd/server_http.c110
4 files changed, 170 insertions, 7 deletions
diff --git a/usr.sbin/httpd/httpd.c b/usr.sbin/httpd/httpd.c
index a1ad9682b8a..c6f183fd9bf 100644
--- a/usr.sbin/httpd/httpd.c
+++ b/usr.sbin/httpd/httpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.c,v 1.34 2015/02/12 10:05:29 reyk Exp $ */
+/* $OpenBSD: httpd.c,v 1.35 2015/02/23 18:43:18 reyk Exp $ */
/*
* Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
@@ -494,6 +494,39 @@ event_again(struct event *ev, int fd, short event,
event_add(ev, &tv);
}
+int
+expand_string(char *label, size_t len, const char *srch, const char *repl)
+{
+ char *tmp;
+ char *p, *q;
+
+ if ((tmp = calloc(1, len)) == NULL) {
+ log_debug("%s: calloc", __func__);
+ return (-1);
+ }
+ p = q = label;
+ while ((q = strstr(p, srch)) != NULL) {
+ *q = '\0';
+ if ((strlcat(tmp, p, len) >= len) ||
+ (strlcat(tmp, repl, len) >= len)) {
+ log_debug("%s: string too long", __func__);
+ free(tmp);
+ return (-1);
+ }
+ q += strlen(srch);
+ p = q;
+ }
+ if (strlcat(tmp, p, len) >= len) {
+ log_debug("%s: string too long", __func__);
+ free(tmp);
+ return (-1);
+ }
+ (void)strlcpy(label, tmp, len); /* always fits */
+ free(tmp);
+
+ return (0);
+}
+
const char *
canonicalize_host(const char *host, char *name, size_t len)
{
diff --git a/usr.sbin/httpd/httpd.conf.5 b/usr.sbin/httpd/httpd.conf.5
index 167ae47e6aa..da51ad37097 100644
--- a/usr.sbin/httpd/httpd.conf.5
+++ b/usr.sbin/httpd/httpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: httpd.conf.5,v 1.52 2015/02/19 09:19:01 florian Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.53 2015/02/23 18:43:18 reyk Exp $
.\"
.\" Copyright (c) 2014, 2015 Reyk Floeter <reyk@openbsd.org>
.\"
@@ -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: February 19 2015 $
+.Dd $Mdocdate: February 23 2015 $
.Dt HTTPD.CONF 5
.Os
.Sh NAME
@@ -164,6 +164,31 @@ The optional
argument can be used with return codes in the 3xx range to send a
.Sq Location:
header for redirection to a specified URI.
+.Pp
+The
+.Ar url
+may contain predefined macros that will be expanded at runtime:
+.Pp
+.Bl -tag -width $DOCUMENT_URI -offset indent -compact
+.It Ic $DOCUMENT_URI
+The request path.
+.It Ic $QUERY_STRING
+The optional query string of the request.
+.It Ic $REMOTE_ADDR
+The IP address of the connected client.
+.It Ic $REMOTE_PORT
+The TCP source port of the connected client.
+.It Ic $REMOTE_USER
+The remote user for HTTP authentication.
+.It Ic $REQUEST_URI
+The request path and optional query string.
+.It Ic $SERVER_ADDR
+The configured IP address of the relay.
+.It Ic $SERVER_PORT
+The configured TCP server port of the relay.
+.It Ic $SERVER_NAME
+The name of the server.
+.El
.It Ic connection Ar option
Set the specified options and limits for HTTP connections.
Valid options are:
diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h
index bb577295e3b..28e02a55217 100644
--- a/usr.sbin/httpd/httpd.h
+++ b/usr.sbin/httpd/httpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.h,v 1.80 2015/02/12 10:05:29 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.81 2015/02/23 18:43:18 reyk Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -584,6 +584,7 @@ int fcgi_add_stdin(struct client *, struct evbuffer *);
void event_again(struct event *, int, short,
void (*)(int, short, void *),
struct timeval *, struct timeval *, void *);
+int expand_string(char *, size_t, const char *, const char *);
const char *url_decode(char *);
char *url_encode(const char *);
const char *canonicalize_host(const char *, char *, size_t);
diff --git a/usr.sbin/httpd/server_http.c b/usr.sbin/httpd/server_http.c
index d4d3c97fe74..b63fc221049 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.74 2015/02/08 00:00:59 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.75 2015/02/23 18:43:18 reyk Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -42,7 +42,9 @@ static int server_httpmethod_cmp(const void *, const void *);
static int server_httperror_cmp(const void *, const void *);
void server_httpdesc_free(struct http_descriptor *);
int server_http_authenticate(struct server_config *,
- struct client *);
+ struct client *);
+char *server_expand_http(struct client *, const char *,
+ char *, size_t);
static struct httpd *env = NULL;
@@ -735,6 +737,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
const char *httperr = NULL, *style;
char *httpmsg, *body = NULL, *extraheader = NULL;
char tmbuf[32], hbuf[128];
+ char buf[IBUF_READ_SIZE], *ptr = NULL;
int bodylen;
if (code == 0) {
@@ -762,10 +765,20 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
switch (code) {
case 301:
case 302:
- if (asprintf(&extraheader, "Location: %s\r\n", msg) == -1) {
+ case 303:
+ if (msg == NULL)
+ break;
+ memset(buf, 0, sizeof(buf));
+ if ((ptr = server_expand_http(clt, msg,
+ buf, sizeof(buf))) == NULL)
+ goto done;
+ if ((ptr = url_encode(ptr)) == NULL)
+ goto done;
+ if (asprintf(&extraheader, "Location: %s\r\n", ptr) == -1) {
code = 500;
extraheader = NULL;
}
+ msg = ptr;
break;
case 401:
if (asprintf(&extraheader,
@@ -829,12 +842,15 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
done:
free(body);
free(extraheader);
+ if (msg == NULL)
+ msg = "\"\"";
if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1) {
server_close(clt, msg);
} else {
server_close(clt, httpmsg);
free(httpmsg);
}
+ free(ptr);
}
void
@@ -855,6 +871,94 @@ server_close_http(struct client *clt)
clt->clt_remote_user = NULL;
}
+char *
+server_expand_http(struct client *clt, const char *val, char *buf,
+ size_t len)
+{
+ struct http_descriptor *desc = clt->clt_descreq;
+ struct server_config *srv_conf = clt->clt_srv_conf;
+ char ibuf[128], *str;
+
+ if (strlcpy(buf, val, len) >= len)
+ return (NULL);
+
+ if (strstr(val, "$DOCUMENT_URI") != NULL) {
+ if (expand_string(buf, len, "$DOCUMENT_URI",
+ desc->http_path) != 0)
+ return (NULL);
+ }
+ if (strstr(val, "$QUERY_STRING") != NULL) {
+ if (expand_string(buf, len, "$QUERY_STRING",
+ desc->http_query == NULL ? "" :
+ desc->http_query) != 0)
+ return (NULL);
+ }
+ if (strstr(val, "$REMOTE_") != NULL) {
+ if (strstr(val, "$REMOTE_ADDR") != NULL) {
+ if (print_host(&clt->clt_ss,
+ ibuf, sizeof(ibuf)) == NULL)
+ return (NULL);
+ if (expand_string(buf, len,
+ "$REMOTE_ADDR", ibuf) != 0)
+ return (NULL);
+ }
+ if (strstr(val, "$REMOTE_PORT") != NULL) {
+ snprintf(ibuf, sizeof(ibuf),
+ "%u", ntohs(clt->clt_port));
+ if (expand_string(buf, len,
+ "$REMOTE_PORT", ibuf) != 0)
+ return (NULL);
+ }
+ if (strstr(val, "$REMOTE_USER") != NULL) {
+ if ((srv_conf->flags & SRVFLAG_AUTH) &&
+ clt->clt_remote_user != NULL)
+ str = clt->clt_remote_user;
+ else
+ str = "";
+ if (expand_string(buf, len,
+ "$REMOTE_USER", str) != 0)
+ return (NULL);
+ }
+ }
+ if (strstr(val, "$REQUEST_URI") != NULL) {
+ if (desc->http_query == NULL) {
+ if ((str = strdup(desc->http_path)) == NULL)
+ return (NULL);
+ } else if (asprintf(&str, "%s?%s",
+ desc->http_path, desc->http_query) == -1)
+ return (NULL);
+ if (expand_string(buf, len, "$REQUEST_URI", str) != 0) {
+ free(str);
+ return (NULL);
+ }
+ free(str);
+ }
+ if (strstr(val, "$SERVER_") != NULL) {
+ if (strstr(val, "$SERVER_ADDR") != NULL) {
+ if (print_host(&srv_conf->ss,
+ ibuf, sizeof(ibuf)) == NULL)
+ return (NULL);
+ if (expand_string(buf, len,
+ "$SERVER_ADDR", ibuf) != 0)
+ return (NULL);
+ }
+ if (strstr(val, "$SERVER_PORT") != NULL) {
+ snprintf(ibuf, sizeof(ibuf), "%u",
+ ntohs(srv_conf->port));
+ if (expand_string(buf, len,
+ "$SERVER_PORT", ibuf) != 0)
+ return (NULL);
+ }
+ if (strstr(val, "$SERVER_NAME") != NULL) {
+ if (expand_string(buf, len,
+ "$SERVER_NAME", srv_conf->name) != 0)
+ return (NULL);
+ }
+ }
+
+ return (buf);
+}
+
int
server_response(struct httpd *httpd, struct client *clt)
{