diff options
author | peter <peter@FreeBSD.org> | 2013-06-18 02:07:41 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2013-06-18 02:07:41 +0000 |
commit | d25dac7fcc6acc838b71bbda8916fd9665c709ab (patch) | |
tree | 135691142dc0e75a5e5d97b5074d03436435b8e0 /subversion/libsvn_auth_gnome_keyring | |
download | FreeBSD-src-d25dac7fcc6acc838b71bbda8916fd9665c709ab.zip FreeBSD-src-d25dac7fcc6acc838b71bbda8916fd9665c709ab.tar.gz |
Import trimmed svn-1.8.0-rc3
Diffstat (limited to 'subversion/libsvn_auth_gnome_keyring')
-rw-r--r-- | subversion/libsvn_auth_gnome_keyring/gnome_keyring.c | 517 | ||||
-rw-r--r-- | subversion/libsvn_auth_gnome_keyring/version.c | 35 |
2 files changed, 552 insertions, 0 deletions
diff --git a/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c b/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c new file mode 100644 index 0000000..48dfa35 --- /dev/null +++ b/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c @@ -0,0 +1,517 @@ +/* + * gnome_keyring.c: GNOME Keyring provider for SVN_AUTH_CRED_* + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +/* ==================================================================== */ + + + +/*** Includes. ***/ + +#include <apr_pools.h> +#include <apr_strings.h> +#include <glib.h> +#include <gnome-keyring.h> + +#include "svn_auth.h" +#include "svn_config.h" +#include "svn_error.h" +#include "svn_hash.h" +#include "svn_pools.h" + +#include "private/svn_auth_private.h" + +#include "svn_private_config.h" + + + +/*-----------------------------------------------------------------------*/ +/* GNOME Keyring simple provider, puts passwords in GNOME Keyring */ +/*-----------------------------------------------------------------------*/ + + +struct gnome_keyring_baton +{ + const char *keyring_name; + GnomeKeyringInfo *info; + GMainLoop *loop; +}; + + +/* Callback function to destroy gnome_keyring_baton. */ +static void +callback_destroy_data_keyring(void *data) +{ + struct gnome_keyring_baton *key_info = data; + + if (data == NULL) + return; + + free((void*)key_info->keyring_name); + key_info->keyring_name = NULL; + + if (key_info->info) + { + gnome_keyring_info_free(key_info->info); + key_info->info = NULL; + } + + return; +} + + +/* Callback function to complete the keyring operation. */ +static void +callback_done(GnomeKeyringResult result, + gpointer data) +{ + struct gnome_keyring_baton *key_info = data; + + g_main_loop_quit(key_info->loop); + return; +} + + +/* Callback function to get the keyring info. */ +static void +callback_get_info_keyring(GnomeKeyringResult result, + GnomeKeyringInfo *info, + void *data) +{ + struct gnome_keyring_baton *key_info = data; + + if (result == GNOME_KEYRING_RESULT_OK && info != NULL) + { + key_info->info = gnome_keyring_info_copy(info); + } + else + { + if (key_info->info != NULL) + gnome_keyring_info_free(key_info->info); + + key_info->info = NULL; + } + + g_main_loop_quit(key_info->loop); + + return; +} + + +/* Callback function to get the default keyring string name. */ +static void +callback_default_keyring(GnomeKeyringResult result, + const char *string, + void *data) +{ + struct gnome_keyring_baton *key_info = data; + + if (result == GNOME_KEYRING_RESULT_OK && string != NULL) + { + key_info->keyring_name = strdup(string); + } + else + { + free((void*)key_info->keyring_name); + key_info->keyring_name = NULL; + } + + g_main_loop_quit(key_info->loop); + + return; +} + +/* Returns the default keyring name, allocated in RESULT_POOL. */ +static char* +get_default_keyring_name(apr_pool_t *result_pool) +{ + char *def = NULL; + struct gnome_keyring_baton key_info; + + key_info.info = NULL; + key_info.keyring_name = NULL; + + /* Finds default keyring. */ + key_info.loop = g_main_loop_new(NULL, FALSE); + gnome_keyring_get_default_keyring(callback_default_keyring, &key_info, NULL); + g_main_loop_run(key_info.loop); + + if (key_info.keyring_name == NULL) + { + callback_destroy_data_keyring(&key_info); + return NULL; + } + + def = apr_pstrdup(result_pool, key_info.keyring_name); + callback_destroy_data_keyring(&key_info); + + return def; +} + +/* Returns TRUE if the KEYRING_NAME is locked. */ +static svn_boolean_t +check_keyring_is_locked(const char *keyring_name) +{ + struct gnome_keyring_baton key_info; + + key_info.info = NULL; + key_info.keyring_name = NULL; + + /* Get details about the default keyring. */ + key_info.loop = g_main_loop_new(NULL, FALSE); + gnome_keyring_get_info(keyring_name, callback_get_info_keyring, &key_info, + NULL); + g_main_loop_run(key_info.loop); + + if (key_info.info == NULL) + { + callback_destroy_data_keyring(&key_info); + return FALSE; + } + + /* Check if keyring is locked. */ + if (gnome_keyring_info_get_is_locked(key_info.info)) + return TRUE; + else + return FALSE; +} + +/* Unlock the KEYRING_NAME with the KEYRING_PASSWORD. If KEYRING was + successfully unlocked return TRUE. */ +static svn_boolean_t +unlock_gnome_keyring(const char *keyring_name, + const char *keyring_password, + apr_pool_t *pool) +{ + struct gnome_keyring_baton key_info; + + key_info.info = NULL; + key_info.keyring_name = NULL; + + /* Get details about the default keyring. */ + key_info.loop = g_main_loop_new(NULL, FALSE); + gnome_keyring_get_info(keyring_name, callback_get_info_keyring, + &key_info, NULL); + g_main_loop_run(key_info.loop); + + if (key_info.info == NULL) + { + callback_destroy_data_keyring(&key_info); + return FALSE; + } + else + { + key_info.loop = g_main_loop_new(NULL, FALSE); + gnome_keyring_unlock(keyring_name, keyring_password, + callback_done, &key_info, NULL); + g_main_loop_run(key_info.loop); + } + callback_destroy_data_keyring(&key_info); + if (check_keyring_is_locked(keyring_name)) + return FALSE; + + return TRUE; +} + + +/* There is a race here: this ensures keyring is unlocked just now, + but will it still be unlocked when we use it? */ +static svn_error_t * +ensure_gnome_keyring_is_unlocked(svn_boolean_t non_interactive, + apr_hash_t *parameters, + apr_pool_t *scratch_pool) +{ + const char *default_keyring = get_default_keyring_name(scratch_pool); + + if (! non_interactive) + { + svn_auth_gnome_keyring_unlock_prompt_func_t unlock_prompt_func = + svn_hash_gets(parameters, + SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC); + void *unlock_prompt_baton = + svn_hash_gets(parameters, + SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON); + + char *keyring_password; + + if (unlock_prompt_func && check_keyring_is_locked(default_keyring)) + { + SVN_ERR((*unlock_prompt_func)(&keyring_password, + default_keyring, + unlock_prompt_baton, + scratch_pool)); + + /* If keyring is locked give up and try the next provider. */ + if (! unlock_gnome_keyring(default_keyring, keyring_password, + scratch_pool)) + return SVN_NO_ERROR; + } + } + else + { + if (check_keyring_is_locked(default_keyring)) + { + return svn_error_create(SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL, + _("GNOME Keyring is locked and " + "we are non-interactive")); + } + } + + return SVN_NO_ERROR; +} + +/* Implementation of svn_auth__password_get_t that retrieves the password + from GNOME Keyring. */ +static svn_error_t * +password_get_gnome_keyring(svn_boolean_t *done, + const char **password, + apr_hash_t *creds, + const char *realmstring, + const char *username, + apr_hash_t *parameters, + svn_boolean_t non_interactive, + apr_pool_t *pool) +{ + GnomeKeyringResult result; + GList *items; + + *done = FALSE; + + SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool)); + + if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed")) + { + result = gnome_keyring_find_network_password_sync(username, realmstring, + NULL, NULL, NULL, NULL, + 0, &items); + } + else + { + result = GNOME_KEYRING_RESULT_DENIED; + } + + if (result == GNOME_KEYRING_RESULT_OK) + { + if (items && items->data) + { + GnomeKeyringNetworkPasswordData *item = items->data; + if (item->password) + { + size_t len = strlen(item->password); + if (len > 0) + { + *password = apr_pstrmemdup(pool, item->password, len); + *done = TRUE; + } + } + gnome_keyring_network_password_list_free(items); + } + } + else + { + svn_hash_sets(parameters, "gnome-keyring-opening-failed", ""); + } + + return SVN_NO_ERROR; +} + +/* Implementation of svn_auth__password_set_t that stores the password in + GNOME Keyring. */ +static svn_error_t * +password_set_gnome_keyring(svn_boolean_t *done, + apr_hash_t *creds, + const char *realmstring, + const char *username, + const char *password, + apr_hash_t *parameters, + svn_boolean_t non_interactive, + apr_pool_t *pool) +{ + GnomeKeyringResult result; + guint32 item_id; + + *done = FALSE; + + SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool)); + + if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed")) + { + result = gnome_keyring_set_network_password_sync(NULL, /* default keyring */ + username, realmstring, + NULL, NULL, NULL, NULL, + 0, password, + &item_id); + } + else + { + result = GNOME_KEYRING_RESULT_DENIED; + } + if (result != GNOME_KEYRING_RESULT_OK) + { + svn_hash_sets(parameters, "gnome-keyring-opening-failed", ""); + } + + *done = (result == GNOME_KEYRING_RESULT_OK); + return SVN_NO_ERROR; +} + +/* Get cached encrypted credentials from the simple provider's cache. */ +static svn_error_t * +simple_gnome_keyring_first_creds(void **credentials, + void **iter_baton, + void *provider_baton, + apr_hash_t *parameters, + const char *realmstring, + apr_pool_t *pool) +{ + return svn_auth__simple_creds_cache_get(credentials, + iter_baton, provider_baton, + parameters, realmstring, + password_get_gnome_keyring, + SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE, + pool); +} + +/* Save encrypted credentials to the simple provider's cache. */ +static svn_error_t * +simple_gnome_keyring_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__simple_creds_cache_set(saved, credentials, + provider_baton, parameters, + realmstring, + password_set_gnome_keyring, + SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE, + pool); +} + +#if GLIB_CHECK_VERSION(2,6,0) +static void +log_noop(const gchar *log_domain, GLogLevelFlags log_level, + const gchar *message, gpointer user_data) +{ + /* do nothing */ +} +#endif + +static void +init_gnome_keyring(void) +{ + const char *application_name = NULL; + application_name = g_get_application_name(); + if (!application_name) + g_set_application_name("Subversion"); + + /* Ideally we call g_log_set_handler() with a log_domain specific to + libgnome-keyring. Unfortunately, at least as of gnome-keyring + 2.22.3, it doesn't have its own log_domain. As a result, we + suppress stderr spam for not only libgnome-keyring, but for + anything else the app is linked to that uses glib logging and + doesn't specify a log_domain. */ +#if GLIB_CHECK_VERSION(2,6,0) + g_log_set_default_handler(log_noop, NULL); +#endif +} + +static const svn_auth_provider_t gnome_keyring_simple_provider = { + SVN_AUTH_CRED_SIMPLE, + simple_gnome_keyring_first_creds, + NULL, + simple_gnome_keyring_save_creds +}; + +/* Public API */ +void +svn_auth_get_gnome_keyring_simple_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_simple_provider; + *provider = po; + + init_gnome_keyring(); +} + + +/*-----------------------------------------------------------------------*/ +/* GNOME Keyring SSL client certificate passphrase provider, */ +/* puts passphrases in GNOME Keyring */ +/*-----------------------------------------------------------------------*/ + +/* Get cached encrypted credentials from the ssl client cert password + provider's cache. */ +static svn_error_t * +ssl_client_cert_pw_gnome_keyring_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_cache_get( + credentials, iter_baton, provider_baton, parameters, realmstring, + password_get_gnome_keyring, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE, + pool); +} + +/* Save encrypted credentials to the ssl client cert password provider's + cache. */ +static svn_error_t * +ssl_client_cert_pw_gnome_keyring_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_cache_set( + saved, credentials, provider_baton, parameters, realmstring, + password_set_gnome_keyring, 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, + ssl_client_cert_pw_gnome_keyring_first_creds, + NULL, + ssl_client_cert_pw_gnome_keyring_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; + + init_gnome_keyring(); +} diff --git a/subversion/libsvn_auth_gnome_keyring/version.c b/subversion/libsvn_auth_gnome_keyring/version.c new file mode 100644 index 0000000..361fe01 --- /dev/null +++ b/subversion/libsvn_auth_gnome_keyring/version.c @@ -0,0 +1,35 @@ +/* + * version.c: libsvn_auth_gnome_keyring version number + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +/* ==================================================================== */ + + + +#include "svn_auth.h" +#include "svn_version.h" + +const svn_version_t * +svn_auth_gnome_keyring_version(void) +{ + SVN_VERSION_BODY; +} |