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