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);