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