kwallet.cpp revision 289180
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"
50289180Speter#include "svn_hash.h"
51251881Speter#include "svn_io.h"
52251881Speter#include "svn_pools.h"
53251881Speter#include "svn_string.h"
54251881Speter#include "svn_version.h"
55251881Speter
56251881Speter#include "private/svn_auth_private.h"
57251881Speter
58251881Speter#include "svn_private_config.h"
59251881Speter
60251881Speter
61251881Speter/*-----------------------------------------------------------------------*/
62251881Speter/* KWallet simple provider, puts passwords in KWallet                    */
63251881Speter/*-----------------------------------------------------------------------*/
64251881Speter
65251881Speterstatic int q_argc = 1;
66251881Speterstatic char q_argv0[] = "svn"; // Build non-const char * from string constant
67251881Speterstatic char *q_argv[] = { q_argv0 };
68251881Speter
69251881Speterstatic const char *
70251881Speterget_application_name(apr_hash_t *parameters,
71251881Speter                     apr_pool_t *pool)
72251881Speter{
73251881Speter  svn_config_t *config =
74251881Speter    static_cast<svn_config_t *> (apr_hash_get(parameters,
75251881Speter                                              SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG,
76251881Speter                                              APR_HASH_KEY_STRING));
77251881Speter  svn_boolean_t svn_application_name_with_pid;
78251881Speter  svn_config_get_bool(config,
79251881Speter                      &svn_application_name_with_pid,
80251881Speter                      SVN_CONFIG_SECTION_AUTH,
81251881Speter                      SVN_CONFIG_OPTION_KWALLET_SVN_APPLICATION_NAME_WITH_PID,
82251881Speter                      FALSE);
83251881Speter  const char *svn_application_name;
84251881Speter  if (svn_application_name_with_pid)
85251881Speter    {
86251881Speter      svn_application_name = apr_psprintf(pool, "Subversion [%ld]", long(getpid()));
87251881Speter    }
88251881Speter  else
89251881Speter    {
90251881Speter      svn_application_name = "Subversion";
91251881Speter    }
92251881Speter  return svn_application_name;
93251881Speter}
94251881Speter
95251881Speterstatic QString
96251881Speterget_wallet_name(apr_hash_t *parameters)
97251881Speter{
98251881Speter  svn_config_t *config =
99251881Speter    static_cast<svn_config_t *> (apr_hash_get(parameters,
100251881Speter                                              SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG,
101251881Speter                                              APR_HASH_KEY_STRING));
102251881Speter  const char *wallet_name;
103251881Speter  svn_config_get(config,
104251881Speter                 &wallet_name,
105251881Speter                 SVN_CONFIG_SECTION_AUTH,
106251881Speter                 SVN_CONFIG_OPTION_KWALLET_WALLET,
107251881Speter                 "");
108251881Speter  if (strcmp(wallet_name, "") == 0)
109251881Speter    {
110251881Speter      return KWallet::Wallet::NetworkWallet();
111251881Speter    }
112251881Speter  else
113251881Speter    {
114251881Speter      return QString::fromUtf8(wallet_name);
115251881Speter    }
116251881Speter}
117251881Speter
118251881Speterstatic WId
119251881Speterget_wid(void)
120251881Speter{
121251881Speter  WId wid = 1;
122251881Speter  const char *wid_env_string = getenv("WINDOWID");
123251881Speter
124251881Speter  if (wid_env_string)
125251881Speter    {
126251881Speter      apr_int64_t wid_env;
127251881Speter      svn_error_t *err;
128251881Speter
129251881Speter      err = svn_cstring_atoi64(&wid_env, wid_env_string);
130251881Speter      if (err)
131251881Speter        svn_error_clear(err);
132251881Speter      else
133251881Speter        wid = (WId)wid_env;
134251881Speter    }
135251881Speter
136251881Speter  return wid;
137251881Speter}
138251881Speter
139289180Speter/* Forward definition */
140289180Speterstatic apr_status_t
141289180Speterkwallet_terminate(void *data);
142289180Speter
143251881Speterstatic KWallet::Wallet *
144251881Speterget_wallet(QString wallet_name,
145251881Speter           apr_hash_t *parameters)
146251881Speter{
147251881Speter  KWallet::Wallet *wallet =
148289180Speter    static_cast<KWallet::Wallet *> (svn_hash_gets(parameters,
149289180Speter                                                  "kwallet-wallet"));
150289180Speter  if (! wallet && ! svn_hash_gets(parameters, "kwallet-opening-failed"))
151251881Speter    {
152251881Speter      wallet = KWallet::Wallet::openWallet(wallet_name, get_wid(),
153251881Speter                                           KWallet::Wallet::Synchronous);
154289180Speter
155289180Speter      if (wallet)
156289180Speter        {
157289180Speter          svn_hash_sets(parameters, "kwallet-wallet", wallet);
158289180Speter
159289180Speter          apr_pool_cleanup_register(apr_hash_pool_get(parameters),
160289180Speter                                    parameters, kwallet_terminate,
161289180Speter                                    apr_pool_cleanup_null);
162289180Speter
163289180Speter          svn_hash_sets(parameters, "kwallet-initialized", "");
164289180Speter        }
165289180Speter      else
166289180Speter        {
167289180Speter          svn_hash_sets(parameters, "kwallet-opening-failed", "");
168289180Speter        }
169251881Speter    }
170251881Speter  return wallet;
171251881Speter}
172251881Speter
173251881Speterstatic apr_status_t
174251881Speterkwallet_terminate(void *data)
175251881Speter{
176251881Speter  apr_hash_t *parameters = static_cast<apr_hash_t *> (data);
177289180Speter  if (svn_hash_gets(parameters, "kwallet-initialized"))
178251881Speter    {
179251881Speter      KWallet::Wallet *wallet = get_wallet(NULL, parameters);
180251881Speter      delete wallet;
181289180Speter      svn_hash_sets(parameters, "kwallet-wallet", NULL);
182289180Speter      svn_hash_sets(parameters, "kwallet-initialized", NULL);
183251881Speter    }
184251881Speter  return APR_SUCCESS;
185251881Speter}
186251881Speter
187251881Speter/* Implementation of svn_auth__password_get_t that retrieves
188251881Speter   the password from KWallet. */
189251881Speterstatic svn_error_t *
190251881Speterkwallet_password_get(svn_boolean_t *done,
191251881Speter                     const char **password,
192251881Speter                     apr_hash_t *creds,
193251881Speter                     const char *realmstring,
194251881Speter                     const char *username,
195251881Speter                     apr_hash_t *parameters,
196251881Speter                     svn_boolean_t non_interactive,
197251881Speter                     apr_pool_t *pool)
198251881Speter{
199251881Speter  QString wallet_name = get_wallet_name(parameters);
200251881Speter
201251881Speter  *done = FALSE;
202251881Speter
203251881Speter  if (! dbus_bus_get(DBUS_BUS_SESSION, NULL))
204251881Speter    {
205251881Speter      return SVN_NO_ERROR;
206251881Speter    }
207251881Speter
208251881Speter  if (non_interactive)
209251881Speter    {
210251881Speter      if (!KWallet::Wallet::isOpen(wallet_name))
211251881Speter        return SVN_NO_ERROR;
212251881Speter
213251881Speter      /* There is a race here: the wallet was open just now, but will
214251881Speter         it still be open when we come to use it below? */
215251881Speter    }
216251881Speter
217251881Speter  QCoreApplication *app;
218251881Speter  if (! qApp)
219251881Speter    {
220251881Speter      int argc = q_argc;
221251881Speter      app = new QCoreApplication(argc, q_argv);
222251881Speter    }
223251881Speter
224251881Speter  KCmdLineArgs::init(q_argc, q_argv,
225251881Speter                     get_application_name(parameters, pool),
226251881Speter                     "subversion",
227251881Speter                     ki18n(get_application_name(parameters, pool)),
228251881Speter                     SVN_VER_NUMBER,
229251881Speter                     ki18n("Version control system"),
230251881Speter                     KCmdLineArgs::CmdLineArgKDE);
231251881Speter  KComponentData component_data(KCmdLineArgs::aboutData());
232251881Speter  QString folder = QString::fromUtf8("Subversion");
233251881Speter  QString key =
234251881Speter    QString::fromUtf8(username) + "@" + QString::fromUtf8(realmstring);
235251881Speter  if (! KWallet::Wallet::keyDoesNotExist(wallet_name, folder, key))
236251881Speter    {
237251881Speter      KWallet::Wallet *wallet = get_wallet(wallet_name, parameters);
238251881Speter      if (wallet)
239251881Speter        {
240251881Speter          if (wallet->setFolder(folder))
241251881Speter            {
242251881Speter              QString q_password;
243251881Speter              if (wallet->readPassword(key, q_password) == 0)
244251881Speter                {
245251881Speter                  *password = apr_pstrmemdup(pool,
246251881Speter                                             q_password.toUtf8().data(),
247251881Speter                                             q_password.size());
248251881Speter                  *done = TRUE;
249251881Speter                }
250251881Speter            }
251251881Speter        }
252251881Speter    }
253251881Speter
254251881Speter  return SVN_NO_ERROR;
255251881Speter}
256251881Speter
257251881Speter/* Implementation of svn_auth__password_set_t that stores
258251881Speter   the password in KWallet. */
259251881Speterstatic svn_error_t *
260251881Speterkwallet_password_set(svn_boolean_t *done,
261251881Speter                     apr_hash_t *creds,
262251881Speter                     const char *realmstring,
263251881Speter                     const char *username,
264251881Speter                     const char *password,
265251881Speter                     apr_hash_t *parameters,
266251881Speter                     svn_boolean_t non_interactive,
267251881Speter                     apr_pool_t *pool)
268251881Speter{
269251881Speter  QString wallet_name = get_wallet_name(parameters);
270251881Speter
271251881Speter  *done = FALSE;
272251881Speter
273251881Speter  if (! dbus_bus_get(DBUS_BUS_SESSION, NULL))
274251881Speter    {
275251881Speter      return SVN_NO_ERROR;
276251881Speter    }
277251881Speter
278251881Speter  if (non_interactive)
279251881Speter    {
280251881Speter      if (!KWallet::Wallet::isOpen(wallet_name))
281251881Speter        return SVN_NO_ERROR;
282251881Speter
283251881Speter      /* There is a race here: the wallet was open just now, but will
284251881Speter         it still be open when we come to use it below? */
285251881Speter    }
286251881Speter
287251881Speter  QCoreApplication *app;
288251881Speter  if (! qApp)
289251881Speter    {
290251881Speter      int argc = q_argc;
291251881Speter      app = new QCoreApplication(argc, q_argv);
292251881Speter    }
293251881Speter
294251881Speter  KCmdLineArgs::init(q_argc, q_argv,
295251881Speter                     get_application_name(parameters, pool),
296251881Speter                     "subversion",
297251881Speter                     ki18n(get_application_name(parameters, pool)),
298251881Speter                     SVN_VER_NUMBER,
299251881Speter                     ki18n("Version control system"),
300251881Speter                     KCmdLineArgs::CmdLineArgKDE);
301251881Speter  KComponentData component_data(KCmdLineArgs::aboutData());
302251881Speter  QString q_password = QString::fromUtf8(password);
303251881Speter  QString folder = QString::fromUtf8("Subversion");
304251881Speter  KWallet::Wallet *wallet = get_wallet(wallet_name, parameters);
305251881Speter  if (wallet)
306251881Speter    {
307251881Speter      if (! wallet->hasFolder(folder))
308251881Speter        {
309251881Speter          wallet->createFolder(folder);
310251881Speter        }
311251881Speter      if (wallet->setFolder(folder))
312251881Speter        {
313251881Speter          QString key = QString::fromUtf8(username) + "@"
314251881Speter            + QString::fromUtf8(realmstring);
315251881Speter          if (wallet->writePassword(key, q_password) == 0)
316251881Speter            {
317251881Speter              *done = TRUE;
318251881Speter            }
319251881Speter        }
320251881Speter    }
321251881Speter
322251881Speter  return SVN_NO_ERROR;
323251881Speter}
324251881Speter
325251881Speter/* Get cached encrypted credentials from the simple provider's cache. */
326251881Speterstatic svn_error_t *
327251881Speterkwallet_simple_first_creds(void **credentials,
328251881Speter                           void **iter_baton,
329251881Speter                           void *provider_baton,
330251881Speter                           apr_hash_t *parameters,
331251881Speter                           const char *realmstring,
332251881Speter                           apr_pool_t *pool)
333251881Speter{
334251881Speter  return svn_auth__simple_creds_cache_get(credentials,
335251881Speter                                          iter_baton,
336251881Speter                                          provider_baton,
337251881Speter                                          parameters,
338251881Speter                                          realmstring,
339251881Speter                                          kwallet_password_get,
340251881Speter                                          SVN_AUTH__KWALLET_PASSWORD_TYPE,
341251881Speter                                          pool);
342251881Speter}
343251881Speter
344251881Speter/* Save encrypted credentials to the simple provider's cache. */
345251881Speterstatic svn_error_t *
346251881Speterkwallet_simple_save_creds(svn_boolean_t *saved,
347251881Speter                          void *credentials,
348251881Speter                          void *provider_baton,
349251881Speter                          apr_hash_t *parameters,
350251881Speter                          const char *realmstring,
351251881Speter                          apr_pool_t *pool)
352251881Speter{
353251881Speter  return svn_auth__simple_creds_cache_set(saved, credentials,
354251881Speter                                          provider_baton,
355251881Speter                                          parameters,
356251881Speter                                          realmstring,
357251881Speter                                          kwallet_password_set,
358251881Speter                                          SVN_AUTH__KWALLET_PASSWORD_TYPE,
359251881Speter                                          pool);
360251881Speter}
361251881Speter
362251881Speterstatic const svn_auth_provider_t kwallet_simple_provider = {
363251881Speter  SVN_AUTH_CRED_SIMPLE,
364251881Speter  kwallet_simple_first_creds,
365251881Speter  NULL,
366251881Speter  kwallet_simple_save_creds
367251881Speter};
368251881Speter
369251881Speter/* Public API */
370251881Speterextern "C" {
371251881Spetervoid
372251881Spetersvn_auth_get_kwallet_simple_provider(svn_auth_provider_object_t **provider,
373251881Speter                                     apr_pool_t *pool)
374251881Speter{
375251881Speter  svn_auth_provider_object_t *po =
376251881Speter    static_cast<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po)));
377251881Speter
378251881Speter  po->vtable = &kwallet_simple_provider;
379251881Speter  *provider = po;
380251881Speter}
381251881Speter}
382251881Speter
383251881Speter
384251881Speter/*-----------------------------------------------------------------------*/
385251881Speter/* KWallet SSL client certificate passphrase provider,                   */
386251881Speter/* puts passphrases in KWallet                                           */
387251881Speter/*-----------------------------------------------------------------------*/
388251881Speter
389251881Speter/* Get cached encrypted credentials from the ssl client cert password
390251881Speter   provider's cache. */
391251881Speterstatic svn_error_t *
392251881Speterkwallet_ssl_client_cert_pw_first_creds(void **credentials,
393251881Speter                                       void **iter_baton,
394251881Speter                                       void *provider_baton,
395251881Speter                                       apr_hash_t *parameters,
396251881Speter                                       const char *realmstring,
397251881Speter                                       apr_pool_t *pool)
398251881Speter{
399251881Speter  return svn_auth__ssl_client_cert_pw_cache_get(credentials,
400251881Speter                                                iter_baton, provider_baton,
401251881Speter                                                parameters, realmstring,
402251881Speter                                                kwallet_password_get,
403251881Speter                                                SVN_AUTH__KWALLET_PASSWORD_TYPE,
404251881Speter                                                pool);
405251881Speter}
406251881Speter
407251881Speter/* Save encrypted credentials to the ssl client cert password provider's
408251881Speter   cache. */
409251881Speterstatic svn_error_t *
410251881Speterkwallet_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
411251881Speter                                      void *credentials,
412251881Speter                                      void *provider_baton,
413251881Speter                                      apr_hash_t *parameters,
414251881Speter                                      const char *realmstring,
415251881Speter                                      apr_pool_t *pool)
416251881Speter{
417251881Speter  return svn_auth__ssl_client_cert_pw_cache_set(saved, credentials,
418251881Speter                                                provider_baton, parameters,
419251881Speter                                                realmstring,
420251881Speter                                                kwallet_password_set,
421251881Speter                                                SVN_AUTH__KWALLET_PASSWORD_TYPE,
422251881Speter                                                pool);
423251881Speter}
424251881Speter
425251881Speterstatic const svn_auth_provider_t kwallet_ssl_client_cert_pw_provider = {
426251881Speter  SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
427251881Speter  kwallet_ssl_client_cert_pw_first_creds,
428251881Speter  NULL,
429251881Speter  kwallet_ssl_client_cert_pw_save_creds
430251881Speter};
431251881Speter
432251881Speter/* Public API */
433251881Speterextern "C" {
434251881Spetervoid
435251881Spetersvn_auth_get_kwallet_ssl_client_cert_pw_provider
436251881Speter    (svn_auth_provider_object_t **provider,
437251881Speter     apr_pool_t *pool)
438251881Speter{
439251881Speter  svn_auth_provider_object_t *po =
440251881Speter    static_cast<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po)));
441251881Speter
442251881Speter  po->vtable = &kwallet_ssl_client_cert_pw_provider;
443251881Speter  *provider = po;
444251881Speter}
445251881Speter}
446