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