You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by co...@apache.org on 2026/09/29 08:30:02 UTC

svn commit: r1938666 - httpd/httpd/trunk/modules/dav/fs

Author: covener
Date: Tue Sep 29 08:30:01 2026
New Revision: 1938666

Log:
block dav state dir

Modified:
   httpd/httpd/trunk/modules/dav/fs/mod_dav_fs.c
   httpd/httpd/trunk/modules/dav/fs/repos.c
   httpd/httpd/trunk/modules/dav/fs/repos.h

Modified: httpd/httpd/trunk/modules/dav/fs/mod_dav_fs.c
==============================================================================
--- httpd/httpd/trunk/modules/dav/fs/mod_dav_fs.c	Tue Sep 29 08:28:40 2026	(r1938665)
+++ httpd/httpd/trunk/modules/dav/fs/mod_dav_fs.c	Tue Sep 29 08:30:01 2026	(r1938666)
@@ -284,11 +284,51 @@ static const command_rec dav_fs_cmds[] =
     { NULL }
 };
 
+/*
+ * dav_fs_get_resource() refuses the state directory, but only requests
+ * which mod_dav routes through the repository provider ever reach it.
+ * GET is not one of those: mod_dav_fs sets handle_get to false, so
+ * dav_fixups() declines and the default handler serves the file straight
+ * off the filesystem, property database and all. Deny the state directory
+ * here instead, for every method, wherever mod_dav_fs is the provider.
+ */
+static int dav_fs_fixups(request_rec *r)
+{
+    const char *provider_name, *pathname;
+
+    provider_name = dav_get_provider_name(r);
+    if (provider_name == NULL
+        || strcmp(provider_name, DAV_FS_PROVIDER_NAME) != 0) {
+        /* DAV is off here, or another provider owns this space */
+        return DECLINED;
+    }
+
+    if (r->filename == NULL) {
+        return DECLINED;
+    }
+
+    /* as in dav_fs_get_resource(), any path_info is part of the pathname */
+    pathname = (r->path_info && *r->path_info)
+        ? apr_pstrcat(r->pool, r->filename, r->path_info, NULL)
+        : r->filename;
+
+    if (!dav_fs_is_state_path(r->pool, pathname)) {
+        return DECLINED;
+    }
+
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10619)
+                  "access to " DAV_FS_STATE_DIR " state directory "
+                  "denied for %s", r->filename);
+    return HTTP_FORBIDDEN;
+}
+
 static void register_hooks(apr_pool_t *p)
 {
     ap_hook_pre_config(dav_fs_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_post_config(dav_fs_post_config, NULL, NULL, APR_HOOK_MIDDLE);
     ap_hook_child_init(dav_fs_child_init, NULL, NULL, APR_HOOK_MIDDLE);
+    /* before mod_dav's fixup, which takes over the request */
+    ap_hook_fixups(dav_fs_fixups, NULL, NULL, APR_HOOK_FIRST);
     
     dav_hook_gather_propsets(dav_fs_gather_propsets, NULL, NULL,
                              APR_HOOK_MIDDLE);

Modified: httpd/httpd/trunk/modules/dav/fs/repos.c
==============================================================================
--- httpd/httpd/trunk/modules/dav/fs/repos.c	Tue Sep 29 08:28:40 2026	(r1938665)
+++ httpd/httpd/trunk/modules/dav/fs/repos.c	Tue Sep 29 08:30:01 2026	(r1938666)
@@ -704,6 +704,42 @@ static dav_error *dav_fs_deleteset(apr_p
 ** REPOSITORY HOOK FUNCTIONS
 */
 
+/* Is PATHNAME the mod_dav_fs state directory itself, or a file directly
+** within it? Both dav_fs_get_resource() and the fixup hook in mod_dav_fs.c
+** use this; the latter is what catches methods such as GET which mod_dav
+** leaves to the default handler and which therefore never reach the
+** repository provider at all.
+*/
+int dav_fs_is_state_path(apr_pool_t *p, const char *pathname)
+{
+    const char *filename, *dirname;
+    char *path, *parent;
+    apr_size_t len;
+
+    /* make sure the pathname does not have a trailing "/" */
+    path = apr_pstrdup(p, pathname);
+    len = strlen(path);
+    if (len > 1 && path[len - 1] == '/') {
+        path[len - 1] = '\0';
+    }
+
+    filename = apr_filepath_name_get(path);
+    parent = ap_make_dirstr_parent(p, path);
+    /* Strip the trailing slash and extract the leaf directory name. */
+    len = strlen(parent);
+    if (len > 1 && parent[len - 1] == '/') {
+        parent[len - 1] = '\0';
+    }
+    dirname = apr_filepath_name_get(parent);
+#ifdef CASE_BLIND_FILESYSTEM
+    return ap_cstr_casecmp(filename, DAV_FS_STATE_DIR) == 0
+        || ap_cstr_casecmp(dirname, DAV_FS_STATE_DIR) == 0;
+#else
+    return strcmp(filename, DAV_FS_STATE_DIR) == 0
+        || strcmp(dirname, DAV_FS_STATE_DIR) == 0;
+#endif
+}
+
 static dav_error * dav_fs_get_resource(
     request_rec *r,
     const char *root_dir,
@@ -713,8 +749,8 @@ static dav_error * dav_fs_get_resource(
 {
     dav_resource_private *ctx;
     dav_resource *resource;
-    char *s, *parent;
-    const char *filename, *dirname;
+    char *s;
+    const char *filename;
     apr_size_t len;
 
     /* ### optimize this into a single allocation! */
@@ -750,21 +786,7 @@ static dav_error * dav_fs_get_resource(
     }
 
     /* Deny any access to, or within, the state directory. */
-    filename = apr_filepath_name_get(s);
-    parent = ap_make_dirstr_parent(r->pool, s);
-    /* Strip the trailing slash and extract the leaf directory name. */
-    len = strlen(parent);
-    if (len > 1 && parent[len - 1] == '/') {
-        parent[len - 1] = '\0';
-    }
-    dirname = apr_filepath_name_get(parent);
-#ifdef CASE_BLIND_FILESYSTEM
-    if (ap_cstr_casecmp(filename, DAV_FS_STATE_DIR) == 0
-        || ap_cstr_casecmp(dirname, DAV_FS_STATE_DIR) == 0) {
-#else
-    if (strcmp(filename, DAV_FS_STATE_DIR) == 0
-        || strcmp(dirname, DAV_FS_STATE_DIR) == 0) {
-#endif
+    if (dav_fs_is_state_path(r->pool, s)) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                       "access to " DAV_FS_STATE_DIR " state directory "
                       "denied for %s", r->filename);
@@ -2423,5 +2445,5 @@ void dav_fs_register(apr_pool_t *p)
     dav_register_liveprop_group(p, &dav_fs_liveprop_group);
 
     /* register the repository provider */
-    dav_register_provider(p, "filesystem", &dav_fs_provider);
+    dav_register_provider(p, DAV_FS_PROVIDER_NAME, &dav_fs_provider);
 }

Modified: httpd/httpd/trunk/modules/dav/fs/repos.h
==============================================================================
--- httpd/httpd/trunk/modules/dav/fs/repos.h	Tue Sep 29 08:28:40 2026	(r1938665)
+++ httpd/httpd/trunk/modules/dav/fs/repos.h	Tue Sep 29 08:30:01 2026	(r1938666)
@@ -27,6 +27,9 @@
 
 #include "util_mutex.h"
 
+/* the name this repository provider is registered under */
+#define DAV_FS_PROVIDER_NAME            "filesystem"
+
 /* the subdirectory to hold all DAV-related information for a directory */
 #define DAV_FS_STATE_DIR                ".DAV"
 #define DAV_FS_STATE_FILE_FOR_DIR       ".state_for_dir"
@@ -39,6 +42,9 @@
 
 #define DAV_FS_BYTES_ERROR      -1
 
+/* is the pathname the state subdirectory, or a file within it? */
+int dav_fs_is_state_path(apr_pool_t *p, const char *pathname);
+
 /* ensure that our state subdirectory is present */
 void dav_fs_ensure_state_dir(apr_pool_t *p, const char *dirname);