diff options
Diffstat (limited to 'subversion/libsvn_auth_kwallet/kwallet.cpp')
-rw-r--r-- | subversion/libsvn_auth_kwallet/kwallet.cpp | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/subversion/libsvn_auth_kwallet/kwallet.cpp b/subversion/libsvn_auth_kwallet/kwallet.cpp new file mode 100644 index 0000000..e1a345e --- /dev/null +++ b/subversion/libsvn_auth_kwallet/kwallet.cpp @@ -0,0 +1,458 @@ +/* + * 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 <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <apr_pools.h> +#include <apr_strings.h> + +#include <dbus/dbus.h> +#include <QtCore/QCoreApplication> +#include <QtCore/QString> + +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <kcomponentdata.h> +#include <klocalizedstring.h> +#include <kwallet.h> + +#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<svn_config_t *> (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<svn_config_t *> (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<KWallet::Wallet *> (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<apr_hash_t *> (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<svn_auth_provider_object_t *> (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<svn_auth_provider_object_t *> (apr_pcalloc(pool, sizeof(*po))); + + po->vtable = &kwallet_ssl_client_cert_pw_provider; + *provider = po; +} +} |