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 /* Returns the default keyring name, allocated in RESULT_POOL. */
54 get_default_keyring_name(apr_pool_t *result_pool)
57 GnomeKeyringResult gkr;
59 gkr = gnome_keyring_get_default_keyring_sync(&name);
60 if (gkr != GNOME_KEYRING_RESULT_OK)
63 def = apr_pstrdup(result_pool, name);
69 /* Returns TRUE if the KEYRING_NAME is locked. */
71 check_keyring_is_locked(const char *keyring_name)
73 GnomeKeyringInfo *info;
75 GnomeKeyringResult gkr;
77 gkr = gnome_keyring_get_info_sync(keyring_name, &info);
78 if (gkr != GNOME_KEYRING_RESULT_OK)
81 if (gnome_keyring_info_get_is_locked(info))
86 gnome_keyring_info_free(info);
91 /* Unlock the KEYRING_NAME with the KEYRING_PASSWORD. If KEYRING was
92 successfully unlocked return TRUE. */
94 unlock_gnome_keyring(const char *keyring_name,
95 const char *keyring_password,
98 GnomeKeyringInfo *info;
99 GnomeKeyringResult gkr;
101 gkr = gnome_keyring_get_info_sync(keyring_name, &info);
102 if (gkr != GNOME_KEYRING_RESULT_OK)
105 gkr = gnome_keyring_unlock_sync(keyring_name, keyring_password);
106 gnome_keyring_info_free(info);
107 if (gkr != GNOME_KEYRING_RESULT_OK)
110 return check_keyring_is_locked(keyring_name);
114 /* There is a race here: this ensures keyring is unlocked just now,
115 but will it still be unlocked when we use it? */
117 ensure_gnome_keyring_is_unlocked(svn_boolean_t non_interactive,
118 apr_hash_t *parameters,
119 apr_pool_t *scratch_pool)
121 const char *default_keyring = get_default_keyring_name(scratch_pool);
123 if (! non_interactive)
125 svn_auth_gnome_keyring_unlock_prompt_func_t unlock_prompt_func =
126 svn_hash_gets(parameters,
127 SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_FUNC);
128 void *unlock_prompt_baton =
129 svn_hash_gets(parameters,
130 SVN_AUTH_PARAM_GNOME_KEYRING_UNLOCK_PROMPT_BATON);
132 char *keyring_password;
134 if (unlock_prompt_func && check_keyring_is_locked(default_keyring))
136 SVN_ERR((*unlock_prompt_func)(&keyring_password,
141 /* If keyring is locked give up and try the next provider. */
142 if (! unlock_gnome_keyring(default_keyring, keyring_password,
149 if (check_keyring_is_locked(default_keyring))
151 return svn_error_create(SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
152 _("GNOME Keyring is locked and "
153 "we are non-interactive"));
160 /* Implementation of svn_auth__password_get_t that retrieves the password
161 from GNOME Keyring. */
163 password_get_gnome_keyring(svn_boolean_t *done,
164 const char **password,
166 const char *realmstring,
167 const char *username,
168 apr_hash_t *parameters,
169 svn_boolean_t non_interactive,
172 GnomeKeyringResult result;
177 SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
179 if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed"))
181 result = gnome_keyring_find_network_password_sync(username, realmstring,
182 NULL, NULL, NULL, NULL,
187 result = GNOME_KEYRING_RESULT_DENIED;
190 if (result == GNOME_KEYRING_RESULT_OK)
192 if (items && items->data)
194 GnomeKeyringNetworkPasswordData *item = items->data;
197 size_t len = strlen(item->password);
200 *password = apr_pstrmemdup(pool, item->password, len);
204 gnome_keyring_network_password_list_free(items);
209 svn_hash_sets(parameters, "gnome-keyring-opening-failed", "");
215 /* Implementation of svn_auth__password_set_t that stores the password in
218 password_set_gnome_keyring(svn_boolean_t *done,
220 const char *realmstring,
221 const char *username,
222 const char *password,
223 apr_hash_t *parameters,
224 svn_boolean_t non_interactive,
227 GnomeKeyringResult result;
232 SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
234 if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed"))
236 result = gnome_keyring_set_network_password_sync(NULL, /* default keyring */
237 username, realmstring,
238 NULL, NULL, NULL, NULL,
244 result = GNOME_KEYRING_RESULT_DENIED;
246 if (result != GNOME_KEYRING_RESULT_OK)
248 svn_hash_sets(parameters, "gnome-keyring-opening-failed", "");
251 *done = (result == GNOME_KEYRING_RESULT_OK);
255 /* Get cached encrypted credentials from the simple provider's cache. */
257 simple_gnome_keyring_first_creds(void **credentials,
259 void *provider_baton,
260 apr_hash_t *parameters,
261 const char *realmstring,
264 return svn_auth__simple_creds_cache_get(credentials,
265 iter_baton, provider_baton,
266 parameters, realmstring,
267 password_get_gnome_keyring,
268 SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
272 /* Save encrypted credentials to the simple provider's cache. */
274 simple_gnome_keyring_save_creds(svn_boolean_t *saved,
276 void *provider_baton,
277 apr_hash_t *parameters,
278 const char *realmstring,
281 return svn_auth__simple_creds_cache_set(saved, credentials,
282 provider_baton, parameters,
284 password_set_gnome_keyring,
285 SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
289 #if GLIB_CHECK_VERSION(2,6,0)
291 log_noop(const gchar *log_domain, GLogLevelFlags log_level,
292 const gchar *message, gpointer user_data)
299 init_gnome_keyring(void)
301 const char *application_name = NULL;
302 application_name = g_get_application_name();
303 if (!application_name)
304 g_set_application_name("Subversion");
306 /* Ideally we call g_log_set_handler() with a log_domain specific to
307 libgnome-keyring. Unfortunately, at least as of gnome-keyring
308 2.22.3, it doesn't have its own log_domain. As a result, we
309 suppress stderr spam for not only libgnome-keyring, but for
310 anything else the app is linked to that uses glib logging and
311 doesn't specify a log_domain. */
312 #if GLIB_CHECK_VERSION(2,6,0)
313 g_log_set_default_handler(log_noop, NULL);
317 static const svn_auth_provider_t gnome_keyring_simple_provider = {
318 SVN_AUTH_CRED_SIMPLE,
319 simple_gnome_keyring_first_creds,
321 simple_gnome_keyring_save_creds
326 svn_auth_get_gnome_keyring_simple_provider
327 (svn_auth_provider_object_t **provider,
330 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
332 po->vtable = &gnome_keyring_simple_provider;
335 init_gnome_keyring();
339 /*-----------------------------------------------------------------------*/
340 /* GNOME Keyring SSL client certificate passphrase provider, */
341 /* puts passphrases in GNOME Keyring */
342 /*-----------------------------------------------------------------------*/
344 /* Get cached encrypted credentials from the ssl client cert password
347 ssl_client_cert_pw_gnome_keyring_first_creds(void **credentials,
349 void *provider_baton,
350 apr_hash_t *parameters,
351 const char *realmstring,
354 return svn_auth__ssl_client_cert_pw_cache_get(
355 credentials, iter_baton, provider_baton, parameters, realmstring,
356 password_get_gnome_keyring, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
360 /* Save encrypted credentials to the ssl client cert password provider's
363 ssl_client_cert_pw_gnome_keyring_save_creds(svn_boolean_t *saved,
365 void *provider_baton,
366 apr_hash_t *parameters,
367 const char *realmstring,
370 return svn_auth__ssl_client_cert_pw_cache_set(
371 saved, credentials, provider_baton, parameters, realmstring,
372 password_set_gnome_keyring, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
376 static const svn_auth_provider_t gnome_keyring_ssl_client_cert_pw_provider = {
377 SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
378 ssl_client_cert_pw_gnome_keyring_first_creds,
380 ssl_client_cert_pw_gnome_keyring_save_creds
385 svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider
386 (svn_auth_provider_object_t **provider,
389 svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
391 po->vtable = &gnome_keyring_ssl_client_cert_pw_provider;
394 init_gnome_keyring();