| /* |
| * 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_hash.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; |
| } |
| |
| /* Forward definition */ |
| static apr_status_t |
| kwallet_terminate(void *data); |
| |
| static KWallet::Wallet * |
| get_wallet(QString wallet_name, |
| apr_hash_t *parameters) |
| { |
| KWallet::Wallet *wallet = |
| static_cast<KWallet::Wallet *> (svn_hash_gets(parameters, |
| "kwallet-wallet")); |
| if (! wallet && ! svn_hash_gets(parameters, "kwallet-opening-failed")) |
| { |
| wallet = KWallet::Wallet::openWallet(wallet_name, get_wid(), |
| KWallet::Wallet::Synchronous); |
| |
| if (wallet) |
| { |
| svn_hash_sets(parameters, "kwallet-wallet", wallet); |
| |
| apr_pool_cleanup_register(apr_hash_pool_get(parameters), |
| parameters, kwallet_terminate, |
| apr_pool_cleanup_null); |
| |
| svn_hash_sets(parameters, "kwallet-initialized", ""); |
| } |
| else |
| { |
| svn_hash_sets(parameters, "kwallet-opening-failed", ""); |
| } |
| } |
| return wallet; |
| } |
| |
| static apr_status_t |
| kwallet_terminate(void *data) |
| { |
| apr_hash_t *parameters = static_cast<apr_hash_t *> (data); |
| if (svn_hash_gets(parameters, "kwallet-initialized")) |
| { |
| KWallet::Wallet *wallet = get_wallet(NULL, parameters); |
| delete wallet; |
| svn_hash_sets(parameters, "kwallet-wallet", NULL); |
| svn_hash_sets(parameters, "kwallet-initialized", 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) |
| { |
| 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; |
| } |
| } |
| } |
| } |
| |
| 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) |
| { |
| 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; |
| } |
| } |
| } |
| |
| 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; |
| } |
| } |