]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge r1918549 from trunk:
authorEric Covener <covener@apache.org>
Mon, 24 Jun 2024 17:52:15 +0000 (17:52 +0000)
committerEric Covener <covener@apache.org>
Mon, 24 Jun 2024 17:52:15 +0000 (17:52 +0000)
add UNCList directive on Windows

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918558 13f79535-47bb-0310-9956-ffa450edef68

docs/manual/mod/core.xml
include/http_core.h
include/httpd.h
server/core.c

index b18b5c68697bfb779586b8d2d5bac5c78095e738..659d92405cf59d0ede4e4e112b4776a8c77acb2b 100644 (file)
@@ -5171,6 +5171,33 @@ hostname or IP address</description>
     different sections are combined when a request is received</seealso>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>UNCList</name>
+<description>Controls what UNC host names can be accessed by the server
+</description>
+<syntax>UNCList<var>hostname</var> ...</syntax>
+<default>unset</default>
+<contextlist><context>server config</context>
+</contextlist>
+<compatibility>Added in 2.4.60, Windows only.</compatibility>
+
+<usage>
+    <p> During request processing, requests to access a filesystem path that
+    resolves to a UNC path will fail unless the hostname in the UNC path
+    has been specified by this directive. The intent is to limit access to
+    paths derived from untrusted inputs.</p>
+
+<note type="warning"><title>Security</title>
+UNC paths accessed outside of request processing, such as during startup,
+are not checked against the hosts configured with this directive.</p>
+</note>
+</usage>
+</directivesynopsis>
+
+
+UNCList
+
+
 <directivesynopsis>
 <name>MergeTrailers</name>
 <description>Determines whether trailers are merged into headers</description>
index 948034f5f2a20a2661c172f757f9680b4d6b9428..9fb9f5135c348743d163ee1456f0b9f4dcd2ed03 100644 (file)
@@ -756,6 +756,9 @@ typedef struct {
     apr_size_t   flush_max_threshold;
     apr_int32_t  flush_max_pipelined;
     unsigned int strict_host_check;
+#ifdef WIN32
+    apr_array_header_t *unc_list;
+#endif
 } core_server_config;
 
 /* for AddOutputFiltersByType in core.c */
index 799cf9705e940fdec3a5873786b3690233f4aaba..826c46ef591f323a8abd1a5fb5caca69cf0e7a82 100644 (file)
@@ -2656,6 +2656,31 @@ AP_DECLARE(const char *)ap_dir_fnmatch(ap_dir_match_t *w, const char *path,
  */
 AP_DECLARE(int) ap_is_chunked(apr_pool_t *p, const char *line);
 
+
+/**
+ * apr_filepath_merge with an allow-list
+ * Merge additional file path onto the previously processed rootpath
+ * @param newpath the merged paths returned
+ * @param rootpath the root file path (NULL uses the current working path)
+ * @param addpath the path to add to the root path
+ * @param flags the desired APR_FILEPATH_ rules to apply when merging
+ * @param p the pool to allocate the new path string from
+ * @remark if the flag APR_FILEPATH_TRUENAME is given, and the addpath
+ * contains wildcard characters ('*', '?') on platforms that don't support
+ * such characters within filenames, the paths will be merged, but the
+ * result code will be APR_EPATHWILD, and all further segments will not
+ * reflect the true filenames including the wildcard and following segments.
+ */
+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
+#define apr_filepath_merge  ap_filepath_merge
+#endif
+
 #ifdef __cplusplus
 }
 #endif
index e5e059e6edeb5f8b54e47d58f80e1664e9d6604e..f511bba489708daaf656f7898327573e56025423 100644 (file)
@@ -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 */
 
@@ -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);