summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/config.c2
-rw-r--r--server/core.c103
-rw-r--r--server/listen.c69
-rw-r--r--server/log.c6
-rw-r--r--server/util.c31
-rw-r--r--server/vhost.c19
6 files changed, 190 insertions, 40 deletions
diff --git a/server/config.c b/server/config.c
index 3d11ff5..635b65d 100644
--- a/server/config.c
+++ b/server/config.c
@@ -418,7 +418,7 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
}
if (!r->handler) {
- if (r->content_type) {
+ if (r->content_type && AP_REQUEST_IS_TRUSTED_CT(r)) {
handler = r->content_type;
if ((p=ap_strchr_c(handler, ';')) != NULL) {
char *new_handler = (char *)apr_pmemdup(r->pool, handler,
diff --git a/server/core.c b/server/core.c
index e5e059e..843b973 100644
--- a/server/core.c
+++ b/server/core.c
@@ -4426,6 +4426,25 @@ static const char *set_merge_trailers(cmd_parms *cmd, void *dummy, int arg)
return NULL;
}
+#ifdef WIN32
+static const char *set_unc_list(cmd_parms *cmd, void *d_, int argc, char *const argv[])
+{
+ core_server_config *sconf = ap_get_core_module_config(cmd->server->module_config);
+ int i;
+ const char *err;
+
+ if ((err = ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST)) != NULL)
+ return err;
+
+ sconf->unc_list = apr_array_make(cmd->pool, argc, sizeof(char *));
+
+ for (i = 0; i < argc; i++) {
+ *(char **)apr_array_push(sconf->unc_list) = apr_pstrdup(cmd->pool, argv[i]);
+ }
+
+ return NULL;
+}
+#endif
/* Note --- ErrorDocument will now work from .htaccess files.
* The AllowOverride of Fileinfo allows webmasters to turn it off
*/
@@ -4527,6 +4546,10 @@ AP_INIT_TAKE1("FlushMaxThreshold", set_flush_max_threshold, NULL, RSRC_CONF,
AP_INIT_TAKE1("FlushMaxPipelined", set_flush_max_pipelined, NULL, RSRC_CONF,
"Maximum number of pipelined responses (pending) above which they are "
"flushed to the network"),
+#ifdef WIN32
+AP_INIT_TAKE_ARGV("UNCList", set_unc_list, NULL, RSRC_CONF,
+ "Controls what UNC hosts may be looked up"),
+#endif
/* Old server config file commands */
@@ -4812,7 +4835,7 @@ static int core_override_type(request_rec *r)
/* Check for overrides with ForceType / SetHandler
*/
if (conf->mime_type && strcmp(conf->mime_type, "none"))
- ap_set_content_type(r, (char*) conf->mime_type);
+ ap_set_content_type_ex(r, (char*) conf->mime_type, 1);
if (conf->expr_handler) {
const char *err;
@@ -5632,6 +5655,84 @@ AP_CORE_DECLARE(apr_status_t) ap_get_pollfd_from_conn(conn_rec *c,
return ap_run_get_pollfd_from_conn(c, pfd, ptimeout);
}
+#ifdef WIN32
+static apr_status_t check_unc(const char *path, apr_pool_t *p)
+{
+ int i;
+ char *s, *teststring;
+ apr_status_t rv = APR_EACCES;
+ core_server_config *sconf = NULL;
+
+ if (!ap_server_conf) {
+ return APR_SUCCESS; /* this early, if we have a UNC, it's specified by an admin */
+ }
+
+ if (!path || (path != ap_strstr_c(path, "\\\\") &&
+ path != ap_strstr_c(path, "//"))) {
+ return APR_SUCCESS; /* not a UNC */
+ }
+
+ sconf = ap_get_core_module_config(ap_server_conf->module_config);
+ s = teststring = apr_pstrdup(p, path);
+ *s++ = '/';
+ *s++ = '/';
+
+ ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
+ "ap_filepath_merge: check converted path %s allowed %d",
+ teststring,
+ sconf->unc_list ? sconf->unc_list->nelts : 0);
+
+ for (i = 0; sconf->unc_list && i < sconf->unc_list->nelts; i++) {
+ char *configured_unc = ((char **)sconf->unc_list->elts)[i];
+ apr_uri_t uri;
+ if (APR_SUCCESS == apr_uri_parse(p, teststring, &uri) &&
+ (uri.hostinfo == NULL ||
+ !ap_cstr_casecmp(uri.hostinfo, configured_unc))) {
+ rv = APR_SUCCESS;
+ ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
+ "ap_filepath_merge: match %s %s",
+ uri.hostinfo, configured_unc);
+ break;
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
+ "ap_filepath_merge: no match %s %s", uri.hostinfo,
+ configured_unc);
+ }
+ }
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(10504)
+ "ap_filepath_merge: UNC path %s not allowed by UNCList", teststring);
+ }
+
+ return rv;
+}
+#endif
+
+AP_DECLARE(apr_status_t) ap_filepath_merge(char **newpath,
+ const char *rootpath,
+ const char *addpath,
+ apr_int32_t flags,
+ apr_pool_t *p)
+{
+#ifdef WIN32
+ apr_status_t rv;
+
+ if (APR_SUCCESS != (rv = check_unc(rootpath, p))) {
+ return rv;
+ }
+ if (APR_SUCCESS != (rv = check_unc(addpath, p))) {
+ return rv;
+ }
+#undef apr_filepath_merge
+#endif
+ return apr_filepath_merge(newpath, rootpath, addpath, flags, p);
+#ifdef WIN32
+#define apr_filepath_merge ap_filepath_merge
+#endif
+}
+
+
static void register_hooks(apr_pool_t *p)
{
errorlog_hash = apr_hash_make(p);
diff --git a/server/listen.c b/server/listen.c
index 5242c2a..9577d60 100644
--- a/server/listen.c
+++ b/server/listen.c
@@ -19,6 +19,7 @@
#define APR_WANT_STRFUNC
#include "apr_want.h"
+#include "apr_version.h"
#include "ap_config.h"
#include "httpd.h"
@@ -277,8 +278,32 @@ static apr_status_t close_listeners_on_exec(void *v)
return APR_SUCCESS;
}
+/* Returns non-zero if socket address SA matches hostname, port and
+ * scope_id. p is used for temporary allocations. */
+static int match_address(const apr_sockaddr_t *sa,
+ const char *hostname, apr_port_t port,
+ const char *scope_id, apr_pool_t *p)
+{
+ const char *old_scope = NULL;
+
+#if APR_VERSION_AT_LEAST(1,7,0)
+ /* To be clever here we could correctly match numeric and
+ * non-numeric zone ids. Ignore failure, old_scope will be left
+ * as NULL. */
+ (void) apr_sockaddr_zone_get(sa, &old_scope, NULL, p);
+#endif
+
+ return port == sa->port
+ && ((!hostname && !sa->hostname)
+ || (hostname && sa->hostname && !strcmp(sa->hostname, hostname)))
+ && ((!scope_id && !old_scope)
+ || (scope_id && old_scope && !strcmp(scope_id, old_scope)));
+}
+
+/* ### This logic doesn't cope with DNS changes across a restart. */
static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
- const char *addr, apr_port_t port)
+ const char *addr, apr_port_t port,
+ const char *scope_id, apr_pool_t *temp_pool)
{
int found = 0;
@@ -288,15 +313,10 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
/* Some listeners are not real so they will not have a bind_addr. */
if (sa) {
ap_listen_rec *new;
- apr_port_t oldport;
- oldport = sa->port;
- /* If both ports are equivalent, then if their names are equivalent,
- * then we will re-use the existing record.
- */
- if (port == oldport &&
- ((!addr && !sa->hostname) ||
- ((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
+ /* Re-use the existing record if it matches completely
+ * against an existing listener. */
+ if (match_address(sa, addr, port, scope_id, temp_pool)) {
found = 1;
if (!to) {
break;
@@ -317,19 +337,21 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
static const char *alloc_listener(process_rec *process, const char *addr,
apr_port_t port, const char* proto,
- void *slave)
+ const char *scope_id, void *slave,
+ apr_pool_t *temp_pool)
{
ap_listen_rec *last;
apr_status_t status;
apr_sockaddr_t *sa;
/* see if we've got a listener for this address:port, which is an error */
- if (find_listeners(&ap_listeners, NULL, addr, port)) {
+ if (find_listeners(&ap_listeners, NULL, addr, port, scope_id, temp_pool)) {
return "Cannot define multiple Listeners on the same IP:port";
}
/* see if we've got an old listener for this address:port */
- if (find_listeners(&old_listeners, &ap_listeners, addr, port)) {
+ if (find_listeners(&old_listeners, &ap_listeners, addr, port,
+ scope_id, temp_pool)) {
if (ap_listeners->slave != slave) {
return "Cannot define a slave on the same IP:port as a Listener";
}
@@ -383,6 +405,18 @@ static const char *alloc_listener(process_rec *process, const char *addr,
return "Listen setup failed";
}
+#if APR_VERSION_AT_LEAST(1,7,0)
+ if (scope_id) {
+ status = apr_sockaddr_zone_set(new->bind_addr, scope_id);
+ if (status) {
+ ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool, APLOGNO(10102)
+ "alloc_listener: failed to set scope for %pI to %s",
+ new->bind_addr, scope_id);
+ return "Listen step failed";
+ }
+ }
+#endif
+
/* We need to preserve the order returned by getaddrinfo() */
if (last == NULL) {
ap_listeners = last = new;
@@ -835,10 +869,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
host = NULL;
}
+#if !APR_VERSION_AT_LEAST(1,7,0)
if (scope_id) {
- /* XXX scope id support is useful with link-local IPv6 addresses */
- return "Scope id is not supported";
+ return apr_pstrcat(cmd->pool,
+ "Scope ID in address '", argv[0],
+ "' not supported with APR " APR_VERSION_STRING,
+ NULL);
}
+#endif
if (!port) {
return "Port must be specified";
@@ -856,7 +894,8 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
ap_str_tolower(proto);
}
- return alloc_listener(cmd->server->process, host, port, proto, NULL);
+ return alloc_listener(cmd->server->process, host, port, proto,
+ scope_id, NULL, cmd->temp_pool);
}
AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd,
diff --git a/server/log.c b/server/log.c
index 22d2f8d..9576d07 100644
--- a/server/log.c
+++ b/server/log.c
@@ -64,6 +64,10 @@
#undef APLOG_MODULE_INDEX
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
+#ifndef DEFAULT_LOG_TID
+#define DEFAULT_LOG_TID NULL
+#endif
+
typedef struct {
const char *t_name;
int t_val;
@@ -990,7 +994,7 @@ static int do_errorlog_default(const ap_errorlog_info *info, char *buf,
#if APR_HAS_THREADS
field_start = len;
len += cpystrn(buf + len, ":tid ", buflen - len);
- item_len = log_tid(info, NULL, buf + len, buflen - len);
+ item_len = log_tid(info, DEFAULT_LOG_TID, buf + len, buflen - len);
if (!item_len)
len = field_start;
else
diff --git a/server/util.c b/server/util.c
index 45502b8..11d0e40 100644
--- a/server/util.c
+++ b/server/util.c
@@ -75,17 +75,6 @@
*/
#include "test_char.h"
-/* Win32/NetWare/OS2 need to check for both forward and back slashes
- * in ap_normalize_path() and ap_escape_url().
- */
-#ifdef CASE_BLIND_FILESYSTEM
-#define IS_SLASH(s) ((s == '/') || (s == '\\'))
-#define SLASHES "/\\"
-#else
-#define IS_SLASH(s) (s == '/')
-#define SLASHES "/"
-#endif
-
/* we know core's module_index is 0 */
#undef APLOG_MODULE_INDEX
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
@@ -492,7 +481,7 @@ AP_DECLARE(apr_status_t) ap_pregsub_ex(apr_pool_t *p, char **result,
/* Forward declare */
static char x2c(const char *what);
-#define IS_SLASH_OR_NUL(s) (s == '\0' || IS_SLASH(s))
+#define IS_SLASH_OR_NUL(s) (s == '\0' || AP_IS_SLASH(s))
/*
* Inspired by mod_jk's jk_servlet_normalize().
@@ -504,7 +493,7 @@ AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags)
int decode_unreserved = (flags & AP_NORMALIZE_DECODE_UNRESERVED) != 0;
int merge_slashes = (flags & AP_NORMALIZE_MERGE_SLASHES) != 0;
- if (!IS_SLASH(path[0])) {
+ if (!AP_IS_SLASH(path[0])) {
/* Besides "OPTIONS *", a request-target should start with '/'
* per RFC 7230 section 5.3, so anything else is invalid.
*/
@@ -545,12 +534,12 @@ AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags)
}
}
- if (w == 0 || IS_SLASH(path[w - 1])) {
+ if (w == 0 || AP_IS_SLASH(path[w - 1])) {
/* Collapse ///// sequences to / */
- if (merge_slashes && IS_SLASH(path[l])) {
+ if (merge_slashes && AP_IS_SLASH(path[l])) {
do {
l++;
- } while (IS_SLASH(path[l]));
+ } while (AP_IS_SLASH(path[l]));
continue;
}
@@ -579,7 +568,7 @@ AP_DECLARE(int) ap_normalize_path(char *path, unsigned int flags)
if (w > 1) {
do {
w--;
- } while (w && !IS_SLASH(path[w - 1]));
+ } while (w && !AP_IS_SLASH(path[w - 1]));
}
else {
/* Already at root, ignore and return a failure
@@ -1915,7 +1904,7 @@ static int unescape_url(char *url, const char *forbid, const char *reserved,
char decoded;
decoded = x2c(y + 1);
if ((decoded == '\0')
- || (forbid_slashes && IS_SLASH(decoded))
+ || (forbid_slashes && AP_IS_SLASH(decoded))
|| (forbid && ap_strchr_c(forbid, decoded))) {
badpath = 1;
*x = decoded;
@@ -1923,7 +1912,7 @@ static int unescape_url(char *url, const char *forbid, const char *reserved,
}
else if ((keep_unreserved && TEST_CHAR(decoded,
T_URI_UNRESERVED))
- || (keep_slashes && IS_SLASH(decoded))
+ || (keep_slashes && AP_IS_SLASH(decoded))
|| (reserved && ap_strchr_c(reserved, decoded))) {
*x++ = *y++;
*x++ = *y++;
@@ -1950,7 +1939,7 @@ static int unescape_url(char *url, const char *forbid, const char *reserved,
AP_DECLARE(int) ap_unescape_url(char *url)
{
/* Traditional */
- return unescape_url(url, SLASHES, NULL, 0);
+ return unescape_url(url, AP_SLASHES, NULL, 0);
}
AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
{
@@ -1960,7 +1949,7 @@ AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes)
return unescape_url(url, NULL, NULL, 0);
} else {
/* reserve (do not decode) encoded slashes */
- return unescape_url(url, NULL, SLASHES, 0);
+ return unescape_url(url, NULL, AP_SLASHES, 0);
}
}
AP_DECLARE(int) ap_unescape_url_ex(char *url, unsigned int flags)
diff --git a/server/vhost.c b/server/vhost.c
index 489c141..ee93481 100644
--- a/server/vhost.c
+++ b/server/vhost.c
@@ -23,6 +23,7 @@
#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
+#include "apr_version.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
@@ -182,9 +183,14 @@ static const char *get_addresses(apr_pool_t *p, const char *w_,
if (!host) {
return "Missing address for VirtualHost";
}
+#if !APR_VERSION_AT_LEAST(1,7,0)
if (scope_id) {
- return "Scope ids are not supported";
+ return apr_pstrcat(p,
+ "Scope ID in address '", w,
+ "' not supported with APR " APR_VERSION_STRING,
+ NULL);
}
+#endif
if (!port && !wild_port) {
port = default_port;
}
@@ -203,6 +209,17 @@ static const char *get_addresses(apr_pool_t *p, const char *w_,
"Could not resolve host name %s -- ignoring!", host);
return NULL;
}
+#if APR_VERSION_AT_LEAST(1,7,0)
+ if (scope_id) {
+ rv = apr_sockaddr_zone_set(my_addr, scope_id);
+ if (rv) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO(10103)
+ "Could not set scope ID %s for %pI -- ignoring!",
+ scope_id, my_addr);
+ return NULL;
+ }
+ }
+#endif
}
/* Remember all addresses for the host */