2 * gnome_keyring.c: GNOME Keyring provider for SVN_AUTH_CRED_*
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
24 /* ==================================================================== */
30 #include <apr_pools.h>
31 #include <apr_strings.h>
33 #include <gnome-keyring.h>
36 #include "svn_config.h"
37 #include "svn_error.h"
39 #include "svn_pools.h"
41 #include "private/svn_auth_private.h"
43 #include "svn_private_config.h"
47 /*-----------------------------------------------------------------------*/
48 /* GNOME Keyring simple provider, puts passwords in GNOME Keyring */
49 /*-----------------------------------------------------------------------*/
52 struct gnome_keyring_baton
54 const char *keyring_name;
55 GnomeKeyringInfo *info;
60 /* Callback function to destroy gnome_keyring_baton. */
62 callback_destroy_data_keyring(void *data)
64 struct gnome_keyring_baton *key_info = data;
69 free((void*)key_info->keyring_name);
70 key_info->keyring_name = NULL;
74 gnome_keyring_info_free(key_info->info);
75 key_info->info = NULL;
82 /* Callback function to complete the keyring operation. */
84 callback_done(GnomeKeyringResult result,
87 struct gnome_keyring_baton *key_info = data;
89 g_main_loop_quit(key_info->loop);
94 /* Callback function to get the keyring info. */
96 callback_get_info_keyring(GnomeKeyringResult result,
97 GnomeKeyringInfo *info,
100 struct gnome_keyring_baton *key_info = data;
102 if (result == GNOME_KEYRING_RESULT_OK && info != NULL)
104 key_info->info = gnome_keyring_info_copy(info);
108 if (key_info->info != NULL)
109 gnome_keyring_info_free(key_info->info);
111 key_info->info = NULL;
114 g_main_loop_quit(key_info->loop);
120 /* Callback function to get the default keyring string name. */
122 callback_default_keyring(GnomeKeyringResult result,
126 struct gnome_keyring_baton *key_info = data;
128 if (result == GNOME_KEYRING_RESULT_OK && string != NULL)
130 key_info->keyring_name = strdup(string);
134 free((void*)key_info->keyring_name);
135 key_info->keyring_name = NULL;
138 g_main_loop_quit(key_info->loop);
143 /* Returns the default keyring name, allocated in RESULT_POOL. */
145 get_default_keyring_name(apr_pool_t *result_pool)
148 struct gnome_keyring_baton key_info;
150 key_info.info = NULL;
151 key_info.keyring_name = NULL;
153 /* Finds default keyring. */
154 key_info.loop = g_main_loop_new(NULL, FALSE);
155 gnome_keyring_get_default_keyring(callback_default_keyring, &key_info, NULL);
156 g_main_loop_run(key_info.loop);
158 if (key_info.keyring_name == NULL)
160 callback_destroy_data_keyring(&key_info);
164 def = apr_pstrdup(result_pool, key_info.keyring_name);
165 callback_destroy_data_keyring(&key_info);
170 /* Returns TRUE if the KEYRING_NAME is locked. */
172 check_keyring_is_locked(const char *keyring_name)
174 struct gnome_keyring_baton key_info;
176 key_info.info = NULL;
177 key_info.keyring_name = NULL;
179 /* Get details about the default keyring. */
180 key_info.loop = g_main_loop_new(NULL, FALSE);
181 gnome_keyring_get_info(keyring_name, callback_get_info_keyring, &key_info,
183 g_main_loop_run(key_info.loop);
185 if (key_info.info == NULL)
187 callback_destroy_data_keyring(&key_info);
191 /* Check if keyring is locked. */
192 if (gnome_keyring_info_get_is_locked(key_info.info))
198 /* Unlock the KEYRING_NAME with the KEYRING_PASSWORD. If KEYRING was
199 successfully unlocked return TRUE. */
201 unlock_gnome_keyring(const char *keyring_name,
202 const char *keyring_password,
205 struct gnome_keyring_baton key_info;
207 key_info.info = NULL;
208 key_info.keyring_name = NULL;
210 /* Get details about the default keyring. */
211 key_info.loop = g_main_loop_new(NULL, FALSE);
212 gnome_keyring_get_info(keyring_name, callback_get_info_keyring,
214 g_main_loop_run(key_info.loop);
216 if (key_info.info == NULL)
218 callback_destroy_data_keyring(&key_info);
223 key_info.loop = g_main_loop_new(NULL, FALSE);
224 gnome_keyring_unlock(keyring_name, keyring_password,
225 callback_done, &key_info, NULL);
226 g_main_loop_run(key_info.loop);
228 callback_destroy_data_keyring(&key_info);
229 if (check_keyring_is_locked(keyring_name))
236 /* There is a race here: this ensures keyring is unlocked just now,
237 but will it still be unlocked when we use it? */
239 ensure_gnome_keyring_is_unlocked(svn_boolean_t non_interactive,
240 apr_hash_t *parameters,
241 apr_pool_t *scratch_pool)
243 const char *default_keyring = get_default_keyring_name(scratch_pool);
245 if (! non_interactive)
247 svn_auth_gnome_keyring_unlock_prompt_func_t unlock_prompt_func =
248 svn_hash_gets(parameters,
249 SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC);
250 void *unlock_prompt_baton =
251 svn_hash_gets(parameters,
252 SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON);
254 char *keyring_password;
256 if (unlock_prompt_func && check_keyring_is_locked(default_keyring))
258 SVN_ERR((*unlock_prompt_func)(&keyring_password,
263 /* If keyring is locked give up and try the next provider. */
264 if (! unlock_gnome_keyring(default_keyring, keyring_password,
271 if (check_keyring_is_locked(default_keyring))
273 return svn_error_create(SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
274 _("GNOME Keyring is locked and "
275 "we are non-interactive"));
282 /* Implementation of svn_auth__password_get_t that retrieves the password
283 from GNOME Keyring. */
285 password_get_gnome_keyring(svn_boolean_t *done,
286 const char **password,
288 const char *realmstring,
289 const char *username,
290 apr_hash_t *parameters,
291 svn_boolean_t non_interactive,
294 GnomeKeyringResult result;
299 SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
301 if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed"))
303 result = gnome_keyring_find_network_password_sync(username, realmstring,
304 NULL, NULL, NULL, NULL,
309 result = GNOME_KEYRING_RESULT_DENIED;
312 if (result == GNOME_KEYRING_RESULT_OK)
314 if (items && items->data)
316 GnomeKeyringNetworkPasswordData *item = items->data;
319 size_t len = strlen(item->password);
322 *password = apr_pstrmemdup(pool, item->password, len);
326 gnome_keyring_network_password_list_free(items);
331 svn_hash_sets(parameters, "gnome-keyring-opening-failed", "");
337 /* Implementation of svn_auth__password_set_t that stores the password in
340 password_set_gnome_keyring(svn_boolean_t *done,
342 const char *realmstring,
343 const char *username,
344 const char *password,
345 apr_hash_t *parameters,
346 svn_boolean_t non_interactive,
349 GnomeKeyringResult result;
354 SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
356 if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed"))
358 result = gnome_keyring_set_network_password_sync(NULL, /* default keyring */
359 username, realmstring,
360 NULL, NULL, NULL, NULL,
366 result = GNOME_KEYRING_RESULT_DENIED;
368 if (result != GNOME_KEYRING_RESULT_OK)
370 svn_hash_sets(parameters, "gnome-keyring-opening-failed", "");
373 *done = (result == GNOME_KEYRING_RESULT_OK);
377 /* Get cached encrypted credentials from the simple provider's cache. */
379 simple_gnome_keyring_first_creds(void **credentials,
381 void *provider_baton,
382 apr_hash_t *parameters,
383 const char *realmstring,
386 return svn_auth__simple_creds_cache_get(credentials,
387 iter_baton, provider_baton,
388 parameters, realmstring,
389 password_get_gnome_keyring,
390 SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
394 /* Save encrypted credentials to the simple provider's cache. */
396 simple_gnome_keyring_save_creds(svn_boolean_t *saved,
398 void *provider_baton,
399 apr_hash_t *parameters,
400 const char *realmstring,
403 return svn_auth__simple_creds_cache_set(saved, credentials,
404 provider_baton, parameters,
406 password_set_gnome_keyring,
407 SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
411 #if GLIB_CHECK_VERSION(2,6,0)
413 log_noop(const gchar *log_domain, GLogLevelFlags log_level,
414 const gchar *message, gpointer user_data)
421 init_gnome_keyring(void)
423 const char *application_name = NULL;
424 application_name = g_get_application_name();
425 if (!application_name)
426 g_set_application_name("Subversion");
428 /* Ideally we call g_log_set_handler() with a log_domain specific to
429 libgnome-keyring. Unfortunately, at least as of gnome-keyring
430 2.22.3, it doesn't have its own log_domain. As a result, we
431 suppress stderr spam for not only libgnome-keyring, but for
432 anything else the app is linked to that uses glib logging and
433 doesn't specify a log_domain. */
434 #if GLIB_CHECK_VERSION(2,6,0)
435 g_log_set_default_handler(log_noop, NULL);
439 static const svn_auth_provider_t gnome_keyring_simple_provider = {
440 SVN_AUTH_CRED_SIMPLE,
441 simple_gnome_keyring_first_creds,
443 simple_gnome_keyring_save_creds
448 svn_auth_get_gnome_keyring_simple_provider
449 (svn_auth_provider_object_t **provider,
452 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
454 po->vtable = &gnome_keyring_simple_provider;
457 init_gnome_keyring();
461 /*-----------------------------------------------------------------------*/
462 /* GNOME Keyring SSL client certificate passphrase provider, */
463 /* puts passphrases in GNOME Keyring */
464 /*-----------------------------------------------------------------------*/
466 /* Get cached encrypted credentials from the ssl client cert password
469 ssl_client_cert_pw_gnome_keyring_first_creds(void **credentials,
471 void *provider_baton,
472 apr_hash_t *parameters,
473 const char *realmstring,
476 return svn_auth__ssl_client_cert_pw_cache_get(
477 credentials, iter_baton, provider_baton, parameters, realmstring,
478 password_get_gnome_keyring, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
482 /* Save encrypted credentials to the ssl client cert password provider's
485 ssl_client_cert_pw_gnome_keyring_save_creds(svn_boolean_t *saved,
487 void *provider_baton,
488 apr_hash_t *parameters,
489 const char *realmstring,
492 return svn_auth__ssl_client_cert_pw_cache_set(
493 saved, credentials, provider_baton, parameters, realmstring,
494 password_set_gnome_keyring, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
498 static const svn_auth_provider_t gnome_keyring_ssl_client_cert_pw_provider = {
499 SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
500 ssl_client_cert_pw_gnome_keyring_first_creds,
502 ssl_client_cert_pw_gnome_keyring_save_creds
507 svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider
508 (svn_auth_provider_object_t **provider,
511 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
513 po->vtable = &gnome_keyring_ssl_client_cert_pw_provider;
516 init_gnome_keyring();