kwallet.cpp revision 251881
1251881Speter/*
2251881Speter * kwallet.cpp: KWallet provider for SVN_AUTH_CRED_*
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter/* ==================================================================== */
25251881Speter
26251881Speter
27251881Speter
28251881Speter/*** Includes. ***/
29251881Speter
30251881Speter#include <stdlib.h>
31251881Speter#include <string.h>
32251881Speter#include <unistd.h>
33251881Speter
34251881Speter#include <apr_pools.h>
35251881Speter#include <apr_strings.h>
36251881Speter
37251881Speter#include <dbus/dbus.h>
38251881Speter#include <QtCore/QCoreApplication>
39251881Speter#include <QtCore/QString>
40251881Speter
41251881Speter#include <kaboutdata.h>
42251881Speter#include <kcmdlineargs.h>
43251881Speter#include <kcomponentdata.h>
44251881Speter#include <klocalizedstring.h>
45251881Speter#include <kwallet.h>
46251881Speter
47251881Speter#include "svn_auth.h"
48251881Speter#include "svn_config.h"
49251881Speter#include "svn_error.h"
50251881Speter#include "svn_io.h"
51251881Speter#include "svn_pools.h"
52251881Speter#include "svn_string.h"
53251881Speter#include "svn_version.h"
54251881Speter
55251881Speter#include "private/svn_auth_private.h"
56251881Speter
57251881Speter#include "svn_private_config.h"
58251881Speter
59251881Speter
60251881Speter/*-----------------------------------------------------------------------*/
61251881Speter/* KWallet simple provider, puts passwords in KWallet                    */
62251881Speter/*-----------------------------------------------------------------------*/
63251881Speter
64251881Speterstatic int q_argc = 1;
65251881Speterstatic char q_argv0[] = "svn"; // Build non-const char * from string constant
66251881Speterstatic char *q_argv[] = { q_argv0 };
67251881Speter
68251881Speterstatic const char *
69251881Speterget_application_name(apr_hash_t *parameters,
70251881Speter                     apr_pool_t *pool)
71251881Speter{
72251881Speter  svn_config_t *config =
73251881Speter    static_cast<svn_config_t *> (apr_hash_get(parameters,
74251881Speter                                              SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG,
75251881Speter                                              APR_HASH_KEY_STRING));
76251881Speter  svn_boolean_t svn_application_name_with_pid;
77251881Speter  svn_config_get_bool(config,
78251881Speter                      &svn_application_name_with_pid,
79251881Speter                      SVN_CONFIG_SECTION_AUTH,
80251881Speter                      SVN_CONFIG_OPTION_KWALLET_SVN_APPLICATION_NAME_WITH_PID,
81251881Speter                      FALSE);
82251881Speter  const char *svn_application_name;
83251881Speter  if (svn_application_name_with_pid)
84251881Speter    {
85251881Speter      svn_application_name = apr_psprintf(pool, "Subversion [%ld]", long(getpid()));
86251881Speter    }
87251881Speter  else
88251881Speter    {
89251881Speter      svn_application_name = "Subversion";
90251881Speter    }
91251881Speter  return svn_application_name;
92251881Speter}
93251881Speter
94251881Speterstatic QString
95251881Speterget_wallet_name(apr_hash_t *parameters)
96251881Speter{
97251881Speter  svn_config_t *config =
98251881Speter    static_cast<svn_config_t *> (apr_hash_get(parameters,
99251881Speter                                              SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG,
100251881Speter                                              APR_HASH_KEY_STRING));
101251881Speter  const char *wallet_name;
102251881Speter  svn_config_get(config,
103251881Speter                 &wallet_name,
104251881Speter                 SVN_CONFIG_SECTION_AUTH,
105251881Speter                 SVN_CONFIG_OPTION_KWALLET_WALLET,
106251881Speter                 "");
107251881Speter  if (strcmp(wallet_name, "") == 0)
108251881Speter    {
109251881Speter      return KWallet::Wallet::NetworkWallet();
110251881Speter    }
111251881Speter  else
112251881Speter    {
113251881Speter      return QString::fromUtf8(wallet_name);
114251881Speter    }
115251881Speter}
116251881Speter
117251881Speterstatic WId
118251881Speterget_wid(void)
119251881Speter{
120251881Speter  WId wid = 1;
121251881Speter  const char *wid_env_string = getenv("WINDOWID");
122251881Speter
123251881Speter  if (wid_env_string)
124251881Speter    {
125251881Speter      apr_int64_t wid_env;
126251881Speter      svn_error_t *err;
127251881Speter
128251881Speter      err = svn_cstring_atoi64(&wid_env, wid_env_string);
129251881Speter      if (err)
130251881Speter        svn_error_clear(err);
131251881Speter      else
132251881Speter        wid = (WId)wid_env;
133251881Speter    }
134251881Speter
135251881Speter  return wid;
136251881Speter}
137251881Speter
138251881Speterstatic KWallet::Wallet *
139251881Speterget_wallet(QString wallet_name,
140251881Speter           apr_hash_t *parameters)
141251881Speter{
142251881Speter  KWallet::Wallet *wallet =
143251881Speter    static_cast<KWallet::Wallet *> (apr_hash_get(parameters,
144251881Speter                                                 "kwallet-wallet",
145251881Speter                                                 APR_HASH_KEY_STRING));
146251881Speter  if (! wallet && ! apr_hash_get(parameters,
147251881Speter                                 "kwallet-opening-failed",
148251881Speter                                 APR_HASH_KEY_STRING))
149251881Speter    {
150251881Speter      wallet = KWallet::Wallet::openWallet(wallet_name, get_wid(),
151251881Speter                                           KWallet::Wallet::Synchronous);
152251881Speter    }
153251881Speter  if (wallet)
154251881Speter    {
155251881Speter      apr_hash_set(parameters,
156251881Speter                   "kwallet-wallet",
157251881Speter                   APR_HASH_KEY_STRING,
158251881Speter                   wallet);
159251881Speter    }
160251881Speter  else
161251881Speter    {
162251881Speter      apr_hash_set(parameters,
163251881Speter                   "kwallet-opening-failed",
164251881Speter                   APR_HASH_KEY_STRING,
165251881Speter                   "");
166251881Speter    }
167251881Speter  return wallet;
168251881Speter}
169251881Speter
170251881Speterstatic apr_status_t
171251881Speterkwallet_terminate(void *data)
172251881Speter{
173251881Speter  apr_hash_t *parameters = static_cast<apr_hash_t *> (data);
174251881Speter  if (apr_hash_get(parameters, "kwallet-initialized", APR_HASH_KEY_STRING))
175251881Speter    {
176251881Speter      KWallet::Wallet *wallet = get_wallet(NULL, parameters);
177251881Speter      delete wallet;
178251881Speter      apr_hash_set(parameters,
179251881Speter                   "kwallet-initialized",
180251881Speter                   APR_HASH_KEY_STRING,
181251881Speter                   NULL);
182251881Speter    }
183251881Speter  return APR_SUCCESS;
184251881Speter}
185251881Speter
186251881Speter/* Implementation of svn_auth__password_get_t that retrieves
187251881Speter   the password from KWallet. */
188251881Speterstatic svn_error_t *
189251881Speterkwallet_password_get(svn_boolean_t *done,
190251881Speter                     const char **password,
191251881Speter                     apr_hash_t *creds,
192251881Speter                     const char *realmstring,
193251881Speter                     const char *username,
194251881Speter                     apr_hash_t *parameters,
195251881Speter                     svn_boolean_t non_interactive,
196251881Speter                     apr_pool_t *pool)
197251881Speter{
198251881Speter  QString wallet_name = get_wallet_name(parameters);
199251881Speter
200251881Speter  *done = FALSE;
201251881Speter
202251881Speter  if (! dbus_bus_get(DBUS_BUS_SESSION, NULL))
203251881Speter    {
204251881Speter      return SVN_NO_ERROR;
205251881Speter    }
206251881Speter
207251881Speter  if (non_interactive)
208251881Speter    {
209251881Speter      if (!KWallet::Wallet::isOpen(wallet_name))
210251881Speter        return SVN_NO_ERROR;
211251881Speter
212251881Speter      /* There is a race here: the wallet was open just now, but will
213251881Speter         it still be open when we come to use it below? */
214251881Speter    }
215251881Speter
216251881Speter  QCoreApplication *app;
217251881Speter  if (! qApp)
218251881Speter    {
219251881Speter      int argc = q_argc;
220251881Speter      app = new QCoreApplication(argc, q_argv);
221251881Speter    }
222251881Speter
223251881Speter  KCmdLineArgs::init(q_argc, q_argv,
224251881Speter                     get_application_name(parameters, pool),
225251881Speter                     "subversion",
226251881Speter                     ki18n(get_application_name(parameters, pool)),
227251881Speter                     SVN_VER_NUMBER,
228251881Speter                     ki18n("Version control system"),
229251881Speter                     KCmdLineArgs::CmdLineArgKDE);
230251881Speter  KComponentData component_data(KCmdLineArgs::aboutData());
231251881Speter  QString folder = QString::fromUtf8("Subversion");
232251881Speter  QString key =
233251881Speter    QString::fromUtf8(username) + "@" + QString::fromUtf8(realmstring);
234251881Speter  if (! KWallet::Wallet::keyDoesNotExist(wallet_name, folder, key))
235251881Speter    {
236251881Speter      KWallet::Wallet *wallet = get_wallet(wallet_name, parameters);
237251881Speter      if (wallet)
238251881Speter        {
239251881Speter          apr_hash_set(parameters,
240251881Speter                       "kwallet-initialized",
241251881Speter                       APR_HASH_KEY_STRING,
242251881Speter                       "");
243251881Speter          if (wallet->setFolder(folder))
244251881Speter            {
245251881Speter              QString q_password;
246251881Speter              if (wallet->readPassword(key, q_password) == 0)
247251881Speter                {
248251881Speter                  *password = apr_pstrmemdup(pool,
249251881Speter                                             q_password.toUtf8().data(),
250251881Speter                                             q_password.size());
251251881Speter                  *done = TRUE;
252251881Speter                }
253251881Speter            }
254251881Speter        }
255251881Speter    }
256251881Speter
257251881Speter  apr_pool_cleanup_register(pool, parameters, kwallet_terminate,
258251881Speter                            apr_pool_cleanup_null);
259251881Speter
260251881Speter  return SVN_NO_ERROR;
261251881Speter}
262251881Speter
263251881Speter/* Implementation of svn_auth__password_set_t that stores
264251881Speter   the password in KWallet. */
265251881Speterstatic svn_error_t *
266251881Speterkwallet_password_set(svn_boolean_t *done,
267251881Speter                     apr_hash_t *creds,
268251881Speter                     const char *realmstring,
269251881Speter                     const char *username,
270251881Speter                     const char *password,
271251881Speter                     apr_hash_t *parameters,
272251881Speter                     svn_boolean_t non_interactive,
273251881Speter                     apr_pool_t *pool)
274251881Speter{
275251881Speter  QString wallet_name = get_wallet_name(parameters);
276251881Speter
277251881Speter  *done = FALSE;
278251881Speter
279251881Speter  if (! dbus_bus_get(DBUS_BUS_SESSION, NULL))
280251881Speter    {
281251881Speter      return SVN_NO_ERROR;
282251881Speter    }
283251881Speter
284251881Speter  if (non_interactive)
285251881Speter    {
286251881Speter      if (!KWallet::Wallet::isOpen(wallet_name))
287251881Speter        return SVN_NO_ERROR;
288251881Speter
289251881Speter      /* There is a race here: the wallet was open just now, but will
290251881Speter         it still be open when we come to use it below? */
291251881Speter    }
292251881Speter
293251881Speter  QCoreApplication *app;
294251881Speter  if (! qApp)
295251881Speter    {
296251881Speter      int argc = q_argc;
297251881Speter      app = new QCoreApplication(argc, q_argv);
298251881Speter    }
299251881Speter
300251881Speter  KCmdLineArgs::init(q_argc, q_argv,
301251881Speter                     get_application_name(parameters, pool),
302251881Speter                     "subversion",
303251881Speter                     ki18n(get_application_name(parameters, pool)),
304251881Speter                     SVN_VER_NUMBER,
305251881Speter                     ki18n("Version control system"),
306251881Speter                     KCmdLineArgs::CmdLineArgKDE);
307251881Speter  KComponentData component_data(KCmdLineArgs::aboutData());
308251881Speter  QString q_password = QString::fromUtf8(password);
309251881Speter  QString folder = QString::fromUtf8("Subversion");
310251881Speter  KWallet::Wallet *wallet = get_wallet(wallet_name, parameters);
311251881Speter  if (wallet)
312251881Speter    {
313251881Speter      apr_hash_set(parameters,
314251881Speter                   "kwallet-initialized",
315251881Speter                   APR_HASH_KEY_STRING,
316251881Speter                   "");
317251881Speter      if (! wallet->hasFolder(folder))
318251881Speter        {
319251881Speter          wallet->createFolder(folder);
320251881Speter        }
321251881Speter      if (wallet->setFolder(folder))
322251881Speter        {
323251881Speter          QString key = QString::fromUtf8(username) + "@"
324251881Speter            + QString::fromUtf8(realmstring);
325251881Speter          if (wallet->writePassword(key, q_password) == 0)
326251881Speter            {
327251881Speter              *done = TRUE;
328251881Speter            }
329251881Speter        }
330251881Speter    }
331251881Speter
332251881Speter  apr_pool_cleanup_register(pool, parameters, kwallet_terminate,
333251881Speter                            apr_pool_cleanup_null);
334251881Speter
335251881Speter  return SVN_NO_ERROR;
336251881Speter}
337251881Speter
338251881Speter/* Get cached encrypted credentials from the simple provider's cache. */
339251881Speterstatic svn_error_t *
340251881Speterkwallet_simple_first_creds(void **credentials,
341251881Speter                           void **iter_baton,
342251881Speter                           void *provider_baton,
343251881Speter                           apr_hash_t *parameters,
344251881Speter                           const char *realmstring,
345251881Speter                           apr_pool_t *pool)
346251881Speter{
347251881Speter  return svn_auth__simple_creds_cache_get(credentials,
348251881Speter                                          iter_baton,
349251881Speter                                          provider_baton,
350251881Speter                                          parameters,
351251881Speter                                          realmstring,
352251881Speter                                          kwallet_password_get,
353251881Speter                                          SVN_AUTH__KWALLET_PASSWORD_TYPE,
354251881Speter                                          pool);
355251881Speter}
356251881Speter
357251881Speter/* Save encrypted credentials to the simple provider's cache. */
358251881Speterstatic svn_error_t *
359251881Speterkwallet_simple_save_creds(svn_boolean_t *saved,
360251881Speter                          void *credentials,
361251881Speter                          void *provider_baton,
362251881Speter                          apr_hash_t *parameters,
363251881Speter                          const char *realmstring,
364251881Speter                          apr_pool_t *pool)
365251881Speter{
366251881Speter  return svn_auth__simple_creds_cache_set(saved, credentials,
367251881Speter                                          provider_baton,
368251881Speter                                          parameters,
369251881Speter                                          realmstring,
370251881Speter                                          kwallet_password_set,
371251881Speter                                          SVN_AUTH__KWALLET_PASSWORD_TYPE,
372251881Speter                                          pool);
373251881Speter}
374251881Speter
375251881Speterstatic const svn_auth_provider_t kwallet_simple_provider = {
376251881Speter  SVN_AUTH_CRED_SIMPLE,
377251881Speter  kwallet_simple_first_creds,
378251881Speter  NULL,
379251881Speter  kwallet_simple_save_creds
380251881Speter};
381251881Speter
382251881Speter/* Public API */
383251881Speterextern "C" {
384251881Spetervoid
385251881Spetersvn_auth_get_kwallet_simple_provider(svn_auth_provider_object_t **provider,
386251881Speter                                     apr_pool_t *pool)
387251881Speter{
388251881Speter  svn_auth_provider_object_t *po =
389251881Speter    static_cast<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po)));
390251881Speter
391251881Speter  po->vtable = &kwallet_simple_provider;
392251881Speter  *provider = po;
393251881Speter}
394251881Speter}
395251881Speter
396251881Speter
397251881Speter/*-----------------------------------------------------------------------*/
398251881Speter/* KWallet SSL client certificate passphrase provider,                   */
399251881Speter/* puts passphrases in KWallet                                           */
400251881Speter/*-----------------------------------------------------------------------*/
401251881Speter
402251881Speter/* Get cached encrypted credentials from the ssl client cert password
403251881Speter   provider's cache. */
404251881Speterstatic svn_error_t *
405251881Speterkwallet_ssl_client_cert_pw_first_creds(void **credentials,
406251881Speter                                       void **iter_baton,
407251881Speter                                       void *provider_baton,
408251881Speter                                       apr_hash_t *parameters,
409251881Speter                                       const char *realmstring,
410251881Speter                                       apr_pool_t *pool)
411251881Speter{
412251881Speter  return svn_auth__ssl_client_cert_pw_cache_get(credentials,
413251881Speter                                                iter_baton, provider_baton,
414251881Speter                                                parameters, realmstring,
415251881Speter                                                kwallet_password_get,
416251881Speter                                                SVN_AUTH__KWALLET_PASSWORD_TYPE,
417251881Speter                                                pool);
418251881Speter}
419251881Speter
420251881Speter/* Save encrypted credentials to the ssl client cert password provider's
421251881Speter   cache. */
422251881Speterstatic svn_error_t *
423251881Speterkwallet_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
424251881Speter                                      void *credentials,
425251881Speter                                      void *provider_baton,
426251881Speter                                      apr_hash_t *parameters,
427251881Speter                                      const char *realmstring,
428251881Speter                                      apr_pool_t *pool)
429251881Speter{
430251881Speter  return svn_auth__ssl_client_cert_pw_cache_set(saved, credentials,
431251881Speter                                                provider_baton, parameters,
432251881Speter                                                realmstring,
433251881Speter                                                kwallet_password_set,
434251881Speter                                                SVN_AUTH__KWALLET_PASSWORD_TYPE,
435251881Speter                                                pool);
436251881Speter}
437251881Speter
438251881Speterstatic const svn_auth_provider_t kwallet_ssl_client_cert_pw_provider = {
439251881Speter  SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
440251881Speter  kwallet_ssl_client_cert_pw_first_creds,
441251881Speter  NULL,
442251881Speter  kwallet_ssl_client_cert_pw_save_creds
443251881Speter};
444251881Speter
445251881Speter/* Public API */
446251881Speterextern "C" {
447251881Spetervoid
448251881Spetersvn_auth_get_kwallet_ssl_client_cert_pw_provider
449251881Speter    (svn_auth_provider_object_t **provider,
450251881Speter     apr_pool_t *pool)
451251881Speter{
452251881Speter  svn_auth_provider_object_t *po =
453251881Speter    static_cast<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po)));
454251881Speter
455251881Speter  po->vtable = &kwallet_ssl_client_cert_pw_provider;
456251881Speter  *provider = po;
457251881Speter}
458251881Speter}
459