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 /* ==================================================================== */
28 #include <apr_pools.h>
29 #include <apr_strings.h>
32 #include "svn_version.h"
33 #include "private/svn_auth_private.h"
34 #include "svn_private_config.h"
36 #ifdef SVN_HAVE_LIBSECRET
38 #include <libsecret/secret.h>
40 /* Return TRUE if the default collection is available and FALSE
41 otherwise. In interactive mode the collection only has to exist to
42 be available, it can be locked or unlocked. The default collection
43 will be created if necessary.
45 In non-interactive mode the collection is only available if it
46 already exists and is unlocked. Such an available collection can
47 be used without prompting. Strictly this is racy: nothing ensures
48 the collection remains unlocked. A similar issue affects the
49 KWallet and original GNOME Keyring providers.
51 As a non-racy alternative one could override prompt_async in the
52 _SecretServiceClass vtable, the get/set would still fail but there
53 would be no prompt and no race. This "works" but it is not clear
54 to me whether it is legitimate since the SecretService is a
55 singleton and the effect would be application-wide.
58 available_collection(svn_boolean_t non_interactive,
61 GError *gerror = NULL;
62 SecretService *service = NULL;
63 SecretCollection *collection = NULL;
65 service = secret_service_get_sync(SECRET_SERVICE_NONE, NULL, &gerror);
66 if (gerror || !service)
69 collection = secret_collection_for_alias_sync(service,
70 SECRET_COLLECTION_DEFAULT,
71 SECRET_COLLECTION_NONE,
81 /* "Default" is the label used by the old libgnome-keyring. */
82 collection = secret_collection_create_sync(service, "Default",
83 SECRET_COLLECTION_DEFAULT,
85 if (gerror || !collection)
89 if (non_interactive && secret_collection_get_locked(collection))
92 g_object_unref(collection);
93 g_object_unref(service);
101 g_object_unref(collection);
103 g_object_unref(service);
107 /* Implementation of svn_auth__password_get_t that retrieves the password
110 password_get_gnome_keyring(svn_boolean_t *done,
111 const char **password,
113 const char *realmstring,
114 const char *username,
115 apr_hash_t *parameters,
116 svn_boolean_t non_interactive,
119 GError *gerror = NULL;
122 if (!available_collection(non_interactive, pool))
125 gpassword = secret_password_lookup_sync(SECRET_SCHEMA_COMPAT_NETWORK, NULL,
127 "domain", realmstring,
132 g_error_free(gerror);
136 *password = apr_pstrdup(pool, gpassword);
144 /* Implementation of svn_auth__password_set_t that stores the password
147 password_set_gnome_keyring(svn_boolean_t *done,
149 const char *realmstring,
150 const char *username,
151 const char *password,
152 apr_hash_t *parameters,
153 svn_boolean_t non_interactive,
156 GError *gerror = NULL;
159 if (!available_collection(non_interactive, pool))
162 /* "network password" is the label used by the old libgnome-keyring. */
163 gstatus = secret_password_store_sync(SECRET_SCHEMA_COMPAT_NETWORK,
164 SECRET_COLLECTION_DEFAULT,
168 "domain", realmstring,
173 g_error_free(gerror);
183 #endif /* SVN_HAVE_LIBSECRET */
185 #ifdef SVN_HAVE_GNOME_KEYRING
188 #include <gnome-keyring.h>
190 /* Returns the default keyring name, allocated in RESULT_POOL. */
192 get_default_keyring_name(apr_pool_t *result_pool)
195 GnomeKeyringResult gkr;
197 gkr = gnome_keyring_get_default_keyring_sync(&name);
198 if (gkr != GNOME_KEYRING_RESULT_OK)
201 def = apr_pstrdup(result_pool, name);
207 /* Returns TRUE if the KEYRING_NAME is locked. */
209 check_keyring_is_locked(const char *keyring_name)
211 GnomeKeyringInfo *info;
212 svn_boolean_t locked;
213 GnomeKeyringResult gkr;
215 gkr = gnome_keyring_get_info_sync(keyring_name, &info);
216 if (gkr != GNOME_KEYRING_RESULT_OK)
219 if (gnome_keyring_info_get_is_locked(info))
224 gnome_keyring_info_free(info);
229 /* Unlock the KEYRING_NAME with the KEYRING_PASSWORD. If KEYRING was
230 successfully unlocked return TRUE. */
232 unlock_gnome_keyring(const char *keyring_name,
233 const char *keyring_password,
236 GnomeKeyringInfo *info;
237 GnomeKeyringResult gkr;
239 gkr = gnome_keyring_get_info_sync(keyring_name, &info);
240 if (gkr != GNOME_KEYRING_RESULT_OK)
243 gkr = gnome_keyring_unlock_sync(keyring_name, keyring_password);
244 gnome_keyring_info_free(info);
245 if (gkr != GNOME_KEYRING_RESULT_OK)
248 return check_keyring_is_locked(keyring_name);
252 /* There is a race here: this ensures keyring is unlocked just now,
253 but will it still be unlocked when we use it? */
255 ensure_gnome_keyring_is_unlocked(svn_boolean_t non_interactive,
256 apr_hash_t *parameters,
257 apr_pool_t *scratch_pool)
259 const char *default_keyring = get_default_keyring_name(scratch_pool);
261 if (! non_interactive)
263 svn_auth_gnome_keyring_unlock_prompt_func_t unlock_prompt_func =
264 svn_hash_gets(parameters,
265 SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC);
266 void *unlock_prompt_baton =
267 svn_hash_gets(parameters,
268 SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON);
270 char *keyring_password;
272 if (unlock_prompt_func && check_keyring_is_locked(default_keyring))
274 SVN_ERR((*unlock_prompt_func)(&keyring_password,
279 /* If keyring is locked give up and try the next provider. */
280 if (! unlock_gnome_keyring(default_keyring, keyring_password,
287 if (check_keyring_is_locked(default_keyring))
289 return svn_error_create(SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
290 _("GNOME Keyring is locked and "
291 "we are non-interactive"));
298 /* Implementation of svn_auth__password_get_t that retrieves the password
299 from GNOME Keyring. */
301 password_get_gnome_keyring(svn_boolean_t *done,
302 const char **password,
304 const char *realmstring,
305 const char *username,
306 apr_hash_t *parameters,
307 svn_boolean_t non_interactive,
310 GnomeKeyringResult result;
315 SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
317 if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed"))
319 result = gnome_keyring_find_network_password_sync(username, realmstring,
320 NULL, NULL, NULL, NULL,
325 result = GNOME_KEYRING_RESULT_DENIED;
328 if (result == GNOME_KEYRING_RESULT_OK)
330 if (items && items->data)
332 GnomeKeyringNetworkPasswordData *item = items->data;
335 size_t len = strlen(item->password);
338 *password = apr_pstrmemdup(pool, item->password, len);
342 gnome_keyring_network_password_list_free(items);
347 svn_hash_sets(parameters, "gnome-keyring-opening-failed", "");
353 /* Implementation of svn_auth__password_set_t that stores the password in
356 password_set_gnome_keyring(svn_boolean_t *done,
358 const char *realmstring,
359 const char *username,
360 const char *password,
361 apr_hash_t *parameters,
362 svn_boolean_t non_interactive,
365 GnomeKeyringResult result;
370 SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
372 if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed"))
374 result = gnome_keyring_set_network_password_sync(NULL, /* default keyring */
375 username, realmstring,
376 NULL, NULL, NULL, NULL,
382 result = GNOME_KEYRING_RESULT_DENIED;
384 if (result != GNOME_KEYRING_RESULT_OK)
386 svn_hash_sets(parameters, "gnome-keyring-opening-failed", "");
389 *done = (result == GNOME_KEYRING_RESULT_OK);
393 #if GLIB_CHECK_VERSION(2,6,0)
395 log_noop(const gchar *log_domain, GLogLevelFlags log_level,
396 const gchar *message, gpointer user_data)
403 init_gnome_keyring(void)
405 const char *application_name = NULL;
406 application_name = g_get_application_name();
407 if (!application_name)
408 g_set_application_name("Subversion");
410 /* Ideally we call g_log_set_handler() with a log_domain specific to
411 libgnome-keyring. Unfortunately, at least as of gnome-keyring
412 2.22.3, it doesn't have its own log_domain. As a result, we
413 suppress stderr spam for not only libgnome-keyring, but for
414 anything else the app is linked to that uses glib logging and
415 doesn't specify a log_domain. */
416 #if GLIB_CHECK_VERSION(2,6,0)
417 g_log_set_default_handler(log_noop, NULL);
421 #endif /* SVN_HAVE_GNOME_KEYRING */
424 /*-----------------------------------------------------------------------*/
425 /* GNOME Keyring simple provider, puts passwords in GNOME Keyring */
426 /*-----------------------------------------------------------------------*/
428 /* Get cached encrypted credentials from the simple provider's cache. */
430 simple_gnome_keyring_first_creds(void **credentials,
432 void *provider_baton,
433 apr_hash_t *parameters,
434 const char *realmstring,
437 return svn_auth__simple_creds_cache_get(credentials,
438 iter_baton, provider_baton,
439 parameters, realmstring,
440 password_get_gnome_keyring,
441 SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
445 /* Save encrypted credentials to the simple provider's cache. */
447 simple_gnome_keyring_save_creds(svn_boolean_t *saved,
449 void *provider_baton,
450 apr_hash_t *parameters,
451 const char *realmstring,
454 return svn_auth__simple_creds_cache_set(saved, credentials,
455 provider_baton, parameters,
457 password_set_gnome_keyring,
458 SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
462 static const svn_auth_provider_t gnome_keyring_simple_provider = {
463 SVN_AUTH_CRED_SIMPLE,
464 simple_gnome_keyring_first_creds,
466 simple_gnome_keyring_save_creds
471 svn_auth_get_gnome_keyring_simple_provider
472 (svn_auth_provider_object_t **provider,
475 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
477 po->vtable = &gnome_keyring_simple_provider;
480 #ifdef SVN_HAVE_GNOME_KEYRING
481 init_gnome_keyring();
487 /*-----------------------------------------------------------------------*/
488 /* GNOME Keyring SSL client certificate passphrase provider, */
489 /* puts passphrases in GNOME Keyring */
490 /*-----------------------------------------------------------------------*/
492 /* Get cached encrypted credentials from the ssl client cert password
495 ssl_client_cert_pw_gnome_keyring_first_creds(void **credentials,
497 void *provider_baton,
498 apr_hash_t *parameters,
499 const char *realmstring,
502 return svn_auth__ssl_client_cert_pw_cache_get(
503 credentials, iter_baton, provider_baton, parameters, realmstring,
504 password_get_gnome_keyring, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
508 /* Save encrypted credentials to the ssl client cert password provider's
511 ssl_client_cert_pw_gnome_keyring_save_creds(svn_boolean_t *saved,
513 void *provider_baton,
514 apr_hash_t *parameters,
515 const char *realmstring,
518 return svn_auth__ssl_client_cert_pw_cache_set(
519 saved, credentials, provider_baton, parameters, realmstring,
520 password_set_gnome_keyring, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
524 static const svn_auth_provider_t gnome_keyring_ssl_client_cert_pw_provider = {
525 SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
526 ssl_client_cert_pw_gnome_keyring_first_creds,
528 ssl_client_cert_pw_gnome_keyring_save_creds
533 svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider
534 (svn_auth_provider_object_t **provider,
537 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
539 po->vtable = &gnome_keyring_ssl_client_cert_pw_provider;
542 #ifdef SVN_HAVE_GNOME_KEYRING
543 init_gnome_keyring();