[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] Cache ssl client cert passphrase in gnome-keyring

From: Senthil Kumaran S <senthil_at_collab.net>
Date: Fri, 30 May 2008 16:50:15 +0530

Hi Arfrever,

Arfrever Frehtes Taifersar Arahesis wrote:
>> Index: subversion/libsvn_auth_gnome_keyring/gnome_keyring.c
>> ===================================================================
>> --- subversion/libsvn_auth_gnome_keyring/gnome_keyring.c (revision 31507)
>> +++ subversion/libsvn_auth_gnome_keyring/gnome_keyring.c (working copy)
>> @@ -189,3 +189,60 @@
>>
>> gnome_keyring_init();
>> }
>> +
>> +/* Get cached encrypted credentials from the ssl client cert password
>> + * provider's cache. */
>> +static svn_error_t *
>> +gnome_keyring_ssl_client_cert_pw_first_creds(void **credentials,
>> + void **iter_baton,
>> + void *provider_baton,
>> + apr_hash_t *parameters,
>> + const char *realmstring,
>> + apr_pool_t *pool)
>> +{
>> + return svn_auth__ssl_client_cert_pw_file_first_creds_helper
>> + (credentials,
>> + iter_baton, provider_baton,
>> + parameters, realmstring,
>> + gnome_keyring_password_get,
>> + SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
>> + pool);
>> +}
>> +
>> +/* Save encrypted credentials to the ssl client cert password provider's
>> + * cache. */
>> +static svn_error_t *
>> +gnome_keyring_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
>> + void *credentials,
>> + void *provider_baton,
>> + apr_hash_t *parameters,
>> + const char *realmstring,
>> + apr_pool_t *pool)
>> +{
>> + return svn_auth__ssl_client_cert_pw_file_save_creds_helper
>> + (saved, credentials,
>> + provider_baton, parameters,
>> + realmstring,
>> + gnome_keyring_password_set,
>> + SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
>> + pool);
>> +}
>
> You use gnome_keyring_password_get() and gnome_keyring_password_set().
> Won't it cause collision with passwords stored by GNOME Keyring simple provider?

No it wont't cause a collision since we have realmstring to differentiate. I
verified it.

Updated patch attached as per your other comments.

-- 
Senthil Kumaran S
http://www.stylesen.org/

[[[
Cache ssl client certificate passphrase.

* subversion/libsvn_ra/ra_loader.c
  (svn_ra_open3): Load config options for storing passphrase from servers
   config file.

* subversion/libsvn_subr/config_file.c
  (ensure_auth_dirs): Create new auth dir to store ssl client cert passphrase.
  (svn_config_ensure): Add doc for the new options in the servers file string.

* subversion/libsvn_subr/cmdline.c
  (get_auth_simple_provider): Rename ...
  (get_auth_provider): ... Return providers based on the provider_type.
  (svn_cmdline_setup_auth_baton): If we have gnome keyring support get the
   corresponding ssl client cert passphrase provider.

* subversion/libsvn_subr/ssl_client_cert_pw_providers.c
  (): Include some private headers. Define SVN_AUTH__AUTHFILE_PASSPHRASE_KEY,
   SVN_AUTH__AUTHFILE_PASSTYPE_KEY.
  (ssl_client_cert_pw_file_provider_baton_t): New baton for ssl client cert
   passphrase provider.
  (simple_passphrase_get): New function to get plaintext passphrase.
  (simple_passphrase_set): New function to store plaintext passphrase.
  (ssl_client_cert_pw_file_first_credentials): Move logic to new helper.
  (ssl_client_cert_pw_file_save_credentials): Move logic to new helper.
  (svn_auth__ssl_client_cert_pw_file_first_creds_helper): New helper function
   for ssl_client_cert_pw_file_first_credentials.
  (svn_auth__ssl_client_cert_pw_file_save_creds_helper): New helper function
   for ssl_client_cert_pw_file_save_credentials.
  (ssl_client_cert_pw_file_provider): Add provision for saving credentials.
  (svn_auth_get_ssl_client_cert_pw_file_provider2): New public API which has
   a prompt function now.
  (svn_auth_get_ssl_client_cert_pw_file_provider): Update API for the above.

* subversion/libsvn_subr/prompt.c
  (plaintext_prompt_helper): New function which has the logic for plaintext
   promting functions.
  (svn_cmdline_auth_plaintext_prompt): Move logic to above function.
  (svn_cmdline_auth_plaintext_passphrase_prompt): New prompt function for
   plaintext passphrase prompt.

* subversion/libsvn_auth_gnome_keyring/gnome_keyring.c
  (gnome_keyring_ssl_client_cert_pw_first_creds): New function to get ssl
   client cert passphrase from encrypted credentials.
  (gnome_keyring_ssl_client_cert_pw_save_creds): New function to save
   encrypted ssl client cert passphrase.
  (gnome_keyring_ssl_client_cert_pw_provider): New baton.
  (svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider): New public API for
   gnome keyring based ssl client cert passphrase storage and retrieval.

* subversion/include/svn_config.h
  (SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP): New option to store ssl client
   cert passphrase.
  (SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSPHRASE): New option to store plaintext
   passphrase.
  (SVN_CONFIG_DEFAULT_OPTION_STORE_PASSPHRASE): New default option for storing
   passphrase set to 'yes'.
  (SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSPHRASE): New default option to
   store plaintext passphrase set to 'ask'.

* subversion/include/svn_auth_dso.h
  (svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider): New public API.

* subversion/include/svn_cmdline.h
  (svn_cmdline_auth_plaintext_passphrase_prompt): New public API added to
   prompt for storing plaintext passphrases.

* subversion/include/private/svn_auth_private.h
  (svn_auth__ssl_client_cert_pw_file_first_creds_helper): New private function.
  (svn_auth__ssl_client_cert_pw_file_save_creds_helper): New private function.

* subversion/include/svn_auth.h
  (svn_auth_ssl_client_cert_pw_provider_func_t): Define function type for the
   provider.
  (svn_auth_plaintext_passphrase_prompt_func_t): New function prototype.
  (SVN_AUTH_PARAM_DONT_STORE_PASSPHRASE): New constant.
  (SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSPHRASE): New constant.
  (svn_auth_get_ssl_client_cert_pw_file_provider2): New public API.

* subversion/libsvn_ra_neon/session.c
  (client_ssl_decrypt_cert): Call svn_auth_save_credentials to save the ssl
   client certificate passphrase.

Patch by: stylesen
]]]
Index: subversion/libsvn_ra/ra_loader.c
===================================================================
--- subversion/libsvn_ra/ra_loader.c (revision 31532)
+++ subversion/libsvn_ra/ra_loader.c (working copy)
@@ -401,6 +401,9 @@
   svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
   const char *store_plaintext_passwords
     = SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
+ const char *store_plaintext_passphrase
+ = SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSPHRASE;
+ svn_boolean_t store_passphrase = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSPHRASE;
 
   if (callbacks->auth_baton)
     {
@@ -447,6 +450,16 @@
              SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS));
 
           SVN_ERR(svn_config_get_bool
+ (servers, &store_passphrase, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
+ store_passphrase));
+
+ SVN_ERR(svn_config_get_yes_no_ask
+ (servers, &store_plaintext_passphrase, SVN_CONFIG_SECTION_GLOBAL,
+ SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSPHRASE,
+ SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSPHRASE));
+
+ SVN_ERR(svn_config_get_bool
             (servers, &store_auth_creds, SVN_CONFIG_SECTION_GLOBAL,
               SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
               store_auth_creds));
@@ -483,6 +496,16 @@
                 (servers, &store_plaintext_passwords, server_group,
                  SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
                  store_plaintext_passwords));
+
+ SVN_ERR(svn_config_get_bool
+ (servers, &store_passphrase,
+ server_group, SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
+ store_passphrase));
+
+ SVN_ERR(svn_config_get_yes_no_ask
+ (servers, &store_plaintext_passphrase, server_group,
+ SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSPHRASE,
+ store_plaintext_passphrase));
             }
 #ifdef MUST_CHOOSE_DAV
           /* Now, which DAV-based RA method do we want to use today? */
@@ -513,6 +536,14 @@
                              SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
                              store_plaintext_passwords);
 
+ if (! store_passphrase)
+ svn_auth_set_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_DONT_STORE_PASSPHRASE, "");
+
+ svn_auth_set_parameter(callbacks->auth_baton,
+ SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSPHRASE,
+ store_plaintext_passphrase);
+
       if (! store_auth_creds)
         svn_auth_set_parameter(callbacks->auth_baton,
                                SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
Index: subversion/libsvn_subr/config_file.c
===================================================================
--- subversion/libsvn_subr/config_file.c (revision 31532)
+++ subversion/libsvn_subr/config_file.c (working copy)
@@ -497,6 +497,15 @@
       svn_error_clear(err);
       svn_error_clear(svn_io_dir_make(auth_subdir, APR_OS_DEFAULT, pool));
     }
+
+ auth_subdir = svn_path_join_many(pool, auth_dir,
+ SVN_AUTH_CRED_SSL_CLIENT_CERT_PW, NULL);
+ err = svn_io_check_path(auth_subdir, &kind, pool);
+ if (err || kind == svn_node_none)
+ {
+ svn_error_clear(err);
+ svn_error_clear(svn_io_dir_make(auth_subdir, APR_OS_DEFAULT, pool));
+ }
 }
 
 
@@ -757,7 +766,12 @@
         "### to disk in any way." NL
         "### store-plaintext-passwords Specifies whether passwords may" NL
         "### be cached on disk unencrypted." NL
- "###" NL
+ "### store-ssl-client-cert-pp Specifies whether passphrase used" NL
+ "### to authenticate against a client" NL
+ "### certificate may be cached to disk" NL
+ "### in any way" NL
+ "### store-plaintext-passphrase Specifies whether passphrases may" NL
+ "### be cached on disk unencrypted." NL
         "### store-auth-creds Specifies whether any auth info" NL
         "### (passwords as well as server certs)"
                                                                              NL
@@ -780,6 +794,24 @@
         "### this option has no effect if either 'store-passwords' or " NL
         "### 'store-auth-creds' is set to 'no'." NL
         "###" NL
+ "### Set store-ssl-client-cert-pp to 'no' to avoid storing ssl" NL
+ "### client certificate passphrase in the auth/ area of your" NL
+ "### config directory. It defaults to 'yes', but Subversion will" NL
+ "### never save your passphrase to disk in plaintext unless you tell"NL
+ "### it to." NL
+ "### Note that this option only prevents saving of *new* passphrase;"NL
+ "### it doesn't invalidate existing passphrase. (To do that, remove" NL
+ "### the cache files by hand as described in the Subversion book.)" NL
+ "###" NL
+ "### Set store-plaintext-passphrase to 'no' to avoid storing" NL
+ "### passphrase in unencrypted form in the auth/ area of your config"NL
+ "### directory. Set it to 'yes' to allow Subversion to store" NL
+ "### unencrypted passphrase in the auth/ area. The default is" NL
+ "### 'ask', which means that Subversion will ask you before" NL
+ "### saving a passphrase to disk in unencrypted form. Note that" NL
+ "### this option has no effect if either 'store-passphrase' or " NL
+ "### 'store-auth-creds' is set to 'no'." NL
+ "###" NL
         "### Set store-auth-creds to 'no' to avoid storing any Subversion" NL
         "### credentials in the auth/ area of your config directory." NL
         "### Note that this includes SSL server certificates." NL
Index: subversion/libsvn_subr/cmdline.c
===================================================================
--- subversion/libsvn_subr/cmdline.c (revision 31532)
+++ subversion/libsvn_subr/cmdline.c (working copy)
@@ -355,11 +355,12 @@
 }
 
 #if defined(SVN_HAVE_KWALLET) || defined(SVN_HAVE_GNOME_KEYRING)
-/* Dynamically load authentication simple provider. */
+/* Dynamically load authentication provider. */
 static svn_boolean_t
-get_auth_simple_provider(svn_auth_provider_object_t **provider,
- const char *provider_name,
- apr_pool_t *pool)
+get_auth_provider(svn_auth_provider_object_t **provider,
+ const char *provider_name,
+ const char *provider_type,
+ apr_pool_t *pool)
 {
   apr_dso_handle_t *dso;
   apr_dso_handle_sym_t symbol;
@@ -372,8 +373,9 @@
                          provider_name,
                          SVN_VER_MAJOR);
   funcname = apr_psprintf(pool,
- "svn_auth_get_%s_simple_provider",
- provider_name);
+ "svn_auth_get_%s_%s_provider",
+ provider_name, provider_type);
+
   err = svn_dso_load(&dso, libname);
   if (err == SVN_NO_ERROR)
     {
@@ -381,10 +383,20 @@
         {
           if (! apr_dso_sym(&symbol, dso, funcname))
             {
- svn_auth_simple_provider_func_t func;
- func = (svn_auth_simple_provider_func_t) symbol;
- func(provider, pool);
- ret = TRUE;
+ if (strcmp(provider_type, "simple") == 0)
+ {
+ svn_auth_simple_provider_func_t func;
+ func = (svn_auth_simple_provider_func_t) symbol;
+ func(provider, pool);
+ ret = TRUE;
+ }
+ else if (strcmp(provider_type, "ssl_client_cert_pw") == 0)
+ {
+ svn_auth_ssl_client_cert_pw_provider_func_t func;
+ func = (svn_auth_ssl_client_cert_pw_provider_func_t) symbol;
+ func(provider, pool);
+ ret = TRUE;
+ }
             }
         }
     }
@@ -464,10 +476,16 @@
       if (apr_strnatcmp(password_store, "gnome-keyring") == 0)
         {
 #ifdef SVN_HAVE_GNOME_KEYRING
- if (get_auth_simple_provider(&provider, "gnome_keyring", pool))
+ if (get_auth_provider(&provider, "gnome_keyring", "simple", pool))
             {
               APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
             }
+ if (get_auth_provider(&provider, "gnome_keyring",
+ "ssl_client_cert_pw", pool))
+ {
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *)
+ = provider;
+ }
 #endif
           continue;
         }
@@ -475,7 +493,7 @@
       if (apr_strnatcmp(password_store, "kwallet") == 0)
         {
 #ifdef SVN_HAVE_KWALLET
- if (get_auth_simple_provider(&provider, "kwallet", pool))
+ if (get_auth_provider(&provider, "kwallet", pool))
             {
               APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
             }
@@ -490,10 +508,8 @@
 
   if (non_interactive == FALSE)
     {
- /* This provider is odd in that it isn't a prompting provider in
- the classic sense. That is, it doesn't need to prompt in
- order to get creds, but it *does* need to prompt the user
- regarding the *cache storage* of creds. */
+ /* This provider doesn't prompt the user in order to get creds.
+ * It prompts the user regarding the caching of creds. */
       svn_auth_get_simple_provider2(&provider,
                                     svn_cmdline_auth_plaintext_prompt,
                                     pb, pool);
@@ -515,7 +531,20 @@
   APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
   svn_auth_get_ssl_client_cert_file_provider(&provider, pool);
   APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
- svn_auth_get_ssl_client_cert_pw_file_provider(&provider, pool);
+
+ if (non_interactive == FALSE)
+ {
+ /* This provider doesn't prompt the user in order to get creds.
+ * It prompts the user regarding the caching of creds. */
+ svn_auth_get_ssl_client_cert_pw_file_provider2
+ (&provider, svn_cmdline_auth_plaintext_passphrase_prompt,
+ pb, pool);
+ }
+ else
+ {
+ svn_auth_get_ssl_client_cert_pw_file_provider2(&provider, NULL, NULL,
+ pool);
+ }
   APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
 
   if (non_interactive == FALSE)
Index: subversion/libsvn_subr/ssl_client_cert_pw_providers.c
===================================================================
--- subversion/libsvn_subr/ssl_client_cert_pw_providers.c (revision 31532)
+++ subversion/libsvn_subr/ssl_client_cert_pw_providers.c (working copy)
@@ -28,31 +28,112 @@
 #include "svn_error.h"
 #include "svn_config.h"
 
+#include "private/svn_auth_private.h"
+
+#include "svn_private_config.h"
 
 /*-----------------------------------------------------------------------*/
 /* File provider */
 /*-----------------------------------------------------------------------*/
 
-/* retrieve and load a password for a client certificate from servers file */
-static svn_error_t *
-ssl_client_cert_pw_file_first_credentials(void **credentials_p,
- void **iter_baton,
- void *provider_baton,
- apr_hash_t *parameters,
- const char *realmstring,
- apr_pool_t *pool)
+/* The keys that will be stored on disk */
+#define SVN_AUTH__AUTHFILE_PASSPHRASE_KEY "passphrase"
+#define SVN_AUTH__AUTHFILE_PASSTYPE_KEY "passtype"
+
+/* Baton type for the ssl client cert passphrase provider. */
+typedef struct
 {
+ svn_auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func;
+ void *prompt_baton;
+ /* We cache the user's answer to the plaintext prompt, keyed
+ * by realm, in case we'll be called multiple times for the
+ * same realm. */
+ apr_hash_t *plaintext_answers;
+} ssl_client_cert_pw_file_provider_baton_t;
+
+/* Implementation of svn_auth__password_get_t that retrieves
+ the plaintext passphrase from CREDS. */
+static svn_boolean_t
+simple_passphrase_get(const char **passphrase,
+ apr_hash_t *creds,
+ const char *realmstring,
+ const char *username,
+ svn_boolean_t non_interactive,
+ apr_pool_t *pool)
+{
+ svn_string_t *str;
+ str = apr_hash_get(creds, SVN_AUTH__AUTHFILE_PASSPHRASE_KEY,
+ APR_HASH_KEY_STRING);
+ if (str && str->data)
+ {
+ *passphrase = str->data;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Implementation of svn_auth__password_set_t that stores
+ the plaintext passphrase in CREDS. */
+static svn_boolean_t
+simple_passphrase_set(apr_hash_t *creds,
+ const char *realmstring,
+ const char *username,
+ const char *passphrase,
+ svn_boolean_t non_interactive,
+ apr_pool_t *pool)
+{
+ apr_hash_set(creds, SVN_AUTH__AUTHFILE_PASSPHRASE_KEY, APR_HASH_KEY_STRING,
+ svn_string_create(passphrase, pool));
+ return TRUE;
+}
+
+/* retrieve and load a password for a client certificate from servers file,
+ * else from the auth/ cache. */
+svn_error_t *
+svn_auth__ssl_client_cert_pw_file_first_creds_helper
+ (void **credentials_p,
+ void **iter_baton,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ svn_auth__password_get_t passphrase_get,
+ const char *passtype,
+ apr_pool_t *pool)
+{
   svn_config_t *cfg = apr_hash_get(parameters,
                                    SVN_AUTH_PARAM_CONFIG,
                                    APR_HASH_KEY_STRING);
   const char *server_group = apr_hash_get(parameters,
                                           SVN_AUTH_PARAM_SERVER_GROUP,
                                           APR_HASH_KEY_STRING);
-
+ svn_boolean_t non_interactive = apr_hash_get(parameters,
+ SVN_AUTH_PARAM_NON_INTERACTIVE,
+ APR_HASH_KEY_STRING) != NULL;
   const char *password =
     svn_config_get_server_setting(cfg, server_group,
                                   SVN_CONFIG_OPTION_SSL_CLIENT_CERT_PASSWORD,
                                   NULL);
+ if (! password)
+ {
+ svn_error_t *err;
+ apr_hash_t *creds_hash = NULL;
+ const char *config_dir = apr_hash_get(parameters,
+ SVN_AUTH_PARAM_CONFIG_DIR,
+ APR_HASH_KEY_STRING);
+
+ /* Try to load passphrase from the auth/ cache. */
+ err = svn_config_read_auth_data(&creds_hash,
+ SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
+ realmstring, config_dir, pool);
+ svn_error_clear(err);
+ if (! err && creds_hash)
+ {
+ if (!passphrase_get(&password, creds_hash, realmstring,
+ NULL, non_interactive, pool))
+ password = NULL;
+ }
+ }
+
   if (password)
     {
       svn_auth_cred_ssl_client_cert_pw_t *cred
@@ -67,23 +148,244 @@
 }
 
 
+/* Save passphrase for a client certificate in auth/ cache */
+svn_error_t *
+svn_auth__ssl_client_cert_pw_file_save_creds_helper
+ (svn_boolean_t *saved,
+ void *credentials,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ svn_auth__password_set_t passphrase_set,
+ const char *passtype,
+ apr_pool_t *pool)
+{
+ svn_auth_cred_ssl_client_cert_pw_t *creds = credentials;
+ apr_hash_t *creds_hash = NULL;
+ const char *config_dir;
+ svn_error_t *err;
+ svn_boolean_t dont_store_passphrase =
+ apr_hash_get(parameters,
+ SVN_AUTH_PARAM_DONT_STORE_PASSPHRASE,
+ APR_HASH_KEY_STRING) != NULL;
+ const char *store_plaintext_passphrase =
+ apr_hash_get(parameters,
+ SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSPHRASE,
+ APR_HASH_KEY_STRING);
+ svn_boolean_t non_interactive = apr_hash_get(parameters,
+ SVN_AUTH_PARAM_NON_INTERACTIVE,
+ APR_HASH_KEY_STRING) != NULL;
+ ssl_client_cert_pw_file_provider_baton_t *b =
+ (ssl_client_cert_pw_file_provider_baton_t *)provider_baton;
+
+ svn_boolean_t no_auth_cache =
+ (! creds->may_save) || (apr_hash_get(parameters,
+ SVN_AUTH_PARAM_NO_AUTH_CACHE,
+ APR_HASH_KEY_STRING) != NULL);
+
+ *saved = FALSE;
+
+ if (no_auth_cache)
+ return SVN_NO_ERROR;
+
+ config_dir = apr_hash_get(parameters,
+ SVN_AUTH_PARAM_CONFIG_DIR,
+ APR_HASH_KEY_STRING);
+ creds_hash = apr_hash_make(pool);
+
+ /* Don't store passphrase in any form if the user has told
+ * us not to do so. */
+ if (! dont_store_passphrase)
+ {
+ svn_boolean_t may_save_passphrase = FALSE;
+
+ /* If the passphrase is going to be stored encrypted, go right
+ * ahead and store it to disk. Else determine whether saving
+ * in plaintext is OK. */
+ if (strcmp(passtype, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE) == 0)
+ {
+ may_save_passphrase = TRUE;
+ }
+ else
+ {
+ if (svn_cstring_casecmp(store_plaintext_passphrase,
+ SVN_CONFIG_ASK) == 0)
+ {
+ if (non_interactive)
+ /* In non-interactive mode, the default behaviour is
+ * to not store the passphrase */
+ may_save_passphrase = FALSE;
+ else if (b->plaintext_passphrase_prompt_func)
+ {
+ /* We're interactive, and the client provided a
+ * prompt callback. So we can ask the user.
+ *
+ * Check for a cached answer before prompting. */
+ svn_boolean_t *cached_answer;
+ cached_answer = apr_hash_get(b->plaintext_answers,
+ realmstring,
+ APR_HASH_KEY_STRING);
+ if (cached_answer)
+ may_save_passphrase = *cached_answer;
+ else
+ {
+ /* Nothing cached for this realm, prompt the user. */
+ SVN_ERR((*b->plaintext_passphrase_prompt_func)
+ (&may_save_passphrase,
+ realmstring,
+ b->prompt_baton,
+ pool));
+
+ /* Cache the user's answer in case we're called again
+ * for the same realm.
+ *
+ * XXX: Hopefully, our caller has passed us
+ * a pool that survives across RA sessions!
+ * We use that pool to cache user answers, and
+ * we may be called again for the same realm when the
+ * current RA session is reparented, or when a different
+ * RA session using the same realm is opened.
+ * If the pool does not survive until then, caching
+ * won't work, and for some reason the call to
+ * apr_hash_set() below may even end up crashing in
+ * apr_palloc().
+ */
+ cached_answer = apr_palloc(pool, sizeof(svn_boolean_t));
+ *cached_answer = may_save_passphrase;
+ apr_hash_set(b->plaintext_answers, realmstring,
+ APR_HASH_KEY_STRING, cached_answer);
+ }
+ }
+ else
+ {
+ may_save_passphrase = FALSE;
+ }
+ }
+ else if (svn_cstring_casecmp(store_plaintext_passphrase,
+ SVN_CONFIG_FALSE) == 0)
+ {
+ may_save_passphrase = FALSE;
+ }
+ else if (svn_cstring_casecmp(store_plaintext_passphrase,
+ SVN_CONFIG_TRUE) == 0)
+ {
+ may_save_passphrase = TRUE;
+ }
+ else
+ {
+ return svn_error_createf
+ (SVN_ERR_RA_DAV_INVALID_CONFIG_VALUE, NULL,
+ _("Config error: invalid value '%s' for option '%s'"),
+ store_plaintext_passphrase,
+ SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSPHRASE);
+ }
+ }
+
+ if (may_save_passphrase)
+ {
+ *saved = passphrase_set(creds_hash, realmstring,
+ NULL, creds->password,
+ non_interactive, pool);
+
+ if (*saved && passtype)
+ /* Store the passphrase type with the auth data, so that we
+ know which provider owns the password. */
+ apr_hash_set(creds_hash, SVN_AUTH__AUTHFILE_PASSTYPE_KEY,
+ APR_HASH_KEY_STRING,
+ svn_string_create(passtype, pool));
+
+ /* Save credentials to disk. */
+ err = svn_config_write_auth_data(creds_hash,
+ SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
+ realmstring, config_dir, pool);
+ svn_error_clear(err);
+ *saved = ! err;
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Get cached (unencrypted) credentials from the ssl client cert password
+ * provider's cache. */
+static svn_error_t *
+ssl_client_cert_pw_file_first_credentials(void **credentials,
+ void **iter_baton,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return svn_auth__ssl_client_cert_pw_file_first_creds_helper
+ (credentials,
+ iter_baton,
+ provider_baton,
+ parameters,
+ realmstring,
+ simple_passphrase_get,
+ SVN_AUTH__SIMPLE_PASSWORD_TYPE,
+ pool);
+}
+
+
+/* Save (unencrypted) credentials to the ssl client cert password provider's
+ * cache. */
+static svn_error_t *
+ssl_client_cert_pw_file_save_credentials(svn_boolean_t *saved,
+ void *credentials,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return svn_auth__ssl_client_cert_pw_file_save_creds_helper
+ (saved, credentials,
+ provider_baton,
+ parameters,
+ realmstring,
+ simple_passphrase_set,
+ SVN_AUTH__SIMPLE_PASSWORD_TYPE,
+ pool);
+}
+
 static const svn_auth_provider_t ssl_client_cert_pw_file_provider = {
   SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
   ssl_client_cert_pw_file_first_credentials,
   NULL,
- NULL
+ ssl_client_cert_pw_file_save_credentials
 };
 
 
 /*** Public API to SSL file providers. ***/
-void svn_auth_get_ssl_client_cert_pw_file_provider
- (svn_auth_provider_object_t **provider, apr_pool_t *pool)
+void
+svn_auth_get_ssl_client_cert_pw_file_provider2
+ (svn_auth_provider_object_t **provider,
+ svn_auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func,
+ void* prompt_baton,
+ apr_pool_t *pool)
 {
   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+ ssl_client_cert_pw_file_provider_baton_t *pb = apr_pcalloc(pool,
+ sizeof(*pb));
+
+ pb->plaintext_passphrase_prompt_func = plaintext_passphrase_prompt_func;
+ pb->prompt_baton = prompt_baton;
+ pb->plaintext_answers = apr_hash_make(pool);
+
   po->vtable = &ssl_client_cert_pw_file_provider;
+ po->provider_baton = pb;
   *provider = po;
 }
 
+void
+svn_auth_get_ssl_client_cert_pw_file_provider
+ (svn_auth_provider_object_t **provider,
+ apr_pool_t *pool)
+{
+ svn_auth_get_ssl_client_cert_pw_file_provider2(provider, NULL, NULL, pool);
+}
+
 
 /*-----------------------------------------------------------------------*/
 /* Prompt provider */
Index: subversion/libsvn_subr/prompt.c
===================================================================
--- subversion/libsvn_subr/prompt.c (revision 31532)
+++ subversion/libsvn_subr/prompt.c (working copy)
@@ -379,37 +379,25 @@
   return SVN_NO_ERROR;
 }
 
-/* This implements 'svn_auth_plaintext_prompt_func_t'. */
-svn_error_t *
-svn_cmdline_auth_plaintext_prompt(svn_boolean_t *may_save_plaintext,
- const char *realmstring,
- void *baton,
- apr_pool_t *pool)
+/* This is a helper for plaintext prompt functions. */
+static svn_error_t *
+plaintext_prompt_helper(svn_boolean_t *may_save_plaintext,
+ const char *realmstring,
+ const char *prompt_string,
+ const char *prompt_text,
+ void *baton,
+ apr_pool_t *pool)
 {
   const char *answer = NULL;
   svn_boolean_t answered = FALSE;
- const char *prompt_string = _("Store password unencrypted (yes/no)? ");
   svn_cmdline_prompt_baton2_t *pb = baton;
   const char *config_path;
   
   SVN_ERR(svn_config_get_user_config_path(&config_path, pb->config_dir,
                                           SVN_CONFIG_CATEGORY_SERVERS, pool));
 
- SVN_ERR(svn_cmdline_fprintf(stderr, pool,
- _("-----------------------------------------------------------------------\n"
- "ATTENTION! Your password for authentication realm:\n"
- "\n"
- " %s\n"
- "\n"
- "can only be stored to disk unencrypted! You are advised to configure\n"
- "your system so that Subversion can store passwords encrypted, if\n"
- "possible. See the documentation for details.\n"
- "\n"
- "You can avoid future appearances of this warning by setting the value\n"
- "of the 'store-plaintext-passwords' option to either 'yes' or 'no' in\n"
- "'%s'.\n"
- "-----------------------------------------------------------------------\n"
- ), realmstring, config_path));
+ SVN_ERR(svn_cmdline_fprintf(stderr, pool, prompt_text, realmstring,
+ config_path));
 
   do
     {
@@ -443,6 +431,66 @@
   return SVN_NO_ERROR;
 }
 
+/* This implements 'svn_auth_plaintext_prompt_func_t'. */
+svn_error_t *
+svn_cmdline_auth_plaintext_prompt(svn_boolean_t *may_save_plaintext,
+ const char *realmstring,
+ void *baton,
+ apr_pool_t *pool)
+{
+ const char *prompt_string = _("Store password unencrypted (yes/no)? ");
+ const char *prompt_text =
+ _("-----------------------------------------------------------------------\n"
+ "ATTENTION! Your password for authentication realm:\n"
+ "\n"
+ " %s\n"
+ "\n"
+ "can only be stored to disk unencrypted! You are advised to configure\n"
+ "your system so that Subversion can store passwords encrypted, if\n"
+ "possible. See the documentation for details.\n"
+ "\n"
+ "You can avoid future appearances of this warning by setting the value\n"
+ "of the 'store-plaintext-passwords' option to either 'yes' or 'no' in\n"
+ "'%s'.\n"
+ "-----------------------------------------------------------------------\n"
+ );
+
+ SVN_ERR(plaintext_prompt_helper(may_save_plaintext, realmstring,
+ prompt_string, prompt_text, baton,
+ pool));
+ return SVN_NO_ERROR;
+}
+
+/* This implements 'svn_auth_plaintext_passphrase_prompt_func_t'. */
+svn_error_t *
+svn_cmdline_auth_plaintext_passphrase_prompt(svn_boolean_t *may_save_plaintext,
+ const char *realmstring,
+ void *baton,
+ apr_pool_t *pool)
+{
+ const char *prompt_string = _("Store passphrase unencrypted (yes/no)? ");
+ const char *prompt_text =
+ _("-----------------------------------------------------------------------\n"
+ "ATTENTION! Your passphrase for client certificate:\n"
+ "\n"
+ " %s\n"
+ "\n"
+ "can only be stored to disk unencrypted! You are advised to configure\n"
+ "your system so that Subversion can store passphrase encrypted, if\n"
+ "possible. See the documentation for details.\n"
+ "\n"
+ "You can avoid future appearances of this warning by setting the value\n"
+ "of the 'store-plaintext-passphrase' option to either 'yes' or 'no' in\n"
+ "'%s'.\n"
+ "-----------------------------------------------------------------------\n"
+ );
+
+ SVN_ERR(plaintext_prompt_helper(may_save_plaintext, realmstring,
+ prompt_string, prompt_text, baton,
+ pool));
+ return SVN_NO_ERROR;
+}
+
 
 /** Generic prompting. **/
 
Index: subversion/libsvn_auth_gnome_keyring/gnome_keyring.c
===================================================================
--- subversion/libsvn_auth_gnome_keyring/gnome_keyring.c (revision 31532)
+++ subversion/libsvn_auth_gnome_keyring/gnome_keyring.c (working copy)
@@ -192,3 +192,60 @@
 
   gnome_keyring_init();
 }
+
+/* Get cached encrypted credentials from the ssl client cert password
+ * provider's cache. */
+static svn_error_t *
+gnome_keyring_ssl_client_cert_pw_first_creds(void **credentials,
+ void **iter_baton,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return svn_auth__ssl_client_cert_pw_file_first_creds_helper
+ (credentials,
+ iter_baton, provider_baton,
+ parameters, realmstring,
+ gnome_keyring_password_get,
+ SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
+ pool);
+}
+
+/* Save encrypted credentials to the ssl client cert password provider's
+ * cache. */
+static svn_error_t *
+gnome_keyring_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
+ void *credentials,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ apr_pool_t *pool)
+{
+ return svn_auth__ssl_client_cert_pw_file_save_creds_helper
+ (saved, credentials,
+ provider_baton, parameters,
+ realmstring,
+ gnome_keyring_password_set,
+ SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
+ pool);
+}
+
+static const svn_auth_provider_t gnome_keyring_ssl_client_cert_pw_provider = {
+ SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
+ gnome_keyring_ssl_client_cert_pw_first_creds,
+ NULL,
+ gnome_keyring_ssl_client_cert_pw_save_creds
+};
+
+/* Public API */
+void
+svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider
+ (svn_auth_provider_object_t **provider,
+ apr_pool_t *pool)
+{
+ svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+
+ po->vtable = &gnome_keyring_ssl_client_cert_pw_provider;
+ *provider = po;
+}
Index: subversion/include/svn_config.h
===================================================================
--- subversion/include/svn_config.h (revision 31532)
+++ subversion/include/svn_config.h (working copy)
@@ -77,6 +77,9 @@
 #define SVN_CONFIG_OPTION_STORE_PASSWORDS "store-passwords"
 #define SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS "store-plaintext-passwords"
 #define SVN_CONFIG_OPTION_STORE_AUTH_CREDS "store-auth-creds"
+#define SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP "store-ssl-client-cert-pp"
+#define SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSPHRASE \
+ "store-plaintext-passphrase"
 
 #define SVN_CONFIG_CATEGORY_CONFIG "config"
 #define SVN_CONFIG_SECTION_AUTH "auth"
@@ -146,9 +149,11 @@
 /* Default values for some options. Should be passed as default values
  * to svn_config_get and friends, instead of hard-coding the defaults in
  * multiple places. */
-#define SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS TRUE
-#define SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS SVN_CONFIG_ASK
-#define SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS TRUE
+#define SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS TRUE
+#define SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS SVN_CONFIG_ASK
+#define SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS TRUE
+#define SVN_CONFIG_DEFAULT_OPTION_STORE_PASSPHRASE TRUE
+#define SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSPHRASE SVN_CONFIG_ASK
 
 /** Read configuration information from the standard sources and merge it
  * into the hash @a *cfg_hash. If @a config_dir is not NULL it specifies a
Index: subversion/include/svn_auth_dso.h
===================================================================
--- subversion/include/svn_auth_dso.h (revision 31532)
+++ subversion/include/svn_auth_dso.h (working copy)
@@ -51,6 +51,25 @@
 
 /**
  * Create and return @a *provider, an authentication provider of type @c
+ * svn_auth_cred_ssl_client_cert_pw_t that gets/sets information from the
+ * user's ~/.subversion configuration directory. Allocate @a *provider in
+ * @a pool.
+ *
+ * This is like svn_client_get_ssl_client_cert_pw_file_provider(), except
+ * that the password is stored in GNOME Keyring.
+ *
+ * @since New in 1.6
+ * @note This function actually works only on systems with
+ * libsvn_auth_gnome_keyring and GNOME Keyring installed.
+ */
+void
+svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider
+ (svn_auth_provider_object_t **provider,
+ apr_pool_t *pool);
+
+
+/**
+ * Create and return @a *provider, an authentication provider of type @c
  * svn_auth_cred_simple_t that gets/sets information from the user's
  * ~/.subversion configuration directory. Allocate @a *provider in
  * @a pool.
Index: subversion/include/svn_cmdline.h
===================================================================
--- subversion/include/svn_cmdline.h (revision 31532)
+++ subversion/include/svn_cmdline.h (working copy)
@@ -277,6 +277,17 @@
                                   void *baton,
                                   apr_pool_t *pool);
 
+/** An implementation of @c svn_auth_plaintext_passphrase_prompt_func_t that
+ * prompts the user whether storing unencypted passphrase to disk is OK.
+ *
+ * @since New in 1.6.
+ */
+svn_error_t *
+svn_cmdline_auth_plaintext_passphrase_prompt(svn_boolean_t *may_save_plaintext,
+ const char *realmstring,
+ void *baton,
+ apr_pool_t *pool);
+
 /** Initialize auth baton @a ab with the standard set of authentication
  * providers used by the command line client. @a non_interactive,
  * @a username, @a password, @a config_dir, and @a no_auth_cache are the
Index: subversion/include/private/svn_auth_private.h
===================================================================
--- subversion/include/private/svn_auth_private.h (revision 31532)
+++ subversion/include/private/svn_auth_private.h (working copy)
@@ -93,6 +93,38 @@
                                    const char *passtype,
                                    apr_pool_t *pool);
 
+/* Common implementation for ssl_client_cert_pw_file_first_credentials.
+ Uses PARAMETERS, REALMSTRING and the ssl client passphrase auth provider's
+ passphrase cache to fill the CREDENTIALS. PASSPHRASE_GET is used to obtain
+ the passphrase value. PASSTYPE identifies the type of the cached passphrase.
+ CREDENTIALS are allocated from POOL. */
+svn_error_t *
+svn_auth__ssl_client_cert_pw_file_first_creds_helper
+ (void **credentials,
+ void **iter_baton,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ svn_auth__password_get_t passphrase_get,
+ const char *passtype,
+ apr_pool_t *pool);
+
+/* Common implementation for ssl_client_cert_pw_file_save_credentials and
+ Uses PARAMETERS and REALMSTRING to save a set of CREDENTIALS to the ssl
+ client cert auth provider's passphrase cache. PASSPHRASE_SET is used to
+ store the passphrase. PASSTYPE identifies the type of the cached passphrase.
+ Allocates from POOL. */
+svn_error_t *
+svn_auth__ssl_client_cert_pw_file_save_creds_helper
+ (svn_boolean_t *saved,
+ void *credentials,
+ void *provider_baton,
+ apr_hash_t *parameters,
+ const char *realmstring,
+ svn_auth__password_set_t passphrase_set,
+ const char *passtype,
+ apr_pool_t *pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
Index: subversion/include/svn_auth.h
===================================================================
--- subversion/include/svn_auth.h (revision 31532)
+++ subversion/include/svn_auth.h (working copy)
@@ -238,6 +238,11 @@
 } svn_auth_cred_ssl_client_cert_t;
 
 
+/** A function returning an SSL client certificate passphrase provider. */
+typedef void (*svn_auth_ssl_client_cert_pw_provider_func_t)
+ (svn_auth_provider_object_t **provider,
+ apr_pool_t *pool);
+
 /** SSL client certificate passphrase credential type.
  *
  * @note The realmstring used with this credential type must be a name that
@@ -500,6 +505,38 @@
    void *baton,
    apr_pool_t *pool);
 
+/** Called only by providers which save passphrase unencrypted.
+ * In this callback, clients should ask the user whether storing
+ * a passphrase for the realm identified by @a realmstring to disk
+ * in plaintext is allowed.
+ *
+ * The answer is returned in @a *may_save_plaintext.
+ * @a baton is an implementation-specific closure.
+ * All allocations should be done in @a pool.
+ *
+ * This callback is called only once per authentication realm,
+ * not once per RA session. This means that clients implementing
+ * this callback must make sure that the pool passed to any
+ * implementation of save_credentials (part of svn_auth_provider_t)
+ * survives across RA sessions.
+ *
+ * If this callback is NULL it is not called.
+ * Client developers are highly encouraged to provide this callback
+ * to ensure their users are made aware of the fact that their passphrase
+ * is going to be stored unencrypted.
+ *
+ * Clients can however set the callback to NULL and set
+ * SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSPHRASE to SVN_CONFIG_FALSE or
+ * SVN_CONFIG_TRUE to enforce a certain behaviour.
+ *
+ * @since New in 1.6
+ */
+typedef svn_error_t *(*svn_auth_plaintext_passphrase_prompt_func_t)
+ (svn_boolean_t *may_save_plaintext,
+ const char *realmstring,
+ void *baton,
+ apr_pool_t *pool);
+
 
 /** Initialize an authentication system.
  *
@@ -572,6 +609,18 @@
 #define SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS SVN_AUTH_PARAM_PREFIX \
                                                   "store-plaintext-passwords"
 
+/** @brief The application doesn't want any providers to save passphrase
+ * to disk. Property value is irrelevant; only property's existence
+ * matters. */
+#define SVN_AUTH_PARAM_DONT_STORE_PASSPHRASE SVN_AUTH_PARAM_PREFIX \
+ "dont-store-passphrase"
+
+/** @brief Indicates whether providers may save passphrase to disk in
+ * plaintext. Property value can be either SVN_CONFIG_TRUE,
+ * SVN_CONFIG_FALSE, or SVN_CONFIG_ASK. */
+#define SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSPHRASE SVN_AUTH_PARAM_PREFIX \
+ "store-plaintext-passphrase"
+
 /** @brief The application doesn't want any providers to save credentials
  * to disk. Property value is irrelevant; only property's existence
  * matters. */
@@ -832,12 +881,29 @@
 
 
 /** Create and return @a *provider, an authentication provider of type @c
- * svn_auth_cred_ssl_client_cert_pw_t, allocated in @a pool.
+ * svn_auth_cred_ssl_client_cert_pw_t that gets/sets information from the user's
+ * ~/.subversion configuration directory.
  *
- * @a *provider retrieves its credentials from the configuration
- * mechanism. The returned credential is used when a loaded client
- * certificate is protected by a passphrase.
+ * If the provider is going to save the passphrase unencrypted,
+ * it calls @a plaintext_passphrase_prompt_func before saving the
+ * passphrase.
  *
+ * @a prompt_baton is passed to @a plaintext_passphrase_prompt_func.
+ *
+ * Allocate @a *provider in @a pool.
+ *
+ * @since New in 1.6.
+ */
+void svn_auth_get_ssl_client_cert_pw_file_provider2
+ (svn_auth_provider_object_t **provider,
+ svn_auth_plaintext_passphrase_prompt_func_t plaintext_passphrase_prompt_func,
+ void* prompt_baton,
+ apr_pool_t *pool);
+
+/** Like svn_auth_get_simple_provider2, but without the ability to
+ * call the svn_auth_plaintext_passphrase_prompt_func_t callback.
+ *
+ * @deprecated Provided for backwards compatibility with the 1.5 API.
  * @since New in 1.4.
  */
 void svn_auth_get_ssl_client_cert_pw_file_provider
Index: subversion/libsvn_ra_neon/session.c
===================================================================
--- subversion/libsvn_ra_neon/session.c (revision 31532)
+++ subversion/libsvn_ra_neon/session.c (working copy)
@@ -290,6 +290,10 @@
 
           if (ne_ssl_clicert_decrypt(clicert, pw_creds->password) == 0)
             {
+ error = svn_auth_save_credentials(state, pool);
+ if (error)
+ svn_error_clear(error);
+
               /* Success */
               ok = TRUE;
               break;

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe_at_subversion.tigris.org
For additional commands, e-mail: dev-help_at_subversion.tigris.org
Received on 2008-05-30 13:21:15 CEST

This is an archived mail posted to the Subversion Dev mailing list.