You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by cm...@apache.org on 2012/08/02 21:26:22 UTC

svn commit: r1368658 - in /subversion/branches/master-passphrase/subversion: include/svn_auth.h libsvn_subr/cmdline.c libsvn_subr/gpg_agent.c

Author: cmpilato
Date: Thu Aug  2 19:26:22 2012
New Revision: 1368658

URL: http://svn.apache.org/viewvc?rev=1368658&view=rev
Log:
On the 'master-passphrase' branch: introduce GPG-Agent caching of the
master passphrase.

* subversion/include/svn_auth.h
  (svn_auth_get_gpg_agent_master_passphrase_provider): New function.

* subversion/libsvn_subr/cmdline.c
  (open_auth_store): Register the gpg-agent master passphrase provider
    where available.

* subversion/libsvn_subr/gpg_agent.c
  (get_password_via_agent): New function, abstracted from of
    password_get_gpg_agent().
  (password_get_gpg_agent): Now just a wrapper around
    get_password_via_agent().
  (master_passphrase_gpg_agent_first_creds,
   gpg_agent_master_passphrase_provider,
   svn_auth_get_gpg_agent_master_passphrase_provider): New stuff.

Modified:
    subversion/branches/master-passphrase/subversion/include/svn_auth.h
    subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c
    subversion/branches/master-passphrase/subversion/libsvn_subr/gpg_agent.c

Modified: subversion/branches/master-passphrase/subversion/include/svn_auth.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/include/svn_auth.h?rev=1368658&r1=1368657&r2=1368658&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/include/svn_auth.h (original)
+++ subversion/branches/master-passphrase/subversion/include/svn_auth.h Thu Aug  2 19:26:22 2012
@@ -1328,6 +1328,22 @@ void svn_auth_get_master_passphrase_prom
   int retry_limit,
   apr_pool_t *pool);
 
+
+#if !defined(WIN32) || defined(DOXYGEN)
+/** Set @a *provider to an authentication provider of type @c
+ * svn_auth_cred_master_passphrase_t, allocated in @a pool.
+ *
+ * @a *provider retrieves its credentials via GPG-Agent.  The returned
+ * credentials are used to unlock Subversion's encrypted
+ * authentication credential store.
+ *
+ * @since New in 1.8.
+ */
+void
+svn_auth_get_gpg_agent_master_passphrase_provider(
+  svn_auth_provider_object_t **provider,
+  apr_pool_t *pool);
+#endif /* !defined(WIN32) || defined(DOXYGEN) */
   
 #ifdef __cplusplus
 }

Modified: subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c?rev=1368658&r1=1368657&r2=1368658&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/cmdline.c Thu Aug  2 19:26:22 2012
@@ -477,6 +477,12 @@ open_auth_store(svn_auth__store_t **auth
                                     sizeof(svn_auth_provider_object_t *));
       if (! non_interactive)
         {
+#if !defined(WIN32) || defined(DOXYGEN)
+          /* ### FIXME!!  This should be done by code that inspects
+             and honors the 'password-stores' configuration setting! */
+          svn_auth_get_gpg_agent_master_passphrase_provider(&provider, pool);
+          APR_ARRAY_PUSH(mp_providers, svn_auth_provider_object_t *) = provider;
+#endif /* !defined(WIN32) || defined(DOXYGEN) */
           svn_auth_get_master_passphrase_prompt_provider(
               &provider, svn_cmdline_auth_master_passphrase_prompt,
               pb, 3, 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=1368658&r1=1368657&r2=1368658&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_subr/gpg_agent.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_subr/gpg_agent.c Thu Aug  2 19:26:22 2012
@@ -155,12 +155,11 @@ send_option(int sd, char *buf, size_t n,
 /* 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,
+get_password_via_agent(svn_boolean_t *done,
                        const char **password,
-                       apr_hash_t *creds,
                        const char *realmstring,
-                       const char *username,
-                       apr_hash_t *parameters,
+                       const char *escaped_password_prompt,
+                       const char *escaped_realm_prompt,
                        svn_boolean_t non_interactive,
                        apr_pool_t *pool)
 {
@@ -180,8 +179,6 @@ password_get_gpg_agent(svn_boolean_t *do
   const char *display;
   const char *socket_name = NULL;
   svn_checksum_t *digest = NULL;
-  char *password_prompt;
-  char *realm_prompt;
 
   *done = FALSE;
 
@@ -336,16 +333,12 @@ password_get_gpg_agent(svn_boolean_t *do
                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",
+  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));
+                         escaped_password_prompt,
+                         escaped_realm_prompt);
 
   if (write(sd, request, strlen(request)) == -1)
     {
@@ -381,6 +374,30 @@ 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)
+{
+  char *escaped_password_prompt =
+    escape_blanks(apr_psprintf(pool, _("Password for '%s': "), username));
+  char *escaped_realm_prompt =
+    escape_blanks(apr_psprintf(pool, _("Enter your Subversion password for %s"),
+                               realmstring));
+
+  SVN_ERR(get_password_via_agent(done, password, realmstring,
+                                 escaped_password_prompt, escaped_realm_prompt,
+                                 non_interactive, pool));
+  return SVN_NO_ERROR;
+}
+
 /* 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 +473,71 @@ svn_auth_get_gpg_agent_simple_provider(s
   *provider = po;
 }
 
+
+
+/*** Master Passphrase Provider ***/
+
+/* An implementation of svn_auth_provider_t::first_credentials() */
+static svn_error_t *
+master_passphrase_gpg_agent_first_creds(void **credentials,
+                                        void **iter_baton,
+                                        void *provider_baton,
+                                        apr_hash_t *parameters,
+                                        const char *realmstring,
+                                        apr_pool_t *pool)
+{
+  char *escaped_password_prompt = _("Subversion+master+password");
+  char *escaped_realm_prompt = _("Enter+your+Subversion+master+password");
+  svn_boolean_t non_interactive = apr_hash_get(parameters,
+                                               SVN_AUTH_PARAM_NON_INTERACTIVE,
+                                               APR_HASH_KEY_STRING) != NULL;
+  svn_boolean_t done;
+  const char *passphrase;
+
+  *credentials = NULL;
+
+  SVN_ERR(get_password_via_agent(&done, &passphrase, realmstring,
+                                 escaped_password_prompt, escaped_realm_prompt,
+                                 non_interactive, pool));
+  if (done && passphrase)
+    {
+      svn_auth_cred_master_passphrase_t *creds;
+      svn_checksum_t *checksum;
+      int passphrase_len = strlen(passphrase);
+
+      SVN_ERR(svn_checksum(&checksum, svn_checksum_sha1,
+                           passphrase, passphrase_len, pool));
+      memset((void *)passphrase, 0, passphrase_len);
+      creds = apr_pcalloc(pool, sizeof(*creds));
+      creds->passphrase = svn_string_ncreate((const char *)checksum->digest,
+                                             svn_checksum_size(checksum),
+                                             pool);
+      *credentials = creds;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+static const svn_auth_provider_t gpg_agent_master_passphrase_provider = {
+  SVN_AUTH_CRED_MASTER_PASSPHRASE,
+  master_passphrase_gpg_agent_first_creds,
+  NULL,
+  NULL,
+};
+
+
+/* Public API */
+void
+svn_auth_get_gpg_agent_master_passphrase_provider(
+  svn_auth_provider_object_t **provider,
+  apr_pool_t *pool)
+{
+  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
+
+  po->vtable = &gpg_agent_master_passphrase_provider;
+  *provider = po;
+}
+
 #endif /* SVN_HAVE_GPG_AGENT */
 #endif /* !WIN32 */