Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id A6CBE200B9B for ; Wed, 12 Oct 2016 21:58:36 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id A5424160ACA; Wed, 12 Oct 2016 19:58:36 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 28812160AF5 for ; Wed, 12 Oct 2016 21:58:35 +0200 (CEST) Received: (qmail 21900 invoked by uid 500); 12 Oct 2016 19:54:24 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 21883 invoked by uid 99); 12 Oct 2016 19:54:24 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd1-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 12 Oct 2016 19:54:24 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd1-us-west.apache.org (ASF Mail Server at spamd1-us-west.apache.org) with ESMTP id 68313C1A7D for ; Wed, 12 Oct 2016 19:52:18 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd1-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -1.199 X-Spam-Level: X-Spam-Status: No, score=-1.199 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RP_MATCHES_RCVD=-2.999] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd1-us-west.apache.org [10.40.0.7]) (amavisd-new, port 10024) with ESMTP id zXL-30YMw_nD for ; Wed, 12 Oct 2016 19:52:15 +0000 (UTC) Received: from mailrelay1-us-west.apache.org (mailrelay1-us-west.apache.org [209.188.14.139]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with ESMTP id 22ED65FB38 for ; Wed, 12 Oct 2016 19:52:15 +0000 (UTC) Received: from svn01-us-west.apache.org (svn.apache.org [10.41.0.6]) by mailrelay1-us-west.apache.org (ASF Mail Server at mailrelay1-us-west.apache.org) with ESMTP id 3ABD4E0239 for ; Wed, 12 Oct 2016 19:52:11 +0000 (UTC) Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 388773A0016 for ; Wed, 12 Oct 2016 19:52:11 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1764531 - /subversion/branches/master-passphrase/BRANCH-README Date: Wed, 12 Oct 2016 19:52:11 -0000 To: commits@subversion.apache.org From: cmpilato@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20161012195211.388773A0016@svn01-us-west.apache.org> archived-at: Wed, 12 Oct 2016 19:58:36 -0000 Author: cmpilato Date: Wed Oct 12 19:52:11 2016 New Revision: 1764531 URL: http://svn.apache.org/viewvc?rev=1764531&view=rev Log: On branch 'master-passphrase': * BRANCH-README bus_factor++ Modified: subversion/branches/master-passphrase/BRANCH-README Modified: subversion/branches/master-passphrase/BRANCH-README URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/BRANCH-README?rev=1764531&r1=1764530&r2=1764531&view=diff ============================================================================== --- subversion/branches/master-passphrase/BRANCH-README (original) +++ subversion/branches/master-passphrase/BRANCH-README Wed Oct 12 19:52:11 2016 @@ -5,3 +5,908 @@ protect disk-cached Subversion credentia See http://wiki.apache.org/subversion/MasterPassphrase and http://subversion.tigris.org/issues/show_bug.cgi?id=4145 for details. + +cmpilato had to bail on this work, but left behind the following +(presumably incomplete, at-best-partially functional) patch: + +{{{ +Index: subversion/include/private/svn_auth_private.h +=================================================================== +--- subversion/include/private/svn_auth_private.h (revision 1367185) ++++ subversion/include/private/svn_auth_private.h (working copy) +@@ -32,6 +32,8 @@ + + #include "svn_types.h" + #include "svn_error.h" ++#include "svn_auth.h" ++#include "svn_private_config.h" + + #ifdef __cplusplus + extern "C" { +@@ -48,6 +50,12 @@ + #define SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE "gnome-keyring" + #define SVN_AUTH__GPG_AGENT_PASSWORD_TYPE "gpg-agent" + ++/* Default ordered list of available third-party password storage ++ * providers. ++ */ ++#define SVN_AUTH__DEFAULT_PROVIDER_LIST \ ++ "gnome-keyring,kwallet,keychain,gpg-agent,windows-cryptoapi" ++ + /* A function that stores in *PASSWORD (potentially after decrypting it) + the user's password. It might be obtained directly from CREDS, or + from an external store, using REALMSTRING and USERNAME as keys. +@@ -213,6 +221,42 @@ + svn_boolean_t non_interactive, + apr_pool_t *pool); + ++ ++/*** Master passphrase providers. */ ++ ++#if defined(SVN_HAVE_GPG_AGENT) ++/* Set *PROVIDER to a master passphrase provider which uses the GPG ++ Agent for storage/retrieval. */ ++void svn_auth__get_gpg_agent_masterpass_provider( ++ svn_auth_masterpass_provider_object_t **provider, ++ apr_pool_t *pool); ++#endif /* defined(SVN_HAVE_GPG_AGENT) */ ++ ++#ifdef SVN_HAVE_KEYCHAIN_SERVICES ++/* Set *PROVIDER to a master passphrase provider which uses the MacOS ++ X Keychain services for storage/retrieval. */ ++void svn_auth__get_keychain_masterpass_provider( ++ svn_auth_masterpass_provider_object_t **provider, ++ apr_pool_t *pool); ++#endif ++ ++#if defined(SVN_HAVE_GNOME_KEYRING) ++/* Set *PROVIDER to a master passphrase provider which uses the GNOME ++ Keyring service for storage/retrieval. */ ++void svn_auth__get_gnome_keyring_masterpass_provider( ++ svn_auth_masterpass_provider_object_t **provider, ++ apr_pool_t *pool); ++#endif ++ ++#if defined(SVN_HAVE_KWALLET) ++/* Set *PROVIDER to a master passphrase provider which uses the KDE ++ Wallet service for storage/retrieval. */ ++void svn_auth__get_kwallet_masterpass_provider( ++ svn_auth_masterpass_provider_object_t **provider, ++ apr_pool_t *pool); ++#endif ++ ++ + #ifdef __cplusplus + } + #endif /* __cplusplus */ +Index: subversion/include/svn_auth.h +=================================================================== +--- subversion/include/svn_auth.h (revision 1367185) ++++ subversion/include/svn_auth.h (working copy) +@@ -1247,7 +1247,88 @@ + int retry_limit, + apr_pool_t *pool); + ++ ++/** Generic third-party master password caching mechanisms. ++ * ++ * @defgroup auth_mp_fns Master password functions ++ * @{ ++ */ ++ ++/** The master passphrase "provider" vtable. ++ * ++ * @since New in 1.8. ++ */ ++typedef struct svn_auth_masterpass_provider_t ++{ ++ /** Set @a passphrase_digest to the value of the Subversion master ++ * passphrase hash digest string. If @a non_interactive is set, do ++ * not prompt the user. Set @a *done to TRUE if the passphrase is ++ * successfully fetched; to FALSE otherwise. ++ */ ++ svn_error_t * (*first_masterpass)(const svn_string_t **passphrase_digest, ++ svn_boolean_t non_interactive, ++ void *provider_baton, ++ apr_pool_t *pool); + ++ /** Set @a passphrase_digest to the value of the Subversion master ++ * passphrase hash digest string. If @a non_interactive is set, do ++ * not prompt the user. Set @a *done to TRUE if the passphrase is ++ * successfully fetched; to FALSE otherwise. ++ * ++ * This function is optional, and used only after @c ++ * first_masterpass has been called for this provider. ++ */ ++ svn_error_t * (*next_masterpass)(const svn_string_t **passphrase_digest, ++ svn_boolean_t non_interactive, ++ void *provider_baton, ++ apr_pool_t *pool); ++ ++ /** Store @a passphrase_digest as the value of the Subversion master ++ * passphrase hash digest string. If @a non_interactive is set, do ++ * not prompt the user. Set @a *stored to TRUE if the passphrase is ++ * successfully stored; to FALSE otherwise. ++ */ ++ svn_error_t * (*store_masterpass)(svn_boolean_t *stored, ++ const svn_string_t *passphrase_digest, ++ svn_boolean_t non_interactive, ++ void *provider_baton, ++ apr_pool_t *pool); ++ ++} svn_auth_masterpass_provider_t; ++ ++/** A master passphrase provider object and baton. ++ * ++ * @since New in 1.8. ++ */ ++typedef struct svn_auth_masterpass_provider_object_t ++{ ++ const svn_auth_masterpass_provider_t *vtable; ++ void *provider_baton; ++ ++} svn_auth_masterpass_provider_object_t; ++ ++/** A type of function which returns a master passphrase provider. ++ * ++ * @since New in 1.8. ++ */ ++typedef void (*svn_auth_masterpass_provider_func_t)( ++ svn_auth_masterpass_provider_object_t **provider, ++ apr_pool_t *pool); ++ ++/** Set @a *providers to an array of @c svn_auth_provider_object_t's ++ * appropriate for the client platform and which honor the allowed, ++ * ordered providers specified in @a config. Allocate providers from ++ * @a pool. ++ * ++ * @since New in 1.8. ++ */ ++svn_error_t * ++svn_auth_get_masterpass_providers(apr_array_header_t **providers, ++ svn_config_t *config, ++ apr_pool_t *pool); ++ ++/** @} */ ++ + #ifdef __cplusplus + } + #endif /* __cplusplus */ +Index: subversion/include/svn_cmdline.h +=================================================================== +--- subversion/include/svn_cmdline.h (revision 1367185) ++++ subversion/include/svn_cmdline.h (working copy) +@@ -324,7 +324,7 @@ + */ + svn_error_t * + svn_cmdline_auth_master_passphrase_prompt(const svn_string_t **secret, +- void *baton, ++ svn_cmdline_prompt_baton2_t *baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +Index: subversion/libsvn_subr/auth.c +=================================================================== +--- subversion/libsvn_subr/auth.c (revision 1367185) ++++ subversion/libsvn_subr/auth.c (working copy) +@@ -34,6 +34,7 @@ + #include "svn_private_config.h" + #include "svn_dso.h" + #include "svn_version.h" ++#include "private/svn_auth_private.h" + + /* AN OVERVIEW + =========== +@@ -519,38 +520,28 @@ + apr_pool_t *pool) + { + svn_auth_provider_object_t *provider; +- const char *password_stores_config_option; ++ const char *password_stores_config_option = SVN_AUTH__DEFAULT_PROVIDER_LIST; + apr_array_header_t *password_stores; + int i; + +-#define SVN__DEFAULT_AUTH_PROVIDER_LIST \ +- "gnome-keyring,kwallet,keychain,gpg-agent,windows-cryptoapi" +- + if (config) + { +- svn_config_get +- (config, +- &password_stores_config_option, +- SVN_CONFIG_SECTION_AUTH, +- SVN_CONFIG_OPTION_PASSWORD_STORES, +- SVN__DEFAULT_AUTH_PROVIDER_LIST); ++ svn_config_get(config, &password_stores_config_option, ++ SVN_CONFIG_SECTION_AUTH, ++ SVN_CONFIG_OPTION_PASSWORD_STORES, ++ SVN_AUTH__DEFAULT_PROVIDER_LIST); + } +- else +- { +- password_stores_config_option = SVN__DEFAULT_AUTH_PROVIDER_LIST; +- } + + *providers = apr_array_make(pool, 12, sizeof(svn_auth_provider_object_t *)); + +- password_stores +- = svn_cstring_split(password_stores_config_option, " ,", TRUE, pool); ++ password_stores = svn_cstring_split(password_stores_config_option, ++ " ,", TRUE, pool); + + for (i = 0; i < password_stores->nelts; i++) + { + const char *password_store = APR_ARRAY_IDX(password_stores, i, + const char *); + +- + /* GNOME Keyring */ + if (apr_strnatcmp(password_store, "gnome-keyring") == 0) + { +Index: subversion/libsvn_subr/auth_masterpass.c +=================================================================== +--- subversion/libsvn_subr/auth_masterpass.c (revision 0) ++++ subversion/libsvn_subr/auth_masterpass.c (working copy) +@@ -0,0 +1,321 @@ ++/* ++ * auth_store.c: Generic authentication credential storage routines. ++ * ++ * ==================================================================== ++ * 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. ++ * ==================================================================== ++ */ ++ ++#include "svn_auth.h" ++#include "svn_string.h" ++#include "svn_dso.h" ++#include "svn_version.h" ++#include "svn_private_config.h" ++#include "private/svn_auth_private.h" ++ ++ ++ ++/*** Private Helper Functions ***/ ++ ++static svn_error_t * ++get_masterpass_provider(svn_auth_masterpass_provider_object_t **provider, ++ const char *provider_name, ++ apr_pool_t *pool) ++{ ++ *provider = NULL; ++ ++ if (apr_strnatcmp(provider_name, "gnome_keyring") == 0 || ++ apr_strnatcmp(provider_name, "kwallet") == 0) ++ { ++#if (defined(SVN_HAVE_GNOME_KEYRING) || defined(SVN_HAVE_KWALLET)) ++ apr_dso_handle_t *dso; ++ apr_dso_handle_sym_t provider_func_symbol, version_func_symbol; ++ const char *provider_func_name, *version_func_name; ++ const char *library_label, *library_name; ++ ++ library_name = apr_psprintf(pool, "libsvn_auth_%s-%d.so.0", ++ provider_name, SVN_VER_MAJOR); ++ library_label = apr_psprintf(pool, "svn_%s", provider_name); ++ provider_func_name = apr_psprintf(pool, ++ "svn_auth__get_%s_masterpass_provider", ++ provider_name); ++ version_func_name = apr_psprintf(pool, ++ "svn_auth_%s_version", ++ provider_name); ++ SVN_ERR(svn_dso_load(&dso, library_name)); ++ if (dso) ++ { ++ if (apr_dso_sym(&version_func_symbol, dso, version_func_name) == 0) ++ { ++ svn_version_func_t version_func = version_func_symbol; ++ svn_version_checklist_t check_list[2]; ++ ++ check_list[0].label = library_label; ++ check_list[0].version_query = version_func; ++ check_list[1].label = NULL; ++ check_list[1].version_query = NULL; ++ SVN_ERR(svn_ver_check_list(svn_subr_version(), check_list)); ++ } ++ if (apr_dso_sym(&provider_func_symbol, dso, provider_func_name) == 0) ++ { ++ svn_auth_masterpass_provider_func_t provider_func = ++ provider_func_symbol; ++ provider_func(provider, pool); ++ } ++ } ++#endif /* defined(SVN_HAVE_GNOME_KEYRING) || defined(SVN_HAVE_KWALLET) */ ++ } ++ else if (strcmp(provider_name, "gpg_agent") == 0) ++ { ++#if defined(SVN_HAVE_GPG_AGENT) ++ svn_auth__get_gpg_agent_masterpass_provider(provider, pool); ++#endif /* defined(SVN_HAVE_GPG_AGENT) */ ++ } ++ else if (strcmp(provider_name, "keychain") == 0) ++ { ++#ifdef SVN_HAVE_KEYCHAIN_SERVICES ++ svn_auth__get_keychain_masterpass_provider(provider, pool); ++#endif /* SVN_HAVE_KEYCHAIN_SERVICES */ ++ } ++ ++ return SVN_NO_ERROR; ++} ++ ++svn_error_t * ++svn_auth__masterpass_fetch(const svn_string_t **passphrase_digest, ++ apr_array_header_t *providers, ++ svn_boolean_t non_interactive, ++ apr_pool_t *result_pool, ++ apr_pool_t *scratch_pool) ++{ ++ int i; ++ ++ *passphrase_digest = NULL; ++ ++ for (i = 0; i < providers->nelts; i++) ++ { ++ svn_auth_masterpass_provider_object_t *provider = ++ APR_ARRAY_IDX(providers, i, svn_auth_masterpass_provider_object_t *); ++ const svn_string_t *pw_digest; ++ svn_error_t *err; ++ ++ /* No vtable? Weird, but whatever... */ ++ if (! provider->vtable) ++ continue; ++ ++ /* No fetch function in the vtable? So much for "providing" ... */ ++ if (! provider->vtable->masterpass_fetch) ++ continue; ++ ++ err = provider->vtable->masterpass_fetch(&pw_digest, non_interactive, ++ provider->provider_baton, ++ result_pool); ++ if (err) ++ { ++ svn_error_clear(err); ++ } ++ else if (pw_digest) ++ { ++ *passphrase_digest = pw_digest; ++ return SVN_NO_ERROR; ++ } ++ } ++ ++ return SVN_NO_ERROR; ++} ++ ++svn_error_t * ++svn_auth__masterpass_store(apr_array_header_t *providers, ++ const svn_string_t **passphrase_digest, ++ apr_pool_t *result_pool, ++ apr_pool_t *scratch_pool) ++{ ++ int i; ++ ++ for (i = 0; i < providers->nelts; i++) ++ { ++ svn_auth_masterpass_provider_object_t *provider = ++ APR_ARRAY_IDX(providers, i, svn_auth_masterpass_provider_object_t *); ++ svn_boolean_t pw_stored; ++ svn_error_t *err; ++ ++ /* No vtable or storage function? Nothing to do. */ ++ if (! (provider->vtable && provider->vtable->masterpass_store)) ++ continue; ++ ++ err = provider->vtable->masterpass_store(&pw_stored, passphrase_digest, ++ non_interactive, ++ provider->provider_baton, ++ result_pool); ++ if (err) ++ { ++ svn_error_clear(err); ++ } ++ else if (pw_stored) ++ { ++ return SVN_NO_ERROR; ++ } ++ } ++ ++ return SVN_NO_ERROR; ++} ++ ++ ++ ++/*** Master Password Prompting Provider (fetch-only) ***/ ++ ++/* Implements svn_auth_masterpass_fetch_t. */ ++static svn_error_t * ++prompt_masterpass_fetch(const svn_string_t **passphrase_digest, ++ svn_boolean_t non_interactive, ++ void *provider_baton, ++ apr_pool_t *pool) ++{ ++ if (! non_interactive) ++ { ++ svn_cmdline_prompt_baton2_t *pb = provider_baton; ++ ++ SVN_ERR(svn_cmdline_auth_master_passphrase_prompt(passphrase_digest, pb, ++ pool, pool)); ++ } ++ return SVN_NO_ERROR; ++} ++ ++/* Implements svn_auth__masterpass_store_t. */ ++static svn_error_t * ++prompt_masterpass_store(svn_boolean_t *stored, ++ const svn_string_t *passphrase, ++ svn_boolean_t non_interactive, ++ void *provider_baton, ++ apr_pool_t *pool) ++{ ++ *stored = FALSE; ++ return SVN_NO_ERROR; ++} ++ ++/* Prompting master password provider. */ ++static const svn_auth_masterpass_provider_t ++prompt_masterpass_provider = { ++ prompt_masterpass_fetch, ++ prompt_masterpass_store ++}; ++ ++ ++ ++/*** Public APIs ***/ ++ ++/* If provider P is non-NULL, add it to the providers LIST. */ ++#define SVN__MAYBE_ADD_PROVIDER(list,p) \ ++ { if (p) APR_ARRAY_PUSH(list, \ ++ svn_auth_masterpass_provider_object_t *) = p; } \ ++ ++svn_error_t * ++svn_auth_get_masterpass_providers(apr_array_header_t **providers, ++ svn_config_t *config, ++ apr_pool_t *pool) ++{ ++ svn_auth_masterpass_provider_object_t *provider; ++ const char *password_stores_config_option = SVN_AUTH__DEFAULT_PROVIDER_LIST; ++ apr_array_header_t *password_stores; ++ int i; ++ ++ /* Initialize our output. */ ++ *providers = apr_array_make(pool, 12, ++ sizeof(svn_auth_masterpass_provider_object_t *)); ++ ++ if (config) ++ { ++ svn_config_get(config, &password_stores_config_option, ++ SVN_CONFIG_SECTION_AUTH, ++ SVN_CONFIG_OPTION_PASSWORD_STORES, ++ SVN_AUTH__DEFAULT_PROVIDER_LIST); ++ } ++ ++ password_stores = svn_cstring_split(password_stores_config_option, ++ " ,", TRUE, pool); ++ for (i = 0; i < password_stores->nelts; i++) ++ { ++ const char *password_store = APR_ARRAY_IDX(password_stores, i, ++ const char *); ++ ++#if 0 ++ /* GNOME Keyring */ ++ if (apr_strnatcmp(password_store, "gnome-keyring") == 0) ++ { ++ SVN_ERR(get_masterpass_provider(&provider, "gnome_keyring", pool)); ++ SVN__MAYBE_ADD_PROVIDER(*providers, provider); ++ continue; ++ } ++#endif ++ ++ /* GPG-Agent */ ++ if (apr_strnatcmp(password_store, "gpg-agent") == 0) ++ { ++ SVN_ERR(get_masterpass_provider(&provider, "gpg_agent", pool)); ++ SVN__MAYBE_ADD_PROVIDER(*providers, provider); ++ continue; ++ } ++ ++#if 0 ++ /* KWallet */ ++ if (apr_strnatcmp(password_store, "kwallet") == 0) ++ { ++ SVN_ERR(get_masterpass_provider(&provider, "kwallet", pool)); ++ SVN__MAYBE_ADD_PROVIDER(*providers, provider); ++ continue; ++ } ++ ++ /* Keychain */ ++ if (apr_strnatcmp(password_store, "keychain") == 0) ++ { ++ SVN_ERR(get_masterpass_provider(&provider, "keychain", pool)); ++ SVN__MAYBE_ADD_PROVIDER(*providers, provider); ++ continue; ++ } ++ ++ /* Windows */ ++ if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0) ++ { ++ SVN_ERR(get_masterpass_provider(&provider, "windows", pool)); ++ SVN__MAYBE_ADD_PROVIDER(*providers, provider); ++ continue; ++ } ++#endif ++ ++ return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, ++ _("Invalid config: unknown password store '%s'"), ++ password_store); ++ } ++ ++ return SVN_NO_ERROR; ++} ++ ++#undef SVN__MAYBE_ADD_PROVIDER ++ ++void ++svn_auth_get_prompt_masterpass_provider( ++ svn_auth_masterpass_provider_object_t **provider, ++ svn_cmdline_prompt_baton2_t *pb, ++ apr_pool_t *pool) ++{ ++ svn_auth_masterpass_provider_object_t *po = apr_pcalloc(pool, sizeof(*po)); ++ ++ po->vtable = &prompt_masterpass_provider; ++ po->provider_baton = pb; ++ *provider = po; ++} + +Property changes on: subversion/libsvn_subr/auth_masterpass.c +___________________________________________________________________ +Added: svn:mime-type +## -0,0 +1 ## ++text/x-csrc +\ No newline at end of property +Added: svn:eol-style +## -0,0 +1 ## ++native +\ No newline at end of property +Index: subversion/libsvn_subr/cmdline.c +=================================================================== +--- subversion/libsvn_subr/cmdline.c (revision 1367185) ++++ subversion/libsvn_subr/cmdline.c (working copy) +@@ -451,6 +451,7 @@ + static svn_error_t * + open_auth_store(svn_auth__store_t **auth_store_p, + const char *config_dir, ++ svn_config_t *cfg, + svn_boolean_t use_master_password, + svn_cmdline_prompt_baton2_t *pb, + apr_pool_t *pool) +@@ -461,7 +462,9 @@ + { + svn_crypto__ctx_t *crypto_ctx; + const char *auth_config_path; ++ apr_array_header_t *providers; + ++ SVN_ERR(svn_auth_get_masterpass_providers(&providers, cfg, pool)); + SVN_ERR(svn_config_get_user_config_path(&auth_config_path, config_dir, + SVN_CONFIG__AUTH_SUBDIR, pool)); + SVN_ERR(svn_crypto__context_create(&crypto_ctx, pool)); +@@ -620,7 +623,7 @@ + auth_password); + + /* Open the appropriate auth store, and cache it in the auth baton. */ +- SVN_ERR(open_auth_store(&auth_store, config_dir, use_master_password, ++ SVN_ERR(open_auth_store(&auth_store, config_dir, cfg, use_master_password, + pb, pool)); + svn_auth_set_parameter(*ab, SVN_AUTH_PARAM_AUTH_STORE, auth_store); + +Index: subversion/libsvn_subr/gpg_agent.c +=================================================================== +--- subversion/libsvn_subr/gpg_agent.c (revision 1367185) ++++ subversion/libsvn_subr/gpg_agent.c (working copy) +@@ -57,13 +57,10 @@ + + /*** Includes. ***/ + +-#ifndef WIN32 ++#include "svn_private_config.h" /* for SVN_HAVE_GPG_AGENT */ + +-#include ++#ifdef SVN_HAVE_GPG_AGENT + +-#include +-#include +- + #include + #include "svn_auth.h" + #include "svn_config.h" +@@ -72,32 +69,18 @@ + #include "svn_cmdline.h" + #include "svn_checksum.h" + #include "svn_string.h" +- + #include "private/svn_auth_private.h" + +-#include "svn_private_config.h" + +-#ifdef SVN_HAVE_GPG_AGENT ++/*** NOTE: We only support GPG-Agent on non-Windows platforms. */ ++#ifndef WIN32 + ++#include ++#include ++#include ++ + #define BUFFER_SIZE 1024 + +-/* Modify STR in-place such that blanks are escaped as required by the +- * gpg-agent protocol. Return a pointer to STR. */ +-static char * +-escape_blanks(char *str) +-{ +- char *s = str; +- +- while (*s) +- { +- if (*s == ' ') +- *s = '+'; +- s++; +- } +- +- return str; +-} +- + /* Attempt to read a gpg-agent response message from the socket SD into + * buffer BUF. Buf is assumed to be N bytes large. Return TRUE if a response + * message could be read that fits into the buffer. Else return FALSE. +@@ -152,17 +135,19 @@ + return (strncmp(buf, "OK", 2) == 0); + } + +-/* Implementation of svn_auth__password_get_t that retrieves the password +- from gpg-agent */ ++/* Set *PASSWORD to the password (retrieved from GPG-Agent) associated ++ with CACHE_ID. Use PASSWORD_PROMPT and REALM_PROMPT to construct a ++ prompt for the user when the password isn't found in the agent. If ++ NON_INTERACTIVE is set, though, don't do any prompting. Set *DONE ++ iff the operation completes. */ + static svn_error_t * +-password_get_gpg_agent(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) ++password_get_gpg_agent_helper(svn_boolean_t *done, ++ const char **password, ++ const char *password_prompt, ++ const char *realm_prompt, ++ const char *cache_id, ++ svn_boolean_t non_interactive, ++ apr_pool_t *pool) + { + int sd; + char *gpg_agent_info = NULL; +@@ -172,16 +157,12 @@ + + apr_array_header_t *socket_details; + const char *request = NULL; +- const char *cache_id = NULL; + struct sockaddr_un addr; + const char *tty_name; + const char *tty_type; + const char *lc_ctype; + const char *display; + const char *socket_name = NULL; +- svn_checksum_t *digest = NULL; +- char *password_prompt; +- char *realm_prompt; + + *done = FALSE; + +@@ -330,22 +311,11 @@ + } + } + +- /* Create the CACHE_ID which will be generated based on REALMSTRING similar +- to other password caching mechanisms. */ +- svn_checksum(&digest, svn_checksum_md5, realmstring, strlen(realmstring), +- pool); +- cache_id = svn_checksum_to_cstring(digest, pool); +- +- password_prompt = apr_psprintf(pool, _("Password for '%s': "), username); +- realm_prompt = apr_psprintf(pool, _("Enter your Subversion password for %s"), +- realmstring); + request = apr_psprintf(pool, + "GET_PASSPHRASE --data %s--repeat=1 " + "%s X %s %s\n", + non_interactive ? "--no-ask " : "", +- cache_id, +- escape_blanks(password_prompt), +- escape_blanks(realm_prompt)); ++ cache_id, password_prompt, realm_prompt); + + if (write(sd, request, strlen(request)) == -1) + { +@@ -380,7 +350,83 @@ + return SVN_NO_ERROR; + } + ++#else /* !WIN32 */ + ++static svn_error_t * ++password_get_gpg_agent_helper(svn_boolean_t *done, ++ const char **password, ++ const char *password_prompt, ++ const char *realm_prompt, ++ const char *cache_id, ++ svn_boolean_t non_interactive, ++ apr_pool_t *pool) ++{ ++ return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, 0, ++ "GPG Agent is currently unsupported on this system"); ++} ++ ++#endif /* !WIN32 */ ++ ++ ++/* Modify STR in-place such that blanks are escaped as required by the ++ * gpg-agent protocol. Return a pointer to STR. */ ++static char * ++escape_blanks(char *str) ++{ ++ char *s = str; ++ ++ while (*s) ++ { ++ if (*s == ' ') ++ *s = '+'; ++ s++; ++ } ++ ++ return str; ++} ++ ++/* Create the CACHE_ID which will be generated based on REALMSTRING ++ (similar to other password caching mechanisms). */ ++static const char * ++cacheid_from_realmstring(const char *realmstring, ++ apr_pool_t *pool) ++{ ++ svn_checksum_t *digest = svn_checksum_create(svn_checksum_md5, pool); ++ svn_checksum(&digest, svn_checksum_md5, realmstring, ++ strlen(realmstring), pool); ++ return svn_checksum_to_cstring(digest, pool); ++} ++ ++ ++/* Implementation of svn_auth__password_get_t that retrieves the password ++ from gpg-agent */ ++static svn_error_t * ++password_get_gpg_agent(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) ++{ ++ const char *cache_id = cacheid_from_realmstring(realmstring, pool); ++ char *password_prompt = ++ apr_psprintf(pool, _("Password for '%s': "), username); ++ char *realm_prompt = ++ apr_psprintf(pool, _("Enter your Subversion password for %s"), realmstring); ++ ++ escape_blanks(realm_prompt); ++ escape_blanks(password_prompt); ++ ++ return svn_error_trace(password_get_gpg_agent_helper(done, password, ++ cache_id, ++ password_prompt, ++ realm_prompt, ++ non_interactive, ++ pool)); ++} ++ + /* Implementation of svn_auth__password_set_t that would store the + password in GPG Agent if that's how this particular integration + worked. But it isn't. GPG Agent stores the password provided by +@@ -456,5 +502,63 @@ + *provider = po; + } + ++ ++ ++/*-----------------------------------------------------------------------*/ ++/* GPG Agent master passphrase. */ ++/*-----------------------------------------------------------------------*/ ++ ++/* Implements svn_auth_masterpass_fetch_t. */ ++static svn_error_t * ++gpg_agent_masterpass_fetch(const char **passphrase, ++ svn_boolean_t non_interactive, ++ void *provider_baton, ++ apr_pool_t *pool) ++{ ++ const char *cache_id = "Subversion Master Password"; ++ const char *password_prompt = _("Password:"); ++ const char *realm_prompt = _("Enter+your+Subversion+master+password"); ++ svn_boolean_t done; ++ const char *password; ++ svn_checksum_t *digest; ++ ++ SVN_ERR(password_get_gpg_agent_helper(&done, &password, cache_id, ++ password_prompt, realm_prompt, ++ non_interactive, pool)); ++ ++ /* ### FIXME: Should be SHA-256 */ ++ svn_checksum(&digest, svn_checksum_sha1, password, strlen(password), pool); ++ *passphrase = svn_checksum_to_cstring_display(digest, pool); ++ return SVN_NO_ERROR; ++} ++ ++/* Implements svn_auth__masterpass_store_t. */ ++static svn_error_t * ++gpg_agent_masterpass_store(const char *passphrase, ++ svn_boolean_t non_interactive, ++ void *provider_baton, ++ apr_pool_t *pool) ++{ ++ return SVN_NO_ERROR; ++} ++ ++static const svn_auth_masterpass_provider_t ++gpg_agent_masterpass_provider = { ++ gpg_agent_masterpass_fetch, ++ gpg_agent_masterpass_store ++}; ++ ++/* Public API */ ++void ++svn_auth__get_gpg_agent_masterpass_provider( ++ svn_auth_masterpass_provider_object_t **provider, ++ apr_pool_t *pool) ++{ ++ svn_auth_masterpass_provider_object_t *po = apr_pcalloc(pool, sizeof(*po)); ++ ++ po->vtable = &gpg_agent_masterpass_provider; ++ *provider = po; ++} ++ ++ + #endif /* SVN_HAVE_GPG_AGENT */ +-#endif /* !WIN32 */ +Index: subversion/libsvn_subr/prompt.c +=================================================================== +--- subversion/libsvn_subr/prompt.c (revision 1367185) ++++ subversion/libsvn_subr/prompt.c (working copy) +@@ -501,13 +501,12 @@ + /* This implements 'svn_auth__master_passphrase_fetch_t'. */ + svn_error_t * + svn_cmdline_auth_master_passphrase_prompt(const svn_string_t **secret, +- void *baton, ++ svn_cmdline_prompt_baton2_t *pb, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) + { + const char *response; + int response_len; +- svn_cmdline_prompt_baton2_t *pb = baton; + svn_checksum_t *checksum; + + SVN_ERR(prompt(&response, _("Enter master passphrase: "), +}}} \ No newline at end of file