diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2015-02-23 18:43:19 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2015-02-23 18:43:19 +0000 |
commit | 2a732b5ee8b6f6ba4012fbd23b247661dcf64643 (patch) | |
tree | 80960047bf584cffddfa7e16ab3a5e10ca89bb3f /usr.sbin | |
parent | 47a2d5d0615cf84871f46dd70e2187128f0b2144 (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.c | 35 | ||||
-rw-r--r-- | usr.sbin/httpd/httpd.conf.5 | 29 | ||||
-rw-r--r-- | usr.sbin/httpd/httpd.h | 3 | ||||
-rw-r--r-- | usr.sbin/httpd/server_http.c | 110 |
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) { |