Author: cmpilato
Date: Tue Apr 10 19:46:12 2012
New Revision: 1311958
URL: http://svn.apache.org/viewvc?rev=1311958&view=rev
Log:
On the 'master-passphrase' branch, introduce the concept of master
passphrase providers. None of this code is actually used yet.
* subversion/include/private/svn_auth_private.h
(svn_auth__masterpass_provider_t, svn_auth__masterpass_provider_object_t,
svn_auth__masterpass_provider_func_t, svn_auth__get_masterpass_providers,
svn_auth__get_gpg_agent_masterpass_provider): New typedefs and
function prototypes.
* subversion/libsvn_subr/auth.c
(AUTHN_MASTER_PASS_KNOWN_TEXT, AUTHN_FAUX_REALMSTRING, AUTHN_CHECKTEXT_KEY,
AUTHN_PASSTYPE_KEY, encrypt_text, decrypt_text,
svn_auth_master_passphrase_get, svn_auth_master_passphrase_set):
Moved these to masterpass.c.
* subversion/libsvn_subr/masterpass.c
New file, containing the stuff moved out of auth.c, plus...
(get_masterpass_provider, svn_auth__get_masterpass_providers): ...these new
functions.
* subversion/libsvn_subr/gpg_agent.c
(cacheid_from_realmstring, password_get_gpg_agent_helper): New
helper functions, mostly carved out of password_get_gpg_agent().
(password_get_gpg_agent): Reimplement has a wrapper around
cacheid_from_realmstring() and password_get_gpg_agent_helper().
(gpg_agent_masterpass_fetch, gpg_agent_masterpass_store,
gpg_agent_masterpass_provider, svn_auth__get_gpg_agent_masterpass_provider):
New functions and static structures.
Added:
subversion/branches/master-passphrase/subversion/libsvn_subr/masterpass.c
(with props)
Modified:
subversion/branches/master-passphrase/subversion/include/private/svn_auth_private.h
subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c
subversion/branches/master-passphrase/subversion/libsvn_subr/gpg_agent.c
Modified:
subversion/branches/master-passphrase/subversion/include/private/svn_auth_private.h
URL:
http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/include/private/svn_auth_private.h?rev=1311958&r1=1311957&r2=1311958&view=diff
==============================================================================
---
subversion/branches/master-passphrase/subversion/include/private/svn_auth_private.h
(original)
+++
subversion/branches/master-passphrase/subversion/include/private/svn_auth_private.h
Tue Apr 10 19:46:12 2012
@@ -213,6 +213,63 @@ svn_auth__ssl_client_cert_pw_set(svn_boo
svn_boolean_t non_interactive,
apr_pool_t *pool);
+
+/*** Master Passphrase ***/
+
+/** The master passphrase "provider" vtable. */
+typedef struct svn_auth__masterpass_provider_t
+{
+ /* Set *PASSPHRASE to the value of the Subversion master passphrase
+ hash digest string. If NON_INTERACTIVE is set, do not prompt
+ the user. Set *DONE to TRUE if the passphrase is successfully
+ fetched; to FALSE otherwise. */
+ svn_error_t *
+ (*svn_auth__masterpass_fetch_t)(const char **passphrase,
+ svn_boolean_t non_interactive,
+ void *provider_baton,
+ apr_pool_t *pool);
+
+ /* Store PASSPHRASE as the value of the Subversion master
+ passphrase hash digest string. If NON_INTERACTIVE is set, do
+ not prompt the user. Set *DONE to TRUE if the passphrase is
+ successfully stored; to FALSE otherwise. */
+ svn_error_t *
+ (*svn_auth__masterpass_store_t)(const char *passphrase,
+ svn_boolean_t non_interactive,
+ void *provider_baton,
+ apr_pool_t *pool);
+
+} svn_auth__masterpass_provider_t;
+
+/** A master passphrase provider object and baton. */
+typedef struct svn__auth_masterpass_provider_object_t
+{
+ const svn_auth__masterpass_provider_t *vtable;
+ void *provider_baton;
+
+} svn_auth__masterpass_provider_object_t;
+
+/** The type of function returning a master passphrase provider. */
+typedef void (*svn_auth__masterpass_provider_func_t)(
+ svn_auth__masterpass_provider_object_t **provider,
+ apr_pool_t *pool);
+
+/* Set *PROVIDERS to an array of svn_auth_provider_object_t's
+ appropriate for the client platform and which honor the allowed
+ providers specified in CONFIG. Allocate providers from POOL. */
+svn_error_t *
+svn_auth__get_masterpass_providers(apr_array_header_t **providers,
+ svn_config_t *config,
+ apr_pool_t *pool);
+
+#if !defined(WIN32)
+/* 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(WIN32) */
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c
URL:
http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c?rev=1311958&r1=1311957&r2=1311958&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c
(original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/auth.c Tue Apr
10 19:46:12 2012
@@ -660,192 +660,3 @@ svn_auth_get_platform_specific_client_pr
return SVN_NO_ERROR;
}
-
-
-/*** Master Passphrase ***/
-
-#define AUTHN_MASTER_PASS_KNOWN_TEXT "Subversion"
-#define AUTHN_FAUX_REALMSTRING "localhost.localdomain"
-#define AUTHN_CHECKTEXT_KEY "checktext"
-#define AUTHN_PASSTYPE_KEY "passtype"
-
-
-/* Use SECRET to encrypt TEXT, returning the result (allocated from
- RESULT_POOL) in *CRYPT_TEXT. Use SCRATCH_POOL for temporary
- allocations. */
-static svn_error_t *
-encrypt_text(const svn_string_t **crypt_text,
- const svn_string_t *text,
- const char *secret,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- /* ### FIXME! This a mindless temporary implementation, offering
- all the security and privacy of a glass bathroom! ***/
-
- SVN_ERR_ASSERT(text && text->data);
- SVN_ERR_ASSERT(secret);
-
- *crypt_text = svn_base64_encode_string2(svn_string_createf(scratch_pool,
- "%s+%s",
- text->data,
- secret),
- FALSE, result_pool);
- return SVN_NO_ERROR;
-}
-
-
-/* Use SECRET to decrypt CRYPT_TEXT, returning the result (allocated
- from RESULT_POOL) in *TEXT. Use SCRATCH_POOL for temporary
- allocations. */
-static svn_error_t *
-decrypt_text(const svn_string_t **text,
- const svn_string_t *crypt_text,
- const char *secret,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- /* ### FIXME! This a mindless temporary implementation, offering
- all the security and privacy of a glass bathroom! ***/
-
- const svn_string_t *work_text;
- int secret_len, text_len;
-
- SVN_ERR_ASSERT(crypt_text && crypt_text->data);
- SVN_ERR_ASSERT(secret);
-
- secret_len = strlen(secret);
- work_text = svn_base64_decode_string(crypt_text, scratch_pool);
- if (work_text->len < (secret_len + 1))
- return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL,
- "Invalid master passphrase.");
- text_len = work_text->len - secret_len - 1;
- if (work_text->data[text_len] != '+')
- return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL,
- "Invalid master passphrase.");
- if (strcmp(work_text->data + text_len + 1, secret) != 0)
- return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL,
- "Invalid master passphrase.");
- *text = svn_string_ncreate(work_text->data,
- work_text->len - secret_len - 1,
- result_pool);
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_auth_master_passphrase_get(const char **passphrase,
- svn_auth_baton_t *auth_baton,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- apr_hash_t *creds_hash;
- const svn_string_t *check_text;
- const char *config_dir = apr_hash_get(auth_baton->parameters,
- SVN_AUTH_PARAM_CONFIG_DIR,
- APR_HASH_KEY_STRING);
-#ifdef SVN_AUTH_TEMP_USE_FAUX_PASSPHRASE
- const char *default_passphrase = SVN_AUTH_TEMP_MASTER_PASSPHRASE;
-#else
- const char *default_passphrase =
- apr_hash_get(auth_baton->parameters,
- SVN_AUTH_PARAM_DEFAULT_MASTER_PASSPHRASE,
- APR_HASH_KEY_STRING);
-#endif
-
- /* Read the existing passphrase storage record so we can validate
- any master passphrase we have or fetch. If there's no check text,
- we must assume that there's no global master passphrase set, so
- we'll just return that fact. */
- SVN_ERR(svn_config_read_auth_data(&creds_hash,
- SVN_AUTH_CRED_MASTER_PASSPHRASE,
- AUTHN_FAUX_REALMSTRING, config_dir,
- scratch_pool));
- check_text = apr_hash_get(creds_hash, AUTHN_CHECKTEXT_KEY,
- APR_HASH_KEY_STRING);
- if (! check_text)
- {
- *passphrase = NULL;
- return SVN_NO_ERROR;
- }
-
- /* If there's a default passphrase, verify that it matches the
- stored known-text. */
- if (default_passphrase)
- {
- const svn_string_t *crypt_text;
- SVN_ERR(encrypt_text(&crypt_text,
- svn_string_create(AUTHN_MASTER_PASS_KNOWN_TEXT,
- scratch_pool),
- default_passphrase, scratch_pool, scratch_pool));
- if (svn_string_compare(crypt_text, check_text))
- {
- *passphrase = apr_pstrdup(result_pool, default_passphrase);
- return SVN_NO_ERROR;
- }
- default_passphrase = NULL;
- }
-
- /* We do not yet know the master passphrase, so we need to consult
- the providers. */
- /* ### TODO ### */
-
- default_passphrase = NULL;
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_auth_master_passphrase_set(svn_auth_baton_t *auth_baton,
- const char *new_passphrase,
- apr_pool_t *scratch_pool)
-{
- apr_hash_t *creds_hash;
- const char *config_dir = apr_hash_get(auth_baton->parameters,
- SVN_AUTH_PARAM_CONFIG_DIR,
- APR_HASH_KEY_STRING);
- const char *old_passphrase;
- const svn_string_t *old_check_text, *new_check_text;
-
- /* First, fetch the existing passphrase. */
- SVN_ERR(svn_auth_master_passphrase_get(&old_passphrase, auth_baton,
- scratch_pool, scratch_pool));
-
- /* Now, read the existing passphrase storage record and grab the
- current checkidentify. */
- SVN_ERR(svn_config_read_auth_data(&creds_hash,
- SVN_AUTH_CRED_MASTER_PASSPHRASE,
- AUTHN_FAUX_REALMSTRING, config_dir,
- scratch_pool));
- old_check_text = apr_hash_get(creds_hash, AUTHN_CHECKTEXT_KEY,
- APR_HASH_KEY_STRING);
-
- SVN_ERR(svn_config_write_auth_data(creds_hash,
- SVN_AUTH_CRED_MASTER_PASSPHRASE,
- AUTHN_FAUX_REALMSTRING, config_dir,
- scratch_pool));
-
- if (new_passphrase)
- {
- /* Encrypt the known text with NEW_PASSPHRASE to form the crypttext,
- and stuff that into the CREDS_HASH. */
- SVN_ERR(encrypt_text(&new_check_text,
- svn_string_create(AUTHN_MASTER_PASS_KNOWN_TEXT,
- scratch_pool),
- new_passphrase, scratch_pool, scratch_pool));
- apr_hash_set(creds_hash, AUTHN_CHECKTEXT_KEY,
- APR_HASH_KEY_STRING, new_check_text);
- }
- else
- {
- apr_hash_set(creds_hash, AUTHN_CHECKTEXT_KEY, APR_HASH_KEY_STRING, NULL);
- }
-
- /* Re-encrypt all stored credentials in light of NEW_PASSPHRASE. */
- /* ### TODO ### */
-
- /* Save credentials to disk. */
- return svn_config_write_auth_data(creds_hash,
- SVN_AUTH_CRED_MASTER_PASSPHRASE,
- AUTHN_FAUX_REALMSTRING, config_dir,
- scratch_pool);
-}
Modified:
subversion/branches/master-passphrase/subversion/libsvn_subr/gpg_agent.c
URL:
http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/gpg_agent.c?rev=1311958&r1=1311957&r2=1311958&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/gpg_agent.c
(original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/gpg_agent.c
Tue Apr 10 19:46:12 2012
@@ -152,17 +152,29 @@ send_option(int sd, char *buf, size_t n,
return (strncmp(buf, "OK", 2) == 0);
}
+/* 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)
+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 +184,12 @@ password_get_gpg_agent(svn_boolean_t *do
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,23 +338,11 @@ password_get_gpg_agent(svn_boolean_t *do
}
}
- /* Create the CACHE_ID which will be generated based on REALMSTRING similar
- to other password caching mechanisms. */
- digest = svn_checksum_create(svn_checksum_md5, pool);
- 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)
{
@@ -382,6 +378,35 @@ password_get_gpg_agent(svn_boolean_t *do
}
+/* 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
@@ -457,5 +482,65 @@ svn_auth_get_gpg_agent_simple_provider(s
*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 */
Added: subversion/branches/master-passphrase/subversion/libsvn_subr/masterpass.c
URL:
http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/masterpass.c?rev=1311958&view=auto
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/masterpass.c
(added)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/masterpass.c
Tue Apr 10 19:46:12 2012
@@ -0,0 +1,390 @@
+/*
+ * masterpass.c: master passphrase support functions for Subversion
+ *
+ * ====================================================================
+ * 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 <apr_pools.h>
+#include <apr_tables.h>
+#include <apr_strings.h>
+
+#include "svn_string.h"
+#include "svn_error.h"
+#include "svn_auth.h"
+#include "svn_config.h"
+#include "svn_private_config.h"
+#include "svn_dso.h"
+#include "svn_base64.h"
+#include "svn_version.h"
+#include "private/svn_auth_private.h"
+
+#include "crypto.h"
+
+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_function_symbol, version_function_symbol;
+ const char *library_label, *library_name;
+ const char *provider_function_name, *version_function_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_function_name =
+ apr_psprintf(pool, "svn_auth_get_%s_masterpass_provider",
+ provider_name);
+ version_function_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_function_symbol,
+ dso,
+ version_function_name) == 0)
+ {
+ svn_version_func_t version_function
+ = version_function_symbol;
+ const svn_version_checklist_t check_list[] =
+ {
+ { library_label, version_function },
+ { NULL, NULL }
+ };
+ SVN_ERR(svn_ver_check_list(svn_subr_version(), check_list));
+ }
+ if (apr_dso_sym(&provider_function_symbol,
+ dso,
+ provider_function_name) == 0)
+ {
+ svn_auth__masterpass_provider_func_t provider_function =
+ provider_function_symbol;
+ provider_function(provider, pool);
+ }
+ }
+#endif
+ }
+ else
+ {
+#if defined(SVN_HAVE_GPG_AGENT)
+ if (strcmp(provider_name, "gpg_agent") == 0)
+ {
+ svn_auth__get_gpg_agent_masterpass_provider(provider, pool);
+ }
+#endif
+#ifdef SVN_HAVE_KEYCHAIN_SERVICES
+ /* ### TODO: Implement MacOS X Keychain provider. */
+#endif
+#if defined(WIN32) && !defined(__MINGW32__)
+ /* ### TODO: Can Windows actually use this? It's less of a
+ ### store and more of a service. */
+#endif
+ }
+
+ return SVN_NO_ERROR;
+}
+
+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;
+ 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);
+ }
+ 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);
+
+ 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)
+ {
+ SVN_ERR(get_masterpass_provider(&provider, "gnome_keyring", pool));
+ if (provider)
+ APR_ARRAY_PUSH(*providers,
+ svn_auth__masterpass_provider_object_t *) =
provider;
+ continue;
+ }
+
+ /* GPG-AGENT */
+ if (apr_strnatcmp(password_store, "gpg-agent") == 0)
+ {
+ SVN_ERR(get_masterpass_provider(&provider, "gpg_agent", pool));
+ if (provider)
+ APR_ARRAY_PUSH(*providers,
+ svn_auth__masterpass_provider_object_t *) =
provider;
+ continue;
+ }
+
+ /* KWallet */
+ if (apr_strnatcmp(password_store, "kwallet") == 0)
+ {
+ SVN_ERR(get_masterpass_provider(&provider, "kwallet", pool));
+ if (provider)
+ APR_ARRAY_PUSH(*providers,
+ svn_auth__masterpass_provider_object_t *) =
provider;
+ continue;
+ }
+
+ /* Keychain */
+ if (apr_strnatcmp(password_store, "keychain") == 0)
+ {
+ SVN_ERR(get_masterpass_provider(&provider, "keychain", pool));
+ if (provider)
+ APR_ARRAY_PUSH(*providers,
+ svn_auth__masterpass_provider_object_t *) =
provider;
+ continue;
+ }
+
+ /* Windows */
+ if (apr_strnatcmp(password_store, "windows-cryptoapi") == 0)
+ {
+ SVN_ERR(get_masterpass_provider(&provider, "windows", pool));
+ if (provider)
+ APR_ARRAY_PUSH(*providers,
+ svn_auth__masterpass_provider_object_t *) =
provider;
+ continue;
+ }
+
+ return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+ _("Invalid config: unknown password store
'%s'"),
+ password_store);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/*** Master Passphrase ***/
+
+#define AUTHN_MASTER_PASS_KNOWN_TEXT "Subversion"
+#define AUTHN_FAUX_REALMSTRING "localhost.localdomain"
+#define AUTHN_CHECKTEXT_KEY "checktext"
+#define AUTHN_PASSTYPE_KEY "passtype"
+
+
+/* Use SECRET to encrypt TEXT, returning the result (allocated from
+ RESULT_POOL) in *CRYPT_TEXT. Use SCRATCH_POOL for temporary
+ allocations. */
+static svn_error_t *
+encrypt_text(const svn_string_t **crypt_text,
+ const svn_string_t *text,
+ const char *secret,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ /* ### FIXME! This a mindless temporary implementation, offering
+ all the security and privacy of a glass bathroom! ***/
+
+ SVN_ERR_ASSERT(text && text->data);
+ SVN_ERR_ASSERT(secret);
+
+ *crypt_text = svn_base64_encode_string2(svn_string_createf(scratch_pool,
+ "%s+%s",
+ text->data,
+ secret),
+ FALSE, result_pool);
+ return SVN_NO_ERROR;
+}
+
+
+/* Use SECRET to decrypt CRYPT_TEXT, returning the result (allocated
+ from RESULT_POOL) in *TEXT. Use SCRATCH_POOL for temporary
+ allocations. */
+static svn_error_t *
+decrypt_text(const svn_string_t **text,
+ const svn_string_t *crypt_text,
+ const char *secret,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ /* ### FIXME! This a mindless temporary implementation, offering
+ all the security and privacy of a glass bathroom! ***/
+
+ const svn_string_t *work_text;
+ int secret_len, text_len;
+
+ SVN_ERR_ASSERT(crypt_text && crypt_text->data);
+ SVN_ERR_ASSERT(secret);
+
+ secret_len = strlen(secret);
+ work_text = svn_base64_decode_string(crypt_text, scratch_pool);
+ if (work_text->len < (secret_len + 1))
+ return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL,
+ "Invalid master passphrase.");
+ text_len = work_text->len - secret_len - 1;
+ if (work_text->data[text_len] != '+')
+ return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL,
+ "Invalid master passphrase.");
+ if (strcmp(work_text->data + text_len + 1, secret) != 0)
+ return svn_error_create(SVN_ERR_AUTHN_FAILED, NULL,
+ "Invalid master passphrase.");
+ *text = svn_string_ncreate(work_text->data,
+ work_text->len - secret_len - 1,
+ result_pool);
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_auth_master_passphrase_get(const char **passphrase,
+ svn_auth_baton_t *auth_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *creds_hash;
+ const svn_string_t *check_text;
+ const char *config_dir = svn_auth_get_parameter(auth_baton,
+ SVN_AUTH_PARAM_CONFIG_DIR);
+#ifdef SVN_AUTH_TEMP_USE_FAUX_PASSPHRASE
+ const char *default_passphrase = SVN_AUTH_TEMP_MASTER_PASSPHRASE;
+#else
+ const char *default_passphrase =
+ svn_auth_get_parameter(auth_baton,
+ SVN_AUTH_PARAM_DEFAULT_MASTER_PASSPHRASE);
+#endif
+
+ /* Read the existing passphrase storage record so we can validate
+ any master passphrase we have or fetch. If there's no check text,
+ we must assume that there's no global master passphrase set, so
+ we'll just return that fact. */
+ SVN_ERR(svn_config_read_auth_data(&creds_hash,
+ SVN_AUTH_CRED_MASTER_PASSPHRASE,
+ AUTHN_FAUX_REALMSTRING, config_dir,
+ scratch_pool));
+ check_text = apr_hash_get(creds_hash, AUTHN_CHECKTEXT_KEY,
+ APR_HASH_KEY_STRING);
+ if (! check_text)
+ {
+ *passphrase = NULL;
+ return SVN_NO_ERROR;
+ }
+
+ /* If there's a default passphrase, verify that it matches the
+ stored known-text. */
+ if (default_passphrase)
+ {
+ const svn_string_t *crypt_text;
+ SVN_ERR(encrypt_text(&crypt_text,
+ svn_string_create(AUTHN_MASTER_PASS_KNOWN_TEXT,
+ scratch_pool),
+ default_passphrase, scratch_pool, scratch_pool));
+ if (svn_string_compare(crypt_text, check_text))
+ {
+ *passphrase = apr_pstrdup(result_pool, default_passphrase);
+ return SVN_NO_ERROR;
+ }
+ default_passphrase = NULL;
+ }
+
+ /* We do not yet know the master passphrase, so we need to consult
+ the providers. */
+ /* ### TODO ### */
+
+ default_passphrase = NULL;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_auth_master_passphrase_set(svn_auth_baton_t *auth_baton,
+ const char *new_passphrase,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *creds_hash;
+ const char *config_dir = svn_auth_get_parameter(auth_baton,
+ SVN_AUTH_PARAM_CONFIG_DIR);
+ const char *old_passphrase;
+ const svn_string_t *old_check_text, *new_check_text;
+
+ /* First, fetch the existing passphrase. */
+ SVN_ERR(svn_auth_master_passphrase_get(&old_passphrase, auth_baton,
+ scratch_pool, scratch_pool));
+
+ /* Now, read the existing passphrase storage record and grab the
+ current checkidentify. */
+ SVN_ERR(svn_config_read_auth_data(&creds_hash,
+ SVN_AUTH_CRED_MASTER_PASSPHRASE,
+ AUTHN_FAUX_REALMSTRING, config_dir,
+ scratch_pool));
+ old_check_text = apr_hash_get(creds_hash, AUTHN_CHECKTEXT_KEY,
+ APR_HASH_KEY_STRING);
+
+ SVN_ERR(svn_config_write_auth_data(creds_hash,
+ SVN_AUTH_CRED_MASTER_PASSPHRASE,
+ AUTHN_FAUX_REALMSTRING, config_dir,
+ scratch_pool));
+
+ if (new_passphrase)
+ {
+ /* Encrypt the known text with NEW_PASSPHRASE to form the crypttext,
+ and stuff that into the CREDS_HASH. */
+ SVN_ERR(encrypt_text(&new_check_text,
+ svn_string_create(AUTHN_MASTER_PASS_KNOWN_TEXT,
+ scratch_pool),
+ new_passphrase, scratch_pool, scratch_pool));
+ apr_hash_set(creds_hash, AUTHN_CHECKTEXT_KEY,
+ APR_HASH_KEY_STRING, new_check_text);
+ }
+ else
+ {
+ apr_hash_set(creds_hash, AUTHN_CHECKTEXT_KEY, APR_HASH_KEY_STRING, NULL);
+ }
+
+ /* Re-encrypt all stored credentials in light of NEW_PASSPHRASE. */
+ /* ### TODO ### */
+
+ /* Save credentials to disk. */
+ return svn_config_write_auth_data(creds_hash,
+ SVN_AUTH_CRED_MASTER_PASSPHRASE,
+ AUTHN_FAUX_REALMSTRING, config_dir,
+ scratch_pool);
+}
Propchange:
subversion/branches/master-passphrase/subversion/libsvn_subr/masterpass.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
subversion/branches/master-passphrase/subversion/libsvn_subr/masterpass.c
------------------------------------------------------------------------------
svn:mime-type = text/x-csrc