aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2021-01-25 10:35:06 +0100
committerWerner Koch <wk@gnupg.org>2021-01-25 10:35:06 +0100
commit224e26cf7b67f22bb0140133eac6b4ad24f3b1b7 (patch)
tree8ffb4f94ef64331109af30f6984237be37da61e4
parent60499d98940d4b7a1673b8584cafe0f7ac2901dd (diff)
downloadgnupg-224e26cf7b67f22bb0140133eac6b4ad24f3b1b7.tar.gz
agent: Support ssh-agent extensions for environment variables.
* common/session-env.c (session_env_list_stdenvnames): Extend to allow return all names as one string. * agent/command-ssh.c (SSH_REQUEST_EXTENSION): New. (SSH_RESPONSE_EXTENSION_FAILURE): New. (request_specs): Add handler for the extension command. (ssh_handler_extension): New. -- The extension mechanism is specified in https://tools.ietf.org/html/draft-miller-ssh-agent-04 Signed-off-by: Werner Koch <wk@gnupg.org>
-rw-r--r--agent/command-ssh.c86
-rw-r--r--common/session-env.c38
2 files changed, 120 insertions, 4 deletions
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index ee9270491..393ee91e9 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -70,6 +70,7 @@
#define SSH_REQUEST_LOCK 22
#define SSH_REQUEST_UNLOCK 23
#define SSH_REQUEST_ADD_ID_CONSTRAINED 25
+#define SSH_REQUEST_EXTENSION 27
/* Options. */
#define SSH_OPT_CONSTRAIN_LIFETIME 1
@@ -80,6 +81,7 @@
#define SSH_RESPONSE_FAILURE 5
#define SSH_RESPONSE_IDENTITIES_ANSWER 12
#define SSH_RESPONSE_SIGN_RESPONSE 14
+#define SSH_RESPONSE_EXTENSION_FAILURE 28
/* Other constants. */
#define SSH_DSA_SIGNATURE_PADDING 20
@@ -249,6 +251,9 @@ static gpg_error_t ssh_handler_lock (ctrl_t ctrl,
static gpg_error_t ssh_handler_unlock (ctrl_t ctrl,
estream_t request,
estream_t response);
+static gpg_error_t ssh_handler_extension (ctrl_t ctrl,
+ estream_t request,
+ estream_t response);
static gpg_error_t ssh_key_modifier_rsa (const char *elems, gcry_mpi_t *mpis);
static gpg_error_t ssh_signature_encoder_rsa (ssh_key_type_spec_t *spec,
@@ -290,7 +295,8 @@ static const ssh_request_spec_t request_specs[] =
REQUEST_SPEC_DEFINE (REMOVE_IDENTITY, remove_identity, 0),
REQUEST_SPEC_DEFINE (REMOVE_ALL_IDENTITIES, remove_all_identities, 0),
REQUEST_SPEC_DEFINE (LOCK, lock, 0),
- REQUEST_SPEC_DEFINE (UNLOCK, unlock, 0)
+ REQUEST_SPEC_DEFINE (UNLOCK, unlock, 0),
+ REQUEST_SPEC_DEFINE (EXTENSION, extension, 0)
#undef REQUEST_SPEC_DEFINE
};
@@ -3304,6 +3310,84 @@ ssh_handler_unlock (ctrl_t ctrl, estream_t request, estream_t response)
return ret_err;
}
+/* Handler for the "extension" command. */
+static gpg_error_t
+ssh_handler_extension (ctrl_t ctrl, estream_t request, estream_t response)
+{
+ gpg_error_t ret_err;
+ gpg_error_t err;
+ char *exttype = NULL;
+ char *name = NULL;
+ char *value = NULL;
+
+ err = stream_read_cstring (request, &exttype);
+ if (err)
+ goto leave;
+
+ if (opt.verbose)
+ log_info ("ssh-agent extension '%s' received\n", exttype);
+ if (!strcmp (exttype, "ssh-env@gnupg.org"))
+ {
+ for (;;)
+ {
+ xfree (name); name = NULL;
+ err = stream_read_cstring (request, &name);
+ if (gpg_err_code (err) == GPG_ERR_EOF)
+ break; /* ready. */
+ if (err)
+ {
+ if (opt.verbose)
+ log_error ("error reading ssh-agent env name\n");
+ goto leave;
+ }
+ xfree (value); value = NULL;
+ err = stream_read_cstring (request, &value);
+ if (err)
+ {
+ if (opt.verbose)
+ log_error ("error reading ssh-agent env value\n");
+ goto leave;
+ }
+ if (opt.debug)
+ log_debug ("ssh-agent env '%s'='%s'\n", name, value);
+ err = session_env_setenv (ctrl->session_env, name,
+ *value? value : NULL);
+ if (err)
+ {
+ log_error ("error setting ssh-agent env value: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+ }
+ err = 0;
+ }
+ else if (!strcmp (exttype, "ssh-envnames@gnupg.org"))
+ {
+ ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
+ if (!ret_err)
+ ret_err = stream_write_cstring
+ (response, session_env_list_stdenvnames (NULL, NULL));
+ goto finalleave;
+ }
+ else
+ {
+ if (opt.verbose)
+ log_info ("ssh-agent extension '%s' not supported\n", exttype);
+ err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+ }
+
+ leave:
+ if (!err)
+ ret_err = stream_write_byte (response, SSH_RESPONSE_SUCCESS);
+ else
+ ret_err = stream_write_byte (response, SSH_RESPONSE_FAILURE);
+ finalleave:
+ xfree (exttype);
+ xfree (name);
+ xfree (value);
+ return ret_err;
+}
+
/* Return the request specification for the request identified by TYPE
diff --git a/common/session-env.c b/common/session-env.c
index 1df2c4431..5d6b66dd6 100644
--- a/common/session-env.c
+++ b/common/session-env.c
@@ -98,13 +98,45 @@ static size_t lastallocatedarraysize;
/* Return the names of standard environment variables one after the
other. The caller needs to set the value at the address of
- ITERATOR initially to 0 and then call this function until it returns
- NULL. */
+ ITERATOR initially to 0 and then call this function until it
+ returns NULL. If ITERATOR is NULL, a single comma delimited string
+ with the names is returned; NULL is never returned in this case and
+ R_ASSNAME is ignored. */
const char *
session_env_list_stdenvnames (int *iterator, const char **r_assname)
{
- int idx = *iterator;
+ int idx;
+ static char *commastring;
+
+ if (!iterator)
+ {
+ if (!commastring)
+ {
+ size_t len = 0;
+ char *p;
+
+ for (idx = 0; idx < DIM (stdenvnames); idx++)
+ len += strlen (stdenvnames[idx].name) + 1;
+ commastring = xtrymalloc (len);
+ if (!commastring)
+ {
+ log_error ("%s: error allocating string: %s\n", __func__,
+ gpg_strerror (gpg_error_from_syserror ()));
+ return "GPG_TTY,TERM,DISPLAY";
+ }
+ p = commastring;
+ for (idx = 0; idx < DIM (stdenvnames); idx++)
+ {
+ if (idx)
+ *p++ = ',';
+ p = stpcpy (p, stdenvnames[idx].name);
+ }
+ gpgrt_annotate_leaked_object (commastring);
+ }
+ return commastring;
+ }
+ idx = *iterator;
if (idx < 0 || idx >= DIM (stdenvnames))
return NULL;
*iterator = idx + 1;