aboutsummaryrefslogtreecommitdiffstats
path: root/agent/command-ssh.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2014-03-07 08:46:44 +0000
committerWerner Koch <[email protected]>2014-03-07 08:48:10 +0000
commit5105c8d2d344fd7301d456d8c13c7e90a54f7e98 (patch)
treebf8c125202e32087ee5dacefb32fa09babdb1c46 /agent/command-ssh.c
parentagent: Fix binary vs. text mode problem in ssh. (diff)
downloadgnupg-5105c8d2d344fd7301d456d8c13c7e90a54f7e98.tar.gz
gnupg-5105c8d2d344fd7301d456d8c13c7e90a54f7e98.zip
ssh: Add support for Putty.
* agent/gpg-agent.c [W32]: Include Several Windows header. (opts): Change help text for enable-ssh-support. (opts, main): Add option --enable-putty-support (putty_support, PUTTY_IPC_MAGIC, PUTTY_IPC_MAXLEN): New for W32. (agent_init_default_ctrl): Add and asssert call. (putty_message_proc, putty_message_thread): New. (handle_connections) [W32]: Start putty message thread. * common/sysutils.c (w32_get_user_sid): New for W32 only * tools/gpgconf-comp.c (gc_options_gpg_agent): Add --enable-ssh-support and --enable-putty-support. Make the configuration group visible at basic level. * agent/command-ssh.c (serve_mmapped_ssh_request): New for W32 only. -- This patch enables support for Putty. It has been tested with Putty 0.62 using an Unix created ssh key copied to the private-keys-v1.d directory on Windows and with a manually crafted sshcontrol file. It also works with a smartcard key. May thanks to gniibe who implemented a proxy in Python to test the putty/gpg-agent communication. Signed-off-by: Werner Koch <[email protected]> (cherry picked from commit 9f32499f99a0817f63f7a73b09bdcebe60d4775d) Resolved conflicts: NEWS agent/agent.h agent/gpg-agent.c: Convert from pth to npth. common/sysutils.c common/sysutils.h
Diffstat (limited to '')
-rw-r--r--agent/command-ssh.c146
1 files changed, 146 insertions, 0 deletions
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 46aa94c5e..4bd1aa7a7 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -3443,3 +3443,149 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
if (stream_sock)
es_fclose (stream_sock);
}
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Serve one ssh-agent request. This is used for the Putty support.
+ REQUEST is the the mmapped memory which may be accessed up to a
+ length of MAXREQLEN. Returns 0 on success which also indicates
+ that a valid SSH response message is now in REQUEST. */
+int
+serve_mmapped_ssh_request (ctrl_t ctrl,
+ unsigned char *request, size_t maxreqlen)
+{
+ gpg_error_t err;
+ int send_err = 0;
+ int valid_response = 0;
+ ssh_request_spec_t *spec;
+ u32 msglen;
+ estream_t request_stream, response_stream;
+
+ if (setup_ssh_env (ctrl))
+ goto leave; /* Error setting up the environment. */
+
+ if (maxreqlen < 5)
+ goto leave; /* Caller error. */
+
+ msglen = uint32_construct (request[0], request[1], request[2], request[3]);
+ if (msglen < 1 || msglen > maxreqlen - 4)
+ {
+ log_error ("ssh message len (%u) out of range", (unsigned int)msglen);
+ goto leave;
+ }
+
+ spec = request_spec_lookup (request[4]);
+ if (!spec)
+ {
+ send_err = 1; /* Unknown request type. */
+ goto leave;
+ }
+
+ /* Create a stream object with the data part of the request. */
+ if (spec->secret_input)
+ request_stream = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+");
+ else
+ request_stream = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+");
+ if (!request_stream)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ /* We have to disable the estream buffering, because the estream
+ core doesn't know about secure memory. */
+ if (es_setvbuf (request_stream, NULL, _IONBF, 0))
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ /* Copy the request to the stream but omit the request type. */
+ err = stream_write_data (request_stream, request + 5, msglen - 1);
+ if (err)
+ goto leave;
+ es_rewind (request_stream);
+
+ response_stream = es_fopenmem (0, "r+b");
+ if (!response_stream)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ if (opt.verbose)
+ log_info ("ssh request handler for %s (%u) started\n",
+ spec->identifier, spec->type);
+
+ err = (*spec->handler) (ctrl, request_stream, response_stream);
+
+ if (opt.verbose)
+ {
+ if (err)
+ log_info ("ssh request handler for %s (%u) failed: %s\n",
+ spec->identifier, spec->type, gpg_strerror (err));
+ else
+ log_info ("ssh request handler for %s (%u) ready\n",
+ spec->identifier, spec->type);
+ }
+
+ es_fclose (request_stream);
+ request_stream = NULL;
+
+ if (err)
+ {
+ send_err = 1;
+ goto leave;
+ }
+
+ /* Put the response back into the mmapped buffer. */
+ {
+ void *response_data;
+ size_t response_size;
+
+ /* NB: In contrast to the request-stream, the response stream
+ includes the the message type byte. */
+ if (es_fclose_snatch (response_stream, &response_data, &response_size))
+ {
+ log_error ("snatching ssh response failed: %s",
+ gpg_strerror (gpg_error_from_syserror ()));
+ send_err = 1; /* Ooops. */
+ goto leave;
+ }
+
+ if (opt.verbose > 1)
+ log_info ("sending ssh response of length %u\n",
+ (unsigned int)response_size);
+ if (response_size > maxreqlen - 4)
+ {
+ log_error ("invalid length of the ssh response: %s",
+ gpg_strerror (GPG_ERR_INTERNAL));
+ es_free (response_data);
+ send_err = 1;
+ goto leave;
+ }
+
+ request[0] = response_size >> 24;
+ request[1] = response_size >> 16;
+ request[2] = response_size >> 8;
+ request[3] = response_size >> 0;
+ memcpy (request+4, response_data, response_size);
+ es_free (response_data);
+ valid_response = 1;
+ }
+
+ leave:
+ if (send_err)
+ {
+ request[0] = 0;
+ request[1] = 0;
+ request[2] = 0;
+ request[3] = 1;
+ request[4] = SSH_RESPONSE_FAILURE;
+ valid_response = 1;
+ }
+
+ /* Reset the SCD in case it has been used. */
+ agent_reset_scd (ctrl);
+
+ return valid_response? 0 : -1;
+}
+#endif /*HAVE_W32_SYSTEM*/