/* * kwallet.cpp: KWallet provider for SVN_AUTH_CRED_* * * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ==================================================================== */ /* ==================================================================== */ /*** Includes. ***/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "svn_auth.h" #include "svn_config.h" #include "svn_error.h" #include "svn_io.h" #include "svn_pools.h" #include "svn_string.h" #include "svn_version.h" #include "private/svn_auth_private.h" #include "svn_private_config.h" /*-----------------------------------------------------------------------*/ /* KWallet simple provider, puts passwords in KWallet */ /*-----------------------------------------------------------------------*/ static int q_argc = 1; static char q_argv0[] = "svn"; // Build non-const char * from string constant static char *q_argv[] = { q_argv0 }; static const char * get_application_name(apr_hash_t *parameters, apr_pool_t *pool) { svn_config_t *config = static_cast (apr_hash_get(parameters, SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG, APR_HASH_KEY_STRING)); svn_boolean_t svn_application_name_with_pid; svn_config_get_bool(config, &svn_application_name_with_pid, SVN_CONFIG_SECTION_AUTH, SVN_CONFIG_OPTION_KWALLET_SVN_APPLICATION_NAME_WITH_PID, FALSE); const char *svn_application_name; if (svn_application_name_with_pid) { svn_application_name = apr_psprintf(pool, "Subversion [%ld]", long(getpid())); } else { svn_application_name = "Subversion"; } return svn_application_name; } static QString get_wallet_name(apr_hash_t *parameters) { svn_config_t *config = static_cast (apr_hash_get(parameters, SVN_AUTH_PARAM_CONFIG_CATEGORY_CONFIG, APR_HASH_KEY_STRING)); const char *wallet_name; svn_config_get(config, &wallet_name, SVN_CONFIG_SECTION_AUTH, SVN_CONFIG_OPTION_KWALLET_WALLET, ""); if (strcmp(wallet_name, "") == 0) { return KWallet::Wallet::NetworkWallet(); } else { return QString::fromUtf8(wallet_name); } } static WId get_wid(void) { WId wid = 1; const char *wid_env_string = getenv("WINDOWID"); if (wid_env_string) { apr_int64_t wid_env; svn_error_t *err; err = svn_cstring_atoi64(&wid_env, wid_env_string); if (err) svn_error_clear(err); else wid = (WId)wid_env; } return wid; } static KWallet::Wallet * get_wallet(QString wallet_name, apr_hash_t *parameters) { KWallet::Wallet *wallet = static_cast (apr_hash_get(parameters, "kwallet-wallet", APR_HASH_KEY_STRING)); if (! wallet && ! apr_hash_get(parameters, "kwallet-opening-failed", APR_HASH_KEY_STRING)) { wallet = KWallet::Wallet::openWallet(wallet_name, get_wid(), KWallet::Wallet::Synchronous); } if (wallet) { apr_hash_set(parameters, "kwallet-wallet", APR_HASH_KEY_STRING, wallet); } else { apr_hash_set(parameters, "kwallet-opening-failed", APR_HASH_KEY_STRING, ""); } return wallet; } static apr_status_t kwallet_terminate(void *data) { apr_hash_t *parameters = static_cast (data); if (apr_hash_get(parameters, "kwallet-initialized", APR_HASH_KEY_STRING)) { KWallet::Wallet *wallet = get_wallet(NULL, parameters); delete wallet; apr_hash_set(parameters, "kwallet-initialized", APR_HASH_KEY_STRING, NULL); } return APR_SUCCESS; } /* Implementation of svn_auth__password_get_t that retrieves the password from KWallet. */ static svn_error_t * kwallet_password_get(svn_boolean_t *done, const char **password, apr_hash_t *creds, const char *realmstring, const char *username, apr_hash_t *parameters, svn_boolean_t non_interactive, apr_pool_t *pool) { QString wallet_name = get_wallet_name(parameters); *done = FALSE; if (! dbus_bus_get(DBUS_BUS_SESSION, NULL)) { return SVN_NO_ERROR; } if (non_interactive) { if (!KWallet::Wallet::isOpen(wallet_name)) return SVN_NO_ERROR; /* There is a race here: the wallet was open just now, but will it still be open when we come to use it below? */ } QCoreApplication *app; if (! qApp) { int argc = q_argc; app = new QCoreApplication(argc, q_argv); } KCmdLineArgs::init(q_argc, q_argv, get_application_name(parameters, pool), "subversion", ki18n(get_application_name(parameters, pool)), SVN_VER_NUMBER, ki18n("Version control system"), KCmdLineArgs::CmdLineArgKDE); KComponentData component_data(KCmdLineArgs::aboutData()); QString folder = QString::fromUtf8("Subversion"); QString key = QString::fromUtf8(username) + "@" + QString::fromUtf8(realmstring); if (! KWallet::Wallet::keyDoesNotExist(wallet_name, folder, key)) { KWallet::Wallet *wallet = get_wallet(wallet_name, parameters); if (wallet) { apr_hash_set(parameters, "kwallet-initialized", APR_HASH_KEY_STRING, ""); if (wallet->setFolder(folder)) { QString q_password; if (wallet->readPassword(key, q_password) == 0) { *password = apr_pstrmemdup(pool, q_password.toUtf8().data(), q_password.size()); *done = TRUE; } } } } apr_pool_cleanup_register(pool, parameters, kwallet_terminate, apr_pool_cleanup_null); return SVN_NO_ERROR; } /* Implementation of svn_auth__password_set_t that stores the password in KWallet. */ static svn_error_t * kwallet_password_set(svn_boolean_t *done, apr_hash_t *creds, const char *realmstring, const char *username, const char *password, apr_hash_t *parameters, svn_boolean_t non_interactive, apr_pool_t *pool) { QString wallet_name = get_wallet_name(parameters); *done = FALSE; if (! dbus_bus_get(DBUS_BUS_SESSION, NULL)) { return SVN_NO_ERROR; } if (non_interactive) { if (!KWallet::Wallet::isOpen(wallet_name)) return SVN_NO_ERROR; /* There is a race here: the wallet was open just now, but will it still be open when we come to use it below? */ } QCoreApplication *app; if (! qApp) { int argc = q_argc; app = new QCoreApplication(argc, q_argv); } KCmdLineArgs::init(q_argc, q_argv, get_application_name(parameters, pool), "subversion", ki18n(get_application_name(parameters, pool)), SVN_VER_NUMBER, ki18n("Version control system"), KCmdLineArgs::CmdLineArgKDE); KComponentData component_data(KCmdLineArgs::aboutData()); QString q_password = QString::fromUtf8(password); QString folder = QString::fromUtf8("Subversion"); KWallet::Wallet *wallet = get_wallet(wallet_name, parameters); if (wallet) { apr_hash_set(parameters, "kwallet-initialized", APR_HASH_KEY_STRING, ""); if (! wallet->hasFolder(folder)) { wallet->createFolder(folder); } if (wallet->setFolder(folder)) { QString key = QString::fromUtf8(username) + "@" + QString::fromUtf8(realmstring); if (wallet->writePassword(key, q_password) == 0) { *done = TRUE; } } } apr_pool_cleanup_register(pool, parameters, kwallet_terminate, apr_pool_cleanup_null); return SVN_NO_ERROR; } /* Get cached encrypted credentials from the simple provider's cache. */ static svn_error_t * kwallet_simple_first_creds(void **credentials, void **iter_baton, void *provider_baton, apr_hash_t *parameters, const char *realmstring, apr_pool_t *pool) { return svn_auth__simple_creds_cache_get(credentials, iter_baton, provider_baton, parameters, realmstring, kwallet_password_get, SVN_AUTH__KWALLET_PASSWORD_TYPE, pool); } /* Save encrypted credentials to the simple provider's cache. */ static svn_error_t * kwallet_simple_save_creds(svn_boolean_t *saved, void *credentials, void *provider_baton, apr_hash_t *parameters, const char *realmstring, apr_pool_t *pool) { return svn_auth__simple_creds_cache_set(saved, credentials, provider_baton, parameters, realmstring, kwallet_password_set, SVN_AUTH__KWALLET_PASSWORD_TYPE, pool); } static const svn_auth_provider_t kwallet_simple_provider = { SVN_AUTH_CRED_SIMPLE, kwallet_simple_first_creds, NULL, kwallet_simple_save_creds }; /* Public API */ extern "C" { void svn_auth_get_kwallet_simple_provider(svn_auth_provider_object_t **provider, apr_pool_t *pool) { svn_auth_provider_object_t *po = static_cast (apr_pcalloc(pool, sizeof(*po))); po->vtable = &kwallet_simple_provider; *provider = po; } } /*-----------------------------------------------------------------------*/ /* KWallet SSL client certificate passphrase provider, */ /* puts passphrases in KWallet */ /*-----------------------------------------------------------------------*/ /* Get cached encrypted credentials from the ssl client cert password provider's cache. */ static svn_error_t * kwallet_ssl_client_cert_pw_first_creds(void **credentials, void **iter_baton, void *provider_baton, apr_hash_t *parameters, const char *realmstring, apr_pool_t *pool) { return svn_auth__ssl_client_cert_pw_cache_get(credentials, iter_baton, provider_baton, parameters, realmstring, kwallet_password_get, SVN_AUTH__KWALLET_PASSWORD_TYPE, pool); } /* Save encrypted credentials to the ssl client cert password provider's cache. */ static svn_error_t * kwallet_ssl_client_cert_pw_save_creds(svn_boolean_t *saved, void *credentials, void *provider_baton, apr_hash_t *parameters, const char *realmstring, apr_pool_t *pool) { return svn_auth__ssl_client_cert_pw_cache_set(saved, credentials, provider_baton, parameters, realmstring, kwallet_password_set, SVN_AUTH__KWALLET_PASSWORD_TYPE, pool); } static const svn_auth_provider_t kwallet_ssl_client_cert_pw_provider = { SVN_AUTH_CRED_SSL_CLIENT_CERT_PW, kwallet_ssl_client_cert_pw_first_creds, NULL, kwallet_ssl_client_cert_pw_save_creds }; /* Public API */ extern "C" { void svn_auth_get_kwallet_ssl_client_cert_pw_provider (svn_auth_provider_object_t **provider, apr_pool_t *pool) { svn_auth_provider_object_t *po = static_cast (apr_pcalloc(pool, sizeof(*po))); po->vtable = &kwallet_ssl_client_cert_pw_provider; *provider = po; } }