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 <klocalizedstring.h> 43251881Speter#include <kwallet.h> 44251881Speter 45251881Speter#include "svn_auth.h" 46251881Speter#include "svn_config.h" 47251881Speter#include "svn_error.h" 48289180Speter#include "svn_hash.h" 49251881Speter#include "svn_io.h" 50251881Speter#include "svn_pools.h" 51251881Speter#include "svn_string.h" 52251881Speter#include "svn_version.h" 53251881Speter 54251881Speter#include "private/svn_auth_private.h" 55251881Speter 56251881Speter#include "svn_private_config.h" 57251881Speter 58362181Sdim#ifndef SVN_HAVE_KF5 59362181Sdim#include <kcmdlineargs.h> 60362181Sdim#include <kcomponentdata.h> 61362181Sdim#endif 62251881Speter 63251881Speter/*-----------------------------------------------------------------------*/ 64251881Speter/* KWallet simple provider, puts passwords in KWallet */ 65251881Speter/*-----------------------------------------------------------------------*/ 66251881Speter 67251881Speterstatic int q_argc = 1; 68251881Speterstatic char q_argv0[] = "svn"; // Build non-const char * from string constant 69251881Speterstatic char *q_argv[] = { q_argv0 }; 70251881Speter 71251881Speterstatic const char * 72251881Speterget_application_name(apr_hash_t *parameters, 73251881Speter apr_pool_t *pool) 74251881Speter{ 75251881Speter svn_config_t *config = 76251881Speter static_cast<svn_config_t *> (apr_hash_get(parameters, 77251881Speter SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG, 78251881Speter APR_HASH_KEY_STRING)); 79251881Speter svn_boolean_t svn_application_name_with_pid; 80251881Speter svn_config_get_bool(config, 81251881Speter &svn_application_name_with_pid, 82251881Speter SVN_CONFIG_SECTION_AUTH, 83251881Speter SVN_CONFIG_OPTION_KWALLET_SVN_APPLICATION_NAME_WITH_PID, 84251881Speter FALSE); 85251881Speter const char *svn_application_name; 86251881Speter if (svn_application_name_with_pid) 87251881Speter { 88251881Speter svn_application_name = apr_psprintf(pool, "Subversion [%ld]", long(getpid())); 89251881Speter } 90251881Speter else 91251881Speter { 92251881Speter svn_application_name = "Subversion"; 93251881Speter } 94251881Speter return svn_application_name; 95251881Speter} 96251881Speter 97251881Speterstatic QString 98251881Speterget_wallet_name(apr_hash_t *parameters) 99251881Speter{ 100251881Speter svn_config_t *config = 101251881Speter static_cast<svn_config_t *> (apr_hash_get(parameters, 102251881Speter SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG, 103251881Speter APR_HASH_KEY_STRING)); 104251881Speter const char *wallet_name; 105251881Speter svn_config_get(config, 106251881Speter &wallet_name, 107251881Speter SVN_CONFIG_SECTION_AUTH, 108251881Speter SVN_CONFIG_OPTION_KWALLET_WALLET, 109251881Speter ""); 110251881Speter if (strcmp(wallet_name, "") == 0) 111251881Speter { 112251881Speter return KWallet::Wallet::NetworkWallet(); 113251881Speter } 114251881Speter else 115251881Speter { 116251881Speter return QString::fromUtf8(wallet_name); 117251881Speter } 118251881Speter} 119251881Speter 120251881Speterstatic WId 121251881Speterget_wid(void) 122251881Speter{ 123251881Speter WId wid = 1; 124251881Speter const char *wid_env_string = getenv("WINDOWID"); 125251881Speter 126251881Speter if (wid_env_string) 127251881Speter { 128251881Speter apr_int64_t wid_env; 129251881Speter svn_error_t *err; 130251881Speter 131251881Speter err = svn_cstring_atoi64(&wid_env, wid_env_string); 132251881Speter if (err) 133251881Speter svn_error_clear(err); 134251881Speter else 135251881Speter wid = (WId)wid_env; 136251881Speter } 137251881Speter 138251881Speter return wid; 139251881Speter} 140251881Speter 141289180Speter/* Forward definition */ 142289180Speterstatic apr_status_t 143289180Speterkwallet_terminate(void *data); 144289180Speter 145251881Speterstatic KWallet::Wallet * 146251881Speterget_wallet(QString wallet_name, 147251881Speter apr_hash_t *parameters) 148251881Speter{ 149251881Speter KWallet::Wallet *wallet = 150289180Speter static_cast<KWallet::Wallet *> (svn_hash_gets(parameters, 151289180Speter "kwallet-wallet")); 152289180Speter if (! wallet && ! svn_hash_gets(parameters, "kwallet-opening-failed")) 153251881Speter { 154251881Speter wallet = KWallet::Wallet::openWallet(wallet_name, get_wid(), 155251881Speter KWallet::Wallet::Synchronous); 156289180Speter 157289180Speter if (wallet) 158289180Speter { 159289180Speter svn_hash_sets(parameters, "kwallet-wallet", wallet); 160289180Speter 161289180Speter apr_pool_cleanup_register(apr_hash_pool_get(parameters), 162289180Speter parameters, kwallet_terminate, 163289180Speter apr_pool_cleanup_null); 164289180Speter 165289180Speter svn_hash_sets(parameters, "kwallet-initialized", ""); 166289180Speter } 167289180Speter else 168289180Speter { 169289180Speter svn_hash_sets(parameters, "kwallet-opening-failed", ""); 170289180Speter } 171251881Speter } 172251881Speter return wallet; 173251881Speter} 174251881Speter 175251881Speterstatic apr_status_t 176251881Speterkwallet_terminate(void *data) 177251881Speter{ 178251881Speter apr_hash_t *parameters = static_cast<apr_hash_t *> (data); 179289180Speter if (svn_hash_gets(parameters, "kwallet-initialized")) 180251881Speter { 181251881Speter KWallet::Wallet *wallet = get_wallet(NULL, parameters); 182251881Speter delete wallet; 183289180Speter svn_hash_sets(parameters, "kwallet-wallet", NULL); 184289180Speter svn_hash_sets(parameters, "kwallet-initialized", NULL); 185251881Speter } 186251881Speter return APR_SUCCESS; 187251881Speter} 188251881Speter 189251881Speter/* Implementation of svn_auth__password_get_t that retrieves 190251881Speter the password from KWallet. */ 191251881Speterstatic svn_error_t * 192251881Speterkwallet_password_get(svn_boolean_t *done, 193251881Speter const char **password, 194251881Speter apr_hash_t *creds, 195251881Speter const char *realmstring, 196251881Speter const char *username, 197251881Speter apr_hash_t *parameters, 198251881Speter svn_boolean_t non_interactive, 199251881Speter apr_pool_t *pool) 200251881Speter{ 201251881Speter QString wallet_name = get_wallet_name(parameters); 202251881Speter 203251881Speter *done = FALSE; 204251881Speter 205251881Speter if (! dbus_bus_get(DBUS_BUS_SESSION, NULL)) 206251881Speter { 207251881Speter return SVN_NO_ERROR; 208251881Speter } 209251881Speter 210251881Speter if (non_interactive) 211251881Speter { 212251881Speter if (!KWallet::Wallet::isOpen(wallet_name)) 213251881Speter return SVN_NO_ERROR; 214251881Speter 215251881Speter /* There is a race here: the wallet was open just now, but will 216251881Speter it still be open when we come to use it below? */ 217251881Speter } 218251881Speter 219251881Speter QCoreApplication *app; 220251881Speter if (! qApp) 221251881Speter { 222251881Speter int argc = q_argc; 223251881Speter app = new QCoreApplication(argc, q_argv); 224251881Speter } 225251881Speter 226362181Sdim#if SVN_HAVE_KF5 227362181Sdim KLocalizedString::setApplicationDomain("subversion"); /* translation domain */ 228362181Sdim 229362181Sdim /* componentName appears in KDE GUI prompts */ 230362181Sdim KAboutData aboutData(QString("subversion"), /* componentName */ 231362181Sdim i18n(get_application_name(parameters, 232362181Sdim pool)), /* displayName */ 233362181Sdim QString(SVN_VER_NUMBER)); 234362181Sdim KAboutData::setApplicationData(aboutData); 235362181Sdim#else 236251881Speter KCmdLineArgs::init(q_argc, q_argv, 237251881Speter get_application_name(parameters, pool), 238251881Speter "subversion", 239251881Speter ki18n(get_application_name(parameters, pool)), 240251881Speter SVN_VER_NUMBER, 241251881Speter ki18n("Version control system"), 242251881Speter KCmdLineArgs::CmdLineArgKDE); 243251881Speter KComponentData component_data(KCmdLineArgs::aboutData()); 244362181Sdim#endif 245362181Sdim 246251881Speter QString folder = QString::fromUtf8("Subversion"); 247251881Speter QString key = 248251881Speter QString::fromUtf8(username) + "@" + QString::fromUtf8(realmstring); 249251881Speter if (! KWallet::Wallet::keyDoesNotExist(wallet_name, folder, key)) 250251881Speter { 251251881Speter KWallet::Wallet *wallet = get_wallet(wallet_name, parameters); 252251881Speter if (wallet) 253251881Speter { 254251881Speter if (wallet->setFolder(folder)) 255251881Speter { 256251881Speter QString q_password; 257251881Speter if (wallet->readPassword(key, q_password) == 0) 258251881Speter { 259251881Speter *password = apr_pstrmemdup(pool, 260251881Speter q_password.toUtf8().data(), 261251881Speter q_password.size()); 262251881Speter *done = TRUE; 263251881Speter } 264251881Speter } 265251881Speter } 266251881Speter } 267251881Speter 268251881Speter return SVN_NO_ERROR; 269251881Speter} 270251881Speter 271251881Speter/* Implementation of svn_auth__password_set_t that stores 272251881Speter the password in KWallet. */ 273251881Speterstatic svn_error_t * 274251881Speterkwallet_password_set(svn_boolean_t *done, 275251881Speter apr_hash_t *creds, 276251881Speter const char *realmstring, 277251881Speter const char *username, 278251881Speter const char *password, 279251881Speter apr_hash_t *parameters, 280251881Speter svn_boolean_t non_interactive, 281251881Speter apr_pool_t *pool) 282251881Speter{ 283251881Speter QString wallet_name = get_wallet_name(parameters); 284251881Speter 285251881Speter *done = FALSE; 286251881Speter 287251881Speter if (! dbus_bus_get(DBUS_BUS_SESSION, NULL)) 288251881Speter { 289251881Speter return SVN_NO_ERROR; 290251881Speter } 291251881Speter 292251881Speter if (non_interactive) 293251881Speter { 294251881Speter if (!KWallet::Wallet::isOpen(wallet_name)) 295251881Speter return SVN_NO_ERROR; 296251881Speter 297251881Speter /* There is a race here: the wallet was open just now, but will 298251881Speter it still be open when we come to use it below? */ 299251881Speter } 300251881Speter 301251881Speter QCoreApplication *app; 302251881Speter if (! qApp) 303251881Speter { 304251881Speter int argc = q_argc; 305251881Speter app = new QCoreApplication(argc, q_argv); 306251881Speter } 307251881Speter 308362181Sdim#if SVN_HAVE_KF5 309362181Sdim KLocalizedString::setApplicationDomain("subversion"); /* translation domain */ 310362181Sdim 311362181Sdim /* componentName appears in KDE GUI prompts */ 312362181Sdim KAboutData aboutData(QString("subversion"), /* componentName */ 313362181Sdim i18n(get_application_name(parameters, 314362181Sdim pool)), /* displayName */ 315362181Sdim QString(SVN_VER_NUMBER)); 316362181Sdim KAboutData::setApplicationData(aboutData); 317362181Sdim#else 318251881Speter KCmdLineArgs::init(q_argc, q_argv, 319251881Speter get_application_name(parameters, pool), 320251881Speter "subversion", 321251881Speter ki18n(get_application_name(parameters, pool)), 322251881Speter SVN_VER_NUMBER, 323251881Speter ki18n("Version control system"), 324251881Speter KCmdLineArgs::CmdLineArgKDE); 325251881Speter KComponentData component_data(KCmdLineArgs::aboutData()); 326362181Sdim#endif 327362181Sdim 328251881Speter QString q_password = QString::fromUtf8(password); 329251881Speter QString folder = QString::fromUtf8("Subversion"); 330251881Speter KWallet::Wallet *wallet = get_wallet(wallet_name, parameters); 331251881Speter if (wallet) 332251881Speter { 333251881Speter if (! wallet->hasFolder(folder)) 334251881Speter { 335251881Speter wallet->createFolder(folder); 336251881Speter } 337251881Speter if (wallet->setFolder(folder)) 338251881Speter { 339251881Speter QString key = QString::fromUtf8(username) + "@" 340251881Speter + QString::fromUtf8(realmstring); 341251881Speter if (wallet->writePassword(key, q_password) == 0) 342251881Speter { 343251881Speter *done = TRUE; 344251881Speter } 345251881Speter } 346251881Speter } 347251881Speter 348251881Speter return SVN_NO_ERROR; 349251881Speter} 350251881Speter 351251881Speter/* Get cached encrypted credentials from the simple provider's cache. */ 352251881Speterstatic svn_error_t * 353251881Speterkwallet_simple_first_creds(void **credentials, 354251881Speter void **iter_baton, 355251881Speter void *provider_baton, 356251881Speter apr_hash_t *parameters, 357251881Speter const char *realmstring, 358251881Speter apr_pool_t *pool) 359251881Speter{ 360251881Speter return svn_auth__simple_creds_cache_get(credentials, 361251881Speter iter_baton, 362251881Speter provider_baton, 363251881Speter parameters, 364251881Speter realmstring, 365251881Speter kwallet_password_get, 366251881Speter SVN_AUTH__KWALLET_PASSWORD_TYPE, 367251881Speter pool); 368251881Speter} 369251881Speter 370251881Speter/* Save encrypted credentials to the simple provider's cache. */ 371251881Speterstatic svn_error_t * 372251881Speterkwallet_simple_save_creds(svn_boolean_t *saved, 373251881Speter void *credentials, 374251881Speter void *provider_baton, 375251881Speter apr_hash_t *parameters, 376251881Speter const char *realmstring, 377251881Speter apr_pool_t *pool) 378251881Speter{ 379251881Speter return svn_auth__simple_creds_cache_set(saved, credentials, 380251881Speter provider_baton, 381251881Speter parameters, 382251881Speter realmstring, 383251881Speter kwallet_password_set, 384251881Speter SVN_AUTH__KWALLET_PASSWORD_TYPE, 385251881Speter pool); 386251881Speter} 387251881Speter 388251881Speterstatic const svn_auth_provider_t kwallet_simple_provider = { 389251881Speter SVN_AUTH_CRED_SIMPLE, 390251881Speter kwallet_simple_first_creds, 391251881Speter NULL, 392251881Speter kwallet_simple_save_creds 393251881Speter}; 394251881Speter 395251881Speter/* Public API */ 396251881Speterextern "C" { 397251881Spetervoid 398251881Spetersvn_auth_get_kwallet_simple_provider(svn_auth_provider_object_t **provider, 399251881Speter apr_pool_t *pool) 400251881Speter{ 401251881Speter svn_auth_provider_object_t *po = 402251881Speter static_cast<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po))); 403251881Speter 404251881Speter po->vtable = &kwallet_simple_provider; 405251881Speter *provider = po; 406251881Speter} 407251881Speter} 408251881Speter 409251881Speter 410251881Speter/*-----------------------------------------------------------------------*/ 411251881Speter/* KWallet SSL client certificate passphrase provider, */ 412251881Speter/* puts passphrases in KWallet */ 413251881Speter/*-----------------------------------------------------------------------*/ 414251881Speter 415251881Speter/* Get cached encrypted credentials from the ssl client cert password 416251881Speter provider's cache. */ 417251881Speterstatic svn_error_t * 418251881Speterkwallet_ssl_client_cert_pw_first_creds(void **credentials, 419251881Speter void **iter_baton, 420251881Speter void *provider_baton, 421251881Speter apr_hash_t *parameters, 422251881Speter const char *realmstring, 423251881Speter apr_pool_t *pool) 424251881Speter{ 425251881Speter return svn_auth__ssl_client_cert_pw_cache_get(credentials, 426251881Speter iter_baton, provider_baton, 427251881Speter parameters, realmstring, 428251881Speter kwallet_password_get, 429251881Speter SVN_AUTH__KWALLET_PASSWORD_TYPE, 430251881Speter pool); 431251881Speter} 432251881Speter 433251881Speter/* Save encrypted credentials to the ssl client cert password provider's 434251881Speter cache. */ 435251881Speterstatic svn_error_t * 436251881Speterkwallet_ssl_client_cert_pw_save_creds(svn_boolean_t *saved, 437251881Speter void *credentials, 438251881Speter void *provider_baton, 439251881Speter apr_hash_t *parameters, 440251881Speter const char *realmstring, 441251881Speter apr_pool_t *pool) 442251881Speter{ 443251881Speter return svn_auth__ssl_client_cert_pw_cache_set(saved, credentials, 444251881Speter provider_baton, parameters, 445251881Speter realmstring, 446251881Speter kwallet_password_set, 447251881Speter SVN_AUTH__KWALLET_PASSWORD_TYPE, 448251881Speter pool); 449251881Speter} 450251881Speter 451251881Speterstatic const svn_auth_provider_t kwallet_ssl_client_cert_pw_provider = { 452251881Speter SVN_AUTH_CRED_SSL_CLIENT_CERT_PW, 453251881Speter kwallet_ssl_client_cert_pw_first_creds, 454251881Speter NULL, 455251881Speter kwallet_ssl_client_cert_pw_save_creds 456251881Speter}; 457251881Speter 458251881Speter/* Public API */ 459251881Speterextern "C" { 460251881Spetervoid 461251881Spetersvn_auth_get_kwallet_ssl_client_cert_pw_provider 462251881Speter (svn_auth_provider_object_t **provider, 463251881Speter apr_pool_t *pool) 464251881Speter{ 465251881Speter svn_auth_provider_object_t *po = 466251881Speter static_cast<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po))); 467251881Speter 468251881Speter po->vtable = &kwallet_ssl_client_cert_pw_provider; 469251881Speter *provider = po; 470251881Speter} 471251881Speter} 472