Index: configure.in
===================================================================
--- configure.in	(revision 20489)
+++ configure.in	(working copy)
@@ -256,6 +256,11 @@
 
 SVN_LIB_SASL
 
+if test "$svn_lib_sasl" = "yes"; then
+  AC_DEFINE(SVN_HAVE_SASL, 1,
+            [Defined if Cyrus SASL v2 is present on the system])
+fi
+
 dnl Mac OS KeyChain -------------------
 
 AC_ARG_ENABLE(keychain,
Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h	(revision 20489)
+++ subversion/include/svn_config.h	(working copy)
@@ -104,6 +104,10 @@
 #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_SECTION_SASL                 "sasl"
+#define SVN_CONFIG_OPTION_USE_SASL                  "use-sasl"
+#define SVN_CONFIG_OPTION_MIN_ENC_STRENGTH          "min-enc-strength"
+#define SVN_CONFIG_OPTION_MAX_ENC_STRENGTH          "max-enc-strength"
 
 /* For repository password database */
 #define SVN_CONFIG_SECTION_USERS                "users"
Index: subversion/libsvn_repos/repos.c
===================================================================
--- subversion/libsvn_repos/repos.c	(revision 20489)
+++ subversion/libsvn_repos/repos.c	(working copy)
@@ -1419,6 +1419,10 @@
       APR_EOL_STR
       "### the file's location is relative to the conf directory."
       APR_EOL_STR
+#ifdef SVN_HAVE_SASL
+      "### If use-sasl is set to \"true\" below, this file will NOT be used."
+      APR_EOL_STR
+#endif
       "### Uncomment the line below to use the default password file."
       APR_EOL_STR
       "# password-db = passwd"
@@ -1446,6 +1450,33 @@
       "### is repository's uuid."
       APR_EOL_STR
       "# realm = My First Repository"
+#ifdef SVN_HAVE_SASL
+      APR_EOL_STR
+      APR_EOL_STR
+      "[sasl]"
+      APR_EOL_STR
+      "### This option specifies whether you want to use the Cyrus SASL"
+      APR_EOL_STR
+      "### library for authentication and (optionally) encryption. Default "
+      APR_EOL_STR
+      "### is false."
+      APR_EOL_STR
+      "# use-sasl = true"
+      APR_EOL_STR
+      "### These options specify the desired strength of the security layer"
+      APR_EOL_STR
+      "### that you want SASL to provide. 0 means no encryption, 1 means"
+      APR_EOL_STR
+      "### integrity-checking only, values larger than 1 are roughly"
+      APR_EOL_STR
+      "### correlated to the effective key length for encryption (e.g. 128"
+      APR_EOL_STR
+      "### means 128-bit encryption). The values below are the defaults."
+      APR_EOL_STR
+      "# min-enc-strength = 0"
+      APR_EOL_STR
+      "# max-enc-strength = 0"
+#endif
       APR_EOL_STR;
 
     SVN_ERR_W(svn_io_file_create(svn_repos_svnserve_conf(repos, pool),
Index: subversion/libsvn_ra_svn/client.c
===================================================================
--- subversion/libsvn_ra_svn/client.c	(revision 20489)
+++ subversion/libsvn_ra_svn/client.c	(working copy)
@@ -44,26 +44,15 @@
 #include "ra_svn.h"
 
 typedef struct {
+  svn_ra_svn__session_baton_t *sess_baton;
   apr_pool_t *pool;
-  svn_ra_svn_conn_t *conn;
-  int protocol_version;
-  svn_boolean_t is_tunneled;
-  svn_auth_baton_t *auth_baton;
-  const char *user;
-  const char *realm_prefix;
-  const char **tunnel_argv;
-} ra_svn_session_baton_t;
-
-typedef struct {
-  ra_svn_session_baton_t *sess_baton;
-  apr_pool_t *pool;
   svn_revnum_t *new_rev;
   svn_commit_callback2_t callback;
   void *callback_baton;
 } ra_svn_commit_callback_baton_t;
 
 typedef struct {
-  ra_svn_session_baton_t *sess_baton;
+  svn_ra_svn__session_baton_t *sess_baton;
   svn_ra_svn_conn_t *conn;
   apr_pool_t *pool;
   const svn_delta_editor_t *editor;
@@ -230,28 +219,11 @@
 
 /* --- AUTHENTICATION ROUTINES --- */
 
-static svn_boolean_t find_mech(apr_array_header_t *mechlist, const char *mech)
+svn_error_t *svn_ra_svn__auth_response(svn_ra_svn_conn_t *conn,
+                                       apr_pool_t *pool,
+                                       const char *mech, const char *mech_arg,
+                                       svn_boolean_t compat)
 {
-  int i;
-  svn_ra_svn_item_t *elt;
-
-  for (i = 0; i < mechlist->nelts; i++)
-    {
-      elt = &((svn_ra_svn_item_t *) mechlist->elts)[i];
-      if (elt->kind == SVN_RA_SVN_WORD && strcmp(elt->u.word, mech) == 0)
-        return TRUE;
-    }
-  return FALSE;
-}
-
-/* Having picked a mechanism, start authentication by writing out an
- * auth response.  If COMPAT is true, also write out a version number
- * and capability list.  MECH_ARG may be NULL for mechanisms with no
- * initial client response. */
-static svn_error_t *auth_response(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                  const char *mech, const char *mech_arg,
-                                  svn_boolean_t compat)
-{
   if (compat)
     return svn_ra_svn_write_tuple(conn, pool, "nw(?c)(www)", (apr_uint64_t) 1,
                                   mech, mech_arg,
@@ -262,79 +234,7 @@
     return svn_ra_svn_write_tuple(conn, pool, "w(?c)", mech, mech_arg);
 }
 
-/* Read the "success" response to ANONYMOUS or EXTERNAL authentication. */
-static svn_error_t *read_success(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
-{
-  const char *status, *arg;
-
-  SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "w(?c)", &status, &arg));
-  if (strcmp(status, "failure") == 0 && arg)
-    return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                             _("Authentication error from server: %s"), arg);
-  else if (strcmp(status, "success") != 0 || arg)
-    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                            _("Unexpected server response to authentication"));
-  return SVN_NO_ERROR;
-}
-
-/* Respond to an auth request and perform authentication.  REALM may
- * be NULL for the initial authentication exchange of protocol version
- * 1. */
-static svn_error_t *do_auth(ra_svn_session_baton_t *sess,
-                            apr_array_header_t *mechlist,
-                            const char *realm, apr_pool_t *pool)
-{
-  svn_ra_svn_conn_t *conn = sess->conn;
-  const char *realmstring, *user, *password, *msg;
-  svn_auth_iterstate_t *iterstate;
-  void *creds;
-  svn_boolean_t compat = (realm == NULL);
-
-  realmstring = realm ? apr_psprintf(pool, "%s %s", sess->realm_prefix, realm)
-    : sess->realm_prefix;
-  if (sess->is_tunneled && find_mech(mechlist, "EXTERNAL"))
-    {
-      /* Ask the server to use the tunnel connection environment (on
-       * Unix, that means uid) to determine the authentication name. */
-      SVN_ERR(auth_response(conn, pool, "EXTERNAL", "", compat));
-      return read_success(conn, pool);
-    }
-  else if (find_mech(mechlist, "ANONYMOUS"))
-    {
-      SVN_ERR(auth_response(conn, pool, "ANONYMOUS", "", compat));
-      return read_success(conn, pool);
-    }
-  else if (find_mech(mechlist, "CRAM-MD5"))
-    {
-      SVN_ERR(svn_auth_first_credentials(&creds, &iterstate,
-                                         SVN_AUTH_CRED_SIMPLE, realmstring,
-                                         sess->auth_baton, pool));
-      if (!creds)
-        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                                _("Can't get password"));
-      while (creds)
-        {
-          user = ((svn_auth_cred_simple_t *) creds)->username;
-          password = ((svn_auth_cred_simple_t *) creds)->password;
-          SVN_ERR(auth_response(conn, pool, "CRAM-MD5", NULL, compat));
-          SVN_ERR(svn_ra_svn__cram_client(conn, pool, user, password, &msg));
-          if (!msg)
-            break;
-          SVN_ERR(svn_auth_next_credentials(&creds, iterstate, pool));
-        }
-      if (!creds)
-        return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                                 _("Authentication error from server: %s"),
-                                 msg);
-      SVN_ERR(svn_auth_save_credentials(iterstate, pool));
-      return SVN_NO_ERROR;
-    }
-  else
-    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                            _("Cannot negotiate authentication mechanism"));
-}
-
-static svn_error_t *handle_auth_request(ra_svn_session_baton_t *sess,
+static svn_error_t *handle_auth_request(svn_ra_svn__session_baton_t *sess,
                                         apr_pool_t *pool)
 {
   svn_ra_svn_conn_t *conn = sess->conn;
@@ -346,7 +246,7 @@
   SVN_ERR(svn_ra_svn_read_cmd_response(conn, pool, "lc", &mechlist, &realm));
   if (mechlist->nelts == 0)
     return SVN_NO_ERROR;
-  return do_auth(sess, mechlist, realm, pool);
+  return svn_ra_svn__handle_auth(sess, mechlist, realm, pool);
 }
 
 /* --- REPORTER IMPLEMENTATION --- */
@@ -417,7 +317,7 @@
   ra_svn_abort_report
 };
 
-static void ra_svn_get_reporter(ra_svn_session_baton_t *sess_baton,
+static void ra_svn_get_reporter(svn_ra_svn__session_baton_t *sess_baton,
                                 apr_pool_t *pool,
                                 const svn_delta_editor_t *editor,
                                 void *edit_baton,
@@ -569,7 +469,6 @@
 
   /* Guard against dotfile output to stdout on the server. */
   *conn = svn_ra_svn_create_conn(NULL, proc->out, proc->in, pool);
-  (*conn)->proc = proc;
   SVN_ERR(svn_ra_svn_skip_leading_garbage(*conn, pool));
   return SVN_NO_ERROR;
 }
@@ -597,14 +496,14 @@
    URI is a parsed version of URL.  AUTH_BATON is 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(ra_svn_session_baton_t **sess_p,
+static svn_error_t *open_session(svn_ra_svn__session_baton_t **sess_p,
                                  const char *url,
                                  const apr_uri_t *uri,
                                  svn_auth_baton_t *auth_baton,
                                  const char **tunnel_argv,
                                  apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess;
+  svn_ra_svn__session_baton_t *sess;
   svn_ra_svn_conn_t *conn;
   apr_socket_t *sock;
   apr_uint64_t minver, maxver;
@@ -643,17 +542,16 @@
    * capability list, and the URL, and subsequently there is an auth
    * request.  In version 1, we send back the protocol version, auth
    * mechanism, mechanism initial response, and capability list, and;
-   * then send the URL after authentication.  do_auth temporarily has
+   * then send the URL after authentication.  svn_ra_svn__handle_auth temporarily has
    * support for the mixed-style response. */
   /* When we punt support for protocol version 1, we should:
    * - Eliminate this conditional and the similar one below
-   * - Remove v1 support from auth_response and inline it into do_auth
-   * - Remove the (realm == NULL) support from do_auth
-   * - Inline do_auth into handle_auth_request
+   * - Remove v1 support from svn_ra_svn__auth_response and inline it into svn_ra_svn__handle_auth
+   * - Remove the (realm == NULL) support from svn_ra_svn__handle_auth
    * - Remove the protocol version check from handle_auth_request */
   if (sess->protocol_version == 1)
     {
-      SVN_ERR(do_auth(sess, mechlist, NULL, pool));
+      SVN_ERR(svn_ra_svn__handle_auth(sess, mechlist, NULL, pool));
       SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "c", url));
     }
   else
@@ -714,7 +612,7 @@
                                 apr_pool_t *pool)
 {
   apr_pool_t *sess_pool = svn_pool_create(pool);
-  ra_svn_session_baton_t *sess;
+  svn_ra_svn__session_baton_t *sess;
   const char *tunnel, **tunnel_argv;
   apr_uri_t uri;
   
@@ -741,11 +639,11 @@
                                     const char *url,
                                     apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess = ra_session->priv;
+  svn_ra_svn__session_baton_t *sess = ra_session->priv;
   svn_ra_svn_conn_t *conn = sess->conn;
   svn_error_t *err;
   apr_pool_t *sess_pool;
-  ra_svn_session_baton_t *new_sess;
+  svn_ra_svn__session_baton_t *new_sess;
   apr_uri_t uri;
 
   SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "reparent", "c", url));
@@ -782,7 +680,7 @@
 static svn_error_t *ra_svn_get_latest_rev(svn_ra_session_t *session,
                                           svn_revnum_t *rev, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "get-latest-rev", ""));
@@ -795,7 +693,7 @@
                                          svn_revnum_t *rev, apr_time_t tm,
                                          apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "get-dated-rev", "c",
@@ -810,7 +708,7 @@
                                            const svn_string_t *value,
                                            apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "change-rev-prop", "rc?s",
@@ -823,7 +721,7 @@
 static svn_error_t *ra_svn_get_uuid(svn_ra_session_t *session, const char **uuid,
                                     apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   *uuid = conn->uuid;
@@ -833,7 +731,7 @@
 static svn_error_t *ra_svn_get_repos_root(svn_ra_session_t *session, const char **url,
                                           apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   if (!conn->repos_root)
@@ -846,7 +744,7 @@
 static svn_error_t *ra_svn_rev_proplist(svn_ra_session_t *session, svn_revnum_t rev,
                                         apr_hash_t **props, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   apr_array_header_t *proplist;
 
@@ -861,7 +759,7 @@
                                     const char *name,
                                     svn_string_t **value, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   SVN_ERR(svn_ra_svn_write_cmd(conn, pool, "rev-prop", "rc", rev, name));
@@ -897,7 +795,7 @@
                                   svn_boolean_t keep_locks,
                                   apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   ra_svn_commit_callback_baton_t *ccb;
   apr_hash_index_t *hi;
@@ -946,7 +844,7 @@
                                     apr_hash_t **props,
                                     apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   svn_ra_svn_item_t *item;
   apr_array_header_t *proplist;
@@ -1016,7 +914,7 @@
                                    apr_hash_t **props,
                                    apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   svn_revnum_t crev;
   apr_array_header_t *proplist, *dirlist;
@@ -1102,7 +1000,7 @@
                                   const svn_delta_editor_t *update_editor,
                                   void *update_baton, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   /* Tell the server we want to start an update. */
@@ -1125,7 +1023,7 @@
                                   const svn_delta_editor_t *update_editor,
                                   void *update_baton, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   /* Tell the server we want to start a switch. */
@@ -1148,7 +1046,7 @@
                                   const svn_delta_editor_t *status_editor,
                                   void *status_baton, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   /* Tell the server we want to start a status operation. */
@@ -1174,7 +1072,7 @@
                                 const svn_delta_editor_t *diff_editor,
                                 void *diff_baton, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
 
   /* Tell the server we want to start a diff. */
@@ -1199,7 +1097,7 @@
                                svn_log_message_receiver_t receiver,
                                void *receiver_baton, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   apr_pool_t *subpool;
   int i;
@@ -1283,7 +1181,7 @@
                                       const char *path, svn_revnum_t rev,
                                       svn_node_kind_t *kind, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   const char *kind_word;
 
@@ -1311,7 +1209,7 @@
                                 const char *path, svn_revnum_t rev,
                                 svn_dirent_t **dirent, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   apr_array_header_t *list = NULL;
   const char *kind, *cdate, *cauthor;
@@ -1359,7 +1257,7 @@
                                          apr_array_header_t *location_revisions,
                                          apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
   svn_revnum_t revision;
   svn_ra_svn_item_t *item;
@@ -1417,7 +1315,7 @@
                                          svn_ra_file_rev_handler_t handler,
                                          void *handler_baton, apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess_baton = session->priv;
+  svn_ra_svn__session_baton_t *sess_baton = session->priv;
   apr_pool_t *rev_pool, *chunk_pool;
   svn_ra_svn_item_t *item;
   const char *p;
@@ -1526,7 +1424,7 @@
                                        void *lock_baton,
                                        apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t* conn = sess->conn;
   apr_array_header_t *list;
   apr_hash_index_t *hi;
@@ -1590,7 +1488,7 @@
                                          void *lock_baton,
                                          apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t* conn = sess->conn;
   apr_hash_index_t *hi;
   apr_pool_t *iterpool = svn_pool_create(pool);
@@ -1649,7 +1547,7 @@
                                 void *lock_baton,
                                 apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t *conn = sess->conn;
   apr_hash_index_t *hi;
   svn_ra_svn_item_t *elt;
@@ -1770,7 +1668,7 @@
                                   void *lock_baton,
                                   apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t *conn = sess->conn;
   apr_hash_index_t *hi;
   apr_pool_t *subpool = svn_pool_create(pool);
@@ -1888,7 +1786,7 @@
                                     const char *path,
                                     apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t* conn = sess->conn;
   apr_array_header_t *list;
 
@@ -1913,7 +1811,7 @@
                                      const char *path,
                                      apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn__session_baton_t *sess = session->priv;
   svn_ra_svn_conn_t* conn = sess->conn;
   apr_array_header_t *list;
   int i;
@@ -1954,7 +1852,7 @@
                                   void *edit_baton,
                                   apr_pool_t *pool)
 {
-  ra_svn_session_baton_t *sess = session->priv;
+  svn_ra_svn__session_baton_t *sess = session->priv;
 
   SVN_ERR(svn_ra_svn_write_cmd(sess->conn, pool, "replay", "rrb", revision,
                                low_water_mark, send_deltas));
@@ -2030,6 +1928,10 @@
 
   *vtable = &ra_svn_vtable;
 
+#ifdef SVN_HAVE_SASL
+  SVN_ERR(svn_ra_svn__sasl_init());
+#endif
+
   return SVN_NO_ERROR;
 }
 
Index: subversion/libsvn_ra_svn/streams.c
===================================================================
--- subversion/libsvn_ra_svn/streams.c	(revision 0)
+++ subversion/libsvn_ra_svn/streams.c	(revision 0)
@@ -0,0 +1,251 @@
+/*
+ * streams.c :  Stream encapsulation routines for Subversion protocol
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2006 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+#define APR_WANT_STRFUNC
+#include <apr_want.h>
+#include <apr_general.h>
+#include <apr_lib.h>
+#include <apr_strings.h>
+#include <apr_network_io.h>
+#include <apr_poll.h>
+
+#include "svn_types.h"
+#include "svn_string.h"
+#include "svn_error.h"
+#include "svn_pools.h"
+#include "svn_io.h"
+#include "svn_private_config.h"
+
+#include "ra_svn.h"
+
+struct svn_ra_svn_stream {
+  svn_stream_t *stream;
+  void *baton;
+  pending_fn_t pending_fn;
+  timeout_fn_t timeout_fn;
+};
+
+typedef struct {
+  apr_descriptor d;
+  apr_pool_t *pool;
+} baton_t;
+
+/* Return whether or not there is data available for reading
+   descriptor DESC of type TYPE, using POOL for any necessary
+   allocations */
+static svn_boolean_t
+pending(apr_descriptor *desc, apr_datatype_e type, apr_pool_t *pool)
+{
+  apr_pollfd_t pfd;
+  apr_status_t status;
+  int n;
+
+  pfd.desc_type = type;
+  pfd.desc = *desc;
+  pfd.p = pool;
+  pfd.reqevents = APR_POLLIN;
+#ifdef AS400
+  status = apr_poll(&pfd, 1, &n, 0, pool);
+#else
+  status = apr_poll(&pfd, 1, &n, 0);
+#endif
+  return (status == APR_SUCCESS && n);
+}
+
+static svn_error_t *
+file_read_cb(void *baton, char *buffer, apr_size_t *len)
+{
+  baton_t *b = baton;
+  apr_status_t status = apr_file_read(b->d.f, buffer, len);
+  if (status && !APR_STATUS_IS_EOF(status))
+    return svn_error_wrap_apr(status, _("Can't read from connection"));
+  if (*len == 0)
+    return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL,
+                            _("Connection closed unexpectedly"));
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+file_write_cb(void *baton, const char *buffer, apr_size_t *len)
+{
+  baton_t *b = baton;
+  apr_status_t status = apr_file_write(b->d.f, buffer, len);
+  if (status)
+    return svn_error_wrap_apr(status, _("Can't write to connection"));
+  return SVN_NO_ERROR;
+}
+
+
+static void
+file_timeout_cb(void *baton, apr_interval_time_t interval)
+{
+  baton_t *b = baton;
+  apr_file_pipe_timeout_set(b->d.f, interval);
+}
+
+static svn_boolean_t
+file_pending_cb(void *baton)
+{
+  baton_t *b = baton;
+  return pending(&b->d, APR_POLL_FILE, b->pool);
+}
+
+
+void
+svn_ra_svn__stream_pair_from_files(apr_file_t *in_file, apr_file_t *out_file,
+                                   svn_ra_svn_stream_t **in_stream,
+                                   svn_ra_svn_stream_t **out_stream,
+                                   apr_pool_t *pool)
+{
+  baton_t *inb = apr_palloc(pool, sizeof(*inb));
+  baton_t *outb = apr_palloc(pool, sizeof(*outb));
+
+  inb->d.f = in_file;
+  inb->pool = pool;
+
+  outb->d.f = out_file;
+  outb->pool = pool;
+
+  *in_stream = svn_ra_svn__stream_create(inb, file_read_cb, NULL,
+                                         file_timeout_cb, file_pending_cb,
+                                         pool);
+  *out_stream = svn_ra_svn__stream_create(outb, NULL, file_write_cb,
+                                         file_timeout_cb, file_pending_cb,
+                                         pool);
+}
+
+
+static svn_error_t *
+sock_read_cb(void *baton, char *buffer, apr_size_t *len)
+{
+  baton_t *sb = baton;
+  apr_status_t status;
+  apr_socket_t *sock = sb->d.s;
+  apr_interval_time_t old_timeout;
+
+  apr_socket_timeout_get(sock, &old_timeout);
+  /* Always block on read. */
+  apr_socket_timeout_set(sock, -1);
+  status = apr_socket_recv(sock, buffer, len);
+  apr_socket_timeout_set(sock, old_timeout);
+  if (status && !APR_STATUS_IS_EOF(status))
+    return svn_error_wrap_apr(status, _("Can't read from connection"));
+  if (*len == 0)
+    return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL,
+                            _("Connection closed unexpectedly"));
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+sock_write_cb(void *baton, const char *buffer, apr_size_t *len)
+{
+  baton_t *sb = baton;
+
+  apr_status_t status = apr_socket_send(sb->d.s, buffer, len);
+  if (status)
+    return svn_error_wrap_apr(status, _("Can't write to connection"));
+  return SVN_NO_ERROR;
+}
+
+
+static void
+sock_timeout_cb(void *baton, apr_interval_time_t interval)
+{
+  baton_t *b = baton;
+  apr_socket_timeout_set(b->d.s, interval);
+}
+
+
+static svn_boolean_t
+sock_pending_cb(void *baton)
+{
+  baton_t *b = baton;
+  return pending(&b->d, APR_POLL_FILE, b->pool);
+}
+
+
+void
+svn_ra_svn__stream_pair_from_sock(apr_socket_t *sock,
+                                  svn_ra_svn_stream_t **in_stream,
+                                  svn_ra_svn_stream_t **out_stream,
+                                  apr_pool_t *pool)
+{
+  baton_t *sb = apr_palloc(pool, sizeof(*sb));
+
+  sb->d.s = sock;
+  sb->pool = pool;
+
+  *in_stream = svn_ra_svn__stream_create(sb, sock_read_cb, sock_write_cb,
+                                         sock_timeout_cb, sock_pending_cb,
+                                         pool);
+  *out_stream = *in_stream;
+}
+
+svn_ra_svn_stream_t *
+svn_ra_svn__stream_create(void *baton, svn_read_fn_t read_cb,
+                          svn_write_fn_t write_cb, timeout_fn_t timeout_cb,
+                          pending_fn_t pending_cb, apr_pool_t *pool)
+{
+  svn_ra_svn_stream_t *s = apr_palloc(pool, sizeof(*s));
+  s->stream = svn_stream_empty(pool);
+  svn_stream_set_baton(s->stream, baton);
+  if (read_cb)
+    svn_stream_set_read(s->stream, read_cb);
+  if (write_cb)
+    svn_stream_set_write(s->stream, write_cb);
+  s->baton = baton;
+  s->timeout_fn = timeout_cb;
+  s->pending_fn = pending_cb;
+  return s;
+}
+
+svn_error_t *
+svn_ra_svn__stream_write(svn_ra_svn_stream_t *stream,
+                         const char *data, apr_size_t *len)
+{
+  return svn_stream_write(stream->stream, data, len);
+}
+
+
+svn_error_t *
+svn_ra_svn__stream_read(svn_ra_svn_stream_t *stream, char *data,
+                        apr_size_t *len)
+{
+  return svn_stream_read(stream->stream, data, len);
+}
+
+
+void
+svn_ra_svn__stream_timeout(svn_ra_svn_stream_t *stream,
+                           apr_interval_time_t interval)
+{
+  stream->timeout_fn(stream->baton, interval);  
+}
+
+svn_boolean_t
+svn_ra_svn__stream_pending(svn_ra_svn_stream_t *stream)
+{
+  return stream->pending_fn(stream->baton);  
+}
Index: subversion/libsvn_ra_svn/ra_svn_sasl.h
===================================================================
--- subversion/libsvn_ra_svn/ra_svn_sasl.h	(revision 0)
+++ subversion/libsvn_ra_svn/ra_svn_sasl.h	(revision 0)
@@ -0,0 +1,59 @@
+/*
+ * ra_svn_sasl.h :  SASL-related declarations shared between the 
+ * ra_svn and svnserve module
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#ifndef RA_SVN_SASL_H
+#define RA_SVN_SASL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <sasl/sasl.h>
+
+#define DEFAULT_SECPROPS {0, 256, 4096, 0, NULL, NULL}
+
+/* This function is called by the client and the server before
+ * calling sasl_{client, server}_init */
+apr_status_t svn_ra_svn__sasl_common_init();
+
+/* Sets *hostname to the local or remote hostname (depending on 
+ * the value of want_local) and sets localaddr and remoteaddr 
+ * to a string containing the remote or local IP address/port, 
+ * formatted like this: a.b.c.d;port */
+void svn_ra_svn__get_addresses(svn_ra_svn_conn_t *conn,
+                               char **hostname, 
+                               char **localaddr, 
+                               char **remoteaddr,
+                               svn_boolean_t want_local,
+                               apr_pool_t *pool);
+
+/* Attempt to create a SASL security layer on conn.  Set *success
+ * to TRUE if a security layer is established, FALSE otherwise */
+svn_error_t*
+svn_ra_svn__create_security_layer(svn_ra_svn_conn_t *conn,
+                                  sasl_conn_t *sasl_ctx,
+                                  apr_pool_t *pool,
+                                  svn_boolean_t *success);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif  /* RA_SVN_SASL_H */
Index: subversion/libsvn_ra_svn/sasl_auth.c
===================================================================
--- subversion/libsvn_ra_svn/sasl_auth.c	(revision 0)
+++ subversion/libsvn_ra_svn/sasl_auth.c	(revision 0)
@@ -0,0 +1,697 @@
+/*
+ * sasl_auth.c :  Functions for SASL-based authentication
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2006 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+#define APR_WANT_STRFUNC
+#include <apr_want.h>
+#include <apr_general.h>
+#include <apr_strings.h>
+#include <apr_atomic.h>
+#include <apr_thread_mutex.h>
+#include <apr_version.h>
+
+#include "svn_types.h"
+#include "svn_string.h"
+#include "svn_error.h"
+#include "svn_pools.h"
+#include "svn_private_config.h"
+#include "svn_ra.h"
+#include "svn_ra_svn.h"
+#include "svn_base64.h"
+
+#include "ra_svn.h"
+#include "ra_svn_sasl.h"
+
+#ifdef SVN_HAVE_SASL
+
+/* Baton for a SASL stream connection. */
+typedef struct sasl_baton {
+  svn_ra_svn_stream_t *in;     /* Inherited input stream. */
+  svn_ra_svn_stream_t *out;    /* Inherited output stream. */
+  sasl_conn_t *ctx;            /* The SASL context for this connection. */
+  unsigned int maxsize;        /* The maximum amount of data we can encode */
+  const char *read_buf;        /* The buffer returned by sasl_decode */
+  unsigned int read_len;       /* Its current length */
+} sasl_baton_t;
+
+#ifdef APR_HAS_THREADS
+/* We allocate mutexes for SASL from this pool */
+static apr_pool_t *sasl_pool = NULL;
+
+/* An array of allocated, but unused, mutexes */
+static apr_array_header_t *free_mutexes = NULL;
+
+/* A mutex to serialize access to the array */
+static apr_thread_mutex_t *array_mutex;
+
+/* Callbacks we pass to sasl_set_mutex */
+static void *sasl_mutex_alloc_cb(void)
+{
+  apr_thread_mutex_t *mutex;
+  if (apr_is_empty_array(free_mutexes))
+    {
+      int r = apr_thread_mutex_create(&mutex,
+                                      APR_THREAD_MUTEX_DEFAULT, 
+                                      sasl_pool);
+      if (r != APR_SUCCESS)
+        return NULL;
+    }
+  else
+    {
+      apr_thread_mutex_lock(array_mutex);
+      mutex =  *((apr_thread_mutex_t**)apr_array_pop(free_mutexes));
+      apr_thread_mutex_unlock(array_mutex);
+    }
+  return mutex;
+}
+
+static int sasl_mutex_lock_cb(void *mutex)
+{
+  if (mutex)
+    return (apr_thread_mutex_lock(mutex) == APR_SUCCESS) ? 0 : -1;
+  else
+    return 0;
+}
+
+static int sasl_mutex_unlock_cb(void *mutex)
+{
+  if (mutex)
+    return (apr_thread_mutex_unlock(mutex) == APR_SUCCESS) ? 0 : -1;
+  else
+    return 0;
+}
+
+static void sasl_mutex_free_cb(void *mutex)
+{
+  apr_thread_mutex_lock(array_mutex);
+  *((apr_thread_mutex_t**)apr_array_push(free_mutexes)) = mutex;
+  apr_thread_mutex_unlock(array_mutex);
+}
+#endif /* APR_HAS_THREADS */
+
+static sasl_callback_t interactions[] =
+{
+  /* Use SASL interactions for username & password */
+  {SASL_CB_AUTHNAME, NULL, NULL}, 
+  {SASL_CB_PASS, NULL, NULL},
+  {SASL_CB_LIST_END, NULL, NULL}
+};
+
+static apr_status_t sasl_done_cb()
+{
+  sasl_done();
+  return APR_SUCCESS;
+}
+
+static apr_status_t sasl_dispose_cb(void* data)
+{
+  sasl_dispose((sasl_conn_t**) data);
+  return APR_SUCCESS;
+}
+
+apr_status_t svn_ra_svn__sasl_common_init()
+{
+  apr_status_t apr_err = APR_SUCCESS;
+#ifdef APR_HAS_THREADS
+  sasl_set_mutex(sasl_mutex_alloc_cb,
+                 sasl_mutex_lock_cb,
+                 sasl_mutex_unlock_cb,
+                 sasl_mutex_free_cb);
+  sasl_pool = svn_pool_create(NULL);
+  apr_pool_cleanup_register(sasl_pool, NULL, 
+                            &sasl_done_cb,
+                            apr_pool_cleanup_null);
+
+  free_mutexes = apr_array_make(sasl_pool, 0, sizeof(apr_thread_mutex_t *));
+  apr_err = apr_thread_mutex_create(&array_mutex,
+                                    APR_THREAD_MUTEX_DEFAULT, 
+                                    sasl_pool);
+#endif /* APR_HAS_THREADS */
+  return apr_err;
+}
+
+#if APR_MAJOR_VERSION > 0
+# define svn__atomic_t apr_uint32_t
+# define svn__atomic_cas(mem, with, cmp) \
+    apr_atomic_cas32((mem), (with), (cmp))
+#else
+# define svn__atomic_t apr_atomic_t
+# define svn__atomic_cas(mem, with, cmp) \
+    apr_atomic_cas((mem), (with), (cmp))
+#endif
+
+#define SASL_UNINITIALIZED 0
+#define SASL_START_INIT    1
+#define SASL_INIT_FAILED   2
+#define SASL_INITIALIZED   3
+
+static volatile svn__atomic_t sasl_status = SASL_UNINITIALIZED;
+
+svn_error_t *svn_ra_svn__sasl_init()
+{
+#ifdef APR_HAS_THREADS
+  svn__atomic_t status = svn__atomic_cas(&sasl_status, 
+                                         SASL_START_INIT, 
+                                         SASL_UNINITIALIZED);
+  if (status == SASL_UNINITIALIZED)
+#else
+  static svn_boolean_t initialized = FALSE;
+  if (! initialized)
+#endif /* APR_HAS_THREADS */
+    {
+      if (svn_ra_svn__sasl_common_init() != APR_SUCCESS
+          || sasl_client_init(interactions) != SASL_OK)
+        {
+#ifdef APR_HAS_THREADS
+          svn__atomic_cas(&sasl_status, SASL_INIT_FAILED, SASL_START_INIT);
+#endif /* APR_HAS_THREADS */
+          return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                  _("Could not initialize the SASL library"));
+        }
+#ifdef APR_HAS_THREADS
+      svn__atomic_cas(&sasl_status, SASL_INITIALIZED, SASL_START_INIT);
+#else
+      initialized = TRUE;
+#endif /* APR_HAS_THREADS */
+    }
+#ifdef APR_HAS_THREADS
+  /* Make sure that the other threads wait for
+     the initialization to finish */
+  else while (status != SASL_INITIALIZED)
+    {
+      if (status == SASL_INIT_FAILED)
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                _("Could not initialize the SASL library"));
+      apr_sleep(APR_USEC_PER_SEC / 1000);
+      status = svn__atomic_cas(&sasl_status, 
+                               SASL_UNINITIALIZED, 
+                               SASL_UNINITIALIZED);
+    }
+#endif /* APR_HAS_THREADS */
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *new_sasl_ctx(sasl_conn_t **sasl_ctx,
+                                 svn_boolean_t is_tunneled,
+                                 const char *hostname, const char *localaddr,
+                                 const char *remoteaddr, apr_pool_t *pool)
+{
+  sasl_security_properties_t secprops = DEFAULT_SECPROPS;
+  int result;
+
+  result = sasl_client_new("svn", hostname, localaddr, remoteaddr, 
+                           interactions, SASL_SUCCESS_DATA, 
+                           sasl_ctx);
+  if (result != SASL_OK)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            sasl_errdetail(*sasl_ctx));
+
+
+  if (is_tunneled)
+    {
+      /* We need to tell SASL that this connection is tunneled,
+       * otherwise it will ignore EXTERNAL. The third paramater
+       * should be the username, but since we are not actually sending
+       * it to the server, any non-empty string will do. */
+      result = sasl_setprop(*sasl_ctx, 
+                            SASL_AUTH_EXTERNAL, " ");
+      if (result != SASL_OK)
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                sasl_errdetail(*sasl_ctx));
+   }
+
+  /* Set security properties.
+   * Don't allow PLAIN or LOGIN, since we don't support TLS yet. */
+  secprops.security_flags = SASL_SEC_NOPLAINTEXT;
+  sasl_setprop(*sasl_ctx, SASL_SEC_PROPS, &secprops);
+
+  return SVN_NO_ERROR;
+}
+
+/* Get the username and password from the client */
+static svn_error_t* get_creds(svn_auth_iterstate_t **iterstate_p,
+                              svn_ra_svn__session_baton_t *sess,
+                              const char *realmstring,
+                              const char *last_err,
+                              const char **username, const char **password,
+                              apr_pool_t *pool)
+{
+  void *creds;
+
+  if (*iterstate_p == NULL)
+    SVN_ERR(svn_auth_first_credentials(&creds, iterstate_p,
+                                       SVN_AUTH_CRED_SIMPLE, realmstring,
+                                       sess->auth_baton, pool));
+  else
+    SVN_ERR(svn_auth_next_credentials(&creds, *iterstate_p, pool));
+
+  if (!creds)
+    return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                             _("Authentication error from server: %s"),
+                             last_err);
+
+  *username = ((svn_auth_cred_simple_t *)creds)->username;
+  *password = ((svn_auth_cred_simple_t *)creds)->password;
+  return SVN_NO_ERROR;
+}
+
+/* Fill in the information requested by client_interact */
+static svn_error_t *handle_interact(svn_auth_iterstate_t **iterstate_p,
+                                    svn_ra_svn__session_baton_t *sess,
+                                    sasl_interact_t *client_interact,
+                                    const char* realm,
+                                    svn_boolean_t append_realm,
+                                    const char *last_err,
+                                    apr_pool_t *pool)
+{
+  sasl_interact_t *prompt;
+  const char *username=NULL, *password=NULL;
+  const char *realmstring;
+
+  realmstring = realm ? 
+                apr_psprintf(pool, "%s %s", sess->realm_prefix, realm)
+                : sess->realm_prefix;
+
+  SVN_ERR(get_creds(iterstate_p, sess, realmstring, last_err,
+                    &username, &password, pool));
+
+  for (prompt = client_interact; prompt->id != SASL_CB_LIST_END; prompt++)
+    {
+      switch (prompt->id)
+        {
+        case SASL_CB_AUTHNAME:
+          if (append_realm)
+            prompt->result = apr_pstrcat(pool, username, "@", realm, NULL);
+          else
+            prompt->result = username;
+          prompt->len = strlen(username);
+          break;
+        case SASL_CB_PASS:
+          prompt->result = password;
+          prompt->len = strlen(password);
+          break;
+        default:
+          /* This should never be reached */
+          return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                  _("Unhandled SASL interaction"));
+          break;
+        }
+    }
+  return SVN_NO_ERROR;
+}
+
+/* Perform an authentication exchange */
+static svn_error_t *try_auth(svn_ra_svn__session_baton_t *sess,
+                             sasl_conn_t *sasl_ctx,
+                             svn_auth_iterstate_t **iterstate_p,
+                             svn_boolean_t *success,
+                             const char **last_err,
+                             const char *realm,
+                             const char *mechstring,
+                             svn_boolean_t compat,
+                             apr_pool_t *pool)
+{
+  sasl_interact_t *client_interact = NULL;
+  const char *out, *mech, *status = NULL;
+  const svn_string_t *arg = NULL, *in;
+  int result;
+  unsigned int outlen;
+  svn_boolean_t append_realm = FALSE;
+
+  do
+    {
+      result = sasl_client_start(sasl_ctx,
+                                 mechstring,
+                                 &client_interact,
+                                 &out,
+                                 &outlen,
+                                 &mech);
+
+      /* For some reason, SRP wants us to set the realm explicitly.
+       * We do this by appending @realm to the username. */
+      if (strcmp(mech, "SRP") == 0)
+        append_realm = TRUE;
+
+      /* Fill in username and password, if required */
+      if (result == SASL_INTERACT)
+        SVN_ERR(handle_interact(iterstate_p, sess, client_interact,
+                                realm, append_realm, *last_err, pool));
+    }
+  while (result == SASL_INTERACT);
+
+  if (result != SASL_OK && result != SASL_CONTINUE)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            sasl_errdetail(sasl_ctx));
+
+  /* Prepare the initial authentication token. */
+  if (outlen > 0) 
+    arg = svn_base64_encode_string(svn_string_ncreate(out, outlen, pool), 
+                                   pool);
+
+  /* Send the initial client response */
+  SVN_ERR(svn_ra_svn__auth_response(sess->conn, pool, mech, 
+                                    arg ? arg->data : NULL, compat));
+
+  while (result == SASL_CONTINUE) 
+    {
+      /* Read the server response */
+      SVN_ERR(svn_ra_svn_read_tuple(sess->conn, pool, "w(?s)", 
+                                    &status, &in));
+
+      if (strcmp(status, "failure") == 0)
+        {
+          /* Authentication failed.  Use the next set of credentials */
+          *success = FALSE;
+          /* Remember the message sent by the server because we'll want to
+           * return a meaningful error if we run out of auth providers */
+          *last_err = in ? in->data : "";
+          return SVN_NO_ERROR;
+        }
+
+      if ((strcmp(status, "success") != 0 && strcmp(status, "step") != 0) 
+          || in == NULL)
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                _("Unexpected server response to"
+                                " authentication"));
+
+      /* If the mech is CRAM-MD5 we don't base64-decode the server response */
+      if (strcmp(mech, "CRAM-MD5") != 0) 
+        in = svn_base64_decode_string(in, pool);
+ 
+      do
+        {
+          result = sasl_client_step(sasl_ctx, 
+                                    in->data,
+                                    in->len,
+                                    &client_interact, 
+                                    &out, /* filled in by SASL */
+                                    &outlen);
+
+          /* Fill in username and password, if required */
+          if (result == SASL_INTERACT)
+            SVN_ERR(handle_interact(iterstate_p, sess, client_interact, 
+                                    realm, append_realm, *last_err, pool));
+        }
+      while (result == SASL_INTERACT);
+
+      if (result != SASL_OK && result != SASL_CONTINUE)
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                sasl_errdetail(sasl_ctx));
+
+      if (outlen > 0)
+        {
+          arg = svn_string_ncreate(out, outlen, pool); 
+          /* Write our response.
+           * The check is for backward compatibility */
+          if (strcmp(mech, "CRAM-MD5") != 0)
+            arg = svn_base64_encode_string(arg, pool);
+          SVN_ERR(svn_ra_svn_write_cstring(sess->conn, pool, arg->data));
+        }
+    }
+
+  if (!status || strcmp(status, "step") == 0)
+    {
+      /* This is a client-send-last mech.  Read the last server response. */
+      SVN_ERR(svn_ra_svn_read_tuple(sess->conn, pool, "w(?s)", 
+              &status, &in));
+
+      if (strcmp(status, "failure") == 0)
+        {
+          *success = FALSE;
+          *last_err = in ? in->data : "";
+        }
+      else if (strcmp(status, "success") == 0)
+        {
+          /* We're done */
+          *success = TRUE;
+        }
+      else
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                _("Unexpected server response"
+                                " to authentication"));
+    }
+  else
+    *success = TRUE;
+  return SVN_NO_ERROR;
+}
+
+void svn_ra_svn__get_addresses(svn_ra_svn_conn_t *conn,
+                               char **hostname, 
+                               char **localaddr, 
+                               char **remoteaddr,
+                               svn_boolean_t want_local,
+                               apr_pool_t *pool)
+{
+  apr_sockaddr_t *local_sa, *remote_sa;
+  char *localip, *remoteip;
+ 
+  apr_socket_addr_get(&local_sa, APR_LOCAL, conn->sock);
+  apr_socket_addr_get(&remote_sa, APR_REMOTE, conn->sock);
+
+  apr_getnameinfo(hostname, want_local ? local_sa : remote_sa, 0);
+
+  apr_sockaddr_ip_get(&localip, local_sa);
+  apr_sockaddr_ip_get(&remoteip, remote_sa);
+
+  /* Format the IP address and port number like this: a.b.c.d;port */
+  *localaddr = apr_pstrcat(pool, localip, ";",
+                           apr_itoa(pool, (int)local_sa->port), NULL);
+  *remoteaddr = apr_pstrcat(pool, remoteip, ";", 
+                            apr_itoa(pool, (int)remote_sa->port), NULL);
+}
+
+static void sasl_timeout_cb(void *baton, apr_interval_time_t interval)
+{
+  sasl_baton_t *sasl_baton = baton;
+  svn_ra_svn__stream_timeout(sasl_baton->out, interval);
+}
+
+static svn_boolean_t sasl_pending_cb(void *baton)
+{
+  sasl_baton_t *sasl_baton = baton;
+  return svn_ra_svn__stream_pending(sasl_baton->in);
+}
+
+static svn_error_t *sasl_read_cb(void *baton, char *buffer, apr_size_t *len)
+{
+  sasl_baton_t *sasl_baton = baton;
+  int result; 
+  unsigned int len2 = *len;
+
+  /* sasl_decode might need more data than a single read can provide,
+   * hence the need to put a loop around the decoding */
+  while (! sasl_baton->read_buf || sasl_baton->read_len == 0)
+    {
+      SVN_ERR(svn_ra_svn__stream_read(sasl_baton->in, buffer, &len2));
+      result = sasl_decode(sasl_baton->ctx, buffer, len2, 
+                           &sasl_baton->read_buf, 
+                           &sasl_baton->read_len);
+      if (result != SASL_OK)
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                sasl_errdetail(sasl_baton->ctx));
+    }
+
+  /* The buffer returned by sasl_decode might be larger than what the 
+   * caller wants.  If this is the case, we only copy back *len bytes now
+   * (the rest will be returned by subsequent calls to this function).
+   * If not, we just copy back the whole thing. */
+  if (*len >= sasl_baton->read_len)
+    {
+      memcpy(buffer, sasl_baton->read_buf, sasl_baton->read_len);
+      *len = sasl_baton->read_len;
+      sasl_baton->read_buf = NULL;
+      sasl_baton->read_len = 0;
+    }
+  else
+    {
+      memcpy(buffer, sasl_baton->read_buf, *len);
+      sasl_baton->read_len -= *len;
+      sasl_baton->read_buf += *len;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *sasl_write_cb(void *baton, const char *buffer, apr_size_t *len)
+{
+  sasl_baton_t *sasl_baton = baton;
+  const char *encoded_data;
+  int result; 
+  unsigned int len2, tmplen;
+
+  /* Make sure we don't write too much. */
+  *len = (*len > sasl_baton->maxsize) ? sasl_baton->maxsize : *len;
+  result = sasl_encode(sasl_baton->ctx, buffer, *len, &encoded_data, &len2);
+
+  if (result != SASL_OK)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            sasl_errdetail(sasl_baton->ctx));
+
+  do 
+    {
+      tmplen = len2;
+      SVN_ERR(svn_ra_svn__stream_write(sasl_baton->out, encoded_data, &tmplen));
+      len2 -= tmplen;
+      encoded_data += tmplen;
+    } 
+  while (len2 > 0);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t* svn_ra_svn__create_security_layer(svn_ra_svn_conn_t *conn,
+                                               sasl_conn_t *sasl_ctx,
+                                               apr_pool_t *pool,
+                                               svn_boolean_t *success)
+{
+  sasl_baton_t *sasl_baton;
+  const sasl_ssf_t *ssfp;
+  int result;
+  const unsigned int *maxsize;
+
+  *success = FALSE;
+
+  if (! conn->is_encrypted)
+    {
+      /* Get the strength of the security layer. */
+      result = sasl_getprop(sasl_ctx, SASL_SSF, (void*) &ssfp);
+      if (result != SASL_OK)
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                sasl_errdetail(sasl_ctx));
+
+      if (*ssfp > 0)
+        {
+          /* Yay, we have a security layer! */
+          *success = TRUE;
+          conn->is_encrypted = TRUE;
+
+          /* Now would be a good time to flush the connection. */
+          SVN_ERR(svn_ra_svn_flush(conn, pool));
+
+          /* Find out the maximum input size for sasl_encode. */
+          result = sasl_getprop(sasl_ctx, SASL_MAXOUTBUF, (const void **) &maxsize);
+          if (result != SASL_OK)
+            return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                    sasl_errdetail(sasl_ctx));
+
+          /* Create and initialize the stream baton. */
+          sasl_baton = apr_palloc(pool, sizeof(*sasl_baton));
+
+          sasl_baton->ctx = sasl_ctx;
+          sasl_baton->maxsize = *maxsize;
+
+          sasl_baton->read_buf = NULL;
+          sasl_baton->read_len = 0;
+
+          /* Wrap the existing stream. */
+          sasl_baton->in = conn->in_stream;
+          sasl_baton->out = conn->out_stream;
+
+          apr_pool_cleanup_register(pool, &sasl_baton->ctx,
+                                    sasl_dispose_cb,
+                                    apr_pool_cleanup_null);
+
+          conn->in_stream = svn_ra_svn__stream_create(sasl_baton, sasl_read_cb,
+                                                      sasl_write_cb, sasl_timeout_cb,
+                                                      sasl_pending_cb, pool);
+          conn->out_stream = conn->in_stream;
+        }
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *svn_ra_svn__handle_auth(svn_ra_svn__session_baton_t *sess,
+                                     apr_array_header_t *mechlist,
+                                     const char *realm, apr_pool_t *pool)
+{
+  apr_pool_t *subpool;
+  sasl_conn_t *sasl_ctx;
+  const char *mechstring = "", *last_err = "";
+  svn_ra_svn_item_t *elt;
+  svn_auth_iterstate_t *iterstate = NULL;
+  svn_boolean_t success, compat = (realm == NULL);
+  char *hostname = NULL, *localaddr = NULL, *remoteaddr = NULL;
+  int i;
+
+  if (!sess->is_tunneled)
+    svn_ra_svn__get_addresses(sess->conn, &hostname, 
+                              &localaddr, &remoteaddr, 
+                              FALSE, pool);
+
+  subpool = svn_pool_create(pool);
+
+  /* Create a string containing the list of mechanisms, separated by spaces. */
+  for (i = 0; i < mechlist->nelts; i++)
+    {
+      elt = &APR_ARRAY_IDX(mechlist, i, svn_ra_svn_item_t);
+
+      /* Force the client to use ANONYMOUS if it is available. */
+      if (strcmp(elt->u.word, "ANONYMOUS") == 0)
+        {
+          mechstring = "ANONYMOUS";
+          break;
+        }
+
+      mechstring = apr_pstrcat(subpool, 
+                               mechstring, 
+                               i == 0 ? "" : " ", 
+                               elt->u.word, NULL);
+    }
+
+  do
+    {
+      /* We shouldn't have to create a new SASL context for each
+       * authentication attempt, but it seems that sasl_client_start
+       * forgets to initialise some data structures.  This means that
+       * the library will treat calls to sasl_client_step as if they were part
+       * of the previous auth exchange, which will obviously fail. */
+      SVN_ERR(new_sasl_ctx(&sasl_ctx, sess->is_tunneled,
+                           hostname, localaddr, remoteaddr, 
+                           pool));
+
+      SVN_ERR(try_auth(sess,
+                       sasl_ctx,
+                       &iterstate,
+                       &success,
+                       &last_err,
+                       realm,
+                       mechstring,
+                       compat,
+                       subpool));
+
+      if (! success)
+        {
+          /* Dispose of this SASL context before creating a new one. */
+          sasl_dispose(&sasl_ctx);
+        }
+    }
+  while (! success);
+
+  SVN_ERR(svn_auth_save_credentials(iterstate, pool));
+
+  SVN_ERR(svn_ra_svn__create_security_layer(sess->conn, sasl_ctx,
+                                            pool, &success));
+  /* If we couldn't establish a security layer, destroy the SASL context
+   * since we don't need it any more. */
+  if (! success)
+    sasl_dispose(&sasl_ctx);
+
+  svn_pool_destroy(subpool);
+  return SVN_NO_ERROR;
+}
+
+#endif /* SVN_HAVE_SASL */
Index: subversion/libsvn_ra_svn/marshal.c
===================================================================
--- subversion/libsvn_ra_svn/marshal.c	(revision 20489)
+++ subversion/libsvn_ra_svn/marshal.c	(working copy)
@@ -34,6 +34,7 @@
 #include "svn_error.h"
 #include "svn_pools.h"
 #include "svn_ra_svn.h"
+#include "svn_io.h"
 #include "svn_private_config.h"
 
 #include "ra_svn.h"
@@ -51,8 +52,6 @@
 
   assert((sock && !in_file && !out_file) || (!sock && in_file && out_file));
   conn->sock = sock;
-  conn->in_file = in_file;
-  conn->out_file = out_file;
   conn->read_ptr = conn->read_buf;
   conn->read_end = conn->read_buf;
   conn->write_pos = 0;
@@ -60,6 +59,16 @@
   conn->block_baton = NULL;
   conn->capabilities = apr_hash_make(pool);
   conn->pool = pool;
+#ifdef SVN_HAVE_SASL
+  conn->is_encrypted = FALSE;
+#endif
+
+  if (sock != NULL)
+    svn_ra_svn__stream_pair_from_sock(sock, &conn->in_stream,
+                                      &conn->out_stream, pool);
+  else
+    svn_ra_svn__stream_pair_from_files(in_file, out_file, &conn->in_stream,
+                                       &conn->out_stream, pool);
   return conn;
 }
 
@@ -98,36 +107,13 @@
 
   conn->block_handler = handler;
   conn->block_baton = baton;
-  if (conn->sock)
-    apr_socket_timeout_set(conn->sock, interval);
-  else
-    apr_file_pipe_timeout_set(conn->out_file, interval);
+  svn_ra_svn__stream_timeout(conn->out_stream, interval);
 }
 
 svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn,
                                         apr_pool_t *pool)
 {
-  apr_pollfd_t pfd;
-  int n;
-
-  if (conn->sock)
-    {
-      pfd.desc_type = APR_POLL_SOCKET;
-      pfd.desc.s = conn->sock;
-    }
-  else
-    {
-      pfd.desc_type = APR_POLL_FILE;
-      pfd.desc.f = conn->in_file;
-    }
-  pfd.p = pool;
-  pfd.reqevents = APR_POLLIN;
-#ifndef AS400
-  return ((apr_poll(&pfd, 1, &n, 0) == APR_SUCCESS) && n);
-#else
-  /* OS400 requires a pool argument for apr_poll(). */
-  return ((apr_poll(&pfd, 1, &n, 0, pool) == APR_SUCCESS) && n);
-#endif
+  return svn_ra_svn__stream_pending(conn->in_stream);
 }
 
 /* --- WRITE BUFFER MANAGEMENT --- */
@@ -151,19 +137,13 @@
                                     const char *data, apr_size_t len)
 {
   const char *end = data + len;
-  apr_status_t status;
   apr_size_t count;
   apr_pool_t *subpool = NULL;
 
   while (data < end)
     {
       count = end - data;
-      if (conn->sock)
-        status = apr_socket_send(conn->sock, data, &count);
-      else
-        status = apr_file_write(conn->out_file, data, &count);
-      if (status)
-        return svn_error_wrap_apr(status, _("Can't write to connection"));
+      SVN_ERR(svn_ra_svn__stream_write(conn->out_stream, data, &count));
       if (count == 0)
         {
           if (!subpool)
@@ -244,19 +224,7 @@
 static svn_error_t *readbuf_input(svn_ra_svn_conn_t *conn, char *data,
                                   apr_size_t *len)
 {
-  apr_status_t status;
-
-  /* Always block for reading. */
-  if (conn->sock && conn->block_handler)
-    apr_socket_timeout_set(conn->sock, -1);
-  if (conn->sock)
-    status = apr_socket_recv(conn->sock, data, len);
-  else
-    status = apr_file_read(conn->in_file, data, len);
-  if (conn->sock && conn->block_handler)
-    apr_socket_timeout_set(conn->sock, 0);
-  if (status && !APR_STATUS_IS_EOF(status))
-    return svn_error_wrap_apr(status, _("Can't read from connection"));
+  SVN_ERR(svn_ra_svn__stream_read(conn->in_stream, data, len));
   if (*len == 0)
     return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL,
                             _("Connection closed unexpectedly"));
Index: subversion/libsvn_ra_svn/simple_auth.c
===================================================================
--- subversion/libsvn_ra_svn/simple_auth.c	(revision 0)
+++ subversion/libsvn_ra_svn/simple_auth.c	(revision 0)
@@ -0,0 +1,122 @@
+/*
+ * trivial_auth.c :  Fallback functions for SASL-based authentication
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2006 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+#define APR_WANT_STRFUNC
+#include <apr_want.h>
+#include <apr_general.h>
+#include <apr_strings.h>
+
+#include "svn_types.h"
+#include "svn_string.h"
+#include "svn_error.h"
+#include "svn_private_config.h"
+#include "svn_ra.h"
+#include "svn_ra_svn.h"
+
+#include "ra_svn.h"
+
+#ifndef SVN_HAVE_SASL
+
+static svn_boolean_t find_mech(apr_array_header_t *mechlist, const char *mech)
+{
+  int i;
+  svn_ra_svn_item_t *elt;
+
+  for (i = 0; i < mechlist->nelts; i++)
+    {
+      elt = &APR_ARRAY_IDX(mechlist, i, svn_ra_svn_item_t);
+      if (elt->kind == SVN_RA_SVN_WORD && strcmp(elt->u.word, mech) == 0)
+        return TRUE;
+    }
+  return FALSE;
+}
+
+/* Read the "success" response to ANONYMOUS or EXTERNAL authentication. */
+static svn_error_t *read_success(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
+{
+  const char *status, *arg;
+
+  SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "w(?c)", &status, &arg));
+  if (strcmp(status, "failure") == 0 && arg)
+    return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                             _("Authentication error from server: %s"), arg);
+  else if (strcmp(status, "success") != 0 || arg)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            _("Unexpected server response to authentication"));
+  return SVN_NO_ERROR;
+}
+
+/* Respond to an auth request and perform authentication.  REALM may
+ * be NULL for the initial authentication exchange of protocol version
+ * 1. */
+svn_error_t *svn_ra_svn__handle_auth(svn_ra_svn__session_baton_t *sess,
+                            apr_array_header_t *mechlist,
+                            const char *realm, apr_pool_t *pool)
+{
+  svn_ra_svn_conn_t *conn = sess->conn;
+  const char *realmstring, *user, *password, *msg;
+  svn_auth_iterstate_t *iterstate;
+  void *creds;
+  svn_boolean_t compat = (realm == NULL);
+
+  realmstring = realm ? apr_psprintf(pool, "%s %s", sess->realm_prefix, realm)
+    : sess->realm_prefix;
+
+  if (sess->is_tunneled && find_mech(mechlist, "EXTERNAL"))
+    {
+        /* Ask the server to use the tunnel connection environment (on
+        * Unix, that means uid) to determine the authentication name. */
+      SVN_ERR(svn_ra_svn__auth_response(conn, pool, "EXTERNAL", "", compat));
+      return read_success(conn, pool);
+    }
+  else if (find_mech(mechlist, "ANONYMOUS"))
+    {
+      SVN_ERR(svn_ra_svn__auth_response(conn, pool, "ANONYMOUS", "", compat));
+      return read_success(conn, pool);
+    }
+  else if (find_mech(mechlist, "CRAM-MD5"))
+    {
+      SVN_ERR(svn_auth_first_credentials(&creds, &iterstate,
+                                        SVN_AUTH_CRED_SIMPLE, realmstring,
+                                        sess->auth_baton, pool));
+      if (!creds)
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                _("Can't get password"));
+      while (creds)
+        {
+          user = ((svn_auth_cred_simple_t *) creds)->username;
+          password = ((svn_auth_cred_simple_t *) creds)->password;
+          SVN_ERR(svn_ra_svn__auth_response(conn, pool, "CRAM-MD5", NULL, compat));
+          SVN_ERR(svn_ra_svn__cram_client(conn, pool, user, password, &msg));
+          if (!msg)
+            break;
+          SVN_ERR(svn_auth_next_credentials(&creds, iterstate, pool));
+        }
+      if (!creds)
+        return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                _("Authentication error from server: %s"),
+                                msg);
+      SVN_ERR(svn_auth_save_credentials(iterstate, pool));
+      return SVN_NO_ERROR;
+    }
+  else
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            _("Cannot negotiate authentication mechanism"));
+}
+
+#endif /* SVN_HAVE_SASL */
Index: subversion/libsvn_ra_svn/ra_svn.h
===================================================================
--- subversion/libsvn_ra_svn/ra_svn.h	(revision 20489)
+++ subversion/libsvn_ra_svn/ra_svn.h	(working copy)
@@ -30,19 +30,23 @@
 #include <apr_thread_proc.h>
 #include "svn_ra_svn.h"
 
+typedef svn_boolean_t (*pending_fn_t)(void *baton);
+
+typedef void (*timeout_fn_t)(void *baton, apr_interval_time_t timeout);
+
+typedef struct svn_ra_svn_stream svn_ra_svn_stream_t;
+
 /* Handler for blocked writes. */
 typedef svn_error_t *(*ra_svn_block_handler_t)(svn_ra_svn_conn_t *conn,
                                                apr_pool_t *pool,
                                                void *baton);
 
-
 /* This structure is opaque to the server.  The client pokes at the
  * first few fields during setup and cleanup. */
 struct svn_ra_svn_conn_st {
   apr_socket_t *sock;     /* NULL if using in_file/out_file */
-  apr_file_t *in_file;
-  apr_file_t *out_file;
-  apr_proc_t *proc;       /* Used by client.c when sock is NULL */
+  svn_ra_svn_stream_t *in_stream;
+  svn_ra_svn_stream_t *out_stream;
   char read_buf[4096];
   char *read_ptr;
   char *read_end;
@@ -54,8 +58,22 @@
   void *block_baton;
   apr_hash_t *capabilities;
   apr_pool_t *pool;
+#ifdef SVN_HAVE_SASL
+  svn_boolean_t is_encrypted;
+#endif
 };
 
+typedef struct {
+  apr_pool_t *pool;
+  svn_ra_svn_conn_t *conn;
+  int protocol_version;
+  svn_boolean_t is_tunneled;
+  struct svn_auth_baton_t *auth_baton;
+  const char *user;
+  const char *realm_prefix;
+  const char **tunnel_argv;
+} svn_ra_svn__session_baton_t;
+
 /* Set a callback for blocked writes on conn.  This handler may
  * perform reads on the connection in order to prevent deadlock due to
  * pipelining.  If callback is NULL, the connection goes back to
@@ -95,6 +113,58 @@
 svn_error_t *svn_ra_svn__handle_failure_status(apr_array_header_t *params,
                                                apr_pool_t *pool);
 
+/* Set *in and *out to streams that are mapped onto operations on sock. */
+void svn_ra_svn__stream_pair_from_sock(apr_socket_t *sock,
+                                       svn_ra_svn_stream_t **in,
+                                       svn_ra_svn_stream_t **out,
+                                       apr_pool_t *pool);
+
+/* Set *in and *out to streams that are mapped onto operations on in_file
+   and out_file, respectively. */
+void svn_ra_svn__stream_pair_from_files(apr_file_t *in_file,
+                                        apr_file_t *out_file,
+                                        svn_ra_svn_stream_t **in,
+                                        svn_ra_svn_stream_t **out,
+                                        apr_pool_t *pool);
+
+svn_ra_svn_stream_t *svn_ra_svn__stream_create(void *baton,
+                                               svn_read_fn_t read_cb,
+                                               svn_write_fn_t write_cb,
+                                               timeout_fn_t timeout_cb,
+                                               pending_fn_t pending_cb,
+                                               apr_pool_t *pool);
+
+svn_error_t *svn_ra_svn__stream_write(svn_ra_svn_stream_t *stream,
+                                      const char *data, apr_size_t *len);
+
+svn_error_t *svn_ra_svn__stream_read(svn_ra_svn_stream_t *stream,
+                                     char *data, apr_size_t *len);
+
+/* Set the timeout for operations on STREAM to INTERVAL. */
+void svn_ra_svn__stream_timeout(svn_ra_svn_stream_t *stream,
+                                apr_interval_time_t interval);
+
+/* Return whether or not there is data pending on STREAM. */
+svn_boolean_t svn_ra_svn__stream_pending(svn_ra_svn_stream_t *stream);
+
+/* Respond to an auth request and perform authentication.  REALM may
+ * be NULL for the initial authentication exchange of protocol version
+ * 1. */
+svn_error_t *svn_ra_svn__handle_auth(svn_ra_svn__session_baton_t *sess,
+                              apr_array_header_t *mechlist,
+                              const char *realm, apr_pool_t *pool);
+
+/* Having picked a mechanism, start authentication by writing out an
+ * auth response.  If COMPAT is true, also write out a version number
+ * and capability list.  MECH_ARG may be NULL for mechanisms with no
+ * initial client response. */
+svn_error_t *svn_ra_svn__auth_response(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                                       const char *mech, const char *mech_arg,
+                                       svn_boolean_t compat);
+
+/* Initialize the SASL library */
+svn_error_t *svn_ra_svn__sasl_init();
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: subversion/svnserve/sasl_auth.c
===================================================================
--- subversion/svnserve/sasl_auth.c	(revision 0)
+++ subversion/svnserve/sasl_auth.c	(revision 0)
@@ -0,0 +1,267 @@
+/*
+ * sasl_auth.c :  Functions for SASL-based authentication
+ *
+ * ====================================================================
+ * Copyright (c) 2000-2006 CollabNet.  All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.  The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals.  For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+#define APR_WANT_STRFUNC
+#include <apr_want.h>
+#include <apr_general.h>
+#include <apr_strings.h>
+
+#include "svn_private_config.h"  /* For SVN_HAVE_SASL */
+#include "svn_types.h"
+#include "svn_string.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_ra_svn.h"
+#include "svn_base64.h"
+
+#include "server.h"
+
+#ifdef SVN_HAVE_SASL
+
+#include "../libsvn_ra_svn/ra_svn_sasl.h"
+
+static sasl_callback_t interactions[] =
+{
+  {SASL_CB_LIST_END, NULL, NULL}
+};
+
+svn_error_t *sasl_init()
+{
+  int result;
+  apr_status_t err = svn_ra_svn__sasl_common_init();
+  if (err)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            _("Could not initialize the SASL library"));
+
+  /* "Subversion" is the application name.  SASL will read its configuration
+   * from a file called Subversion.conf in a path specified at build time */
+  result = sasl_server_init(interactions, "Subversion");
+  if (result != SASL_OK)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            sasl_errstring(result, NULL, NULL));
+  return SVN_NO_ERROR;
+}
+
+/* Tell the client the authentication failed */
+static svn_error_t *fail(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                         const char *msg)
+{
+  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(c)", "failure", msg));
+  return svn_ra_svn_flush(conn, pool);
+}
+
+static svn_error_t *try_auth(svn_ra_svn_conn_t *conn, 
+                             sasl_conn_t *sasl_ctx,
+                             apr_pool_t *pool,
+                             server_baton_t *b,
+                             svn_boolean_t *success)
+{
+  const char *out, *mech;
+  const svn_string_t *arg = NULL, *in;
+  unsigned int outlen;
+  int result;
+  svn_boolean_t use_base64;
+
+  *success = TRUE;
+
+  /* Read the client's chosen mech and the initial response */
+  SVN_ERR(svn_ra_svn_read_tuple(conn, pool, "w(?s)", &mech, &in));
+
+  if (strcmp(mech, "EXTERNAL") == 0 && !in)
+    in = svn_string_create(b->tunnel_user, pool);
+  else if (in)
+    in = svn_base64_decode_string(in, pool);
+
+  /* For CRAM-MD5, we don't base64-encode stuff */
+  use_base64 = (strcmp(mech, "CRAM-MD5") != 0);
+
+  result = sasl_server_start(sasl_ctx, mech, 
+                             in ? in->data : NULL, 
+                             in ? in->len : 0, &out, &outlen);
+
+  if (result != SASL_OK && result != SASL_CONTINUE) 
+    {
+      *success = FALSE;
+      return fail(conn, pool, sasl_errdetail(sasl_ctx));
+    }
+
+  while (result == SASL_CONTINUE)
+    {
+      svn_ra_svn_item_t *item;
+
+      arg = svn_string_ncreate(out, outlen, pool);
+      /* Encode what we send to the client */
+      if (use_base64)
+        arg = svn_base64_encode_string(arg, pool);
+  
+      SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(s)", "step", arg));
+
+      /* Read and decode the client response */
+      SVN_ERR(svn_ra_svn_read_item(conn, pool, &item));
+      if (item->kind != SVN_RA_SVN_STRING)
+        {
+          *success = FALSE;
+          return SVN_NO_ERROR;
+        }
+      in = item->u.string;
+      if (use_base64)
+        in = svn_base64_decode_string(in, pool);
+      result = sasl_server_step(sasl_ctx, in->data, in->len, &out, &outlen);
+    }
+
+  if (result != SASL_OK) 
+    {
+      *success = FALSE;
+      return fail(conn, pool, sasl_errdetail(sasl_ctx));
+    }
+
+  /* Send our last response, if necessary */
+  if (outlen)
+    arg = svn_base64_encode_string(svn_string_ncreate(out, outlen, pool),
+                                   pool);
+  else
+    arg = NULL;
+
+  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w(?s)", "success", arg));
+
+  return SVN_NO_ERROR; 
+}
+
+svn_error_t *sasl_auth_request(svn_ra_svn_conn_t *conn, 
+                               apr_pool_t *pool,
+                               server_baton_t *b, 
+                               enum access_type required,
+                               svn_boolean_t needs_username)
+{
+  sasl_conn_t *sasl_ctx;
+  char *hostname = NULL, *localaddr = NULL, *remoteaddr = NULL, *p;
+  const char *mechlist, *val;
+  sasl_security_properties_t secprops = DEFAULT_SECPROPS;
+  svn_boolean_t success, no_anonymous;
+  int mech_count, result = SASL_OK;
+
+  if (! b->tunnel_user)
+    svn_ra_svn__get_addresses(conn, &hostname, 
+                              &localaddr, &remoteaddr, 
+                              TRUE, pool);
+
+  /* Create a SASL context */
+  result = sasl_server_new("svn", 
+                           hostname, b->realm, 
+                           localaddr, remoteaddr,
+                           NULL, SASL_SUCCESS_DATA,
+                           &sasl_ctx);
+  if (result != SASL_OK)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            sasl_errdetail(sasl_ctx));
+
+  /* Don't allow PLAIN or LOGIN, since we don't support TLS yet. */
+  secprops.security_flags = SASL_SEC_NOPLAINTEXT;
+
+  no_anonymous = needs_username || get_access(b, UNAUTHENTICATED) < required;
+  /* Don't allow ANONYMOUS if a username is required */
+  if (no_anonymous)
+    secprops.security_flags |= SASL_SEC_NOANONYMOUS;
+
+  svn_config_get(b->cfg, &val, 
+                 SVN_CONFIG_SECTION_SASL,
+                 SVN_CONFIG_OPTION_MIN_ENC_STRENGTH,
+                 "0");
+  secprops.min_ssf = atoi(val);
+
+  svn_config_get(b->cfg, &val, 
+                 SVN_CONFIG_SECTION_SASL,
+                 SVN_CONFIG_OPTION_MAX_ENC_STRENGTH,
+                 "0");
+  secprops.max_ssf = atoi(val);
+
+  /* Set security properties. */
+  result = sasl_setprop(sasl_ctx, SASL_SEC_PROPS, &secprops);
+  if (result != SASL_OK)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            sasl_errdetail(sasl_ctx));
+
+  /* Tell SASL if we are externally authenticated */
+  if (b->tunnel_user)
+    result = sasl_setprop(sasl_ctx, SASL_AUTH_EXTERNAL, b->tunnel_user);
+  if (result != SASL_OK)
+    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                            sasl_errdetail(sasl_ctx));
+
+  /* Get the list of mechanisms */
+  result = sasl_listmech(sasl_ctx, NULL, NULL, " ", NULL, 
+                         &mechlist, NULL, &mech_count);
+
+  if (result != SASL_OK || mech_count == 0)
+    {
+      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                          _("Could not obtain the list"
+                                          " of SASL mechanisms"));
+      svn_ra_svn_write_cmd_failure(conn, pool, err);
+      SVN_ERR(svn_ra_svn_flush(conn, pool));
+      return err;
+    }
+
+  /* Send the list of mechanisms and the realm to the client */
+  SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w((w)c)", "success",
+                                 mechlist, b->realm));
+
+  apr_pool_t *subpool = svn_pool_create(pool);
+  do
+    {
+      svn_pool_clear(subpool);
+      SVN_ERR(try_auth(conn, sasl_ctx, subpool, b, &success));
+    }
+  while (! success);
+  svn_pool_destroy(subpool);
+
+  if (no_anonymous)
+    {
+      const char *user, *realm;
+
+      /* Get the authenticated username */
+      result = sasl_getprop(sasl_ctx, SASL_USERNAME, (const void **)&user);
+
+      if ((p = strchr(user, '@')) != NULL)
+        {
+          b->user = apr_pstrndup(pool, user, p - user);
+          realm = p + 1;
+        }
+      else
+        return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                "SASL gave us a malformed username");
+
+      if (strcmp(realm, b->realm) != 0)
+        {
+          /* The user authenticated successfully, but to the wrong realm */
+          return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                                   "The user %s authenticated to "
+                                       "the wrong realm: %s",
+                                   b->user, realm);
+        }
+    }
+
+  SVN_ERR(svn_ra_svn__create_security_layer(conn, sasl_ctx, 
+                                            pool, &success));
+  if (! success)
+    sasl_dispose(&sasl_ctx);
+
+  return SVN_NO_ERROR;
+}
+
+#endif /* SVN_HAVE_SASL */
Index: subversion/svnserve/serve.c
===================================================================
--- subversion/svnserve/serve.c	(revision 20489)
+++ subversion/svnserve/serve.c	(working copy)
@@ -32,7 +32,6 @@
 #include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_ra_svn.h"
-#include "svn_repos.h"
 #include "svn_path.h"
 #include "svn_time.h"
 #include "svn_md5.h"
@@ -43,25 +42,7 @@
 #include "server.h"
 
 typedef struct {
-  svn_repos_t *repos;
-  svn_fs_t *fs;            /* For convenience; same as svn_repos_fs(repos) */
-  svn_config_t *cfg;       /* Parsed repository svnserve.conf */
-  svn_config_t *pwdb;      /* Parsed password database */
-  svn_authz_t *authzdb;    /* Parsed authz rules */
-  const char *authz_repos_name; /* The name of the repository */
-  const char *realm;       /* Authentication realm */
-  const char *repos_url;   /* URL to base of repository */
-  svn_stringbuf_t *fs_path;/* Decoded base path inside repository */
-  const char *user;
-  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) */
-  int protocol_version;
   apr_pool_t *pool;
-} server_baton_t;
-
-typedef struct {
-  apr_pool_t *pool;
   svn_revnum_t *new_rev;
   const char **date;
   const char **author;
@@ -85,9 +66,6 @@
   apr_pool_t *pool;  /* Pool provided in the handler call. */
 } file_revs_baton_t;
 
-enum authn_type { UNAUTHENTICATED, AUTHENTICATED };
-enum access_type { NO_ACCESS, READ_ACCESS, WRITE_ACCESS };
-
 /* Verify that URL is inside REPOS_URL and get its fs path. Assume that 
    REPOS_URL and URL are already URI-decoded. */
 static svn_error_t *get_fs_path(const char *repos_url, const char *url,
@@ -182,7 +160,7 @@
 }
 
 
-static enum access_type get_access(server_baton_t *b, enum authn_type auth)
+enum access_type get_access(server_baton_t *b, enum authn_type auth)
 {
   const char *var = (auth == AUTHENTICATED) ? SVN_CONFIG_OPTION_AUTH_ACCESS :
     SVN_CONFIG_OPTION_ANON_ACCESS;
@@ -317,9 +295,11 @@
  * REQUIRED or higher.  Since the client may escape the authentication
  * exchange, the caller should check current_access(b) to see if
  * authentication succeeded. */
-static svn_error_t *auth_request(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                 server_baton_t *b, enum access_type required,
-                                 svn_boolean_t needs_username)
+static svn_error_t *simple_auth_request(svn_ra_svn_conn_t *conn, 
+                                        apr_pool_t *pool,
+                                        server_baton_t *b, 
+                                        enum access_type required,
+                                        svn_boolean_t needs_username)
 {
   svn_boolean_t success;
   const char *mech, *mecharg;
@@ -339,6 +319,19 @@
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *auth_request(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                                 server_baton_t *b, enum access_type required,
+                                 svn_boolean_t needs_username)
+{
+#ifdef SVN_HAVE_SASL
+  if (b->use_sasl)
+    SVN_ERR(sasl_auth_request(conn, pool, b, required, needs_username));
+  else
+#endif
+  SVN_ERR(simple_auth_request(conn, pool, b, required, needs_username));
+  return SVN_NO_ERROR;
+}
+
 /* Send a trivial auth notification on CONN which lists no mechanisms,
  * indicating that authentication is unnecessary.  Usually called in
  * response to invocation of a svnserve command.
@@ -437,7 +430,11 @@
      the first time round. */
   if (b->user == NULL
       && get_access(b, AUTHENTICATED) >= req
-      && (b->tunnel_user || b->pwdb) && b->protocol_version >= 2)
+      && (b->tunnel_user || b->pwdb 
+#ifdef SVN_HAVE_SASL
+          || b->use_sasl
+#endif
+      ) && b->protocol_version >= 2)
     SVN_ERR(auth_request(conn, pool, b, req, TRUE));
 
   /* Now that an authentication has been done get the new take of
@@ -2151,15 +2148,18 @@
         svn_error_clear(err);
       else if (err)
         return err;
-      else
-        {
-          /* Use the repository UUID as the default realm. */
-          SVN_ERR(svn_fs_get_uuid(b->fs, &b->realm, pool));
-          svn_config_get(b->cfg, &b->realm, SVN_CONFIG_SECTION_GENERAL,
-                         SVN_CONFIG_OPTION_REALM, b->realm);
-        }
     }
 
+#ifdef SVN_HAVE_SASL
+  svn_config_get_bool(b->cfg, &b->use_sasl, SVN_CONFIG_SECTION_SASL,
+                      SVN_CONFIG_OPTION_USE_SASL, FALSE);
+#endif
+
+  /* Use the repository UUID as the default realm. */
+  SVN_ERR(svn_fs_get_uuid(b->fs, &b->realm, pool));
+  svn_config_get(b->cfg, &b->realm, SVN_CONFIG_SECTION_GENERAL,
+                 SVN_CONFIG_OPTION_REALM, b->realm);
+
   /* Read authz configuration. */
   svn_config_get(b->cfg, &authz_path, SVN_CONFIG_SECTION_GENERAL,
                  SVN_CONFIG_OPTION_AUTHZ_DB, NULL);
Index: subversion/svnserve/main.c
===================================================================
--- subversion/svnserve/main.c	(revision 20489)
+++ subversion/svnserve/main.c	(working copy)
@@ -329,6 +329,11 @@
   if (svn_cmdline_init("svnserve", stderr) != EXIT_SUCCESS)
     return EXIT_FAILURE;
 
+#ifdef SVN_HAVE_SASL
+  /* Initialize the SASL library. */
+  sasl_init();
+#endif
+
   /* Create our top-level pool. */
   pool = svn_pool_create(NULL);
 
Index: subversion/svnserve/server.h
===================================================================
--- subversion/svnserve/server.h	(revision 20489)
+++ subversion/svnserve/server.h	(working copy)
@@ -27,6 +27,32 @@
 extern "C" {
 #endif /* __cplusplus */
 
+#include "svn_repos.h"
+
+typedef struct {
+  svn_repos_t *repos;
+  svn_fs_t *fs;            /* For convenience; same as svn_repos_fs(repos) */
+  svn_config_t *cfg;       /* Parsed repository svnserve.conf */
+  svn_config_t *pwdb;      /* Parsed password database */
+  svn_authz_t *authzdb;    /* Parsed authz rules */
+  const char *authz_repos_name; /* The name of the repository */
+  const char *realm;       /* Authentication realm */
+  const char *repos_url;   /* URL to base of repository */
+  svn_stringbuf_t *fs_path;/* Decoded base path inside repository */
+  const char *user;
+  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) */
+  int protocol_version;
+  apr_pool_t *pool;
+#ifdef SVN_HAVE_SASL
+  svn_boolean_t use_sasl;
+#endif
+} server_baton_t;
+
+enum authn_type { UNAUTHENTICATED, AUTHENTICATED };
+enum access_type { NO_ACCESS, READ_ACCESS, WRITE_ACCESS };
+
 typedef struct serve_params_t {
   /* The virtual root of the repositories to serve.  The client URL
      path is interpreted relative to this root and is not allowed to
@@ -51,6 +77,18 @@
 svn_error_t *serve(svn_ra_svn_conn_t *conn, serve_params_t *params,
                    apr_pool_t *pool);
 
+enum access_type get_access(server_baton_t *b, enum authn_type auth);
+
+/* Initialize the Cyrus SASL library */
+svn_error_t *sasl_init();
+
+/* Authenticate using Cyrus SASL */
+svn_error_t *sasl_auth_request(svn_ra_svn_conn_t *conn, 
+                               apr_pool_t *pool,
+                               server_baton_t *b, 
+                               enum access_type required,
+                               svn_boolean_t needs_username);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
