]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_auth_kwallet/kwallet.cpp
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / libsvn_auth_kwallet / kwallet.cpp
1 /*
2  * kwallet.cpp: KWallet 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 <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include <apr_pools.h>
35 #include <apr_strings.h>
36
37 #include <dbus/dbus.h>
38 #include <QtCore/QCoreApplication>
39 #include <QtCore/QString>
40
41 #include <kaboutdata.h>
42 #include <kcmdlineargs.h>
43 #include <kcomponentdata.h>
44 #include <klocalizedstring.h>
45 #include <kwallet.h>
46
47 #include "svn_auth.h"
48 #include "svn_config.h"
49 #include "svn_error.h"
50 #include "svn_hash.h"
51 #include "svn_io.h"
52 #include "svn_pools.h"
53 #include "svn_string.h"
54 #include "svn_version.h"
55
56 #include "private/svn_auth_private.h"
57
58 #include "svn_private_config.h"
59
60
61 /*-----------------------------------------------------------------------*/
62 /* KWallet simple provider, puts passwords in KWallet                    */
63 /*-----------------------------------------------------------------------*/
64
65 static int q_argc = 1;
66 static char q_argv0[] = "svn"; // Build non-const char * from string constant
67 static char *q_argv[] = { q_argv0 };
68
69 static const char *
70 get_application_name(apr_hash_t *parameters,
71                      apr_pool_t *pool)
72 {
73   svn_config_t *config =
74     static_cast<svn_config_t *> (apr_hash_get(parameters,
75                                               SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG,
76                                               APR_HASH_KEY_STRING));
77   svn_boolean_t svn_application_name_with_pid;
78   svn_config_get_bool(config,
79                       &svn_application_name_with_pid,
80                       SVN_CONFIG_SECTION_AUTH,
81                       SVN_CONFIG_OPTION_KWALLET_SVN_APPLICATION_NAME_WITH_PID,
82                       FALSE);
83   const char *svn_application_name;
84   if (svn_application_name_with_pid)
85     {
86       svn_application_name = apr_psprintf(pool, "Subversion [%ld]", long(getpid()));
87     }
88   else
89     {
90       svn_application_name = "Subversion";
91     }
92   return svn_application_name;
93 }
94
95 static QString
96 get_wallet_name(apr_hash_t *parameters)
97 {
98   svn_config_t *config =
99     static_cast<svn_config_t *> (apr_hash_get(parameters,
100                                               SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG,
101                                               APR_HASH_KEY_STRING));
102   const char *wallet_name;
103   svn_config_get(config,
104                  &wallet_name,
105                  SVN_CONFIG_SECTION_AUTH,
106                  SVN_CONFIG_OPTION_KWALLET_WALLET,
107                  "");
108   if (strcmp(wallet_name, "") == 0)
109     {
110       return KWallet::Wallet::NetworkWallet();
111     }
112   else
113     {
114       return QString::fromUtf8(wallet_name);
115     }
116 }
117
118 static WId
119 get_wid(void)
120 {
121   WId wid = 1;
122   const char *wid_env_string = getenv("WINDOWID");
123
124   if (wid_env_string)
125     {
126       apr_int64_t wid_env;
127       svn_error_t *err;
128
129       err = svn_cstring_atoi64(&wid_env, wid_env_string);
130       if (err)
131         svn_error_clear(err);
132       else
133         wid = (WId)wid_env;
134     }
135
136   return wid;
137 }
138
139 /* Forward definition */
140 static apr_status_t
141 kwallet_terminate(void *data);
142
143 static KWallet::Wallet *
144 get_wallet(QString wallet_name,
145            apr_hash_t *parameters)
146 {
147   KWallet::Wallet *wallet =
148     static_cast<KWallet::Wallet *> (svn_hash_gets(parameters,
149                                                   "kwallet-wallet"));
150   if (! wallet && ! svn_hash_gets(parameters, "kwallet-opening-failed"))
151     {
152       wallet = KWallet::Wallet::openWallet(wallet_name, get_wid(),
153                                            KWallet::Wallet::Synchronous);
154
155       if (wallet)
156         {
157           svn_hash_sets(parameters, "kwallet-wallet", wallet);
158
159           apr_pool_cleanup_register(apr_hash_pool_get(parameters),
160                                     parameters, kwallet_terminate,
161                                     apr_pool_cleanup_null);
162
163           svn_hash_sets(parameters, "kwallet-initialized", "");
164         }
165       else
166         {
167           svn_hash_sets(parameters, "kwallet-opening-failed", "");
168         }
169     }
170   return wallet;
171 }
172
173 static apr_status_t
174 kwallet_terminate(void *data)
175 {
176   apr_hash_t *parameters = static_cast<apr_hash_t *> (data);
177   if (svn_hash_gets(parameters, "kwallet-initialized"))
178     {
179       KWallet::Wallet *wallet = get_wallet(NULL, parameters);
180       delete wallet;
181       svn_hash_sets(parameters, "kwallet-wallet", NULL);
182       svn_hash_sets(parameters, "kwallet-initialized", NULL);
183     }
184   return APR_SUCCESS;
185 }
186
187 /* Implementation of svn_auth__password_get_t that retrieves
188    the password from KWallet. */
189 static svn_error_t *
190 kwallet_password_get(svn_boolean_t *done,
191                      const char **password,
192                      apr_hash_t *creds,
193                      const char *realmstring,
194                      const char *username,
195                      apr_hash_t *parameters,
196                      svn_boolean_t non_interactive,
197                      apr_pool_t *pool)
198 {
199   QString wallet_name = get_wallet_name(parameters);
200
201   *done = FALSE;
202
203   if (! dbus_bus_get(DBUS_BUS_SESSION, NULL))
204     {
205       return SVN_NO_ERROR;
206     }
207
208   if (non_interactive)
209     {
210       if (!KWallet::Wallet::isOpen(wallet_name))
211         return SVN_NO_ERROR;
212
213       /* There is a race here: the wallet was open just now, but will
214          it still be open when we come to use it below? */
215     }
216
217   QCoreApplication *app;
218   if (! qApp)
219     {
220       int argc = q_argc;
221       app = new QCoreApplication(argc, q_argv);
222     }
223
224   KCmdLineArgs::init(q_argc, q_argv,
225                      get_application_name(parameters, pool),
226                      "subversion",
227                      ki18n(get_application_name(parameters, pool)),
228                      SVN_VER_NUMBER,
229                      ki18n("Version control system"),
230                      KCmdLineArgs::CmdLineArgKDE);
231   KComponentData component_data(KCmdLineArgs::aboutData());
232   QString folder = QString::fromUtf8("Subversion");
233   QString key =
234     QString::fromUtf8(username) + "@" + QString::fromUtf8(realmstring);
235   if (! KWallet::Wallet::keyDoesNotExist(wallet_name, folder, key))
236     {
237       KWallet::Wallet *wallet = get_wallet(wallet_name, parameters);
238       if (wallet)
239         {
240           if (wallet->setFolder(folder))
241             {
242               QString q_password;
243               if (wallet->readPassword(key, q_password) == 0)
244                 {
245                   *password = apr_pstrmemdup(pool,
246                                              q_password.toUtf8().data(),
247                                              q_password.size());
248                   *done = TRUE;
249                 }
250             }
251         }
252     }
253
254   return SVN_NO_ERROR;
255 }
256
257 /* Implementation of svn_auth__password_set_t that stores
258    the password in KWallet. */
259 static svn_error_t *
260 kwallet_password_set(svn_boolean_t *done,
261                      apr_hash_t *creds,
262                      const char *realmstring,
263                      const char *username,
264                      const char *password,
265                      apr_hash_t *parameters,
266                      svn_boolean_t non_interactive,
267                      apr_pool_t *pool)
268 {
269   QString wallet_name = get_wallet_name(parameters);
270
271   *done = FALSE;
272
273   if (! dbus_bus_get(DBUS_BUS_SESSION, NULL))
274     {
275       return SVN_NO_ERROR;
276     }
277
278   if (non_interactive)
279     {
280       if (!KWallet::Wallet::isOpen(wallet_name))
281         return SVN_NO_ERROR;
282
283       /* There is a race here: the wallet was open just now, but will
284          it still be open when we come to use it below? */
285     }
286
287   QCoreApplication *app;
288   if (! qApp)
289     {
290       int argc = q_argc;
291       app = new QCoreApplication(argc, q_argv);
292     }
293
294   KCmdLineArgs::init(q_argc, q_argv,
295                      get_application_name(parameters, pool),
296                      "subversion",
297                      ki18n(get_application_name(parameters, pool)),
298                      SVN_VER_NUMBER,
299                      ki18n("Version control system"),
300                      KCmdLineArgs::CmdLineArgKDE);
301   KComponentData component_data(KCmdLineArgs::aboutData());
302   QString q_password = QString::fromUtf8(password);
303   QString folder = QString::fromUtf8("Subversion");
304   KWallet::Wallet *wallet = get_wallet(wallet_name, parameters);
305   if (wallet)
306     {
307       if (! wallet->hasFolder(folder))
308         {
309           wallet->createFolder(folder);
310         }
311       if (wallet->setFolder(folder))
312         {
313           QString key = QString::fromUtf8(username) + "@"
314             + QString::fromUtf8(realmstring);
315           if (wallet->writePassword(key, q_password) == 0)
316             {
317               *done = TRUE;
318             }
319         }
320     }
321
322   return SVN_NO_ERROR;
323 }
324
325 /* Get cached encrypted credentials from the simple provider's cache. */
326 static svn_error_t *
327 kwallet_simple_first_creds(void **credentials,
328                            void **iter_baton,
329                            void *provider_baton,
330                            apr_hash_t *parameters,
331                            const char *realmstring,
332                            apr_pool_t *pool)
333 {
334   return svn_auth__simple_creds_cache_get(credentials,
335                                           iter_baton,
336                                           provider_baton,
337                                           parameters,
338                                           realmstring,
339                                           kwallet_password_get,
340                                           SVN_AUTH__KWALLET_PASSWORD_TYPE,
341                                           pool);
342 }
343
344 /* Save encrypted credentials to the simple provider's cache. */
345 static svn_error_t *
346 kwallet_simple_save_creds(svn_boolean_t *saved,
347                           void *credentials,
348                           void *provider_baton,
349                           apr_hash_t *parameters,
350                           const char *realmstring,
351                           apr_pool_t *pool)
352 {
353   return svn_auth__simple_creds_cache_set(saved, credentials,
354                                           provider_baton,
355                                           parameters,
356                                           realmstring,
357                                           kwallet_password_set,
358                                           SVN_AUTH__KWALLET_PASSWORD_TYPE,
359                                           pool);
360 }
361
362 static const svn_auth_provider_t kwallet_simple_provider = {
363   SVN_AUTH_CRED_SIMPLE,
364   kwallet_simple_first_creds,
365   NULL,
366   kwallet_simple_save_creds
367 };
368
369 /* Public API */
370 extern "C" {
371 void
372 svn_auth_get_kwallet_simple_provider(svn_auth_provider_object_t **provider,
373                                      apr_pool_t *pool)
374 {
375   svn_auth_provider_object_t *po =
376     static_cast<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po)));
377
378   po->vtable = &kwallet_simple_provider;
379   *provider = po;
380 }
381 }
382
383 \f
384 /*-----------------------------------------------------------------------*/
385 /* KWallet SSL client certificate passphrase provider,                   */
386 /* puts passphrases in KWallet                                           */
387 /*-----------------------------------------------------------------------*/
388
389 /* Get cached encrypted credentials from the ssl client cert password
390    provider's cache. */
391 static svn_error_t *
392 kwallet_ssl_client_cert_pw_first_creds(void **credentials,
393                                        void **iter_baton,
394                                        void *provider_baton,
395                                        apr_hash_t *parameters,
396                                        const char *realmstring,
397                                        apr_pool_t *pool)
398 {
399   return svn_auth__ssl_client_cert_pw_cache_get(credentials,
400                                                 iter_baton, provider_baton,
401                                                 parameters, realmstring,
402                                                 kwallet_password_get,
403                                                 SVN_AUTH__KWALLET_PASSWORD_TYPE,
404                                                 pool);
405 }
406
407 /* Save encrypted credentials to the ssl client cert password provider's
408    cache. */
409 static svn_error_t *
410 kwallet_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
411                                       void *credentials,
412                                       void *provider_baton,
413                                       apr_hash_t *parameters,
414                                       const char *realmstring,
415                                       apr_pool_t *pool)
416 {
417   return svn_auth__ssl_client_cert_pw_cache_set(saved, credentials,
418                                                 provider_baton, parameters,
419                                                 realmstring,
420                                                 kwallet_password_set,
421                                                 SVN_AUTH__KWALLET_PASSWORD_TYPE,
422                                                 pool);
423 }
424
425 static const svn_auth_provider_t kwallet_ssl_client_cert_pw_provider = {
426   SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
427   kwallet_ssl_client_cert_pw_first_creds,
428   NULL,
429   kwallet_ssl_client_cert_pw_save_creds
430 };
431
432 /* Public API */
433 extern "C" {
434 void
435 svn_auth_get_kwallet_ssl_client_cert_pw_provider
436     (svn_auth_provider_object_t **provider,
437      apr_pool_t *pool)
438 {
439   svn_auth_provider_object_t *po =
440     static_cast<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po)));
441
442   po->vtable = &kwallet_ssl_client_cert_pw_provider;
443   *provider = po;
444 }
445 }