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