]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/subversion/subversion/libsvn_auth_gnome_keyring/gnome_keyring.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / contrib / subversion / subversion / libsvn_auth_gnome_keyring / gnome_keyring.c
1 /*
2  * gnome_keyring.c: GNOME Keyring provider for SVN_AUTH_CRED_*
3  *
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
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
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
20  *    under the License.
21  * ====================================================================
22  */
23
24 /* ==================================================================== */
25
26
27 \f
28 /*** Includes. ***/
29
30 #include <apr_pools.h>
31 #include <apr_strings.h>
32 #include <glib.h>
33 #include <gnome-keyring.h>
34
35 #include "svn_auth.h"
36 #include "svn_config.h"
37 #include "svn_error.h"
38 #include "svn_hash.h"
39 #include "svn_pools.h"
40
41 #include "private/svn_auth_private.h"
42
43 #include "svn_private_config.h"
44
45
46 \f
47 /*-----------------------------------------------------------------------*/
48 /* GNOME Keyring simple provider, puts passwords in GNOME Keyring        */
49 /*-----------------------------------------------------------------------*/
50
51
52 /* Returns the default keyring name, allocated in RESULT_POOL. */
53 static char*
54 get_default_keyring_name(apr_pool_t *result_pool)
55 {
56   char *name, *def;
57   GnomeKeyringResult gkr;
58
59   gkr = gnome_keyring_get_default_keyring_sync(&name);
60   if (gkr != GNOME_KEYRING_RESULT_OK)
61     return NULL;
62
63   def = apr_pstrdup(result_pool, name);
64   g_free(name);
65
66   return def;
67 }
68
69 /* Returns TRUE if the KEYRING_NAME is locked. */
70 static svn_boolean_t
71 check_keyring_is_locked(const char *keyring_name)
72 {
73   GnomeKeyringInfo *info;
74   svn_boolean_t locked;
75   GnomeKeyringResult gkr;
76
77   gkr = gnome_keyring_get_info_sync(keyring_name, &info);
78   if (gkr != GNOME_KEYRING_RESULT_OK)
79     return FALSE;
80
81   if (gnome_keyring_info_get_is_locked(info))
82     locked = TRUE;
83   else
84     locked = FALSE;
85
86   gnome_keyring_info_free(info);
87
88   return locked;
89 }
90
91 /* Unlock the KEYRING_NAME with the KEYRING_PASSWORD. If KEYRING was
92    successfully unlocked return TRUE. */
93 static svn_boolean_t
94 unlock_gnome_keyring(const char *keyring_name,
95                      const char *keyring_password,
96                      apr_pool_t *pool)
97 {
98   GnomeKeyringInfo *info;
99   GnomeKeyringResult gkr;
100
101   gkr = gnome_keyring_get_info_sync(keyring_name, &info);
102   if (gkr != GNOME_KEYRING_RESULT_OK)
103     return FALSE;
104
105   gkr = gnome_keyring_unlock_sync(keyring_name, keyring_password);
106   gnome_keyring_info_free(info);
107   if (gkr != GNOME_KEYRING_RESULT_OK)
108     return FALSE;
109
110   return check_keyring_is_locked(keyring_name);
111 }
112
113
114 /* There is a race here: this ensures keyring is unlocked just now,
115    but will it still be unlocked when we use it? */
116 static svn_error_t *
117 ensure_gnome_keyring_is_unlocked(svn_boolean_t non_interactive,
118                                  apr_hash_t *parameters,
119                                  apr_pool_t *scratch_pool)
120 {
121   const char *default_keyring = get_default_keyring_name(scratch_pool);
122
123   if (! non_interactive)
124     {
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);
131
132       char *keyring_password;
133
134       if (unlock_prompt_func && check_keyring_is_locked(default_keyring))
135         {
136           SVN_ERR((*unlock_prompt_func)(&keyring_password,
137                                         default_keyring,
138                                         unlock_prompt_baton,
139                                         scratch_pool));
140
141           /* If keyring is locked give up and try the next provider. */
142           if (! unlock_gnome_keyring(default_keyring, keyring_password,
143                                      scratch_pool))
144             return SVN_NO_ERROR;
145         }
146     }
147   else
148     {
149       if (check_keyring_is_locked(default_keyring))
150         {
151           return svn_error_create(SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
152                                   _("GNOME Keyring is locked and "
153                                     "we are non-interactive"));
154         }
155     }
156
157   return SVN_NO_ERROR;
158 }
159
160 /* Implementation of svn_auth__password_get_t that retrieves the password
161    from GNOME Keyring. */
162 static svn_error_t *
163 password_get_gnome_keyring(svn_boolean_t *done,
164                            const char **password,
165                            apr_hash_t *creds,
166                            const char *realmstring,
167                            const char *username,
168                            apr_hash_t *parameters,
169                            svn_boolean_t non_interactive,
170                            apr_pool_t *pool)
171 {
172   GnomeKeyringResult result;
173   GList *items;
174
175   *done = FALSE;
176
177   SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
178
179   if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed"))
180     {
181       result = gnome_keyring_find_network_password_sync(username, realmstring,
182                                                         NULL, NULL, NULL, NULL,
183                                                         0, &items);
184     }
185   else
186     {
187       result = GNOME_KEYRING_RESULT_DENIED;
188     }
189
190   if (result == GNOME_KEYRING_RESULT_OK)
191     {
192       if (items && items->data)
193         {
194           GnomeKeyringNetworkPasswordData *item = items->data;
195           if (item->password)
196             {
197               size_t len = strlen(item->password);
198               if (len > 0)
199                 {
200                   *password = apr_pstrmemdup(pool, item->password, len);
201                   *done = TRUE;
202                 }
203             }
204           gnome_keyring_network_password_list_free(items);
205         }
206     }
207   else
208     {
209       svn_hash_sets(parameters, "gnome-keyring-opening-failed", "");
210     }
211
212   return SVN_NO_ERROR;
213 }
214
215 /* Implementation of svn_auth__password_set_t that stores the password in
216    GNOME Keyring. */
217 static svn_error_t *
218 password_set_gnome_keyring(svn_boolean_t *done,
219                            apr_hash_t *creds,
220                            const char *realmstring,
221                            const char *username,
222                            const char *password,
223                            apr_hash_t *parameters,
224                            svn_boolean_t non_interactive,
225                            apr_pool_t *pool)
226 {
227   GnomeKeyringResult result;
228   guint32 item_id;
229
230   *done = FALSE;
231
232   SVN_ERR(ensure_gnome_keyring_is_unlocked(non_interactive, parameters, pool));
233
234   if (! svn_hash_gets(parameters, "gnome-keyring-opening-failed"))
235     {
236       result = gnome_keyring_set_network_password_sync(NULL, /* default keyring */
237                                                        username, realmstring,
238                                                        NULL, NULL, NULL, NULL,
239                                                        0, password,
240                                                        &item_id);
241     }
242   else
243     {
244       result = GNOME_KEYRING_RESULT_DENIED;
245     }
246   if (result != GNOME_KEYRING_RESULT_OK)
247     {
248       svn_hash_sets(parameters, "gnome-keyring-opening-failed", "");
249     }
250
251   *done = (result == GNOME_KEYRING_RESULT_OK);
252   return SVN_NO_ERROR;
253 }
254
255 /* Get cached encrypted credentials from the simple provider's cache. */
256 static svn_error_t *
257 simple_gnome_keyring_first_creds(void **credentials,
258                                  void **iter_baton,
259                                  void *provider_baton,
260                                  apr_hash_t *parameters,
261                                  const char *realmstring,
262                                  apr_pool_t *pool)
263 {
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,
269                                           pool);
270 }
271
272 /* Save encrypted credentials to the simple provider's cache. */
273 static svn_error_t *
274 simple_gnome_keyring_save_creds(svn_boolean_t *saved,
275                                 void *credentials,
276                                 void *provider_baton,
277                                 apr_hash_t *parameters,
278                                 const char *realmstring,
279                                 apr_pool_t *pool)
280 {
281   return svn_auth__simple_creds_cache_set(saved, credentials,
282                                           provider_baton, parameters,
283                                           realmstring,
284                                           password_set_gnome_keyring,
285                                           SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE,
286                                           pool);
287 }
288
289 #if GLIB_CHECK_VERSION(2,6,0)
290 static void
291 log_noop(const gchar *log_domain, GLogLevelFlags log_level,
292          const gchar *message, gpointer user_data)
293 {
294   /* do nothing */
295 }
296 #endif
297
298 static void
299 init_gnome_keyring(void)
300 {
301   const char *application_name = NULL;
302   application_name = g_get_application_name();
303   if (!application_name)
304     g_set_application_name("Subversion");
305
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);
314 #endif
315 }
316
317 static const svn_auth_provider_t gnome_keyring_simple_provider = {
318   SVN_AUTH_CRED_SIMPLE,
319   simple_gnome_keyring_first_creds,
320   NULL,
321   simple_gnome_keyring_save_creds
322 };
323
324 /* Public API */
325 void
326 svn_auth_get_gnome_keyring_simple_provider
327     (svn_auth_provider_object_t **provider,
328      apr_pool_t *pool)
329 {
330   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
331
332   po->vtable = &gnome_keyring_simple_provider;
333   *provider = po;
334
335   init_gnome_keyring();
336 }
337
338 \f
339 /*-----------------------------------------------------------------------*/
340 /* GNOME Keyring SSL client certificate passphrase provider,             */
341 /* puts passphrases in GNOME Keyring                                     */
342 /*-----------------------------------------------------------------------*/
343
344 /* Get cached encrypted credentials from the ssl client cert password
345    provider's cache. */
346 static svn_error_t *
347 ssl_client_cert_pw_gnome_keyring_first_creds(void **credentials,
348                                              void **iter_baton,
349                                              void *provider_baton,
350                                              apr_hash_t *parameters,
351                                              const char *realmstring,
352                                              apr_pool_t *pool)
353 {
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,
357              pool);
358 }
359
360 /* Save encrypted credentials to the ssl client cert password provider's
361    cache. */
362 static svn_error_t *
363 ssl_client_cert_pw_gnome_keyring_save_creds(svn_boolean_t *saved,
364                                             void *credentials,
365                                             void *provider_baton,
366                                             apr_hash_t *parameters,
367                                             const char *realmstring,
368                                             apr_pool_t *pool)
369 {
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,
373              pool);
374 }
375
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,
379   NULL,
380   ssl_client_cert_pw_gnome_keyring_save_creds
381 };
382
383 /* Public API */
384 void
385 svn_auth_get_gnome_keyring_ssl_client_cert_pw_provider
386     (svn_auth_provider_object_t **provider,
387      apr_pool_t *pool)
388 {
389   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
390
391   po->vtable = &gnome_keyring_ssl_client_cert_pw_provider;
392   *provider = po;
393
394   init_gnome_keyring();
395 }