Really, actually, merge r23802 and r23803 from trunk to the
artem-soc-work branch.
Branch: artem-soc-work
(I tried to do this in r23805, but botched the copy. Sorry!)
git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/artem-soc-work@863880 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/subversion/mod_dav_svn/authz.c b/subversion/mod_dav_svn/authz.c
index a332d88..e4a1a76 100644
--- a/subversion/mod_dav_svn/authz.c
+++ b/subversion/mod_dav_svn/authz.c
@@ -18,10 +18,12 @@
#include <http_request.h>
#include <http_log.h>
+#include <http_protocol.h>
#include "svn_pools.h"
#include "svn_path.h"
+#include "svn_dav.h"
#include "dav_svn.h"
@@ -58,15 +60,31 @@
/* Build a Version Resource uri representing (rev, path). */
uri = dav_svn__build_uri(repos, uri_type, rev, path, FALSE, pool);
- /* Check if GET would work against this uri. */
- subreq = ap_sub_req_method_uri("GET", uri, r, r->output_filters);
-
- if (subreq)
+ if (dav_svn__get_native_authz_file(r))
{
- if (subreq->status == HTTP_OK)
+ /* Do native auhorization lookup - read access */
+ dav_error *err = dav_svn__check_access(repos->repo_name,
+ path,
+ r,
+ svn_authz_read);
+
+ if (! err)
allowed = TRUE;
- ap_destroy_sub_req(subreq);
+ /* XXX: need to cleanup dav_error? */
+ }
+ else
+ {
+ /* Check if GET would work against this uri. */
+ subreq = ap_sub_req_method_uri("GET", uri, r, r->output_filters);
+
+ if (subreq)
+ {
+ if (subreq->status == HTTP_OK)
+ allowed = TRUE;
+
+ ap_destroy_sub_req(subreq);
+ }
}
return allowed;
@@ -180,3 +198,195 @@
return allow_read(resource->info->r, resource->info->repos,
resource->info->repos_path, rev, pool);
}
+
+
+/* Native path-based authorization */
+
+static int
+check_access(const char *repos_name,
+ const char *repos_path,
+ request_rec* r,
+ svn_repos_authz_access_t required_access)
+{
+ const char *authz_file = NULL;
+ svn_authz_t *access_conf = NULL;
+ svn_error_t *svn_err;
+ const char *cache_key;
+ void *user_data;
+ svn_boolean_t access_granted;
+ char errbuf[128];
+
+ /* If native authz is off, there's nothing to do. Return DONE
+ * instead of OK to indicate that no checks have really been done.
+ */
+ if (! dav_svn__get_native_authz_file(r))
+ return DONE;
+
+ authz_file = dav_svn__get_native_authz_file(r);
+ /* If access file had not been specified, the default
+ behavior is to allow access.
+ XXX: is this right? */
+ if (authz_file == NULL)
+ return OK;
+
+ /* Retrieve/cache authorization file */
+ cache_key = apr_pstrcat(r->pool, "mod_dav_svn:", authz_file, NULL);
+ apr_pool_userdata_get(&user_data, cache_key, r->connection->pool);
+ access_conf = user_data;
+ if (access_conf == NULL)
+ {
+ svn_err = svn_repos_authz_read(&access_conf, authz_file,
+ TRUE, r->connection->pool);
+ if (svn_err)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR,
+ /* If it is an error code that APR can make sense
+ of, then show it, otherwise, pass zero to avoid
+ putting "APR does not understand this error code"
+ in the error log. */
+ ((svn_err->apr_err >= APR_OS_START_USERERR &&
+ svn_err->apr_err < APR_OS_START_CANONERR) ?
+ 0 : svn_err->apr_err),
+ r, "Failed to load the SVNNativeAuthzFile: %s",
+ svn_err_best_message(svn_err,
+ errbuf, sizeof(errbuf)));
+ svn_error_clear(svn_err);
+
+ return DECLINED;
+ }
+
+ /* Cache the open repos for the next request on this connection */
+ apr_pool_userdata_set(access_conf, cache_key,
+ NULL, r->connection->pool);
+ }
+
+ /* Perform authz access control. */
+ svn_err = svn_repos_authz_check_access(access_conf, repos_name,
+ repos_path, r->user,
+ required_access,
+ &access_granted,
+ r->pool);
+
+ if (svn_err)
+ {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR,
+ /* If it is an error code that APR can make
+ sense of, then show it, otherwise, pass
+ zero to avoid putting "APR does not
+ understand this error code" in the error
+ log. */
+ ((svn_err->apr_err >= APR_OS_START_USERERR &&
+ svn_err->apr_err < APR_OS_START_CANONERR) ?
+ 0 : svn_err->apr_err),
+ r, "Failed to perform access control: %s",
+ svn_err_best_message(svn_err, errbuf, sizeof(errbuf)));
+ svn_error_clear(svn_err);
+
+ return DECLINED;
+ }
+
+ if (! access_granted)
+ return DECLINED;
+
+ return OK;
+}
+
+
+/* Log a message indicating the access control decision made about a
+ request. FILE and LINE should be supplied via the APLOG_MARK macro.
+ ALLOWED is boolean. REPOS_PATH and DEST_REPOS_PATH are information
+ about the request. DEST_REPOS_PATH may be NULL. */
+static void
+log_access_verdict(const char *file, int line,
+ const request_rec *r,
+ int allowed,
+ const char *repos_path,
+ svn_repos_authz_access_t required_access)
+{
+ int level = allowed ? APLOG_INFO : APLOG_ERR;
+ const char *verdict = allowed ? "granted" : "denied";
+
+ char access_str[4] = { 0, 0, 0, 0 };
+ int access_idx = 0;
+
+ if (required_access & svn_authz_read)
+ access_str[access_idx++] = 'r';
+
+ if (required_access & svn_authz_write)
+ access_str[access_idx++] = 'w';
+
+ if (required_access & svn_authz_recursive)
+ access_str[access_idx++] = 'R';
+
+ if (repos_path == NULL)
+ repos_path = "<global>";
+
+ if (r->user)
+ {
+ ap_log_rerror(file, line, level, 0, r,
+ "[native] Access %s: '%s' %s %s %s", verdict, r->user,
+ r->method, repos_path, access_str);
+ }
+ else
+ {
+ ap_log_rerror(file, line, level, 0, r,
+ "[native] Access %s: - %s %s %s", verdict,
+ r->method, repos_path, access_str);
+ }
+}
+
+
+dav_error *
+dav_svn__check_access(const char *repos_name,
+ const char *repos_path,
+ request_rec *r,
+ svn_repos_authz_access_t required_access)
+{
+ int status;
+
+ status = check_access(repos_name, repos_path, r, required_access);
+
+ /* If no checks had been done, native authz is off, so don't log
+ * a possibly misleading authorization verdict.
+ */
+ if (status == DONE)
+ return NULL;
+
+ if(status == DECLINED)
+ {
+ log_access_verdict(APLOG_MARK, r, 0, repos_path, required_access);
+ ap_note_auth_failure(r); // XXX: need this?
+
+ // XXX: need better error message
+ return dav_svn__new_error_tag(r->pool, HTTP_FORBIDDEN, 0,
+ "Insufficient rights to access resource.",
+ SVN_DAV_ERROR_NAMESPACE,
+ SVN_DAV_ERROR_TAG);
+ }
+
+ log_access_verdict(APLOG_MARK, r, 1, repos_path, required_access);
+
+ return NULL;
+}
+
+
+dav_error *
+dav_svn__check_resource_access(const dav_resource *resource,
+ const svn_repos_authz_access_t required_access)
+{
+ return dav_svn__check_access(resource->info->repos->repo_name,
+ resource->info->repos_path,
+ resource->info->r,
+ required_access);
+}
+
+
+dav_error *
+dav_svn__check_global_access(const dav_resource *resource,
+ const svn_repos_authz_access_t required_access)
+{
+ return dav_svn__check_access(resource->info->repos->repo_name,
+ NULL, /* global access */
+ resource->info->r,
+ required_access);
+}
diff --git a/subversion/mod_dav_svn/dav_svn.h b/subversion/mod_dav_svn/dav_svn.h
index 142de4c..0e17456 100644
--- a/subversion/mod_dav_svn/dav_svn.h
+++ b/subversion/mod_dav_svn/dav_svn.h
@@ -255,6 +255,9 @@
SVNParentPath allowed? */
svn_boolean_t dav_svn__get_list_parentpath_flag(request_rec *r);
+/* for the repository referred to by this request, where is the access
+ file for native authz */
+const char *dav_svn__get_native_authz_file(request_rec *r);
/* SPECIAL URI
@@ -537,6 +540,22 @@
svn_repos_authz_func_t
dav_svn__authz_read_func(dav_svn__authz_read_baton *baton);
+/* Native path-based authorization */
+dav_error *
+dav_svn__check_access(const char *repos_name,
+ const char *repos_path,
+ request_rec *r,
+ svn_repos_authz_access_t required_access);
+
+/* Helpers for path-based authorization */
+dav_error *
+dav_svn__check_resource_access(const dav_resource *resource,
+ const svn_repos_authz_access_t required_access);
+
+dav_error *
+dav_svn__check_global_access(const dav_resource *resource,
+ const svn_repos_authz_access_t required_access);
+
/*** util.c ***/
diff --git a/subversion/mod_dav_svn/lock.c b/subversion/mod_dav_svn/lock.c
index 0fb12ea..d3ad943 100644
--- a/subversion/mod_dav_svn/lock.c
+++ b/subversion/mod_dav_svn/lock.c
@@ -630,12 +630,30 @@
svn_error_t *serr;
dav_error *derr;
- /* If the resource's fs path is unreadable, we don't allow a lock to
- be created on it. */
- if (! dav_svn__allow_read(resource, SVN_INVALID_REVNUM, resource->pool))
- return dav_new_error(resource->pool, HTTP_FORBIDDEN,
- DAV_ERR_LOCK_SAVE_LOCK,
- "Path is not accessible.");
+ /* This whole if statement is a hack until we get rid of mod_authz_svn
+ * completely. During the times of mod_dav_svn, there was no
+ * equivalent of dav_svn__allow_read() for writing.
+ *
+ * LOCK command needs write access to resource. If native authz
+ * is turned off, we resort to the old way of requiring read access
+ * on the resource.
+ */
+ if (dav_svn__get_native_authz_file(resource->info->r))
+ {
+ /* Path-based authorization: LOCK needs write access to resource */
+ derr = dav_svn__check_resource_access(resource, svn_authz_write);
+ if (derr)
+ return derr;
+ }
+ else
+ {
+ /* If the resource's fs path is unreadable, we don't allow a lock to
+ be created on it. */
+ if (! dav_svn__allow_read(resource, SVN_INVALID_REVNUM, resource->pool))
+ return dav_new_error(resource->pool, HTTP_FORBIDDEN,
+ DAV_ERR_LOCK_SAVE_LOCK,
+ "Path is not accessible.");
+ }
if (lock->next)
return dav_new_error(resource->pool, HTTP_BAD_REQUEST,
@@ -795,12 +813,24 @@
if (info->keep_locks)
return 0;
- /* If the resource's fs path is unreadable, we don't allow a lock to
- be removed from it. */
- if (! dav_svn__allow_read(resource, SVN_INVALID_REVNUM, resource->pool))
- return dav_new_error(resource->pool, HTTP_FORBIDDEN,
- DAV_ERR_LOCK_SAVE_LOCK,
- "Path is not accessible.");
+ if (dav_svn__get_native_authz_file(resource->info->r))
+ {
+ /* Path-based authorization: UNLOCK needs write access to resource */
+ dav_error *derr;
+
+ derr = dav_svn__check_resource_access(resource, svn_authz_write);
+ if (derr)
+ return derr;
+ }
+ else
+ {
+ /* If the resource's fs path is unreadable, we don't allow a lock to
+ be removed from it. */
+ if (! dav_svn__allow_read(resource, SVN_INVALID_REVNUM, resource->pool))
+ return dav_new_error(resource->pool, HTTP_FORBIDDEN,
+ DAV_ERR_LOCK_SAVE_LOCK,
+ "Path is not accessible.");
+ }
if (locktoken == NULL)
{
diff --git a/subversion/mod_dav_svn/mod_dav_svn.c b/subversion/mod_dav_svn/mod_dav_svn.c
index da72967..622607d 100644
--- a/subversion/mod_dav_svn/mod_dav_svn.c
+++ b/subversion/mod_dav_svn/mod_dav_svn.c
@@ -67,6 +67,7 @@
enum conf_flag list_parentpath; /* whether to allow GET of parentpath */
const char *root_dir; /* our top-level directory */
const char *master_uri; /* URI to the master SVN repos */
+ const char *native_authz_file; /* rule file for native authz */
} dir_conf_t;
@@ -164,6 +165,7 @@
newconf->list_parentpath = INHERIT_VALUE(parent, child, list_parentpath);
/* Prefer our parent's value over our new one - hence the swap. */
newconf->root_dir = INHERIT_VALUE(child, parent, root_dir);
+ newconf->native_authz_file = INHERIT_VALUE(parent, child, native_authz_file);
return newconf;
}
@@ -305,6 +307,17 @@
return NULL;
}
+static const char *
+SVNNativeAuthzFile_cmd(cmd_parms *cmd, void *config, const char *arg1)
+{
+ dir_conf_t *conf = config;
+
+ conf->native_authz_file
+ = svn_path_canonicalize(apr_pstrdup(cmd->pool, arg1), cmd->pool);
+
+ return NULL;
+}
+
/** Accessor functions for the module's configuration state **/
@@ -454,6 +467,16 @@
}
+const char *
+dav_svn__get_native_authz_file(request_rec *r)
+{
+ dir_conf_t *conf;
+
+ conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
+ return conf->native_authz_file;
+}
+
+
static void
merge_xml_filter_insert(request_rec *r)
{
@@ -619,6 +642,12 @@
AP_INIT_TAKE1("SVNMasterURI", SVNMasterURI_cmd, NULL, ACCESS_CONF,
"specifies a URI to access a master Subversion repository"),
+ /* per directory/location */
+ AP_INIT_TAKE1("SVNNativeAuthzFile", SVNNativeAuthzFile_cmd, NULL,
+ ACCESS_CONF|RSRC_CONF,
+ "Text file containing permissions of repository paths "
+ "for mod_dav_svn native path-based authorization"),
+
{ NULL }
};
diff --git a/subversion/mod_dav_svn/repos.c b/subversion/mod_dav_svn/repos.c
index 832f183..c3b096e 100644
--- a/subversion/mod_dav_svn/repos.c
+++ b/subversion/mod_dav_svn/repos.c
@@ -1485,6 +1485,45 @@
if (err)
return err;
+#ifdef SVN_DEBUG
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "dav_svn_get_resource(): %s %s %s (%s)",
+ (r->user ? r->user : "-"), r->method, repos_path, r->uri);
+#endif
+
+ /* A special case of path-based authorization for methods
+ * that don't have any saner place to insert authorization to.
+ * XXX: Think of how to do it differently!
+ *
+ * OPTIONS:
+ * A general check, if access is allowed to this resouce,
+ * then OPTIONS will return a valid response. Otherwise
+ * an "Insufficient rights ..." will be returned.
+ *
+ * PROPFIND, PROPPATCH:
+ * An initial check. If the user is not allowed to access
+ * the resouce, no information about it should be revealed
+ * (even "resource does not exist"). Depending on the "Depth"
+ * header, there will be separate authz checks for every
+ * child of this resource.
+ */
+ if (r->method_number == M_OPTIONS
+ || r->method_number == M_PROPFIND
+ || r->method_number == M_PROPPATCH)
+ {
+ /* NOTE: We cannot use "repos_path" or "relative" straight away,
+ * need to add a slash at the beginning...
+ */
+ char *path = NULL;
+
+ if (repos_path)
+ path = svn_path_join("/", repos_path, r->pool);
+
+ err = dav_svn__check_access(repos_name, path, r, svn_authz_read);
+ if (err)
+ return err;
+ }
+
/* The path that we will eventually try to open as an svn
repository. Normally defined by the SVNPath directive. */
fs_path = dav_svn__get_fs_path(r);
@@ -1778,10 +1817,11 @@
{
dav_resource *parent;
dav_resource_private *parentinfo;
- svn_stringbuf_t *path = resource->info->uri_path;
+
+ svn_stringbuf_t *uri_path = resource->info->uri_path;
/* the root of the repository has no parent */
- if (path->len == 1 && *path->data == '/')
+ if (uri_path->len == 1 && *uri_path->data == '/')
{
*parent_resource = NULL;
return NULL;
@@ -2066,6 +2106,11 @@
"Resource body changes may only be made to "
"working resources [at this time].");
}
+
+ /* Path-based authorization: PUT requires write access to resource. */
+ derr = dav_svn__check_resource_access(resource, svn_authz_write);
+ if (derr)
+ return derr;
}
#if 1
@@ -2371,12 +2416,23 @@
set_headers(request_rec *r, const dav_resource *resource)
{
svn_error_t *serr;
+ dav_error *derr;
svn_filesize_t length;
const char *mimetype = NULL;
apr_time_t last_modified;
if (!resource->exists)
return NULL;
+
+ /* Path-based authorization: if the user doesn't have access
+ * to this resource, no information about it should be revealed.
+ *
+ * Here we check for read access, as dav_svn_set_headers() is a
+ * first step of processing a GET request.
+ */
+ derr = dav_svn__check_resource_access(resource, svn_authz_read);
+ if (derr)
+ return derr;
last_modified = get_last_modified(resource);
if (last_modified != -1)
@@ -2722,6 +2778,35 @@
const char *href = name;
svn_boolean_t is_dir = (entry->kind == svn_node_dir);
+ /* Path-based authorization: check if the user has read access
+ * on the entry - if not, hide it.
+ */
+ {
+ dav_error *derr;
+ const char *path;
+ const char *repos_path = resource->info->repos_path;
+
+ svn_pool_clear(entry_pool);
+
+ /* Make a repos_path for an entry we are checking -
+ * If repos_path is "/", we only need to add an entry name.
+ * If repos_path is "/...", we need to add a slash and
+ * then the entry name.
+ */
+ path = apr_psprintf(entry_pool, "%s%s%s",
+ repos_path,
+ (repos_path[0] == '/'
+ && repos_path[1] == 0 ? "" : "/"),
+ name);
+
+ derr = dav_svn__check_access(resource->info->repos->repo_name,
+ path,
+ resource->info->r,
+ svn_authz_read);
+ if (derr)
+ continue;
+ }
+
svn_pool_clear(entry_pool);
/* append a trailing slash onto the name for directories. we NEED
@@ -2955,6 +3040,11 @@
"MKCOL called on regular resource, but "
"autoversioning is not active.");
+ /* Path-based authorization: MKCOL requires write access to the resource */
+ err = dav_svn__check_resource_access(resource, svn_authz_write);
+ if (err)
+ return err;
+
/* ### note that the parent was checked out at some point, and this
### is being preformed relative to the working rsrc for that parent */
@@ -3032,6 +3122,20 @@
"COPY called on regular resource, but "
"autoversioning is not active.");
+ /* Path-based authorization: COPY requires recursive read access
+ * to the source resource and recursive write access to the
+ * destination resource.
+ */
+ err = dav_svn__check_resource_access(src,
+ svn_authz_read | svn_authz_recursive);
+ if (err)
+ return err;
+
+ err = dav_svn__check_resource_access(dst,
+ svn_authz_write | svn_authz_recursive);
+ if (err)
+ return err;
+
/* Auto-versioning copy of regular resource: */
if (dst->type == DAV_RESOURCE_TYPE_REGULAR)
{
@@ -3109,10 +3213,25 @@
/* Handle activity deletions (early exit). */
if (resource->type == DAV_RESOURCE_TYPE_ACTIVITY)
{
+ /* Path-based authorization: DELETE of an activity requires
+ * global write access to the repository.
+ */
+ err = dav_svn__check_global_access(resource, svn_authz_write);
+ if (err)
+ return err;
+
return dav_svn__delete_activity(resource->info->repos,
resource->info->root.activity_id);
}
+ /* Path-based authorization: DELETE requires recursive write access
+ * to the resource.
+ */
+ err = dav_svn__check_resource_access(resource,
+ svn_authz_write | svn_authz_recursive);
+ if (err)
+ return err;
+
/* ### note that the parent was checked out at some point, and this
### is being preformed relative to the working rsrc for that parent */
@@ -3230,6 +3349,20 @@
"MOVE only allowed on two public URIs, and "
"autoversioning must be active.");
+ /* Path-based authorization: MOVE requires recursive write access
+ * to the source resource and recursive write access to the
+ * destinaton resource.
+ */
+ err = dav_svn__check_resource_access(src,
+ svn_authz_write | svn_authz_recursive);
+ if (err)
+ return err;
+
+ err = dav_svn__check_resource_access(dst,
+ svn_authz_write | svn_authz_recursive);
+ if (err)
+ return err;
+
/* Change the dst VCR into a WR, in place. This creates a txn and
changes dst->info->root from a rev-root into a txn-root. */
err = dav_svn__checkout(dst,
@@ -3298,6 +3431,23 @@
/* Clear the temporary pool. */
svn_pool_clear(ctx->info.pool);
+ /* Path-based authorization: initial file resource or
+ * collection resource. Require read access. */
+ if (params->walk_type & DAV_WALKTYPE_AUTH)
+ {
+ err = dav_svn__check_resource_access(&ctx->res, svn_authz_read);
+ if (err)
+ {
+ /* Apache's mod_dav doesn't have any mechanism to handle
+ * access rights violation and returning "403 Forbidden"
+ * status. For now, we just silently skip the entries
+ * that are not accessible.
+ * XXX: better way?
+ */
+ return NULL;
+ }
+ }
+
/* The current resource is a collection (possibly here thru recursion)
and this is the invocation for the collection. Alternatively, this is
the first [and only] entry to do_walk() for a member resource, so
@@ -3381,12 +3531,6 @@
apr_hash_this(hi, &key, &klen, &val);
dirent = val;
- /* authorize access to this resource, if applicable */
- if (params->walk_type & DAV_WALKTYPE_AUTH)
- {
- /* ### how/what to do? */
- }
-
/* append this child to our buffers */
svn_stringbuf_appendbytes(ctx->info.uri_path, key, klen);
svn_stringbuf_appendbytes(ctx->uri, key, klen);
@@ -3398,6 +3542,22 @@
if (dirent->kind == svn_node_file)
{
+ /* Path-based authorization: file resource. Require read access. */
+ if (params->walk_type & DAV_WALKTYPE_AUTH)
+ {
+ err = dav_svn__check_resource_access(&ctx->res, svn_authz_read);
+ if (err)
+ {
+ /* Apache's mod_dav doesn't have any mechanism to handle
+ * access rights violation and returning "403 Forbidden"
+ * status. For now, we just silently skip the entries
+ * that are not accessible.
+ * XXX: better way?
+ */
+ return NULL;
+ }
+ }
+
err = (*params->func)(&ctx->wres, DAV_CALLTYPE_MEMBER);
if (err != NULL)
return err;
diff --git a/subversion/mod_dav_svn/version.c b/subversion/mod_dav_svn/version.c
index 94a7fe1..266ed17 100644
--- a/subversion/mod_dav_svn/version.c
+++ b/subversion/mod_dav_svn/version.c
@@ -261,6 +261,13 @@
dav_error *derr;
dav_svn__uri_info parse;
+ /* Path-based authorization: CHECKOUT requires write access
+ * to the resource.
+ */
+ derr = dav_svn__check_resource_access(resource, svn_authz_write);
+ if (derr)
+ return derr;
+
/* Auto-Versioning Stuff */
if (auto_checkout)
{
@@ -958,7 +965,15 @@
const apr_xml_doc *doc,
ap_filter_t *output)
{
- int ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
+ int ns;
+ dav_error *err;
+
+ /* Path-based authorization: REPORT requires read access to the resource */
+ err = dav_svn__check_resource_access(resource, svn_authz_read);
+ if (err)
+ return err;
+
+ ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
if (doc->root->ns == ns)
{
@@ -1037,7 +1052,14 @@
"DAV:activity-collection-set property.",
SVN_DAV_ERROR_NAMESPACE,
SVN_DAV_ERROR_TAG);
-
+
+ /* Path-based authorization: MKACTIVITY needs global write access
+ * to the repository.
+ */
+ err = dav_svn__check_global_access(resource, svn_authz_write);
+ if (err)
+ return err;
+
err = dav_svn__create_activity(resource->info->repos, &txn_name,
resource->pool);
if (err != NULL)