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