You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2010/10/11 21:26:36 UTC

svn commit: r1021477 - in /subversion/trunk/subversion: include/svn_config.h libsvn_repos/repos.c svnserve/cyrus_auth.c svnserve/main.c svnserve/serve.c svnserve/server.h

Author: cmpilato
Date: Mon Oct 11 19:26:36 2010
New Revision: 1021477

URL: http://svn.apache.org/viewvc?rev=1021477&view=rev
Log:
Finish issue #3726 ("svnserve lacks the equivalent of AuthzForceUsernameCase")
by introducing a new 'force-username-case' svnserve.conf option.

* subversion/libsvn_repos/repos.c
  (create_conf): Add configuration defaults for a new 'force-username-case' 
    option.

* subversion/svnserve/server.h
  (enum username_case_type): New enum.
  (server_baton_t): Add 'username_case' and 'authz_user' members.
  (serve_params_t): Add 'username_case' member.
  (load_configs): Add 'username_case' out parameter, and rewrite the
    docstring for readability.

* subversion/svnserve/main.c
  (main): Initialize 'username_case' baton member, and update call to
    load_configs().

* subversion/svnserve/cyrus_auth.c
  (cyrus_auth_request): Balance braces.

* subversion/svnserve/serve.c
  (load_configs): Add 'username_case' out parameter, populated from
    the configuration.
  (convert_case): New helper.
  (authz_check_access): Calculate the authz_user, converting case as
    necessary, and use that value for authz checks.
  (find_repos): Update call to load_configs().
  (serve): Initialize 'username_case' and 'authz_user' baton members.

* subversion/include/svn_config.h
  (SVN_CONFIG_OPTION_FORCE_USERNAME_CASE): New.

Modified:
    subversion/trunk/subversion/include/svn_config.h
    subversion/trunk/subversion/libsvn_repos/repos.c
    subversion/trunk/subversion/svnserve/cyrus_auth.c
    subversion/trunk/subversion/svnserve/main.c
    subversion/trunk/subversion/svnserve/serve.c
    subversion/trunk/subversion/svnserve/server.h

Modified: subversion/trunk/subversion/include/svn_config.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_config.h?rev=1021477&r1=1021476&r2=1021477&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_config.h (original)
+++ subversion/trunk/subversion/include/svn_config.h Mon Oct 11 19:26:36 2010
@@ -127,6 +127,7 @@ typedef struct svn_config_t svn_config_t
 #define SVN_CONFIG_OPTION_PASSWORD_DB               "password-db"
 #define SVN_CONFIG_OPTION_REALM                     "realm"
 #define SVN_CONFIG_OPTION_AUTHZ_DB                  "authz-db"
+#define SVN_CONFIG_OPTION_FORCE_USERNAME_CASE       "force-username-case"
 #define SVN_CONFIG_SECTION_SASL                 "sasl"
 #define SVN_CONFIG_OPTION_USE_SASL                  "use-sasl"
 #define SVN_CONFIG_OPTION_MIN_SSF                   "min-encryption"

Modified: subversion/trunk/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/repos.c?rev=1021477&r1=1021476&r2=1021477&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/repos.c (original)
+++ subversion/trunk/subversion/libsvn_repos/repos.c Mon Oct 11 19:26:36 2010
@@ -1141,6 +1141,13 @@ create_conf(svn_repos_t *repos, apr_pool
 "### have the same password database, and vice versa.  The default realm"    NL
 "### is repository's uuid."                                                  NL
 "# realm = My First Repository"                                              NL
+"### The force-username-case option causes svnserve to case-normalize"       NL
+"### usernames before comparing them against the authorization rules in the" NL
+"### authz-db file configured above.  Valid values are \"upper\" (to upper-" NL
+"### case the usernames), \"lower\" (to lowercase the usernames), and"       NL
+"### \"none\" (to compare usernames as-is without case conversion, which"    NL
+"### is the default behavior)."                                              NL
+"# force-username-case = none"                                               NL
 ""                                                                           NL
 "[sasl]"                                                                     NL
 "### This option specifies whether you want to use the Cyrus SASL"           NL

Modified: subversion/trunk/subversion/svnserve/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/cyrus_auth.c?rev=1021477&r1=1021476&r2=1021477&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/cyrus_auth.c (original)
+++ subversion/trunk/subversion/svnserve/cyrus_auth.c Mon Oct 11 19:26:36 2010
@@ -360,8 +360,10 @@ svn_error_t *cyrus_auth_request(svn_ra_s
         return fail_cmd(conn, pool, sasl_ctx);
 
       if ((p = strchr(user, '@')) != NULL)
-        /* Drop the realm part. */
-        b->user = apr_pstrndup(b->pool, user, p - (const char *)user);
+        {
+          /* Drop the realm part. */
+          b->user = apr_pstrndup(b->pool, user, p - (const char *)user);
+        }
       else
         {
           svn_error_t *err;

Modified: subversion/trunk/subversion/svnserve/main.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/main.c?rev=1021477&r1=1021476&r2=1021477&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/main.c (original)
+++ subversion/trunk/subversion/svnserve/main.c Mon Oct 11 19:26:36 2010
@@ -431,6 +431,7 @@ int main(int argc, const char *argv[])
   params.pwdb = NULL;
   params.authzdb = NULL;
   params.log_file = NULL;
+  params.username_case = CASE_ASIS;
 
   while (1)
     {
@@ -592,11 +593,11 @@ 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,
-                               config_filename, TRUE,
-                               svn_dirent_dirname(config_filename, pool),
-                               NULL, NULL, /* server baton, conn */
-                               pool));
+    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));
 
   if (log_filename)
     SVN_INT_ERR(svn_io_file_open(&params.log_file, log_filename,

Modified: subversion/trunk/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/serve.c?rev=1021477&r1=1021476&r2=1021477&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/serve.c (original)
+++ subversion/trunk/subversion/svnserve/serve.c Mon Oct 11 19:26:36 2010
@@ -223,6 +223,7 @@ static svn_error_t *log_command(server_b
 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,
@@ -286,6 +287,8 @@ svn_error_t *load_configs(svn_config_t *
                  SVN_CONFIG_OPTION_AUTHZ_DB, NULL);
   if (authzdb_path)
     {
+      const char *case_force_val;
+
       authzdb_path = svn_dirent_join(base, authzdb_path, pool);
       err = svn_repos_authz_read(authzdb, authzdb_path, TRUE, pool);
       if (err)
@@ -304,10 +307,25 @@ svn_error_t *load_configs(svn_config_t *
              * will go to standard error for the admin to see. */
             return err;
         }
+      
+      /* 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_OPTION_FORCE_USERNAME_CASE, NULL);
+      if (case_force_val)
+        {
+          if (strcmp(case_force_val, "upper") == 0)
+            *username_case = CASE_FORCE_UPPER;
+          else if (strcmp(case_force_val, "lower") == 0)
+            *username_case = CASE_FORCE_LOWER;
+          else
+            *username_case = CASE_ASIS;
+        }
     }
   else
     {
       *authzdb = NULL;
+      *username_case = CASE_ASIS;
     }
 
   return SVN_NO_ERROR;
@@ -340,6 +358,18 @@ static svn_error_t *get_fs_path(const ch
 
 /* --- AUTHENTICATION AND AUTHORIZATION FUNCTIONS --- */
 
+/* Convert TEXT to upper case if TO_UPPERCASE is TRUE, else
+   converts it to lower case. */
+static void convert_case(char *text, svn_boolean_t to_uppercase)
+{
+  char *c = text;
+  while (*c)
+    {
+      *c = (to_uppercase ? apr_toupper(*c) : apr_tolower(*c));
+      ++c;
+    }
+}
+
 /* Set *ALLOWED to TRUE if PATH is accessible in the REQUIRED mode to
    the user described in BATON according to the authz rules in BATON.
    Use POOL for temporary allocations only.  If no authz rules are
@@ -369,8 +399,20 @@ static svn_error_t *authz_check_access(s
   if (path && *path != '/')
     path = svn_uri_join("/", path, pool);
 
+  /* If we have a username, and we've not yet used it + any username
+     case normalization that might be requested to determine "the
+     username we used for authz purposes", do so now. */
+  if (b->user && (! b->authz_user))
+    {
+      b->authz_user = apr_pstrdup(b->pool, b->user);
+      if (b->username_case == CASE_FORCE_UPPER)
+        convert_case((char *)b->authz_user, TRUE);
+      else if (b->username_case == CASE_FORCE_LOWER)
+        convert_case((char *)b->authz_user, FALSE);
+    }
+
   return svn_repos_authz_check_access(b->authzdb, b->authz_repos_name,
-                                      path, b->user, required,
+                                      path, b->authz_user, required,
                                       allowed, pool);
 }
 
@@ -2962,7 +3004,7 @@ static svn_error_t *find_repos(const cha
   /* If the svnserve configuration files have not been loaded then
      load them from the repository. */
   if (NULL == b->cfg)
-    SVN_ERR(load_configs(&b->cfg, &b->pwdb, &b->authzdb,
+    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,
@@ -3031,6 +3073,8 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
   b.tunnel_user = get_tunnel_user(params, pool);
   b.read_only = params->read_only;
   b.user = NULL;
+  b.username_case = params->username_case;
+  b.authz_user = NULL;
   b.cfg = params->cfg;
   b.pwdb = params->pwdb;
   b.authzdb = params->authzdb;

Modified: subversion/trunk/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/server.h?rev=1021477&r1=1021476&r2=1021477&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/server.h (original)
+++ subversion/trunk/subversion/svnserve/server.h Mon Oct 11 19:26:36 2010
@@ -36,6 +36,8 @@ extern "C" {
 #include "svn_repos.h"
 #include "svn_ra_svn.h"
 
+enum username_case_type { CASE_FORCE_UPPER, CASE_FORCE_LOWER, CASE_ASIS };
+
 typedef struct server_baton_t {
   svn_repos_t *repos;
   const char *repos_name;  /* URI-encoded name of repository (not for authz) */
@@ -47,7 +49,9 @@ typedef struct server_baton_t {
   const char *realm;       /* Authentication realm */
   const char *repos_url;   /* URL to base of repository */
   svn_stringbuf_t *fs_path;/* Decoded base in-repos path (w/ leading slash) */
-  const char *user;
+  const char *user;        /* Authenticated username of the user */
+  enum username_case_type username_case; /* Case-normalize the username? */
+  const char *authz_user;  /* Username for authz ('user' + 'username_case') */
   svn_boolean_t tunnel;    /* Tunneled through login agent */
   const char *tunnel_user; /* Allow EXTERNAL to authenticate as this */
   svn_boolean_t read_only; /* Disallow write access (global flag) */
@@ -101,6 +105,10 @@ typedef struct serve_params_t {
 
   /* A filehandle open for writing logs to; possibly NULL. */
   apr_file_t *log_file;
+
+  /* Username case normalization style. */
+  enum username_case_type username_case;
+
 } serve_params_t;
 
 /* Serve the connection CONN according to the parameters PARAMS. */
@@ -108,11 +116,16 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
                    apr_pool_t *pool);
 
 /* Load a svnserve configuration file located at FILENAME into CFG,
-   any referenced password database into PWDB and any referenced
-   authorization database into AUTHZDB.  If MUST_EXIST is true and
-   FILENAME does not exist, then this returns an error.  BASE may be
-   specified as the base path to any referenced password and
-   authorization files found in FILENAME.
+   and if such as found, then:
+
+    - 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
@@ -120,6 +133,7 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
 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,