subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bre...@apache.org
Subject svn commit: r1424780 - in /subversion/trunk: ./ subversion/include/ subversion/libsvn_client/ subversion/libsvn_repos/ subversion/libsvn_subr/ subversion/mod_authz_svn/ subversion/svnserve/ subversion/tests/libsvn_repos/ subversion/tests/libsvn_subr/ t...
Date Fri, 21 Dec 2012 00:57:38 GMT
Author: breser
Date: Fri Dec 21 00:57:37 2012
New Revision: 1424780

URL: http://svn.apache.org/viewvc?rev=1424780&view=rev
Log:
Merge the in-repo-authz branch back to trunk.

See http://svn.haxx.se/dev/archive-2012-12/0397.shtml

Modified:
    subversion/trunk/   (props changed)
    subversion/trunk/subversion/include/svn_config.h
    subversion/trunk/subversion/include/svn_path.h
    subversion/trunk/subversion/include/svn_repos.h
    subversion/trunk/subversion/libsvn_client/cmdline.c
    subversion/trunk/subversion/libsvn_repos/authz.c
    subversion/trunk/subversion/libsvn_repos/deprecated.c
    subversion/trunk/subversion/libsvn_repos/repos.c
    subversion/trunk/subversion/libsvn_repos/repos.h
    subversion/trunk/subversion/libsvn_subr/config.c
    subversion/trunk/subversion/libsvn_subr/config_file.c
    subversion/trunk/subversion/libsvn_subr/config_impl.h
    subversion/trunk/subversion/libsvn_subr/path.c
    subversion/trunk/subversion/mod_authz_svn/INSTALL
    subversion/trunk/subversion/mod_authz_svn/mod_authz_svn.c
    subversion/trunk/subversion/svnserve/serve.c
    subversion/trunk/subversion/svnserve/server.h
    subversion/trunk/subversion/svnserve/svnserve.8
    subversion/trunk/subversion/svnserve/svnserve.c
    subversion/trunk/subversion/svnserve/svnserve.conf.5
    subversion/trunk/subversion/tests/libsvn_repos/repos-test.c
    subversion/trunk/subversion/tests/libsvn_subr/config-test.c
    subversion/trunk/subversion/tests/libsvn_subr/path-test.c
    subversion/trunk/tools/server-side/svnauthz-validate.c

Propchange: subversion/trunk/
------------------------------------------------------------------------------
  Merged /subversion/branches/in-repo-authz:r1414342-1424779

Modified: subversion/trunk/subversion/include/svn_config.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_config.h?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_config.h (original)
+++ subversion/trunk/subversion/include/svn_config.h Fri Dec 21 00:57:37 2012
@@ -34,6 +34,7 @@
 #include <apr_hash.h>   /* for apr_hash_t */
 
 #include "svn_types.h"
+#include "svn_io.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -247,6 +248,21 @@ svn_config_read(svn_config_t **cfgp,
                 svn_boolean_t must_exist,
                 apr_pool_t *pool);
 
+/** Read configuration data from @a stream into @a *cfgp, allocated in
+ * @a result_pool.
+ *
+ * If @a section_names_case_sensitive is TRUE, populate section name hashes
+ * case sensitively, except for the default SVN_CONFIG__DEFAULT_SECTION.
+ *
+ * @since New in 1.8.
+ */
+
+svn_error_t *
+svn_config_parse(svn_config_t **cfgp,
+                 svn_stream_t *stream,
+                 svn_boolean_t section_names_case_sensitive,
+                 apr_pool_t *result_pool);
+
 /** Like svn_config_read(), but merges the configuration data from @a file
  * (a file or registry path) into @a *cfg, which was previously returned
  * from svn_config_read().  This function invalidates all value

Modified: subversion/trunk/subversion/include/svn_path.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_path.h?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_path.h (original)
+++ subversion/trunk/subversion/include/svn_path.h Fri Dec 21 00:57:37 2012
@@ -670,6 +670,58 @@ svn_path_cstring_to_utf8(const char **pa
 
 /** @} */
 
+
+/** Repository relative URLs
+ *
+ * @defgroup svn_path_repos_relative_urls Repository relative URLs
+ * @{
+ */
+
+
+/**
+ * Return true iff @a path is a repository-relative URL: specifically that
+ * it starts with the characters "^/"
+ *
+ * @a path is in UTF-8 encoding.
+ *
+ * Does not check whether @a path is a properly URI-encoded, canonical, or
+ * valid in any other way.
+ *
+ * @since New in 1.8.
+ */
+svn_boolean_t
+svn_path_is_repos_relative_url(const char *path);
+
+/**
+ * Set @a absolute_url to the absolute URL represented by @a relative_url
+ * relative to @a repos_root_url.  @a absolute_url will be allocated in
+ * @a pool.
+ *
+ * @a absolute_url will end with a peg revision specifier if @a relative_url
+ * did.
+ *
+ * @a relative_url is in repository-relative syntax: "^/[REL-URL][@PEG]"
+ *
+ * @a repos_root_url is the absolute url of the repository root.
+ *
+ * All strings are in UTF-8 encoding.
+ *
+ * @a repos_root_url and @a relative_url do not have to be properly
+ * URI-encoded, canonical, or valid in any other way.  The caller is expected
+ * to perform canonicalization on @a absolute_url after the call to the
+ * function.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_path_resolve_repos_relative_url(const char **absolute_url,
+                                    const char *relative_url,
+                                    const char *repos_root_url,
+                                    apr_pool_t *pool);
+
+
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/trunk/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_repos.h?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_repos.h (original)
+++ subversion/trunk/subversion/include/svn_repos.h Fri Dec 21 00:57:37 2012
@@ -3148,16 +3148,15 @@ svn_repos_get_fs_build_parser(const svn_
  */
 typedef struct svn_authz_t svn_authz_t;
 
-/** Read authz configuration data from @a file (a file or registry
- * path) into @a *authz_p, allocated in @a pool.
- *
- * If @a file is not a valid authz rule file, then return
- * SVN_AUTHZ_INVALID_CONFIG.  The contents of @a *authz_p is then
- * undefined.  If @a must_exist is TRUE, a missing authz file is also
- * an error.
+/** 
+ * Similar to svn_repos_authz_read2(), but without support for
+ * authz files stored in a Subversion repository (absolute or
+ * relative URLs) and without the @a repos_root argument.
  *
  * @since New in 1.3.
+ * @deprecated Provided for backward compatibility with the 1.7 API.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_repos_authz_read(svn_authz_t **authz_p,
                      const char *file,
@@ -3165,6 +3164,29 @@ svn_repos_authz_read(svn_authz_t **authz
                      apr_pool_t *pool);
 
 /**
+ * Read authz configuration data from @a path (a file, repos relative
+ * url, an absolute file url, or a registry path) into @a *authz_p,
+ * allocated in @a pool.
+ *
+ * If @a path is not a valid authz rule file, then return 
+ * SVN_AUTHZ_INVALID_CONFIG.  The contents of @a *authz_p is then
+ * undefined.  If @a must_exist is TRUE, a missing authz file is also
+ * an error.
+ *
+ * If @path is a repos relative URL then @a repos_root must be set to
+ * the root of the repository the authz configuration will be used with.
+ *
+ * @since New in 1.8
+ */
+svn_error_t *
+svn_repos_authz_read2(svn_authz_t **authz_p,
+                      const char *path,
+                      svn_boolean_t must_exist,
+                      const char *repos_root,
+                      apr_pool_t *pool);
+
+
+/**
  * Check whether @a user can access @a path in the repository @a
  * repos_name with the @a required_access.  @a authz lists the ACLs to
  * check against.  Set @a *access_granted to indicate if the requested

Modified: subversion/trunk/subversion/libsvn_client/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/cmdline.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/cmdline.c (original)
+++ subversion/trunk/subversion/libsvn_client/cmdline.c Fri Dec 21 00:57:37 2012
@@ -43,51 +43,6 @@
 
 #define DEFAULT_ARRAY_SIZE 5
 
-/* Return true iff ARG is a repository-relative URL: specifically that
- * it starts with the characters "^/".
- * ARG is in UTF-8 encoding.
- * Do not check whether ARG is properly URI-encoded, canonical, or valid
- * in any other way. */
-static svn_boolean_t
-arg_is_repos_relative_url(const char *arg)
-{
-  return (0 == strncmp("^/", arg, 2));
-}
-
-/* Set *ABSOLUTE_URL to the absolute URL represented by RELATIVE_URL
- * relative to REPOS_ROOT_URL.
- * *ABSOLUTE_URL will end with a peg revision specifier if RELATIVE_URL did.
- * RELATIVE_URL is in repository-relative syntax:
- * "^/[REL-URL][@PEG]",
- * REPOS_ROOT_URL is the absolute URL of the repository root.
- * All strings are in UTF-8 encoding.
- * Allocate *ABSOLUTE_URL in POOL.
- *
- * REPOS_ROOT_URL and RELATIVE_URL do not have to be properly URI-encoded,
- * canonical, or valid in any other way.  The caller is expected to perform
- * canonicalization on *ABSOLUTE_URL after the call to the function.
- */
-static svn_error_t *
-resolve_repos_relative_url(const char **absolute_url,
-                           const char *relative_url,
-                           const char *repos_root_url,
-                           apr_pool_t *pool)
-{
-  if (! arg_is_repos_relative_url(relative_url))
-    return svn_error_createf(SVN_ERR_BAD_URL, NULL,
-                             _("Improper relative URL '%s'"),
-                             relative_url);
-
-  /* No assumptions are made about the canonicalization of the input
-   * arguments, it is presumed that the output will be canonicalized after
-   * this function, which will remove any duplicate path separator.
-   */
-  *absolute_url = apr_pstrcat(pool, repos_root_url, relative_url + 1,
-                              (char *)NULL);
-
-  return SVN_NO_ERROR;
-}
-
 
 /* Attempt to find the repository root url for TARGET, possibly using CTX for
  * authentication.  If one is found and *ROOT_URL is not NULL, then just check
@@ -189,7 +144,7 @@ svn_client_args_to_target_array2(apr_arr
       SVN_ERR(svn_utf_cstring_to_utf8(&utf8_target,
                                       raw_target, pool));
 
-      if (arg_is_repos_relative_url(utf8_target))
+      if (svn_path_is_repos_relative_url(utf8_target))
         rel_url_found = TRUE;
 
       APR_ARRAY_PUSH(input_targets, const char *) = utf8_target;
@@ -204,7 +159,7 @@ svn_client_args_to_target_array2(apr_arr
           const char *utf8_target = APR_ARRAY_IDX(known_targets,
                                                   i, const char *);
 
-          if (arg_is_repos_relative_url(utf8_target))
+          if (svn_path_is_repos_relative_url(utf8_target))
             rel_url_found = TRUE;
 
           APR_ARRAY_PUSH(input_targets, const char *) = utf8_target;
@@ -220,7 +175,7 @@ svn_client_args_to_target_array2(apr_arr
       /* Relative urls will be canonicalized when they are resolved later in
        * the function
        */
-      if (arg_is_repos_relative_url(utf8_target))
+      if (svn_path_is_repos_relative_url(utf8_target))
         {
           APR_ARRAY_PUSH(output_targets, const char *) = utf8_target;
         }
@@ -367,7 +322,7 @@ svn_client_args_to_target_array2(apr_arr
           const char *target = APR_ARRAY_IDX(output_targets, i,
                                              const char *);
 
-          if (arg_is_repos_relative_url(target))
+          if (svn_path_is_repos_relative_url(target))
             {
               const char *abs_target;
               const char *true_target;
@@ -376,8 +331,9 @@ svn_client_args_to_target_array2(apr_arr
               SVN_ERR(svn_opt__split_arg_at_peg_revision(&true_target, &peg_rev,
                                                          target, pool));
 
-              SVN_ERR(resolve_repos_relative_url(&abs_target, true_target,
-                                                 root_url, pool));
+              SVN_ERR(svn_path_resolve_repos_relative_url(&abs_target,
+                                                          true_target,
+                                                          root_url, pool));
 
               SVN_ERR(svn_opt__arg_canonicalize_url(&true_target, abs_target,
                                                     pool));

Modified: subversion/trunk/subversion/libsvn_repos/authz.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/authz.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/authz.c (original)
+++ subversion/trunk/subversion/libsvn_repos/authz.c Fri Dec 21 00:57:37 2012
@@ -34,6 +34,7 @@
 #include "svn_config.h"
 #include "svn_ctype.h"
 #include "private/svn_fspath.h"
+#include "repos.h"
 
 
 /*** Structures. ***/
@@ -750,21 +751,173 @@ static svn_boolean_t authz_validate_sect
   return TRUE;
 }
 
+/* Retrieve the file at DIRENT (contained in a repo) then parse it as a config
+ * file placing the result into CFG_P allocated in POOL.
+ *
+ * If DIRENT is not a valid authz rule file then return SVN_AUTHZ_INVALD_CONFIG
+ * as the error.  The contents of CFG_P is then undefined.  If MUST_EXIST is
+ * TRUE, a missing authz file is also an error.
+ *
+ * SCRATCH_POOL will be used for temporary allocations. */
+static svn_error_t *
+authz_retrieve_config_repo(svn_config_t **cfg_p, const char *dirent,
+                          svn_boolean_t must_exist,
+                          apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+  svn_repos_t *repos;
+  const char *repos_root_dirent;
+  const char *fs_path;
+  svn_fs_t *fs;
+  svn_fs_root_t *root;
+  svn_revnum_t youngest_rev;
+  svn_node_kind_t node_kind;
+  svn_stream_t *contents;
+  const char *canon_dirent = svn_dirent_canonicalize(dirent, scratch_pool);
+
+  /* Search for a repository in the full path. */
+  repos_root_dirent = svn_repos_find_root_path(canon_dirent, scratch_pool);
+  if (!repos_root_dirent)
+    return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+                             "Unable to find repository at '%s'", dirent);
 
-
-/*** Public functions. ***/
+  /* Attempt to open a repository at repos_root_dirent. */
+  SVN_ERR(svn_repos_open2(&repos, repos_root_dirent, NULL, scratch_pool));
+
+  fs_path = &canon_dirent[strlen(repos_root_dirent)];
+
+  /* Root path is always a directory so no reason to go any further */
+  if (*fs_path == '\0')
+    return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+                             "'/' is not a file in repo '%s'",
+                             repos_root_dirent);
+
+  /* We skip some things that are non-important for how we're going to use
+   * this repo connection.  We do not set any capabilities since none of
+   * the current ones are important for what we're doing.  We also do not
+   * setup the environment that repos hooks would run under since we won't
+   * be triggering any. */
+
+  /* Get the filesystem. */
+  fs = svn_repos_fs(repos);
+
+  /* Find HEAD and the revision root */
+  SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, scratch_pool));
+  SVN_ERR(svn_fs_revision_root(&root, fs, youngest_rev, scratch_pool));
+
+  SVN_ERR(svn_fs_check_path(&node_kind, root, fs_path, scratch_pool));
+  if (node_kind == svn_node_none)
+    {
+      if (!must_exist)
+        {
+          SVN_ERR(svn_config_create(cfg_p, TRUE, scratch_pool));
+          return SVN_NO_ERROR;
+        }
+      else
+        {
+          return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+                                   "'%s' path not found in repo '%s'", fs_path,
+                                   repos_root_dirent);
+        }
+    }
+  else if (node_kind != svn_node_file)
+    {
+      return svn_error_createf(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+                               "'%s' is not a file in repo '%s'", fs_path,
+                               repos_root_dirent);
+    }
+
+  SVN_ERR(svn_fs_file_contents(&contents, root, fs_path, scratch_pool));
+  err = svn_config_parse(cfg_p, contents, TRUE, result_pool);
+
+  /* Add the URL to the error stack since the parser doesn't have it. */
+  if (err != SVN_NO_ERROR)
+    return svn_error_createf(err->apr_err, err, 
+                             "Error parsing config file: '%s' in repo '%s':",
+                             fs_path, repos_root_dirent);
+
+  return SVN_NO_ERROR;
+}
+
+/* Given a PATH which might be a realative repo URL (^/), an absolute
+ * local repo URL (file://), an absolute path outside of the repo
+ * or a location in the Windows registry.
+ *
+ * Retrieve the configuration data that PATH points at and parse it into
+ * CFG_P allocated in POOL.
+ *
+ * If PATH is not a valid authz rule file then return SVN_AUTHZ_INVALD_CONFIG
+ * as the error.  The contents of CFG_P is then undefined.  If MUST_EXIST is
+ * TRUE, a missing authz file is also an error.
+ *
+ * REPOS_ROOT points at the root of the repos you are
+ * going to apply the authz against, can be NULL if you are sure that you
+ * don't have a repos relative URL in PATH. */
+static svn_error_t *
+authz_retrieve_config(svn_config_t **cfg_p, const char *path,
+                      svn_boolean_t must_exist, const char *repos_root,
+                      apr_pool_t *pool)
+{
+  if (svn_path_is_repos_relative_url(path))
+    {
+      const char *dirent;
+      svn_error_t *err;
+      apr_pool_t *scratch_pool = svn_pool_create(pool);
+
+      err = svn_path_resolve_repos_relative_url(&dirent, path,
+                                                repos_root, scratch_pool);
+
+      if (err == SVN_NO_ERROR) 
+        err = authz_retrieve_config_repo(cfg_p, dirent, must_exist, pool,
+                                         scratch_pool);
+
+      /* Close the repos and streams we opened. */
+      svn_pool_destroy(scratch_pool);
+
+      return err;
+    }
+  else if (svn_path_is_url(path))
+    {
+      const char *dirent;
+      svn_error_t *err;
+      apr_pool_t *scratch_pool = svn_pool_create(pool); 
+
+      err = svn_uri_get_dirent_from_file_url(&dirent, path, scratch_pool);
+
+      if (err == SVN_NO_ERROR)
+        err = authz_retrieve_config_repo(cfg_p, dirent, must_exist, pool,
+                                         scratch_pool);
+
+      /* Close the repos and streams we opened. */
+      svn_pool_destroy(scratch_pool);
+
+      return err;
+    }
+  else
+    {
+      /* Outside of repo file or Windows registry*/
+      SVN_ERR(svn_config_read2(cfg_p, path, must_exist, TRUE, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
-svn_repos_authz_read(svn_authz_t **authz_p, const char *file,
-                     svn_boolean_t must_exist, apr_pool_t *pool)
+svn_repos__authz_read(svn_authz_t **authz_p, const char *path,
+                      svn_boolean_t must_exist, svn_boolean_t accept_urls,
+                      const char *repos_root, apr_pool_t *pool)
 {
   svn_authz_t *authz = apr_palloc(pool, sizeof(*authz));
   struct authz_validate_baton baton = { 0 };
 
   baton.err = SVN_NO_ERROR;
 
-  /* Load the rule file. */
-  SVN_ERR(svn_config_read2(&authz->cfg, file, must_exist, TRUE, pool));
+  /* Load the rule file */
+  if (accept_urls)
+    SVN_ERR(authz_retrieve_config(&authz->cfg, path, must_exist, repos_root,
+                                  pool));
+  else
+    SVN_ERR(svn_config_read2(&authz->cfg, path, must_exist, TRUE, pool));
   baton.config = authz->cfg;
 
   /* Step through the entire rule file, stopping on error. */
@@ -777,6 +930,20 @@ svn_repos_authz_read(svn_authz_t **authz
 }
 
 
+
+/*** Public functions. ***/
+
+svn_error_t *
+svn_repos_authz_read2(svn_authz_t **authz_p, const char *path,
+                      svn_boolean_t must_exist, const char *repos_root,
+                      apr_pool_t *pool)
+{
+  return svn_repos__authz_read(authz_p, path, must_exist, TRUE, repos_root,
+                               pool);
+}
+
+
+
 svn_error_t *
 svn_repos_authz_check_access(svn_authz_t *authz, const char *repos_name,
                              const char *path, const char *user,

Modified: subversion/trunk/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/deprecated.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/trunk/subversion/libsvn_repos/deprecated.c Fri Dec 21 00:57:37 2012
@@ -1006,3 +1006,12 @@ svn_repos_fs_begin_txn_for_update(svn_fs
 
   return SVN_NO_ERROR;
 }
+
+/*** From authz.c ***/
+
+svn_error_t *
+svn_repos_authz_read(svn_authz_t **authz_p, const char *file,
+                     svn_boolean_t must_exist, apr_pool_t *pool)
+{
+  return svn_repos__authz_read(authz_p, file, must_exist, FALSE, NULL, pool);
+}

Modified: subversion/trunk/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/repos.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/repos.c (original)
+++ subversion/trunk/subversion/libsvn_repos/repos.c Fri Dec 21 00:57:37 2012
@@ -1019,8 +1019,10 @@ create_conf(svn_repos_t *repos, apr_pool
 "### The authz-db option controls the location of the authorization"         NL
 "### rules for path-based access control.  Unless you specify a path"        NL
 "### starting with a /, the file's location is relative to the"              NL
-"### directory containing this file.  If you don't specify an"               NL
-"### authz-db, no path-based access control is done."                        NL
+"### directory containing this file.  The specified path may be a"           NL
+"### repository relative URL (^/) or an absolute file:// URL to a text"      NL
+"### file in a Subversion repository.  If you don't specify an authz-db,"    NL
+"### no path-based access control is done."                                  NL
 "### Uncomment the line below to use the default authorization file."        NL
 "# authz-db = " SVN_REPOS__CONF_AUTHZ                                        NL
 "### This option specifies the authentication realm of the repository."      NL

Modified: subversion/trunk/subversion/libsvn_repos/repos.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/repos.h?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/repos.h (original)
+++ subversion/trunk/subversion/libsvn_repos/repos.h Fri Dec 21 00:57:37 2012
@@ -304,6 +304,31 @@ svn_repos__hooks_post_unlock(svn_repos_t
                              apr_pool_t *pool);
 
 
+/*** Authz Functions ***/
+
+/* Read authz configuration data from PATH into *AUTHZ_P, allocated
+   in POOL.
+  
+   PATH may be a file or a registry path and iff ACCEPT_URLS is set
+   it may also be a repos relative url or an absolute file url.  When
+   ACCEPT_URLS is FALSE REPOS_ROOT can be NULL.
+  
+   If PATH is not a valid authz rule file, then return 
+   SVN_AUTHZ_INVALID_CONFIG.  The contents of *AUTHZ_P is then
+   undefined.  If MUST_EXIST is TRUE, a missing authz file is also
+   an error.
+  
+   If PATH is a repos relative URL then REPOS_ROOT must be set to
+   the root of the repository the authz configuration will be used with. */
+svn_error_t *
+svn_repos__authz_read(svn_authz_t **authz_p,
+                      const char *path,
+                      svn_boolean_t must_exist,
+                      svn_boolean_t accept_urls,
+                      const char *repos_root,
+                      apr_pool_t *pool);
+
+
 /*** Utility Functions ***/
 
 /* Set *CHANGED_P to TRUE if ROOT1/PATH1 and ROOT2/PATH2 have

Modified: subversion/trunk/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/config.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/config.c (original)
+++ subversion/trunk/subversion/libsvn_subr/config.c Fri Dec 21 00:57:37 2012
@@ -129,7 +129,27 @@ svn_config_read2(svn_config_t **cfgp, co
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_config_parse(svn_config_t **cfgp, svn_stream_t *stream,
+                 svn_boolean_t section_names_case_sensitive,
+                 apr_pool_t *result_pool)
+{
+  svn_config_t *cfg;
+  svn_error_t *err;
+  apr_pool_t *scratch_pool = svn_pool_create(result_pool);
+
+  err = svn_config_create(&cfg, section_names_case_sensitive, result_pool);
 
+  if (err == SVN_NO_ERROR)
+    err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
+
+  if (err == SVN_NO_ERROR)
+    *cfgp = cfg;
+
+  svn_pool_destroy(scratch_pool);
+
+  return err;
+}
 
 /* Read various configuration sources into *CFGP, in this order, with
  * later reads overriding the results of earlier ones:

Modified: subversion/trunk/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/config_file.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/config_file.c (original)
+++ subversion/trunk/subversion/libsvn_subr/config_file.c Fri Dec 21 00:57:37 2012
@@ -50,11 +50,10 @@
 /* File parsing context */
 typedef struct parse_context_t
 {
-  /* This config struct and file */
+  /* This config struct */
   svn_config_t *cfg;
-  const char *file;
 
-  /* The file descriptor */
+  /* The stream struct */
   svn_stream_t *stream;
 
   /* The current line in the file */
@@ -296,8 +295,7 @@ parse_option(int *pch, parse_context_t *
     {
       ch = EOF;
       err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
-                              "%s:%d: Option must end with ':' or '='",
-                              svn_dirent_local_style(ctx->file, scratch_pool),
+                              "line %d: Option must end with ':' or '='",
                               ctx->line);
     }
   else
@@ -340,8 +338,7 @@ parse_section_name(int *pch, parse_conte
     {
       ch = EOF;
       err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
-                              "%s:%d: Section header must end with ']'",
-                              svn_dirent_local_style(ctx->file, scratch_pool),
+                              "line %d: Section header must end with ']'",
                               ctx->line);
     }
   else
@@ -404,8 +401,6 @@ svn_config__parse_file(svn_config_t *cfg
                        svn_boolean_t must_exist, apr_pool_t *result_pool)
 {
   svn_error_t *err = SVN_NO_ERROR;
-  parse_context_t *ctx;
-  int ch, count;
   svn_stream_t *stream;
   apr_pool_t *scratch_pool = svn_pool_create(result_pool);
 
@@ -420,10 +415,32 @@ svn_config__parse_file(svn_config_t *cfg
   else
     SVN_ERR(err);
 
+  err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
+
+  if (err != SVN_NO_ERROR) 
+    {
+      /* Add the filename to the error stack. */
+      err = svn_error_createf(err->apr_err, err,
+                              "Error while parsing config file: %s:",
+                              svn_dirent_local_style(file, scratch_pool));
+    }
+
+  /* Close the streams (and other cleanup): */
+  svn_pool_destroy(scratch_pool);
+
+  return err;
+}
+
+svn_error_t *
+svn_config__parse_stream(svn_config_t *cfg, svn_stream_t *stream,
+                         apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  parse_context_t *ctx;
+  int ch, count;
+
   ctx = apr_palloc(scratch_pool, sizeof(*ctx));
 
   ctx->cfg = cfg;
-  ctx->file = file;
   ctx->stream = stream;
   ctx->line = 1;
   ctx->ungotten_char = EOF;
@@ -444,10 +461,8 @@ svn_config__parse_file(svn_config_t *cfg
             SVN_ERR(parse_section_name(&ch, ctx, scratch_pool));
           else
             return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
-                                     "%s:%d: Section header"
+                                     "line %d: Section header"
                                      " must start in the first column",
-                                     svn_dirent_local_style(file,
-                                                            scratch_pool),
                                      ctx->line);
           break;
 
@@ -459,10 +474,8 @@ svn_config__parse_file(svn_config_t *cfg
             }
           else
             return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
-                                     "%s:%d: Comment"
+                                     "line %d: Comment"
                                      " must start in the first column",
-                                     svn_dirent_local_style(file,
-                                                            scratch_pool),
                                      ctx->line);
           break;
 
@@ -476,15 +489,11 @@ svn_config__parse_file(svn_config_t *cfg
         default:
           if (svn_stringbuf_isempty(ctx->section))
             return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
-                                     "%s:%d: Section header expected",
-                                     svn_dirent_local_style(file,
-                                                            scratch_pool),
+                                     "line %d: Section header expected",
                                      ctx->line);
           else if (count != 0)
             return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
-                                     "%s:%d: Option expected",
-                                     svn_dirent_local_style(file,
-                                                            scratch_pool),
+                                     "line %d: Option expected",
                                      ctx->line);
           else
             SVN_ERR(parse_option(&ch, ctx, scratch_pool));
@@ -493,8 +502,6 @@ svn_config__parse_file(svn_config_t *cfg
     }
   while (ch != EOF);
 
-  /* Close the streams (and other cleanup): */
-  svn_pool_destroy(scratch_pool);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/trunk/subversion/libsvn_subr/config_impl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/config_impl.h?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/config_impl.h (original)
+++ subversion/trunk/subversion/libsvn_subr/config_impl.h Fri Dec 21 00:57:37 2012
@@ -32,6 +32,7 @@
 #include <apr_hash.h>
 #include "svn_types.h"
 #include "svn_string.h"
+#include "svn_io.h"
 #include "svn_config.h"
 #include "svn_private_config.h"
 
@@ -75,6 +76,12 @@ svn_error_t *svn_config__parse_file(svn_
                                     svn_boolean_t must_exist,
                                     apr_pool_t *pool);
 
+/* Read sections and options from a stream. */
+svn_error_t *svn_config__parse_stream(svn_config_t *cfg,
+                                      svn_stream_t *stream,
+                                      apr_pool_t *result_pool,
+                                      apr_pool_t *scratch_pool);
+
 /* The name of the magic [DEFAULT] section. */
 #define SVN_CONFIG__DEFAULT_SECTION "DEFAULT"
 

Modified: subversion/trunk/subversion/libsvn_subr/path.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/path.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/path.c (original)
+++ subversion/trunk/subversion/libsvn_subr/path.c Fri Dec 21 00:57:37 2012
@@ -1281,3 +1281,34 @@ svn_path_splitext(const char **path_root
   if (path_ext)
     *path_ext = "";
 }
+
+
+/* Repository relative URLs (^/). */
+
+svn_boolean_t
+svn_path_is_repos_relative_url(const char *path)
+{
+  return (0 == strncmp("^/", path, 2));
+}
+
+svn_error_t *
+svn_path_resolve_repos_relative_url(const char **absolute_url,
+                                    const char *relative_url,
+                                    const char *repos_root_url,
+                                    apr_pool_t *pool)
+{
+  if (! svn_path_is_repos_relative_url(relative_url))
+    return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                             _("Improper relative URL '%s'"),
+                             relative_url);
+
+  /* No assumptions are made about the canonicalization of the inut
+   * arguments, it is presumed that the output will be canonicalized after
+   * this function, which will remove any duplicate path separator.
+   */
+  *absolute_url = apr_pstrcat(pool, repos_root_url, relative_url + 1,
+                              (char *)NULL);
+
+  return SVN_NO_ERROR;
+}
+

Modified: subversion/trunk/subversion/mod_authz_svn/INSTALL
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_authz_svn/INSTALL?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_authz_svn/INSTALL (original)
+++ subversion/trunk/subversion/mod_authz_svn/INSTALL Fri Dec 21 00:57:37 2012
@@ -100,6 +100,50 @@ II.   Configuration
          NOTE: AuthzSVNReposRelativeAccessFile filename causes the authz file
          to be read from <repo path>/conf/<filename>
 
+      E. Example 5: Authz file stored in a Subversion repository
+
+         This configuration allows storing of the authz file in a repository.
+
+         <Location /svn>
+           DAV svn
+           SVNParentPath /path/to/reposparent
+
+           AuthType Basic
+           AuthName "Subversion repository"
+           AuthUserFile /path/to/htpasswd/file
+
+           AuthzSVNAccessFile file:///path/to/repos/authz
+
+           Require valid-user
+         </Location>
+
+         NOTE: http:// and svn:// URLs are not supported, only local file://
+         absolute URLs may be used.  The URL does not have to point to the
+         same repository as the repository being accessed.  If you wish to 
+         restrict access to this authz file and it is in the same repository
+         you should include a rule for it.
+
+      F. Example 5: Authz file stored inside the repository being accessed.
+
+         This configuration allows providing a relative path within the
+         repository being accessed.
+
+         <Location /svn>
+           DAV svn
+           SVNParentPath /path/to/reposparent
+
+           AuthType Basic
+           AuthName "Subversion repository"
+           AuthUserFile /path/to/htpasswd/file
+
+           AuthzSVNAccessFile ^/authz
+
+           Require valid-user
+         </Location>
+
+         NOTE: You should include rules in your authz file to restirct access
+         to the authz file as desired.  
+
    2. Specifying permissions
 
       The file format of the access file looks like this:

Modified: subversion/trunk/subversion/mod_authz_svn/mod_authz_svn.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_authz_svn/mod_authz_svn.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_authz_svn/mod_authz_svn.c (original)
+++ subversion/trunk/subversion/mod_authz_svn/mod_authz_svn.c Fri Dec 21 00:57:37 2012
@@ -96,7 +96,10 @@ AuthzSVNAccessFile_cmd(cmd_parms *cmd, v
     return "AuthzSVNAccessFile and AuthzSVNReposRelativeAccessFile "
            "directives are mutually exclusive.";
 
-  conf->access_file = ap_server_root_relative(cmd->pool, arg1);
+  if (svn_path_is_repos_relative_url(arg1) || svn_path_is_url(arg1))
+    conf->access_file = arg1;
+  else
+    conf->access_file = ap_server_root_relative(cmd->pool, arg1);
 
   return NULL;
 }
@@ -130,13 +133,17 @@ static const command_rec authz_svn_cmds[
                 NULL,
                 OR_AUTHCFG,
                 "Path to text file containing permissions of repository "
-                "paths."),
+                "paths.  Path may be an repository relative URL (^/) or "
+                "absolute file:// URL to a text file in a Subversion "
+                "repository."),
   AP_INIT_TAKE1("AuthzSVNReposRelativeAccessFile",
                 AuthzSVNReposRelativeAccessFile_cmd,
                 NULL,
                 OR_AUTHCFG,
                 "Path (relative to repository 'conf' directory) to text "
-                "file containing permissions of repository paths. "),
+                "file containing permissions of repository paths. Path may "
+                "be an repository relative URL (^/) or absolute file:// URL "
+                "to a text file in a Subversion repository."),
   AP_INIT_FLAG("AuthzSVNAnonymous", ap_set_flag_slot,
                (void *)APR_OFFSETOF(authz_svn_config_rec, anonymous),
                OR_AUTHCFG,
@@ -161,6 +168,102 @@ static const command_rec authz_svn_cmds[
   { NULL }
 };
 
+
+/* The macros LOG_ARGS_SIGNATURE and LOG_ARGS_CASCADE are expanded as formal
+ * and actual parameters to log_access_verdict with respect to HTTPD version.
+ */
+#if AP_MODULE_MAGIC_AT_LEAST(20100606,0)
+#define LOG_ARGS_SIGNATURE const char *file, int line, int module_index
+#define LOG_ARGS_CASCADE file, line, module_index
+#else
+#define LOG_ARGS_SIGNATURE const char *file, int line
+#define LOG_ARGS_CASCADE file, line
+#endif
+
+/* Log a message indicating the access control decision made about a
+ * request.  The macro LOG_ARGS_SIGNATURE expands to FILE, LINE and
+ * MODULE_INDEX in HTTPD 2.3 as APLOG_MARK macro has been changed for
+ * per-module loglevel configuration.  It expands to FILE and LINE
+ * in older server versions.  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(LOG_ARGS_SIGNATURE,
+                   const request_rec *r, int allowed,
+                   const char *repos_path, const char *dest_repos_path)
+{
+  int level = allowed ? APLOG_INFO : APLOG_ERR;
+  const char *verdict = allowed ? "granted" : "denied";
+
+  if (r->user)
+    {
+      if (dest_repos_path)
+        ap_log_rerror(LOG_ARGS_CASCADE, level, 0, r,
+                      "Access %s: '%s' %s %s %s", verdict, r->user,
+                      r->method, repos_path, dest_repos_path);
+      else
+        ap_log_rerror(LOG_ARGS_CASCADE, level, 0, r,
+                      "Access %s: '%s' %s %s", verdict, r->user,
+                      r->method, repos_path);
+    }
+  else
+    {
+      if (dest_repos_path)
+        ap_log_rerror(LOG_ARGS_CASCADE, level, 0, r,
+                      "Access %s: - %s %s %s", verdict,
+                      r->method, repos_path, dest_repos_path);
+      else
+        ap_log_rerror(LOG_ARGS_CASCADE, level, 0, r,
+                      "Access %s: - %s %s", verdict,
+                      r->method, repos_path);
+    }
+}
+
+/* Log a message indiciating the ERR encountered during the request R.
+ * LOG_ARGS_SIGNATURE expands as in log_access_verdict() above.
+ * PREFIX is inserted at the start of the message.  The rest of the
+ * message is generated by combining the message for each error in the
+ * chain of ERR, excluding for trace errors.  ERR will be cleared
+ * when finished. */
+static void
+log_svn_error(LOG_ARGS_SIGNATURE,
+              request_rec *r, const char *prefix,
+              svn_error_t *err, apr_pool_t *scratch_pool)
+{
+  svn_error_t *err_pos = svn_error_purge_tracing(err);
+  svn_stringbuf_t *buff = svn_stringbuf_create(prefix, scratch_pool);
+
+  /* Build the error chain into a space separated stringbuf. */
+  while (err_pos)
+    {
+      if (err_pos->message)
+        {
+          svn_stringbuf_appendcstr(buff, err_pos->message);
+          svn_stringbuf_appendbyte(buff, ' ');
+        }
+      else
+        {
+          char strerr[256];
+          
+          svn_stringbuf_appendcstr(buff, svn_strerror(err->apr_err, strerr,
+                                                       sizeof(strerr)));
+        }
+
+      err_pos = err_pos->child;
+    }
+
+  ap_log_rerror(LOG_ARGS_CASCADE, 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. */
+                ((err->apr_err >= APR_OS_START_USERERR &&
+                  err->apr_err < APR_OS_START_CANONERR) ?
+                 0 : err->apr_err),
+                r, "%s", buff->data);
+
+  svn_error_clear(err);
+}
+
 /*
  * Get the, possibly cached, svn_authz_t for this request.
  */
@@ -175,18 +278,24 @@ get_access_conf(request_rec *r, authz_sv
   svn_authz_t *access_conf = NULL;
   svn_error_t *svn_err;
   dav_error *dav_err;
-  char errbuf[256];
+
+  dav_err = dav_svn_get_repos_path(r, conf->base_path, &repos_path);
+  if (dav_err)
+    {
+      ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", dav_err->desc);
+      return NULL;
+    }
 
   if (conf->repo_relative_access_file)
     {
-      dav_err = dav_svn_get_repos_path(r, conf->base_path, &repos_path);
-      if (dav_err) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "%s", dav_err->desc);
-        return NULL;
-      }
-      access_file = svn_dirent_join_many(scratch_pool, repos_path, "conf",
-                                         conf->repo_relative_access_file,
-                                         NULL);
+      access_file = conf->repo_relative_access_file;
+      if (!svn_path_is_repos_relative_url(access_file) &&
+          !svn_path_is_url(access_file))
+        {
+          access_file = svn_dirent_join_many(scratch_pool, repos_path, "conf",
+                                             conf->repo_relative_access_file,
+                                             NULL);
+        }
     }
   else
     {
@@ -202,21 +311,13 @@ get_access_conf(request_rec *r, authz_sv
   access_conf = user_data;
   if (access_conf == NULL)
     {
-      svn_err = svn_repos_authz_read(&access_conf, access_file,
-                                     TRUE, r->connection->pool);
+      svn_err = svn_repos_authz_read2(&access_conf, access_file,
+                                      TRUE, repos_path, 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 AuthzSVNAccessFile: %s",
-                        svn_err_best_message(svn_err, errbuf, sizeof(errbuf)));
-          svn_error_clear(svn_err);
+          log_svn_error(APLOG_MARK, r,
+                        "Failed to load the AuthzSVNAccessFile: ",
+                        svn_err, scratch_pool);
           access_conf = NULL;
         }
       else
@@ -285,7 +386,6 @@ req_check_access(request_rec *r,
   svn_boolean_t authz_access_granted = FALSE;
   svn_authz_t *access_conf = NULL;
   svn_error_t *svn_err;
-  char errbuf[256];
   const char *username_to_authorize = get_username_to_authorize(r, conf,
                                                                 r->pool);
 
@@ -458,19 +558,9 @@ req_check_access(request_rec *r,
                                              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);
+          log_svn_error(APLOG_MARK, r,
+                        "Failed to perform access control: ",
+                        svn_err, r->pool);
 
           return DECLINED;
         }
@@ -505,17 +595,9 @@ req_check_access(request_rec *r,
                                              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);
+          log_svn_error(APLOG_MARK, r,
+                        "Failed to perform access control: ",
+                        svn_err, r->pool);
 
           return DECLINED;
         }
@@ -530,56 +612,6 @@ req_check_access(request_rec *r,
   return OK;
 }
 
-/* The macros LOG_ARGS_SIGNATURE and LOG_ARGS_CASCADE are expanded as formal
- * and actual parameters to log_access_verdict with respect to HTTPD version.
- */
-#if AP_MODULE_MAGIC_AT_LEAST(20100606,0)
-#define LOG_ARGS_SIGNATURE const char *file, int line, int module_index
-#define LOG_ARGS_CASCADE file, line, module_index
-#else
-#define LOG_ARGS_SIGNATURE const char *file, int line
-#define LOG_ARGS_CASCADE file, line
-#endif
-
-/* Log a message indicating the access control decision made about a
- * request.  The macro LOG_ARGS_SIGNATURE expands to FILE, LINE and
- * MODULE_INDEX in HTTPD 2.3 as APLOG_MARK macro has been changed for
- * per-module loglevel configuration.  It expands to FILE and LINE
- * in older server versions.  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(LOG_ARGS_SIGNATURE,
-                   const request_rec *r, int allowed,
-                   const char *repos_path, const char *dest_repos_path)
-{
-  int level = allowed ? APLOG_INFO : APLOG_ERR;
-  const char *verdict = allowed ? "granted" : "denied";
-
-  if (r->user)
-    {
-      if (dest_repos_path)
-        ap_log_rerror(LOG_ARGS_CASCADE, level, 0, r,
-                      "Access %s: '%s' %s %s %s", verdict, r->user,
-                      r->method, repos_path, dest_repos_path);
-      else
-        ap_log_rerror(LOG_ARGS_CASCADE, level, 0, r,
-                      "Access %s: '%s' %s %s", verdict, r->user,
-                      r->method, repos_path);
-    }
-  else
-    {
-      if (dest_repos_path)
-        ap_log_rerror(LOG_ARGS_CASCADE, level, 0, r,
-                      "Access %s: - %s %s %s", verdict,
-                      r->method, repos_path, dest_repos_path);
-      else
-        ap_log_rerror(LOG_ARGS_CASCADE, level, 0, r,
-                      "Access %s: - %s %s", verdict,
-                      r->method, repos_path);
-    }
-}
-
 /*
  * Implementation of subreq_bypass with scratch_pool parameter.
  */
@@ -593,7 +625,6 @@ subreq_bypass2(request_rec *r,
   svn_authz_t *access_conf = NULL;
   authz_svn_config_rec *conf = NULL;
   svn_boolean_t authz_access_granted = FALSE;
-  char errbuf[256];
   const char *username_to_authorize;
 
   conf = ap_get_module_config(r->per_dir_config,
@@ -626,18 +657,9 @@ subreq_bypass2(request_rec *r,
                                              scratch_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);
+          log_svn_error(APLOG_MARK, r,
+                        "Failed to perform access control: ",
+                        svn_err, scratch_pool);
           return HTTP_FORBIDDEN;
         }
       if (!authz_access_granted)

Modified: subversion/trunk/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/serve.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/serve.c (original)
+++ subversion/trunk/subversion/svnserve/serve.c Fri Dec 21 00:57:37 2012
@@ -221,37 +221,26 @@ static svn_error_t *log_command(server_b
   return log_write(b->log_file, line, nbytes, pool);
 }
 
-svn_error_t *load_configs(svn_config_t **cfg,
-                          svn_config_t **pwdb,
-                          svn_authz_t **authzdb,
-                          enum username_case_type *username_case,
-                          const char *filename,
-                          svn_boolean_t must_exist,
-                          const char *base,
-                          server_baton_t *server,
-                          svn_ra_svn_conn_t *conn,
-                          apr_pool_t *pool)
+svn_error_t *load_pwdb_config(server_baton_t *server,
+                              svn_ra_svn_conn_t *conn,
+                              apr_pool_t *pool)
 {
-  const char *pwdb_path, *authzdb_path;
+  const char *pwdb_path;
   svn_error_t *err;
 
-  SVN_ERR(svn_config_read2(cfg, filename, must_exist, FALSE, pool));
-
-  svn_config_get(*cfg, &pwdb_path, SVN_CONFIG_SECTION_GENERAL,
+  svn_config_get(server->cfg, &pwdb_path, SVN_CONFIG_SECTION_GENERAL,
                  SVN_CONFIG_OPTION_PASSWORD_DB, NULL);
 
-  *pwdb = NULL;
+  server->pwdb = NULL;
   if (pwdb_path)
     {
       pwdb_path = svn_dirent_canonicalize(pwdb_path, pool);
-      pwdb_path = svn_dirent_join(base, pwdb_path, pool);
+      pwdb_path = svn_dirent_join(server->base, pwdb_path, pool);
 
-      err = svn_config_read2(pwdb, pwdb_path, TRUE, FALSE, pool);
+      err = svn_config_read2(&server->pwdb, pwdb_path, TRUE, FALSE, pool);
       if (err)
         {
-          if (server)
-            /* Called by listening server; log error no matter what it is. */
-            log_server_error(err, server, conn, pool);
+          log_server_error(err, server, conn, pool);
 
           /* Because it may be possible to read the pwdb file with some
              access methods and not others, ignore errors reading the pwdb
@@ -265,18 +254,11 @@ svn_error_t *load_configs(svn_config_t *
           if (err->apr_err != SVN_ERR_BAD_FILENAME
               && ! APR_STATUS_IS_EACCES(err->apr_err))
             {
-              if (server)
-                {
-                  /* Called by listening server: Now that we've logged
-                   * the error, clear it and return a nice, generic
-                   * error to the user
-                   * (http://subversion.tigris.org/issues/show_bug.cgi?id=2271). */
-                  svn_error_clear(err);
-                  return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL, NULL);
-                }
-              /* Called during startup; return the error, whereupon it
-               * will go to standard error for the admin to see. */
-              return err;
+                /* Now that we've logged the error, clear it and return a
+                 * nice, generic error to the user:
+                 * http://subversion.tigris.org/issues/show_bug.cgi?id=2271 */
+                svn_error_clear(err);
+                return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL, NULL);
             }
           else
             /* Ignore SVN_ERR_BAD_FILENAME and APR_EACCES and proceed. */
@@ -284,51 +266,59 @@ svn_error_t *load_configs(svn_config_t *
         }
     }
 
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *load_authz_config(server_baton_t *server,
+                               svn_ra_svn_conn_t *conn,
+                               const char *repos_root,
+                               apr_pool_t *pool)
+{
+  const char *authzdb_path;
+  svn_error_t *err;
+
   /* Read authz configuration. */
-  svn_config_get(*cfg, &authzdb_path, SVN_CONFIG_SECTION_GENERAL,
+  svn_config_get(server->cfg, &authzdb_path, SVN_CONFIG_SECTION_GENERAL,
                  SVN_CONFIG_OPTION_AUTHZ_DB, NULL);
   if (authzdb_path)
     {
       const char *case_force_val;
 
-      authzdb_path = svn_dirent_canonicalize(authzdb_path, pool);
-      authzdb_path = svn_dirent_join(base, authzdb_path, pool);
-      err = svn_repos_authz_read(authzdb, authzdb_path, TRUE, pool);
+      if (!svn_path_is_repos_relative_url(authzdb_path) &&
+          !svn_path_is_url(authzdb_path))
+        {
+          /* Canonicalize and add the base onto authzdb_path (if needed)
+           * when authzdb_path is not a URL (repos relative or absolute). */
+          authzdb_path = svn_dirent_canonicalize(authzdb_path, pool);
+          authzdb_path = svn_dirent_join(server->base, authzdb_path, pool);
+        }
+      err = svn_repos_authz_read2(&server->authzdb, authzdb_path, TRUE,
+                                  repos_root, pool);
       if (err)
         {
-          if (server)
-            {
-              /* Called by listening server: Log the error, clear it,
-               * and return a nice, generic error to the user
-               * (http://subversion.tigris.org/issues/show_bug.cgi?id=2271). */
-              log_server_error(err, server, conn, pool);
-              svn_error_clear(err);
-              return svn_error_create(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL, NULL);
-            }
-          else
-            /* Called during startup; return the error, whereupon it
-             * will go to standard error for the admin to see. */
-            return err;
+          log_server_error(err, server, conn, pool);
+          svn_error_clear(err);
+          return svn_error_create(SVN_ERR_AUTHZ_INVALID_CONFIG, NULL, NULL);
         }
 
       /* Are we going to be case-normalizing usernames when we consult
        * this authz file? */
-      svn_config_get(*cfg, &case_force_val, SVN_CONFIG_SECTION_GENERAL,
+      svn_config_get(server->cfg, &case_force_val, SVN_CONFIG_SECTION_GENERAL,
                      SVN_CONFIG_OPTION_FORCE_USERNAME_CASE, NULL);
       if (case_force_val)
         {
           if (strcmp(case_force_val, "upper") == 0)
-            *username_case = CASE_FORCE_UPPER;
+            server->username_case = CASE_FORCE_UPPER;
           else if (strcmp(case_force_val, "lower") == 0)
-            *username_case = CASE_FORCE_LOWER;
+            server->username_case = CASE_FORCE_LOWER;
           else
-            *username_case = CASE_ASIS;
+            server->username_case = CASE_ASIS;
         }
     }
   else
     {
-      *authzdb = NULL;
-      *username_case = CASE_ASIS;
+      server->authzdb = NULL;
+      server->username_case = CASE_ASIS;
     }
 
   return SVN_NO_ERROR;
@@ -3138,14 +3128,26 @@ static svn_error_t *find_repos(const cha
     b->repos_name = b->authz_repos_name;
   b->repos_name = svn_path_uri_encode(b->repos_name, pool);
 
-  /* If the svnserve configuration files have not been loaded then
-     load them from the repository. */
+  /* If the svnserve configuration has not been loaded then load it from the
+   * repository. */
   if (NULL == b->cfg)
-    SVN_ERR(load_configs(&b->cfg, &b->pwdb, &b->authzdb, &b->username_case,
-                         svn_repos_svnserve_conf(b->repos, pool), FALSE,
-                         svn_repos_conf_dir(b->repos, pool),
-                         b, conn,
-                         pool));
+    {
+      b->base = svn_repos_conf_dir(b->repos, pool);
+
+      SVN_ERR(svn_config_read2(&b->cfg, svn_repos_svnserve_conf(b->repos, pool),
+                               FALSE, /* must_exist */
+                               FALSE, /* section_names_case_sensitive */
+                               pool));
+      SVN_ERR(load_pwdb_config(b, conn, pool));
+      SVN_ERR(load_authz_config(b, conn, repos_root, pool));
+    }
+  /* svnserve.conf has been loaded via the --config-file option so need
+   * to load pwdb and authz. */
+  else
+    {
+      SVN_ERR(load_pwdb_config(b, conn, pool));
+      SVN_ERR(load_authz_config(b, conn, repos_root, pool));
+    }
 
 #ifdef SVN_HAVE_SASL
   /* Should we use Cyrus SASL? */
@@ -3349,9 +3351,10 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
   b.user = NULL;
   b.username_case = params->username_case;
   b.authz_user = NULL;
+  b.base = params->base;
   b.cfg = params->cfg;
-  b.pwdb = params->pwdb;
-  b.authzdb = params->authzdb;
+  b.pwdb = NULL;
+  b.authzdb = NULL;
   b.realm = NULL;
   b.log_file = params->log_file;
   b.pool = pool;

Modified: subversion/trunk/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/server.h?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/server.h (original)
+++ subversion/trunk/subversion/svnserve/server.h Fri Dec 21 00:57:37 2012
@@ -42,6 +42,7 @@ typedef struct server_baton_t {
   svn_repos_t *repos;
   const char *repos_name;  /* URI-encoded name of repository (not for authz) */
   svn_fs_t *fs;            /* For convenience; same as svn_repos_fs(repos) */
+  const char *base;        /* Base directory for config files */
   svn_config_t *cfg;       /* Parsed repository svnserve.conf */
   svn_config_t *pwdb;      /* Parsed password database */
   svn_authz_t *authzdb;    /* Parsed authz rules */
@@ -87,24 +88,15 @@ typedef struct serve_params_t {
      which forces all connections to be read-only. */
   svn_boolean_t read_only;
 
+  /* The base directory for any relative configuration files. */
+  const char *base;
+
   /* A parsed repository svnserve configuration file, ala
      svnserve.conf.  If this is NULL, then no configuration file was
      specified on the command line.  If this is non-NULL, then
      per-repository svnserve.conf are not read. */
   svn_config_t *cfg;
 
-  /* A parsed repository password database.  If this is NULL, then
-     either no svnserve configuration file was specified on the
-     command line, or it was specified and it did not refer to a
-     password database. */
-  svn_config_t *pwdb;
-
-  /* A parsed repository authorization database.  If this is NULL,
-     then either no svnserve configuration file was specified on the
-     command line, or it was specified and it did not refer to a
-     authorization database. */
-  svn_authz_t *authzdb;
-
   /* A filehandle open for writing logs to; possibly NULL. */
   apr_file_t *log_file;
 
@@ -145,31 +137,24 @@ typedef struct serve_params_t {
 svn_error_t *serve(svn_ra_svn_conn_t *conn, serve_params_t *params,
                    apr_pool_t *pool);
 
-/* Load a svnserve configuration file located at FILENAME into CFG,
-   and if such as found, then:
+/* Load the password database for the listening server based on the
+   entries in the SERVER struct. 
 
-    - set *PWDB to any referenced password database,
-    - set *AUTHZDB to any referenced authorization database, and
-    - set *USERNAME_CASE to the enumerated value of the
-      'force-username-case' configuration value (or its default).
-
-   If MUST_EXIST is true and FILENAME does not exist, then return an
-   error.  BASE may be specified as the base path to any referenced
-   password and authorization files found in FILENAME.
-
-   If SERVER is not NULL, log the real errors with SERVER and CONN but
-   return generic errors to the client.  CONN must not be NULL if SERVER
-   is not NULL. */
-svn_error_t *load_configs(svn_config_t **cfg,
-                          svn_config_t **pwdb,
-                          svn_authz_t **authzdb,
-                          enum username_case_type *username_case,
-                          const char *filename,
-                          svn_boolean_t must_exist,
-                          const char *base,
-                          server_baton_t *server,
-                          svn_ra_svn_conn_t *conn,
-                          apr_pool_t *pool);
+   SERVER and CONN must not be NULL. The real errors will be logged with
+   SERVER and CONN but return generic errors to the client. */
+svn_error_t *load_pwdb_config(server_baton_t *server,
+                              svn_ra_svn_conn_t *conn,
+                              apr_pool_t *pool);
+
+/* Load the authz database for the listening server based on the
+   entries in the SERVER struct.
+
+   SERVER and CONN must not be NULL. The real errors will be logged with
+   SERVER and CONN but return generic errors to the client. */
+svn_error_t *load_authz_config(server_baton_t *server,
+                               svn_ra_svn_conn_t *conn,
+                               const char *repos_root,
+                               apr_pool_t *pool);
 
 /* Initialize the Cyrus SASL library. POOL is used for allocations. */
 svn_error_t *cyrus_init(apr_pool_t *pool);

Modified: subversion/trunk/subversion/svnserve/svnserve.8
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/svnserve.8?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/svnserve.8 (original)
+++ subversion/trunk/subversion/svnserve/svnserve.8 Fri Dec 21 00:57:37 2012
@@ -110,12 +110,12 @@ still backgrounds itself at startup time
 .TP 5
 \fB\-\-config\-file\fP=\fIfilename\fP
 When specified, \fBsvnserve\fP reads \fIfilename\fP once at program
-startup and caches the \fBsvnserve\fP configuration and any passwords
-and authorization configuration referenced from \fIfilename\fP.
-\fBsvnserve\fP will not read any per-repository
-\fBconf/svnserve.conf\fP files when this option is used.  See the
-\fBsvnserve.conf\fP(5) man page for details of the file format for
-this option.
+startup and caches the \fBsvnserve\fP configuration.  The password
+and authorization configurations referenced from \fIfilename\fP will
+be loaded on each connection.  \fBsvnserve\fP will not read any
+per-repository \fBconf/svnserve.conf\fP files when this option is
+used.  See the \fBsvnserve.conf\fP(5) man page for details of the
+file format for this option.
 .PP
 .TP 5
 \fB\-\-pid\-file\fP=\fIfilename\fP

Modified: subversion/trunk/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/svnserve.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/svnserve.c (original)
+++ subversion/trunk/subversion/svnserve/svnserve.c Fri Dec 21 00:57:37 2012
@@ -503,9 +503,8 @@ int main(int argc, const char *argv[])
   params.tunnel = FALSE;
   params.tunnel_user = NULL;
   params.read_only = FALSE;
+  params.base = NULL;
   params.cfg = NULL;
-  params.pwdb = NULL;
-  params.authzdb = NULL;
   params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
   params.log_file = NULL;
   params.vhost = FALSE;
@@ -747,11 +746,14 @@ int main(int argc, const char *argv[])
   /* If a configuration file is specified, load it and any referenced
    * password and authorization files. */
   if (config_filename)
-    SVN_INT_ERR(load_configs(&params.cfg, &params.pwdb, &params.authzdb,
-                             &params.username_case, config_filename, TRUE,
-                             svn_dirent_dirname(config_filename, pool),
-                             NULL, NULL, /* server baton, conn */
-                             pool));
+    {
+      params.base = svn_dirent_dirname(config_filename, pool);
+
+      SVN_INT_ERR(svn_config_read2(&params.cfg, config_filename,
+                                   TRUE, /* must_exist */
+                                   FALSE, /* section_names_case_sensitive */
+                                   pool));
+    }
 
   if (log_filename)
     SVN_INT_ERR(svn_io_file_open(&params.log_file, log_filename,

Modified: subversion/trunk/subversion/svnserve/svnserve.conf.5
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/svnserve.conf.5?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/svnserve.conf.5 (original)
+++ subversion/trunk/subversion/svnserve/svnserve.conf.5 Fri Dec 21 00:57:37 2012
@@ -61,11 +61,13 @@ uses only one section "users"; each vari
 username, and each value is a password.
 .PP
 .TP 5
-\fBauthz-db\fP = \fIfilename\fP
+\fBauthz-db\fP = \fIpath\fP
 The authz-db option controls the location of the authorization
-rules for path-based access control.  \fIfilename\fP may be 
-relative to the repository conf directory.  There is no default value.
-If you don't specify an authz-db, no path-based access control is done.
+rules for path-based access control.  \fIpath\fP may be 
+relative to the repository conf directory.  \fIpath\fP may be a repository
+relative URL (^/) or absolute file:// URL to a text file in a Subversion
+repository.  There is no default value.  If you don't specify an authz-db,
+no path-based access control is done.
 .PP
 .TP 5
 \fBrealm\fP = \fIrealm\-name\fP

Modified: subversion/trunk/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_repos/repos-test.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_repos/repos-test.c Fri Dec 21 00:57:37 2012
@@ -1147,6 +1147,60 @@ authz_get_handle(svn_authz_t **authz_p, 
   return SVN_NO_ERROR;
 }
 
+struct check_access_tests {
+  const char *path;
+  const char *repo_name;
+  const char *user;
+  const svn_repos_authz_access_t required;
+  const svn_boolean_t expected;
+};
+
+/* Helper for the authz test.  Runs a set of tests against AUTHZ_CFG
+ * as defined in TESTS. */
+static svn_error_t *
+authz_check_access(svn_authz_t *authz_cfg,
+                   const struct check_access_tests *tests,
+                   apr_pool_t *pool)
+{
+  int i;
+  svn_boolean_t access_granted;
+
+  /* Loop over the test array and test each case. */
+  for (i = 0; !(tests[i].path == NULL
+               && tests[i].required == svn_authz_none); i++)
+    {
+      SVN_ERR(svn_repos_authz_check_access(authz_cfg,
+                                           tests[i].repo_name,
+                                           tests[i].path,
+                                           tests[i].user,
+                                           tests[i].required,
+                                           &access_granted, pool));
+
+      if (access_granted != tests[i].expected)
+        {
+          return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                   "Authz incorrectly %s %s%s access "
+                                   "to %s%s%s for user %s",
+                                   access_granted ?
+                                   "grants" : "denies",
+                                   tests[i].required
+                                   & svn_authz_recursive ?
+                                   "recursive " : "",
+                                   tests[i].required
+                                   & svn_authz_read ?
+                                   "read" : "write",
+                                   tests[i].repo_name ?
+                                   tests[i].repo_name : "",
+                                   tests[i].repo_name ?
+                                   ":" : "",
+                                   tests[i].path,
+                                   tests[i].user ?
+                                   tests[i].user : "-");
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
 
 
 /* Test that authz is giving out the right authorizations. */
@@ -1160,34 +1214,28 @@ authz(apr_pool_t *pool)
   apr_pool_t *subpool = svn_pool_create(pool);
   int i;
   /* Definition of the paths to test and expected replies for each. */
-  struct
-  {
-    const char *path;
-    const char *user;
-    const svn_repos_authz_access_t required;
-    const svn_boolean_t expected;
-  } test_set[] = {
+  struct check_access_tests test_set[] = {
     /* Test that read rules are correctly used. */
-    { "/A", NULL, svn_authz_read, TRUE },
-    { "/iota", NULL, svn_authz_read, FALSE },
+    { "/A", "greek", NULL, svn_authz_read, TRUE },
+    { "/iota", "greek", NULL, svn_authz_read, FALSE },
     /* Test that write rules are correctly used. */
-    { "/A", "plato", svn_authz_write, TRUE },
-    { "/A", NULL, svn_authz_write, FALSE },
+    { "/A", "greek", "plato", svn_authz_write, TRUE },
+    { "/A", "greek", NULL, svn_authz_write, FALSE },
     /* Test that pan-repository rules are found and used. */
-    { "/A/B/lambda", "plato", svn_authz_read, TRUE },
-    { "/A/B/lambda", NULL, svn_authz_read, FALSE },
+    { "/A/B/lambda", "greek", "plato", svn_authz_read, TRUE },
+    { "/A/B/lambda", "greek", NULL, svn_authz_read, FALSE },
     /* Test that authz uses parent path ACLs if no rule for the path
        exists. */
-    { "/A/C", NULL, svn_authz_read, TRUE },
+    { "/A/C", "greek", NULL, svn_authz_read, TRUE },
     /* Test that recursive access requests take into account the rules
        of subpaths. */
-    { "/A/D", "plato", svn_authz_read | svn_authz_recursive, TRUE },
-    { "/A/D", NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D", "greek", "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/A/D", "greek", NULL, svn_authz_read | svn_authz_recursive, FALSE },
     /* Test global write access lookups. */
-    { NULL, "plato", svn_authz_read, TRUE },
-    { NULL, NULL, svn_authz_write, FALSE },
+    { NULL, "greek", "plato", svn_authz_read, TRUE },
+    { NULL, "greek", NULL, svn_authz_write, FALSE },
     /* Sentinel */
-    { NULL, NULL, svn_authz_none, FALSE }
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
   };
 
   /* The test logic:
@@ -1242,34 +1290,7 @@ authz(apr_pool_t *pool)
   SVN_ERR(authz_get_handle(&authz_cfg, contents, subpool));
 
   /* Loop over the test array and test each case. */
-  for (i = 0; !(test_set[i].path == NULL
-               && test_set[i].required == svn_authz_none); i++)
-    {
-      SVN_ERR(svn_repos_authz_check_access(authz_cfg, "greek",
-                                           test_set[i].path,
-                                           test_set[i].user,
-                                           test_set[i].required,
-                                           &access_granted, subpool));
-
-      if (access_granted != test_set[i].expected)
-        {
-          return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
-                                   "Authz incorrectly %s %s%s access "
-                                   "to greek:%s for user %s",
-                                   access_granted ?
-                                   "grants" : "denies",
-                                   test_set[i].required
-                                   & svn_authz_recursive ?
-                                   "recursive " : "",
-                                   test_set[i].required
-                                   & svn_authz_read ?
-                                   "read" : "write",
-                                   test_set[i].path,
-                                   test_set[i].user ?
-                                   test_set[i].user : "-");
-        }
-    }
-
+  SVN_ERR(authz_check_access(authz_cfg, test_set, subpool));
 
   /* The authz rules for the phase 2 tests, first case (cyclic
      dependency). */
@@ -1341,6 +1362,119 @@ authz(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+
+/* Test in-repo authz paths */
+static svn_error_t *
+in_repo_authz(const svn_test_opts_t *opts,
+                                 apr_pool_t *pool)
+{
+  svn_repos_t *repos;
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root;
+  svn_revnum_t youngest_rev;
+  svn_authz_t *authz_cfg;
+  const char *authz_contents;
+  const char *repos_root;
+  const char *repos_url;
+  const char *authz_url;
+  svn_error_t *err;
+  struct check_access_tests test_set[] = {
+    /* reads */
+    { "/A", NULL, NULL, svn_authz_read, FALSE },
+    { "/A", NULL, "plato", svn_authz_read, TRUE },
+    { "/A", NULL, "socrates", svn_authz_read, TRUE },
+    /* writes */
+    { "/A", NULL, NULL, svn_authz_write, FALSE },
+    { "/A", NULL, "socrates", svn_authz_write, FALSE },
+    { "/A", NULL, "plato", svn_authz_write, TRUE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Test plan:
+   * Create an authz file and put it in the repository.
+   * Verify it can be read with an relative URL.
+   * Verify it can be read with an absolute URL.
+   * Verify non-existant path does not error out when must_exist is FALSE. 
+   * Verify non-existant path does error out when must_exist is TRUE.
+   * Verify that an http:// URL produces an error.
+   * Verify that an svn:// URL produces an error.
+   */
+
+  /* What we'll put in the authz file, it's simple since we're not testing
+   * the parsing, just that we got what we expected. */ 
+  authz_contents = 
+    ""                                                                       NL
+    ""                                                                       NL
+    "[/]"                                                                    NL
+    "plato = rw"                                                             NL
+    "socrates = r";
+
+  /* Create a filesystem and repository. */
+  SVN_ERR(svn_test__create_repos(&repos, "test-repo-in-repo-authz",
+                                 opts, pool));
+  fs = svn_repos_fs(repos);
+
+  /* Commit the authz file to the repo. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_file(txn_root, "authz", pool));
+  SVN_ERR(svn_test__set_file_contents(txn_root, "authz", authz_contents,
+                                      pool));
+  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
+
+  /* repos relative URL */
+  repos_root = svn_repos_path(repos, pool);
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/authz", TRUE, repos_root,
+                                pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  /* absolute file URL, repos_root is NULL to validate the contract that it
+   * is not needed except when a repos relative URL is passed. */
+  SVN_ERR(svn_uri_get_file_url_from_dirent(&repos_url, repos_root, pool));
+  authz_url = apr_pstrcat(pool, repos_url, "/authz", (char *)NULL);
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, authz_url, TRUE, NULL, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+  
+  /* Non-existant path in the repo with must_exist set to FALSE */ 
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/A/authz", FALSE, repos_root,
+                                pool));
+
+  /* Non-existant path in the repo with must_exist set to TRUE */ 
+  err = svn_repos_authz_read2(&authz_cfg, "^/A/authz", TRUE, repos_root,
+                              pool);
+  if (!err || err->apr_err != SVN_ERR_AUTHZ_INVALID_CONFIG)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_AUTHZ_INVALID_CONFIG",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+  /* http:// URL which is unsupported */
+  err = svn_repos_authz_read2(&authz_cfg, "http://example.com/repo/authz",
+                              TRUE, repos_root, pool);
+  if (!err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_RA_ILLEGAL_URL",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+  /* svn:// URL which is unsupported */
+  err = svn_repos_authz_read2(&authz_cfg, "svn://example.com/repo/authz",
+                              TRUE, repos_root, pool);
+  if (!err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_RA_ILLEGAL_URL",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+
+  return SVN_NO_ERROR;
+}
 
 
 /* Callback for the commit editor tests that relays requests to
@@ -2585,6 +2719,8 @@ struct svn_test_descriptor_t test_funcs[
                        "test removal of defunct locks"),
     SVN_TEST_PASS2(authz,
                    "test authz access control"),
+    SVN_TEST_OPTS_PASS(in_repo_authz,
+                       "test authz stored in the repo"),
     SVN_TEST_OPTS_PASS(commit_editor_authz,
                        "test authz in the commit editor"),
     SVN_TEST_OPTS_PASS(commit_continue_txn,

Modified: subversion/trunk/subversion/tests/libsvn_subr/config-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/config-test.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/config-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/config-test.c Fri Dec 21 00:57:37 2012
@@ -269,6 +269,31 @@ test_has_section_case_sensitive(apr_pool
 
   return SVN_NO_ERROR;
 }
+
+static svn_error_t *
+test_stream_interface(apr_pool_t *pool)
+{
+  svn_config_t *cfg;
+  const char *cfg_file;
+  svn_stream_t *stream;
+
+  if (!srcdir)
+    SVN_ERR(init_params(pool));
+
+  cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL);
+  SVN_ERR(svn_stream_open_readonly(&stream, cfg_file, pool, pool));
+
+  SVN_ERR(svn_config_parse(&cfg, stream, TRUE, pool));
+
+  /* nominal test to make sure cfg is populated with something since
+   * svn_config_parse will happily return an empty cfg if the stream is
+   * empty. */
+  if (! svn_config_has_section(cfg, "section1"))
+    return fail(pool, "Failed to find section1");
+
+  return SVN_NO_ERROR;
+}
+
 /*
    ====================================================================
    If you add a new test to this file, update this array.
@@ -288,5 +313,7 @@ struct svn_test_descriptor_t test_funcs[
                    "test svn_config_has_section (case insensitive)"),
     SVN_TEST_PASS2(test_has_section_case_sensitive,
                    "test svn_config_has_section (case sensitive)"),
+    SVN_TEST_PASS2(test_stream_interface,
+                   "test svn_config_parse"),
     SVN_TEST_NULL
   };

Modified: subversion/trunk/subversion/tests/libsvn_subr/path-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/path-test.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/path-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/path-test.c Fri Dec 21 00:57:37 2012
@@ -1624,6 +1624,71 @@ test_path_condense_targets(apr_pool_t *p
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_path_is_repos_relative_url(apr_pool_t *pool)
+{
+  int i;
+  struct {
+    const char* path;
+    svn_boolean_t result;
+  } tests[] = {
+    { "^/A",           TRUE },
+    { "http://host/A", FALSE },
+    { "/A/B",          FALSE },
+  };
+
+  for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
+    {
+      svn_boolean_t result = svn_path_is_repos_relative_url(tests[i].path);
+
+      if (tests[i].result != result)
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "svn_path_is_repos_relative_url(\"%s\")"
+                                 " returned \"%s\" expected \"%s\"",
+                                 tests[i].path,
+                                 result ? "TRUE" : "FALSE",
+                                 tests[i].result ? "TRUE" : "FALSE");
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_path_resolve_repos_relative_url(apr_pool_t *pool)
+{
+  int i;
+  struct {
+    const char *relative_url;
+    const char *repos_root_url;
+    const char *absolute_url;
+  } tests[] = {
+    { "^/A", "file:///Z/X", "file:///Z/X/A" },
+    { "^/A", "file:///Z/X/", "file:///Z/X//A" }, /* doesn't canonicalize */
+    { "^/A@2", "file:///Z/X", "file:///Z/X/A@2" }, /* peg rev */
+    { "^/A", "/Z/X", "/Z/X/A" }, /* doesn't verify repos_root is URL */
+  };
+
+  for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
+    {
+      const char *result;
+
+      SVN_ERR(svn_path_resolve_repos_relative_url(&result,
+                                                  tests[i].relative_url,
+                                                  tests[i].repos_root_url,
+                                                  pool));
+
+      if (strcmp(tests[i].absolute_url,result))
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "svn_path_resolve_repos_relative_url(\"%s\","
+                                 "\"%s\") returned \"%s\" expected \"%s\"",
+                                 tests[i].relative_url,
+                                 tests[i].repos_root_url,
+                                 result, tests[i].absolute_url);
+    }
+  
+  return SVN_NO_ERROR;
+}
+
 
 /* local define to support XFail-ing tests on Windows/Cygwin only */
 #ifdef SVN_USE_DOS_PATHS
@@ -1688,5 +1753,9 @@ struct svn_test_descriptor_t test_funcs[
                    "test svn_path_internal_style"),
     SVN_TEST_PASS2(test_path_condense_targets,
                    "test svn_path_condense_targets"),
+    SVN_TEST_PASS2(test_path_is_repos_relative_url,
+                   "test svn_path_is_repos_relative_url"),
+    SVN_TEST_PASS2(test_path_resolve_repos_relative_url,
+                   "test svn_path_resolve_repos_relative_url"),
     SVN_TEST_NULL
   };

Modified: subversion/trunk/tools/server-side/svnauthz-validate.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/server-side/svnauthz-validate.c?rev=1424780&r1=1424779&r2=1424780&view=diff
==============================================================================
--- subversion/trunk/tools/server-side/svnauthz-validate.c (original)
+++ subversion/trunk/tools/server-side/svnauthz-validate.c Fri Dec 21 00:57:37 2012
@@ -34,6 +34,7 @@
 #include "svn_pools.h"
 #include "svn_repos.h"
 #include "svn_utf.h"
+#include "svn_path.h"
 
 enum {
   OPT_USERNAME = SVN_OPT_FIRST_LONGOPT_ID,
@@ -49,6 +50,8 @@ usage(const char *argv0)
          "Optionally prints the access available to USER for FSPATH in\n"
          "repository with authz name REPOS_NAME.  If FSPATH is omitted, reports\n"
          "whether USER has any access at all.\n"
+         "FILE can also be an absolute file:// URL to a authz file in a\n"
+         "repository, but cannot be a repository relative URL (^/).\n"
          "Returns:\n"
          "    0   when syntax is OK.\n"
          "    1   when syntax is invalid.\n"
@@ -141,10 +144,15 @@ main(int argc, const char **argv)
       return 2;
     }
 
-  opts.authz_file = svn_dirent_internal_style(opts.authz_file, pool);
+  /* Can't accept repos relative urls since we don't have the path to the
+   * repository and URLs don't need to be converted to internal style. */
+  if (svn_path_is_repos_relative_url(opts.authz_file))
+    return usage(argv[0]);
+  else if (!svn_path_is_url(opts.authz_file))
+    opts.authz_file = svn_dirent_internal_style(opts.authz_file, pool);
 
   /* Read the access file and validate it. */
-  err = svn_repos_authz_read(&authz, opts.authz_file, TRUE, pool);
+  err = svn_repos_authz_read2(&authz, opts.authz_file, TRUE, NULL, pool);
 
   /* Optionally, print the access a USER has to a given PATH in REPOS.
      PATH and REPOS may be NULL. */



Mime
View raw message