On Tue, Sep 07, 2010 at 02:33:28PM +0700, Victor Sudakov wrote:
> This time it has compiled, but does not work.
> 
> "svn list svn://admin/test/" works OK (IMHO because the ANONYMOUS
> mechanism is sufficient for that) but "svn co svn://admin/test/"
> dumps core immediately.

Hi Victor,

I hope I have found the problem. Does the patch below work better?

Thanks,
Stefan

Index: subversion/libsvn_subr/config_file.c
===================================================================
--- subversion/libsvn_subr/config_file.c        (revision 997080)
+++ subversion/libsvn_subr/config_file.c        (working copy)
@@ -759,6 +759,11 @@ svn_config_ensure(const char *config_dir, apr_pool
                                                                              NL
         "###                              may be cached to disk."            NL
         "###   username                   Specifies the default username."   NL
+        "###   preferred-sasl-mechanism   Specifies which SASL mechanism"    NL
+        "###                              among the ones offered by the "    NL
+        "###                              server should be tried first."     NL
+        "###                              See the SASL documentation for"    NL
+        "###                              a list of mechanisms available."   NL
         "###"                                                                NL
         "### Set store-passwords to 'no' to avoid storing passwords in the"  NL
         "### auth/ area of your config directory.  It defaults to 'yes',"    NL
Index: subversion/libsvn_ra_svn/cyrus_auth.c
===================================================================
--- subversion/libsvn_ra_svn/cyrus_auth.c       (revision 997080)
+++ subversion/libsvn_ra_svn/cyrus_auth.c       (working copy)
@@ -27,6 +27,7 @@
 #include <apr_thread_mutex.h>
 #include <apr_version.h>
 
+#include "svn_config.h"
 #include "svn_types.h"
 #include "svn_string.h"
 #include "svn_error.h"
@@ -720,6 +721,67 @@ svn_error_t *svn_ra_svn__get_addresses(const char
   return SVN_NO_ERROR;
 }
 
+
+/* Return one or more SASL mechanisms from MECHLIST.
+ * SESS is the session baton.
+ * If a preferred SASL mechanism has been defined in the configuration,
+ * prefer it if it occurs within MECHLIST. Else, fall back to EXTERNAL,
+ * then ANONYMOUS, then let SASL decide.
+ * Potentially allocate the returned list of mechanisms in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static const char *
+get_sasl_mechanisms(svn_ra_svn__session_baton_t *sess,
+                    apr_array_header_t *mechlist,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  const char *mechstring = "";
+  svn_config_t *cfg;
+
+  cfg = sess->config ? apr_hash_get(sess->config, SVN_CONFIG_CATEGORY_SERVERS,
+                                    APR_HASH_KEY_STRING) : NULL;
+  if (cfg)
+    {
+      const char *server_group;
+      const char *preferred_mech;
+
+      server_group = svn_config_find_group(cfg, sess->hostname,
+                                           SVN_CONFIG_SECTION_GROUPS,
+                                           scratch_pool);
+      if (server_group)
+        svn_config_get(cfg, &preferred_mech, server_group,
+                       SVN_CONFIG_OPTION_PREFERRED_SASL_MECHANISM, NULL);
+      else
+        preferred_mech = NULL;
+
+      if (preferred_mech && svn_ra_svn__find_mech(mechlist, preferred_mech))
+        return preferred_mech;
+    }
+
+  if (svn_ra_svn__find_mech(mechlist, "EXTERNAL"))
+    return "EXTERNAL";
+  else if (svn_ra_svn__find_mech(mechlist, "ANONYMOUS"))
+    return "ANONYMOUS";
+  else
+    {
+      int i;
+
+      /* Create a string containing the list of mechanisms,
+       * separated by spaces. */
+      for (i = 0; i < mechlist->nelts; i++)
+        {
+          svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(mechlist, i,
+                                                  svn_ra_svn_item_t);
+          mechstring = apr_pstrcat(result_pool,
+                                   mechstring,
+                                   i == 0 ? "" : " ",
+                                   elt->u.word, NULL);
+        }
+    }
+
+  return mechstring;
+}
+
 svn_error_t *
 svn_ra_svn__do_cyrus_auth(svn_ra_svn__session_baton_t *sess,
                           apr_array_header_t *mechlist,
@@ -734,7 +796,6 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__session_bato
      array terminator). */
   sasl_callback_t callbacks[3];
   cred_baton_t cred_baton;
-  int i;
 
   if (!sess->is_tunneled)
     {
@@ -742,24 +803,7 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__session_bato
                                         sess->conn, pool));
     }
 
-  /* Prefer EXTERNAL, then ANONYMOUS, then let SASL decide. */
-  if (svn_ra_svn__find_mech(mechlist, "EXTERNAL"))
-    mechstring = "EXTERNAL";
-  else if (svn_ra_svn__find_mech(mechlist, "ANONYMOUS"))
-    mechstring = "ANONYMOUS";
-  else
-    {
-      /* Create a string containing the list of mechanisms, separated by 
spaces. */
-      for (i = 0; i < mechlist->nelts; i++)
-        {
-          svn_ra_svn_item_t *elt = &APR_ARRAY_IDX(mechlist, i, 
svn_ra_svn_item_t);
-          mechstring = apr_pstrcat(pool,
-                                   mechstring,
-                                   i == 0 ? "" : " ",
-                                   elt->u.word, NULL);
-        }
-    }
-
+  mechstring = get_sasl_mechanisms(sess, mechlist, pool, pool);
   realmstring = apr_psprintf(pool, "%s %s", sess->realm_prefix, realm);
 
   /* Initialize the credential baton. */
Index: subversion/libsvn_ra_svn/client.c
===================================================================
--- subversion/libsvn_ra_svn/client.c   (revision 997080)
+++ subversion/libsvn_ra_svn/client.c   (working copy)
@@ -542,14 +542,16 @@ static svn_error_t *parse_url(const char *url, apr
 }
 
 /* Open a session to URL, returning it in *SESS_P, allocating it in POOL.
-   URI is a parsed version of URL.  CALLBACKS and CALLBACKS_BATON
-   are provided by the caller of ra_svn_open. If tunnel_argv is non-null,
-   it points to a program argument list to use when invoking the tunnel agent.
+   URI is a parsed version of URL. CONFIG is the client configuration.
+   CALLBACKS and CALLBACKS_BATON are provided by the caller of ra_svn_open.
+   If tunnel_argv is non-null, it points to a program argument list to use
+   when invoking the tunnel agent.
 */
 static svn_error_t *open_session(svn_ra_svn__session_baton_t **sess_p,
                                  const char *url,
                                  const apr_uri_t *uri,
                                  const char **tunnel_argv,
+                                 apr_hash_t *config,
                                  const svn_ra_callbacks2_t *callbacks,
                                  void *callbacks_baton,
                                  apr_pool_t *pool)
@@ -573,6 +575,7 @@ static svn_error_t *open_session(svn_ra_svn__sessi
   sess->callbacks = callbacks;
   sess->callbacks_baton = callbacks_baton;
   sess->bytes_read = sess->bytes_written = 0;
+  sess->config = config;
 
   if (tunnel_argv)
     SVN_ERR(make_tunnel(tunnel_argv, &conn, pool));
@@ -713,7 +716,7 @@ static svn_error_t *ra_svn_open(svn_ra_session_t *
 
   /* We open the session in a subpool so we can get rid of it if we
      reparent with a server that doesn't support reparenting. */
-  SVN_ERR(open_session(&sess, url, &uri, tunnel_argv,
+  SVN_ERR(open_session(&sess, url, &uri, tunnel_argv, config,
                        callbacks, callback_baton, sess_pool));
   session->priv = sess;
 
@@ -749,7 +752,7 @@ static svn_error_t *ra_svn_reparent(svn_ra_session
   sess_pool = svn_pool_create(ra_session->pool);
   err = parse_url(url, &uri, sess_pool);
   if (! err)
-    err = open_session(&new_sess, url, &uri, sess->tunnel_argv,
+    err = open_session(&new_sess, url, &uri, sess->tunnel_argv, sess->config,
                        sess->callbacks, sess->callbacks_baton, sess_pool);
   /* We destroy the new session pool on error, since it is allocated in
      the main session pool. */
Index: subversion/libsvn_ra_svn/ra_svn.h
===================================================================
--- subversion/libsvn_ra_svn/ra_svn.h   (revision 997080)
+++ subversion/libsvn_ra_svn/ra_svn.h   (working copy)
@@ -97,6 +97,7 @@ struct svn_ra_svn__session_baton_t {
   void *callbacks_baton;
   apr_off_t bytes_read, bytes_written; /* apr_off_t's because that's what
                                           the callback interface uses */
+  apr_hash_t *config;
 };
 
 /* Set a callback for blocked writes on conn.  This handler may
Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h     (revision 997080)
+++ subversion/include/svn_config.h     (working copy)
@@ -81,6 +81,7 @@ typedef struct svn_config_t svn_config_t;
 #define SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
                                           "store-ssl-client-cert-pp-plaintext"
 #define SVN_CONFIG_OPTION_USERNAME                  "username"
+#define SVN_CONFIG_OPTION_PREFERRED_SASL_MECHANISM  "preferred-sasl-mechanism"
 
 #define SVN_CONFIG_CATEGORY_CONFIG          "config"
 #define SVN_CONFIG_SECTION_AUTH                 "auth"

Reply via email to