File apache2-mod_jk-1.2.40-CVE-2018-11759.patch of Package apache2-mod_jk.9479
commit 75a168cae5409a00340035160e5aa26f64a66def
Author: Mark Thomas <markt@apache.org>
Date: Fri Aug 24 12:31:54 2018 +0000
Refactor normalisation of request URIs to a common location and align the normalisation implementation for mod_jk with that implemented by Tomcat.
git-svn-id: https://svn.apache.org/repos/asf/tomcat/jk/trunk@1838836 13f79535-47bb-0310-9956-ffa450edef68
Index: tomcat-connectors-1.2.40-src/native/apache-2.0/mod_jk.c
===================================================================
--- tomcat-connectors-1.2.40-src.orig/native/apache-2.0/mod_jk.c
+++ tomcat-connectors-1.2.40-src/native/apache-2.0/mod_jk.c
@@ -249,6 +249,7 @@ typedef struct
struct jk_request_conf
{
rule_extension_t *rule_extensions;
+ char *orig_uri;
int jk_handled;
};
@@ -749,6 +750,7 @@ static int init_ws_service(apache_privat
int size;
request_rec *r = private_data->r;
char *ssl_temp = NULL;
+ char *uri = NULL;
const char *reply_timeout = NULL;
const char *sticky_ignore = NULL;
const char *stateless = NULL;
@@ -930,6 +932,8 @@ static int init_ws_service(apache_privat
* uri is use for compatibilty with mod_rewrite with old Tomcats
*/
+ uri = rconf->orig_uri ? rconf->orig_uri : r->uri;
+
switch (conf->options & JK_OPT_FWDURIMASK) {
case JK_OPT_FWDURICOMPATUNPARSED:
@@ -944,17 +948,17 @@ static int init_ws_service(apache_privat
break;
case JK_OPT_FWDURICOMPAT:
- s->req_uri = r->uri;
+ s->req_uri = uri;
break;
case JK_OPT_FWDURIPROXY:
- size = 3 * (int)strlen(r->uri) + 1;
+ size = 3 * (int)strlen(uri) + 1;
s->req_uri = apr_palloc(r->pool, size);
- jk_canonenc(r->uri, s->req_uri, size);
+ jk_canonenc(uri, s->req_uri, size);
break;
case JK_OPT_FWDURIESCAPED:
- s->req_uri = ap_escape_uri(r->pool, r->uri);
+ s->req_uri = ap_escape_uri(r->pool, uri);
break;
default:
@@ -2189,11 +2193,10 @@ static const char *jk_set_options(cmd_pa
mask = 0;
if (action == '-' &&
- (!strncasecmp(w, "ForwardURI", strlen("ForwardURI")) ||
- !strncasecmp(w, "CollapseSlashes", strlen("CollapseSlashes"))))
+ (!strncasecmp(w, "ForwardURI", strlen("ForwardURI")))) {
return apr_pstrcat(cmd->pool, "JkOptions: Illegal option '-", w,
"': option can not be disabled", NULL);
-
+ }
if (!strcasecmp(w, "ForwardURICompat")) {
opt = JK_OPT_FWDURICOMPAT;
mask = JK_OPT_FWDURIMASK;
@@ -2581,6 +2584,15 @@ static int jk_handler(request_rec * r)
return DECLINED;
}
+ rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config, &jk_module);
+ if (rconf == NULL) {
+ rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
+ rconf->jk_handled = JK_FALSE;
+ rconf->rule_extensions = NULL;
+ rconf->orig_uri = NULL;
+ ap_set_module_config(r->request_config, &jk_module, rconf);
+ }
+
worker_name = apr_table_get(r->notes, JK_NOTE_WORKER_NAME);
if (worker_name == NULL) {
@@ -2604,8 +2616,6 @@ static int jk_handler(request_rec * r)
worker_name_extension = JK_TRUE;
parse_rule_extensions(w, e, xconf->log);
worker_name = w;
- rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config,
- &jk_module);
rconf->rule_extensions = e;
}
}
@@ -2630,11 +2640,20 @@ static int jk_handler(request_rec * r)
}
else {
rule_extension_t *e;
- worker_name = map_uri_to_worker_ext(xconf->uw_map, r->uri,
+ char *clean_uri;
+ clean_uri = apr_pstrdup(r->pool, r->uri);
+ rc = jk_servlet_normalize(clean_uri, xconf->log);
+ if (rc != 0) {
+ return HTTP_BAD_REQUEST;
+ }
+
+ worker_name = map_uri_to_worker_ext(xconf->uw_map, clean_uri,
NULL, &e, NULL, xconf->log);
- rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config,
- &jk_module);
- rconf->rule_extensions = e;
+ if (worker_name) {
+ rconf->rule_extensions = e;
+ rconf->orig_uri = r->uri;
+ r->uri = clean_uri;
+ }
}
if (worker_name == NULL && worker_env.num_of_workers) {
@@ -2654,8 +2673,6 @@ static int jk_handler(request_rec * r)
" r->proxyreq=%d",
r->handler, STRNULL_FOR_NULL(worker_name), r->proxyreq);
- rconf = (jk_request_conf_t *)ap_get_module_config(r->request_config,
- &jk_module);
rconf->jk_handled = JK_TRUE;
/* If this is a proxy request, we'll notify an error */
@@ -3500,8 +3517,10 @@ static int jk_post_config(apr_pool_t * p
uri_worker_map_switch(sconf->uw_map, sconf->log);
uri_worker_map_load(sconf->uw_map, sconf->log);
}
- if (conf->options & JK_OPT_COLLAPSEMASK)
- sconf->uw_map->collapse_slashes = conf->options & JK_OPT_COLLAPSEMASK;
+ if (conf->options & JK_OPT_COLLAPSEMASK) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
+ "Deprecated CollapseSlashes setting ignored");
+ }
}
else {
if (sconf->mountcopy == JK_TRUE) {
@@ -3574,6 +3593,7 @@ static int jk_translate(request_rec * r)
jk_request_conf_t *rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
rconf->jk_handled = JK_FALSE;
rconf->rule_extensions = NULL;
+ rconf->orig_uri = NULL;
ap_set_module_config(r->request_config, &jk_module, rconf);
if (!r->proxyreq) {
@@ -3583,7 +3603,10 @@ static int jk_translate(request_rec * r)
&jk_module);
if (conf) {
+ char *clean_uri;
+ int rc;
const char *worker;
+
if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
/* Somebody already set the handler, probably manual config
* or "native" configuration, no need for extra overhead
@@ -3603,6 +3626,12 @@ static int jk_translate(request_rec * r)
return DECLINED;
}
+ clean_uri = apr_pstrdup(r->pool, r->uri);
+ rc = jk_servlet_normalize(clean_uri, conf->log);
+ if (rc != 0) {
+ return HTTP_BAD_REQUEST;
+ }
+
/* Special case to make sure that apache can serve a directory
listing if there are no matches for the DirectoryIndex and
Tomcat webapps are mapped into apache using JkAutoAlias. */
@@ -3612,11 +3641,8 @@ static int jk_translate(request_rec * r)
/* Append the request uri to the JkAutoAlias directory and
determine if the file exists. */
- char *clean_uri;
apr_finfo_t finfo;
finfo.filetype = APR_NOFILE;
- clean_uri = apr_pstrdup(r->pool, r->uri);
- ap_no2slash(clean_uri);
/* Map uri to a context static file */
if (strlen(clean_uri) > 1) {
char *context_path = NULL;
@@ -3648,10 +3674,13 @@ static int jk_translate(request_rec * r)
}
else {
rule_extension_t *e;
- worker = map_uri_to_worker_ext(conf->uw_map, r->uri,
+ worker = map_uri_to_worker_ext(conf->uw_map, clean_uri,
NULL, &e, NULL, conf->log);
- rconf->rule_extensions = e;
- ap_set_module_config(r->request_config, &jk_module, rconf);
+ if (worker) {
+ rconf->rule_extensions = e;
+ rconf->orig_uri = r->uri;
+ r->uri = clean_uri;
+ }
}
if (worker) {
@@ -3668,8 +3697,6 @@ static int jk_translate(request_rec * r)
return OK;
}
else if (conf->alias_dir != NULL) {
- char *clean_uri = apr_pstrdup(r->pool, r->uri);
- ap_no2slash(clean_uri);
/* Automatically map uri to a context static file */
if (JK_IS_DEBUG_LEVEL(conf->log))
jk_log(conf->log, JK_LOG_DEBUG,
@@ -3777,6 +3804,7 @@ static int jk_map_to_storage(request_rec
rconf = apr_palloc(r->pool, sizeof(jk_request_conf_t));
rconf->jk_handled = JK_FALSE;
rconf->rule_extensions = NULL;
+ rconf->orig_uri = NULL;
ap_set_module_config(r->request_config, &jk_module, rconf);
}
@@ -3787,7 +3815,10 @@ static int jk_map_to_storage(request_rec
&jk_module);
if (conf) {
+ char *clean_uri;
+ int rc;
const char *worker;
+
if ((r->handler != NULL) && (!strcmp(r->handler, JK_HANDLER))) {
/* Somebody already set the handler, probably manual config
* or "native" configuration, no need for extra overhead
@@ -3806,6 +3837,13 @@ static int jk_map_to_storage(request_rec
return DECLINED;
}
+
+ clean_uri = apr_pstrdup(r->pool, r->uri);
+ rc = jk_servlet_normalize(clean_uri, conf->log);
+ if (rc != 0) {
+ return HTTP_BAD_REQUEST;
+ }
+
if (!conf->uw_map) {
if (JK_IS_DEBUG_LEVEL(conf->log))
jk_log(conf->log, JK_LOG_DEBUG,
@@ -3816,10 +3854,13 @@ static int jk_map_to_storage(request_rec
}
else {
rule_extension_t *e;
- worker = map_uri_to_worker_ext(conf->uw_map, r->uri,
+ worker = map_uri_to_worker_ext(conf->uw_map, clean_uri,
NULL, &e, NULL, conf->log);
- rconf->rule_extensions = e;
- ap_set_module_config(r->request_config, &jk_module, rconf);
+ if (worker) {
+ rconf->rule_extensions = e;
+ rconf->orig_uri = r->uri;
+ r->uri = clean_uri;
+ }
}
if (worker) {
@@ -3836,23 +3877,12 @@ static int jk_map_to_storage(request_rec
jk_log(conf->log, JK_LOG_DEBUG,
"no match for %s found",
r->uri);
- if (conf->strip_session == JK_TRUE &&
- conf->strip_session_name) {
- char *jsessionid;
+ if (conf->strip_session == JK_TRUE && conf->strip_session_name) {
if (r->uri) {
- jsessionid = strstr(r->uri, conf->strip_session_name);
- if (jsessionid) {
- if (JK_IS_DEBUG_LEVEL(conf->log))
- jk_log(conf->log, JK_LOG_DEBUG,
- "removing session identifier [%s] for non servlet url [%s]",
- jsessionid, r->uri);
- *jsessionid = '\0';
- }
+ jk_strip_session_id(r->uri, conf->strip_session_name, conf->log);
}
if (r->filename) {
- jsessionid = strstr(r->filename, conf->strip_session_name);
- if (jsessionid)
- *jsessionid = '\0';
+ jk_strip_session_id(r->filename, conf->strip_session_name, conf->log);
}
return DECLINED;
}
Index: tomcat-connectors-1.2.40-src/native/common/jk_util.c
===================================================================
--- tomcat-connectors-1.2.40-src.orig/native/common/jk_util.c
+++ tomcat-connectors-1.2.40-src/native/common/jk_util.c
@@ -2144,23 +2144,147 @@ int jk_wildchar_match(const char *str, c
return (str[x] != '\0');
}
-void jk_no2slash(char *name)
+int jk_servlet_normalize(char *path, jk_logger_t *logger)
{
- char *d, *s;
+ int l, w;
- s = d = name;
+ if (JK_IS_DEBUG_LEVEL(logger)) {
+ jk_log(logger, JK_LOG_DEBUG, "URI on entering jk_servlet_normalize: [%s]", path);
+ }
+
+ // This test allows the loops below to start at index 1 rather than 0.
+ if (path[0] != '/') {
+ if (path[0] == '*' && path[1] == '\0') {
+ /* Most likely an "OPTIONS *" request */
+ return 0;
+ }
+ jk_log(logger, JK_LOG_WARNING, "Uri [%s] does not start with '/'.", path);
+ return JK_NORMALIZE_BAD_PATH;
+ }
- while (*s) {
- if ((*d++ = *s) == '/') {
+ /* First pass.
+ * Remove path parameters ;foo=bar/ from any path segment
+ */
+ for (l = 1, w = 1; path[l] != '\0';) {
+ if (path[l] == ';') {
+ l++;
+ while (path[l] != '/' && path[l] != '\0') {
+ l++;
+ }
+ }
+ else
+ path[w++] = path[l++];
+ }
+ path[w] = '\0';
+
+ /*
+ * Second pass.
+ * Collapse ///// sequences to /
+ */
+ for (l = 1, w = 1; path[l] != '\0';) {
+ if (path[w - 1] == '/' && (path[l] == '/')) {
+ l++;
+ }
+ else
+ path[w++] = path[l++];
+ }
+ path[w] = '\0';
+
+ /* Third pass.
+ * Remove /./ segments
+ * Both leading and trailing segments will be removed.
+ */
+ for (l = 1, w = 1; path[l] != '\0';) {
+ if (path[l] == '.' &&
+ (path[l + 1] == '/' || path[l + 1] == '\0') &&
+ (l == 0 || path[l - 1] == '/')) {
+ l++;
+ if (path[l] == '/') {
+ l++;
+ }
+ }
+ else
+ path[w++] = path[l++];
+ }
+ path[w] = '\0';
+
+ /* Fourth pass.
+ * Remove /xx/../ segments
+ * Trailing segments will be removed but leading /../ segments are an error
+ * condition.
+ */
+ for (l = 1, w = 1; path[l] != '\0';) {
+ if (path[l] == '.' && path[l + 1] == '.' &&
+ (path[l + 2] == '/' || path[l + 2] == '\0') &&
+ (l == 0 || path[l - 1] == '/')) {
+
+ // Wind w back to remove the previous segment
+ if (w == 1) {
+ jk_log(logger,
+ JK_LOG_EMERG,
+ "[%s] contains a '/../' sequence that tries to escape above the root.",
+ path);
+ return JK_NORMALIZE_TRAVERSAL;
+ }
do {
- ++s;
- } while (*s == '/');
+ w--;
+ } while (w != 0 && path[w - 1] != '/');
+
+ // Move l forward to the next segment
+ l += 2;
+
+ if (path[l] == '/') {
+ l++;
+ }
+ }
+ else
+ path[w++] = path[l++];
+ }
+ path[w] = '\0';
+
+ if (JK_IS_DEBUG_LEVEL(logger)) {
+ jk_log(logger, JK_LOG_DEBUG, "URI on exiting jk_servlet_normalize: [%s]", path);
+ }
+
+ return 0;
+}
+
+int jk_strip_session_id(char* path, char* session_name, jk_logger_t *logger) {
+
+ char *jsessionid;
+
+ jsessionid = strstr(path, session_name);
+ if (jsessionid) {
+ int i;
+ int j;
+ if (JK_IS_DEBUG_LEVEL(logger)) {
+ jk_log(logger, JK_LOG_DEBUG,
+ "removing session identifier for non servlet uri [%s]", path);
+ }
+ // Found a session path parameter.
+ // Need to skip at least as many characters as there are in
+ // strip_session_name
+ i = (int) strlen(session_name);
+ j = 0;
+ // Increment i until the first character after the parameter
+ while (jsessionid[i] != '\0' && jsessionid[i] != ';' && jsessionid[i] != '/') {
+ i++;
}
- else {
- ++s;
+ // Copy until the end
+ while (jsessionid[i] != '\0') {
+ jsessionid[j++] = jsessionid[i++];
}
+ // Terminate
+ jsessionid[j] = '\0';
+
+ if (JK_IS_DEBUG_LEVEL(logger)) {
+ jk_log(logger, JK_LOG_DEBUG,
+ "result of removing session identifier for non servlet uri is [%s]", path);
+ }
+ return 1;
}
- *d = '\0';
+
+ return 0;
}
#ifdef _MT_CODE_PTHREAD
Index: tomcat-connectors-1.2.40-src/native/common/jk_util.h
===================================================================
--- tomcat-connectors-1.2.40-src.orig/native/common/jk_util.h
+++ tomcat-connectors-1.2.40-src/native/common/jk_util.h
@@ -246,7 +246,12 @@ int is_http_status_fail(unsigned int htt
int jk_wildchar_match(const char *str, const char *exp, int icase);
-void jk_no2slash(char *name);
+int jk_servlet_normalize(char *path, jk_logger_t *logger);
+
+int jk_strip_session_id(char* path, char* session_name, jk_logger_t *logger);
+
+#define JK_NORMALIZE_BAD_PATH -1
+#define JK_NORMALIZE_TRAVERSAL -2
#define TC32_BRIDGE_TYPE 32
#define TC33_BRIDGE_TYPE 33
Index: tomcat-connectors-1.2.40-src/native/iis/jk_isapi_plugin.c
===================================================================
--- tomcat-connectors-1.2.40-src.orig/native/iis/jk_isapi_plugin.c
+++ tomcat-connectors-1.2.40-src/native/iis/jk_isapi_plugin.c
@@ -129,9 +129,6 @@ static char HTTP_WORKER_HEADER_INDEX[RES
#define AUTH_COMPLETE_TAG "auth_complete"
#define REJECT_UNSAFE_TAG "reject_unsafe"
#define COLLAPSE_SLASHES_TAG "collapse_slashes"
-#define COLLAPSE_SLASHES_ALL_VERB "all"
-#define COLLAPSE_SLASHES_NONE_VERB "none"
-#define COLLAPSE_SLASHES_UNMOUNT_VERB "unmount"
#define WATCHDOG_INTERVAL_TAG "watchdog_interval"
#define ENABLE_CHUNKED_ENCODING_TAG "enable_chunked_encoding"
#define ERROR_PAGE_TAG "error_page"
@@ -504,7 +501,6 @@ static int strip_session = 0;
static int use_auth_notification_flags = 1;
static int chunked_encoding_enabled = JK_FALSE;
static int reject_unsafe = 0;
-static int collapse_slashes = JK_COLLAPSE_DEFAULT;
static volatile int watchdog_interval = 0;
static HANDLE watchdog_handle = NULL;
static char error_page_buf[INTERNET_MAX_URL_LENGTH] = {0};
@@ -651,71 +647,6 @@ static int unescape_url(char *url)
return 0;
}
-static void getparents(char *name)
-{
- int l, w;
-
- /* Four paseses, as per RFC 1808 */
- /* a) remove ./ path segments */
-
- for (l = 0, w = 0; name[l] != '\0';) {
- if (name[l] == '.' && name[l + 1] == '/'
- && (l == 0 || name[l - 1] == '/'))
- l += 2;
- else
- name[w++] = name[l++];
- }
-
- /* b) remove trailing . path, segment */
- if (w == 1 && name[0] == '.')
- w--;
- else if (w > 1 && name[w - 1] == '.' && name[w - 2] == '/')
- w--;
- name[w] = '\0';
-
- /* c) remove all xx/../ segments. (including leading ../ and /../) */
- l = 0;
-
- while (name[l] != '\0') {
- if (name[l] == '.' && name[l + 1] == '.' && name[l + 2] == '/' &&
- (l == 0 || name[l - 1] == '/')) {
- register int m = l + 3, n;
-
- l = l - 2;
- if (l >= 0) {
- while (l >= 0 && name[l] != '/')
- l--;
- l++;
- }
- else
- l = 0;
- n = l;
- while ((name[n] = name[m]) != '\0') {
- n++;
- m++;
- }
- }
- else
- ++l;
- }
-
- /* d) remove trailing xx/.. segment. */
- if (l == 2 && name[0] == '.' && name[1] == '.')
- name[0] = '\0';
- else if (l > 2 && name[l - 1] == '.' && name[l - 2] == '.'
- && name[l - 3] == '/') {
- l = l - 4;
- if (l >= 0) {
- while (l >= 0 && name[l] != '/')
- l--;
- l++;
- }
- else
- l = 0;
- name[l] = '\0';
- }
-}
-
/* Apache code to escape a URL */
#define T_OS_ESCAPE_PATH (4)
@@ -1898,7 +1829,8 @@ static DWORD handle_notify_event(PHTTP_F
jk_pool_t pool;
char *uri_undec = NULL;
- char *uri = NULL;
+ char *cleanuri = NULL;
+ char *uri = NULL;
char *host = NULL;
char *translate = NULL;
char szHB[HDR_BUFFER_SIZE] = "/";
@@ -1946,10 +1878,10 @@ static DWORD handle_notify_event(PHTTP_F
else
query = NULL;
}
- if (uri_select_option == URI_SELECT_OPT_UNPARSED) {
- /* Duplicate unparsed uri */
- uri_undec = jk_pool_strdup(&pool, uri);
- }
+
+ /* Duplicate unparsed uri */
+ uri_undec = jk_pool_strdup(&pool, uri);
+
rc = unescape_url(uri);
if (rc == BAD_REQUEST) {
jk_log(logger, JK_LOG_ERROR,
@@ -1967,7 +1899,12 @@ static DWORD handle_notify_event(PHTTP_F
rv = SF_STATUS_REQ_FINISHED;
goto cleanup;
}
- getparents(uri);
+ cleanuri = jk_pool_strdup(&pool, uri);
+ if (jk_servlet_normalize(cleanuri, logger)) {
+ write_error_response(pfc, 404);
+ rv = SF_STATUS_REQ_FINISHED;
+ goto cleanup;
+ }
len = ISIZEOF(szHB) - 1;
if (pfc->GetServerVariable(pfc, "SERVER_NAME", &szHB[1], &len) && len > 1) {
len = ISIZEOF(szPB);
@@ -1979,7 +1916,7 @@ static DWORD handle_notify_event(PHTTP_F
else
host = szHB;
}
- worker = map_uri_to_worker_ext(uw_map, uri, host,
+ worker = map_uri_to_worker_ext(uw_map, cleanuri, host,
&extensions, &worker_index, logger);
/*
* Check if somebody is feading us with his own TOMCAT data headers.
@@ -2135,18 +2072,11 @@ static DWORD handle_notify_event(PHTTP_F
}
else {
if (JK_IS_DEBUG_LEVEL(logger))
- jk_log(logger, JK_LOG_DEBUG,
- "[%s] is not a servlet url", uri);
+ jk_log(logger, JK_LOG_DEBUG, "[%s] is not a servlet url", uri_undec);
if (strip_session) {
- char *jsessionid = strstr(uri, JK_PATH_SESSION_IDENTIFIER);
- if (jsessionid) {
- if (JK_IS_DEBUG_LEVEL(logger))
- jk_log(logger, JK_LOG_DEBUG,
- "removing session identifier [%s] for non servlet url [%s]",
- jsessionid, uri);
- *jsessionid = '\0';
- pfp->SetHeader(pfc, "url", uri);
- }
+ if (jk_strip_session_id(uri_undec, JK_PATH_SESSION_IDENTIFIER, logger)) {
+ pfp->SetHeader(pfc, "url", uri_undec);
+ }
}
}
cleanup:
@@ -2795,7 +2725,6 @@ static int init_jk(char *serverName)
uw_map->reject_unsafe = 1;
else
uw_map->reject_unsafe = 0;
- uw_map->collapse_slashes = collapse_slashes;
uw_map->reload = worker_mount_reload;
if (worker_mount_file[0]) {
uw_map->fname = worker_mount_file;
@@ -2925,17 +2854,6 @@ int parse_uri_select(const char *uri_sel
return -1;
}
-int parse_collapse_slashes(const char *collapse_slashes)
-{
- if (!strcasecmp(collapse_slashes, COLLAPSE_SLASHES_ALL_VERB))
- return JK_OPT_COLLAPSEALL;
- if (!strcasecmp(collapse_slashes, COLLAPSE_SLASHES_NONE_VERB))
- return JK_OPT_COLLAPSENONE;
- if (!strcasecmp(collapse_slashes, COLLAPSE_SLASHES_UNMOUNT_VERB))
- return JK_OPT_COLLAPSEUNMOUNT;
- return -1;
-}
-
static int read_registry_init_data(void)
{
char tmpbuf[MAX_PATH];
@@ -3038,14 +2956,8 @@ static int read_registry_init_data(void)
}
}
if (get_config_parameter(src, COLLAPSE_SLASHES_TAG, tmpbuf, sizeof(tmpbuf))) {
- int opt = parse_collapse_slashes(tmpbuf);
- if (opt >= 0) {
- collapse_slashes = opt;
- }
- else {
- jk_log(logger, JK_LOG_ERROR, "Invalid value '%s' for configuration item '"
- COLLAPSE_SLASHES_TAG "'", tmpbuf);
- }
+ jk_log(logger, JK_LOG_ERROR, "Configuration item '" COLLAPSE_SLASHES_TAG
+ "' is deprecated and will be ignored");
}
shm_config_size = get_config_int(src, SHM_SIZE_TAG, -1);
worker_mount_reload = get_config_int(src, WORKER_MOUNT_RELOAD_TAG, JK_URIMAP_DEF_RELOAD);
@@ -3198,7 +3110,7 @@ static int init_ws_service(isapi_private
JK_TRACE_EXIT(logger);
return JK_FALSE;
}
- getparents(s->req_uri);
+ jk_servlet_normalize(s->req_uri, logger);
}
GET_SERVER_VARIABLE_VALUE("AUTH_TYPE", s->auth_type);
Index: tomcat-connectors-1.2.40-src/xdocs/miscellaneous/changelog.xml
===================================================================
--- tomcat-connectors-1.2.40-src.orig/xdocs/miscellaneous/changelog.xml
+++ tomcat-connectors-1.2.40-src/xdocs/miscellaneous/changelog.xml
@@ -120,6 +120,26 @@
<update>
Minor documentation improvements. (rjung)
</update>
+ <scode>
+ Common: Optimize path parameter handling. (rjung)
+ </scode>
+ <fix>
+ Improve path parameter parsing so that the session ID specified by the
+ <code>session_path</code> worker property for load-balanced workers can
+ be extracted from a path parameter in any segment of the URI, rather
+ than only from the final segment. (markt)
+ </fix>
+ <fix>
+ Apache: Improve path parameter handling so that
+ <code>JkStripSession</code> can remove session IDs that are specified on
+ path parameters in any segment of the URI rather than only the final
+ segment. (markt)
+ </fix>
+ <fix>
+ IIS: Improve path parameter handling so that <code>strip_session</code>
+ can remove session IDs that are specified on path parameters in any
+ segment of the URI rather than only the final segment. (markt)
+ </fix>
</changelog>
</subsection>
</section>
Index: tomcat-connectors-1.2.40-src/native/common/jk_uri_worker_map.c
===================================================================
--- tomcat-connectors-1.2.40-src.orig/native/common/jk_uri_worker_map.c
+++ tomcat-connectors-1.2.40-src/native/common/jk_uri_worker_map.c
@@ -176,10 +176,9 @@ static void uri_worker_map_dump(jk_uri_w
int i, off;
if (JK_IS_DEBUG_LEVEL(l)) {
jk_log(l, JK_LOG_DEBUG, "uri map dump %s: id=%d, index=%d file='%s' reject_unsafe=%d "
- "collapse_slashes=%d reload=%d modified=%d checked=%d",
+ "reload=%d modified=%d checked=%d",
reason, uw_map->id, uw_map->index, STRNULL_FOR_NULL(uw_map->fname),
- uw_map->reject_unsafe, uw_map->collapse_slashes,
- uw_map->reload, uw_map->modified, uw_map->checked);
+ uw_map->reject_unsafe, uw_map->reload, uw_map->modified, uw_map->checked);
}
for (i = 0; i <= 1; i++) {
jk_log(l, JK_LOG_DEBUG, "generation %d: size=%d nosize=%d capacity=%d",
@@ -245,7 +244,6 @@ int uri_worker_map_alloc(jk_uri_worker_m
uw_map->index = 0;
uw_map->fname = NULL;
uw_map->reject_unsafe = 0;
- uw_map->collapse_slashes = JK_COLLAPSE_DEFAULT;
uw_map->reload = JK_URIMAP_DEF_RELOAD;
uw_map->modified = 0;
uw_map->checked = 0;
@@ -1072,7 +1070,6 @@ const char *map_uri_to_worker_ext(jk_uri
unsigned int i;
unsigned int vhost_len;
int reject_unsafe;
- int collapse_slashes;
int rv = -1;
char url[JK_MAX_URI_LEN+1];
@@ -1103,7 +1100,6 @@ const char *map_uri_to_worker_ext(jk_uri
}
}
reject_unsafe = uw_map->reject_unsafe;
- collapse_slashes = uw_map->collapse_slashes;
vhost_len = 0;
/*
* In case we got a vhost, we prepend a slash
@@ -1131,8 +1127,8 @@ const char *map_uri_to_worker_ext(jk_uri
}
vhost_len += off;
}
- /* Make the copy of the provided uri and strip
- * everything after the first ';' char.
+ /* Make the copy of the provided uri, check length
+ * and look for potentially unsafe constructs
*/
for (i = 0; i < strlen(uri); i++) {
if (i == JK_MAX_URI_LEN) {
@@ -1142,15 +1138,11 @@ const char *map_uri_to_worker_ext(jk_uri
JK_TRACE_EXIT(l);
return NULL;
}
- if (uri[i] == ';')
- break;
- else {
- url[i + vhost_len] = uri[i];
- if (reject_unsafe && (uri[i] == '%' || uri[i] == '\\')) {
- jk_log(l, JK_LOG_INFO, "Potentially unsafe request url '%s' rejected", uri);
- JK_TRACE_EXIT(l);
- return NULL;
- }
+ url[i + vhost_len] = uri[i];
+ if (reject_unsafe && (uri[i] == '%' || uri[i] == '\\')) {
+ jk_log(l, JK_LOG_INFO, "Potentially unsafe request url '%s' rejected", uri);
+ JK_TRACE_EXIT(l);
+ return NULL;
}
}
url[i + vhost_len] = '\0';
@@ -1161,12 +1153,6 @@ const char *map_uri_to_worker_ext(jk_uri
jk_log(l, JK_LOG_DEBUG, "Found session identifier '%s' in url '%s'",
url_rewrite, uri);
}
- if (collapse_slashes == JK_COLLAPSE_ALL) {
- /* Remove multiple slashes
- * No need to copy url, because it is local and
- * the unchanged url is no longer needed */
- jk_no2slash(url);
- }
if (JK_IS_DEBUG_LEVEL(l))
jk_log(l, JK_LOG_DEBUG, "Attempting to map URI '%s' from %d maps",
url, IND_THIS(uw_map->size));
@@ -1178,13 +1164,6 @@ const char *map_uri_to_worker_ext(jk_uri
/* In case we found a match, check for the unmounts. */
if (rv >= 0 && IND_THIS(uw_map->nosize)) {
- if (collapse_slashes == JK_COLLAPSE_UNMOUNT) {
- /* Remove multiple slashes when looking for
- * unmount to prevent trivial unmount bypass attack.
- * No need to copy url, because it is local and
- * the unchanged url is no longer needed */
- jk_no2slash(url);
- }
/* Again first including vhost. */
int rc = is_nomatch(uw_map, url, rv, l);
/* If no unmount was find, try without vhost. */
Index: tomcat-connectors-1.2.40-src/native/common/jk_global.h
===================================================================
--- tomcat-connectors-1.2.40-src.orig/native/common/jk_global.h
+++ tomcat-connectors-1.2.40-src/native/common/jk_global.h
@@ -277,7 +277,7 @@ extern "C"
#define JK_OPT_COLLAPSENONE 0x2000
#define JK_OPT_COLLAPSEUNMOUNT 0x4000
-#define JK_OPT_DEFAULT (JK_OPT_FWDURIDEFAULT | JK_OPT_FWDKEYSIZE | JK_OPT_COLLAPSEUNMOUNT)
+#define JK_OPT_DEFAULT (JK_OPT_FWDURIDEFAULT | JK_OPT_FWDKEYSIZE)
/* Check for EBCDIC systems */
Index: tomcat-connectors-1.2.40-src/native/common/jk_uri_worker_map.h
===================================================================
--- tomcat-connectors-1.2.40-src.orig/native/common/jk_uri_worker_map.h
+++ tomcat-connectors-1.2.40-src/native/common/jk_uri_worker_map.h
@@ -58,11 +58,6 @@ extern "C"
#define MATCH_TYPE_STOPPED 0x4000
*/
-#define JK_COLLAPSE_ALL 0x0001
-#define JK_COLLAPSE_NONE 0x0002
-#define JK_COLLAPSE_UNMOUNT 0x0003
-#define JK_COLLAPSE_DEFAULT JK_COLLAPSE_UNMOUNT
-
#define SOURCE_TYPE_WORKERDEF 0x0001
#define SOURCE_TYPE_JKMOUNT 0x0002
#define SOURCE_TYPE_URIMAP 0x0003
@@ -172,9 +167,7 @@ struct jk_uri_worker_map
JK_CRIT_SEC cs;
/* should we forward potentially unsafe URLs */
- int reject_unsafe;
- /* how to handle multiple adjacent slashes in URLs */
- int collapse_slashes;
+ int reject_unsafe;
/* uriworkermap filename */
const char *fname;
/* uriworkermap reload check interval */
Index: tomcat-connectors-1.2.40-src/native/common/jk_lb_worker.c
===================================================================
--- tomcat-connectors-1.2.40-src.orig/native/common/jk_lb_worker.c
+++ tomcat-connectors-1.2.40-src/native/common/jk_lb_worker.c
@@ -431,6 +431,12 @@ static char *get_path_param(jk_ws_servic
if ((id_end = strchr(id_start, ';')) != NULL) {
*id_end = '\0';
}
+ /*
+ * Remove any trailing URI segments.
+ */
+ if ((id_end = strchr(id_start, '/')) != NULL) {
+ *id_end = '\0';
+ }
return id_start;
}
}
@@ -1164,8 +1170,9 @@ static int JK_METHOD service(jk_endpoint
if (p->worker->sequence < p->worker->s->h.sequence)
jk_lb_pull(p->worker, JK_FALSE, l);
for (i = 0; i < num_of_workers; i++) {
+ lb_sub_worker_t *rec;
jk_log(l, JK_LOG_DEBUG, "LB - num_of_workers: %d, retry: %d, lb_retries: %d", num_of_workers, i, p->worker->lb_retries);
- lb_sub_worker_t *rec = &(p->worker->lb_workers[i]);
+ rec = &(p->worker->lb_workers[i]);
if (rec->s->state == JK_LB_STATE_BUSY) {
if (ajp_has_endpoint(rec->worker, l)) {
if (JK_IS_DEBUG_LEVEL(l))