Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F2113410
GnuPG support for ssh (envvars)
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
werner
Jan 25 2021, 10:49 AM
2021-01-25 10:49:24 (UTC+1)
Size
14 KB
Subscribers
None
GnuPG support for ssh (envvars)
View Options
From 3a9a092530396d66d91059efd3737f9dae5051be Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Mon, 25 Jan 2021 10:30:04 +0100
Subject: [PATCH] Allow sending envrionment variables to the agent.
* authfd.c (put_one_env, ssh_send_agent_env): New.
* authfd.h (SSH_AGENTC_EXTENSION): New.
(SSH_AGENT_EXTENSION_FAILURE): New.
* readconf.h (Options): Add fields no_more_agent_env, num_agent_env,
agent_env.
* readconf.c (OpCodes, keywords): Add oAgentEnv and "agentenv".
(free_options): Move macro FREE_ARRAY to outer scope. Free agent_env.
(process_config_line_depth): Parse oAgentEnv.
(initialize_options): Reset AgentEnv stuff.
(dump_client_config): Dump AgentEnv.
* sshconnect.c (maybe_add_key_to_agent): Call ssh_send_agent_env.
* sshconnect2.c (authentication_socket): New.
(pubkey_prepare): Call ssh_send_agent_env via new func.
--
This features comes handy with recent GnuPG versions and avoids the
long standing use of
gpg-connect-agent updatestartuptty /bye
to tell gpg-agent that ssh is now used on the current X-server or tty.
The ssh-agent mechanism is described in
https://tools.ietf.org/html/draft-miller-ssh-agent-04
---
authfd.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++
authfd.h | 3 ++
readconf.c | 71 +++++++++++++++++++++++++++++++++++------
readconf.h | 4 +++
ssh-add.c | 4 +++
ssh-keygen.c | 2 ++
ssh_config | 3 ++
ssh_config.5 | 17 ++++++++++
sshconnect.c | 6 ++++
sshconnect2.c | 25 ++++++++++++++-
10 files changed, 213 insertions(+), 10 deletions(-)
diff --git a/authfd.c b/authfd.c
index 189ebb39..b425f86f 100644
--- a/authfd.c
+++ b/authfd.c
@@ -189,6 +189,94 @@ ssh_close_authentication_socket(int sock)
close(sock);
}
+
+/* Helper for ssh_send_agent_env. */
+static int
+put_one_env (struct sshbuf *msg, const char *name)
+{
+ int r;
+ const char *val;
+
+ val = getenv (name);
+ if ((r = sshbuf_put_cstring(msg, name)) == 0) {
+ if (val)
+ r = sshbuf_put_cstring(msg, val);
+ else
+ r = sshbuf_put_string(msg, "", 1);
+ }
+ return r;
+}
+
+/* Send configured envvars to the agent. Returns an error code. */
+int
+ssh_send_agent_env (int sock, char **env, int num_env)
+{
+ struct sshbuf *msg;
+ int i, r;
+ u_char type;
+ char *p, *ptr;
+ char *namelist = NULL;
+
+ if (num_env < 1)
+ return 0; /* None configured. */
+
+ if ((msg = sshbuf_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+
+ if (num_env == 1 && !strcmp (env[0], "auto")) {
+ /* If only one variable named "auto" is defined, query
+ * the supported variables from the agent. */
+ if ((r = sshbuf_put_u8(msg, SSH_AGENTC_EXTENSION)) != 0 ||
+ (r = sshbuf_put_cstring(msg,"ssh-envnames@gnupg.org"))!= 0)
+ goto out;
+ if ((r = ssh_request_reply(sock, msg, msg)) != 0)
+ goto out;
+ if ((r = sshbuf_get_u8(msg, &type)) != 0)
+ goto out;
+ if (type == SSH_AGENT_EXTENSION_FAILURE)
+ r = SSH_ERR_AGENT_FAILURE;
+ else
+ r = decode_reply(type);
+ if (r)
+ goto out;
+ if ((r = sshbuf_get_cstring(msg, &namelist, NULL)) != 0)
+ goto out;
+ sshbuf_reset (msg);
+ }
+
+ if ((r = sshbuf_put_u8(msg, SSH_AGENTC_EXTENSION)) != 0 ||
+ (r = sshbuf_put_cstring(msg, "ssh-env@gnupg.org")) != 0)
+ goto out;
+
+ if (namelist != NULL) {
+ ptr = namelist;
+ while ((p = strsep (&ptr, ","))) {
+ if ((r = put_one_env (msg, p)))
+ goto out;
+ }
+ }
+ else {
+ for (i = 0; i < num_env; i++) {
+ if ((r = put_one_env (msg, env[i])))
+ goto out;
+ }
+ }
+
+ if ((r = ssh_request_reply(sock, msg, msg)) != 0)
+ goto out;
+ if ((r = sshbuf_get_u8(msg, &type)) != 0)
+ goto out;
+ if (type == SSH_AGENT_EXTENSION_FAILURE)
+ r = SSH_ERR_AGENT_FAILURE;
+ else
+ r = decode_reply(type);
+ out:
+ sshbuf_free(msg);
+ free (namelist);
+ return r;
+
+}
+
/* Lock/unlock agent */
int
ssh_lock_agent(int sock, int lock, const char *password)
diff --git a/authfd.h b/authfd.h
index 4fbf82f8..20cc108b 100644
--- a/authfd.h
+++ b/authfd.h
@@ -27,6 +27,7 @@ int ssh_get_authentication_socket(int *fdp);
int ssh_get_authentication_socket_path(const char *authsocket, int *fdp);
void ssh_close_authentication_socket(int sock);
+int ssh_send_agent_env (int sock, char **env, int num_env);
int ssh_lock_agent(int sock, int lock, const char *password);
int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp);
void ssh_free_identitylist(struct ssh_identitylist *idl);
@@ -75,6 +76,8 @@ int ssh_agent_sign(int sock, const struct sshkey *key,
#define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24
#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25
#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
+#define SSH_AGENTC_EXTENSION 27
+#define SSH_AGENT_EXTENSION_FAILURE 28
#define SSH_AGENT_CONSTRAIN_LIFETIME 1
#define SSH_AGENT_CONSTRAIN_CONFIRM 2
diff --git a/readconf.c b/readconf.c
index c7df93de..50a79e17 100644
--- a/readconf.c
+++ b/readconf.c
@@ -172,7 +172,7 @@ typedef enum {
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
- oSecurityKeyProvider, oKnownHostsCommand,
+ oSecurityKeyProvider, oKnownHostsCommand, oAgentEnv,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@@ -313,11 +313,22 @@ static struct {
{ "proxyjump", oProxyJump },
{ "securitykeyprovider", oSecurityKeyProvider },
{ "knownhostscommand", oKnownHostsCommand },
+ { "agentenv", oAgentEnv },
{ NULL, oBadOption }
};
+/* Free the array A which holds N items and is indexed with a
+ * variable of TYPE. */
+#define FREE_ARRAY(type, n, a) \
+ do { \
+ type _i; \
+ for (_i = 0; _i < (n); _i++) \
+ free((a)[_i]); \
+ } while (0)
+
+
const char *
kex_default_pk_alg(void)
{
@@ -766,6 +777,7 @@ rm_env(Options *options, const char *arg, const char *filename, int linenum)
}
}
+
/*
* Returns the number of the token pointed to by cp or oBadOption.
*/
@@ -2001,6 +2013,49 @@ parse_pubkey_algos:
*charptr = xstrdup(arg);
break;
+ case oAgentEnv:
+ while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
+ if (strchr(arg, '=') != NULL) {
+ error("%s line %d: Invalid environment name.",
+ filename, linenum);
+ return -1;
+ }
+ if (!*activep || options->no_more_agent_env)
+ continue;
+ if ((*arg == '-' || *arg == '#') && arg[1]) {
+ error("%s line %d: Invalid environment name.",
+ filename, linenum);
+ return -1;
+ }
+ if (*arg == '-') {
+ /* Remove all names */
+ if (options->num_agent_env) {
+ FREE_ARRAY(int, options->num_agent_env,
+ options->agent_env);
+ free(options->agent_env);
+ options->agent_env = NULL;
+ options->num_agent_env = 0;
+ }
+ continue;
+ }
+ if (*arg == '#') {
+ options->no_more_agent_env = 1;
+ continue;
+ }
+ if (options->num_agent_env >= INT_MAX) {
+ error("%s line %d: too many agent env.",
+ filename, linenum);
+ return -1;
+ }
+ options->agent_env = xrecallocarray(
+ options->agent_env, options->num_agent_env,
+ options->num_agent_env + 1,
+ sizeof(*options->agent_env));
+ options->agent_env[options->num_agent_env++] =
+ xstrdup(arg);
+ }
+ break;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@@ -2193,6 +2248,9 @@ initialize_options(Options * options)
options->num_send_env = 0;
options->setenv = NULL;
options->num_setenv = 0;
+ options->agent_env = NULL;
+ options->num_agent_env = 0;
+ options->no_more_agent_env = 0;
options->control_path = NULL;
options->control_master = -1;
options->control_persist = -1;
@@ -2496,13 +2554,6 @@ free_options(Options *o)
if (o == NULL)
return;
-#define FREE_ARRAY(type, n, a) \
- do { \
- type _i; \
- for (_i = 0; _i < (n); _i++) \
- free((a)[_i]); \
- } while (0)
-
free(o->forward_agent_sock_path);
free(o->xauth_location);
FREE_ARRAY(u_int, o->num_log_verbose, o->log_verbose);
@@ -2551,6 +2602,8 @@ free_options(Options *o)
free(o->send_env);
FREE_ARRAY(int, o->num_setenv, o->setenv);
free(o->setenv);
+ FREE_ARRAY(int, o->num_agent_env, o->agent_env);
+ free(o->agent_env);
free(o->control_path);
free(o->local_command);
free(o->remote_command);
@@ -2567,7 +2620,6 @@ free_options(Options *o)
free(o->jump_extra);
free(o->ignored_unknown);
explicit_bzero(o, sizeof(*o));
-#undef FREE_ARRAY
}
struct fwdarg {
@@ -3120,6 +3172,7 @@ dump_client_config(Options *o, const char *host)
dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
dump_cfg_strarray(oSetEnv, o->num_setenv, o->setenv);
+ dump_cfg_strarray(oAgentEnv, o->num_agent_env, o->agent_env);
dump_cfg_strarray_oneline(oLogVerbose,
o->num_log_verbose, o->log_verbose);
diff --git a/readconf.h b/readconf.h
index 4ee730b9..e0b5f370 100644
--- a/readconf.h
+++ b/readconf.h
@@ -126,6 +126,10 @@ typedef struct {
char **send_env;
int num_setenv;
char **setenv;
+ int no_more_agent_env;
+ int num_agent_env;
+ char **agent_env;
+
char *control_path;
int control_master;
diff --git a/ssh-add.c b/ssh-add.c
index 7edb9f9a..c6a9b2ce 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -780,6 +780,10 @@ main(int argc, char **argv)
}
log_init(__progname, log_level, log_facility, 1);
+ /* FIXME: Read the AgentEnv option from ssh_config and call
+ * ssh_send_agent_env (int sock, char **env, int num_env)
+ */
+
if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1)
fatal("Invalid combination of actions");
else if (xflag) {
diff --git a/ssh-keygen.c b/ssh-keygen.c
index cfb5f115..331ad7f6 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -2622,6 +2622,8 @@ sig_sign(const char *keypath, const char *sig_namespace, int argc, char **argv)
goto done;
}
+ /* FIXME: Handle AgentEnv */
+
if ((r = ssh_get_authentication_socket(&agent_fd)) != 0)
debug_r(r, "Couldn't get agent socket");
else {
diff --git a/ssh_config b/ssh_config
index 842ea866..05c5539b 100644
--- a/ssh_config
+++ b/ssh_config
@@ -44,3 +44,6 @@
# ProxyCommand ssh -q -W %h:%p gateway.example.com
# RekeyLimit 1G 1h
# UserKnownHostsFile ~/.ssh/known_hosts.d/%k
+
+# For use with GnuPG's ssh-agent implementation use
+# AgentEnv auto
diff --git a/ssh_config.5 b/ssh_config.5
index 96d6f658..fd33e773 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -270,6 +270,23 @@ Valid arguments are
(use IPv4 only), or
.Cm inet6
(use IPv6 only).
+.It Cm AgentEnv
+Specifies what variables from the local
+.Xr environ 7
+should be sent to a running ssh-agent(1).
+The agent may use these environment variables at its own discretion.
+Note that patterns for the variable names are not supported. To empty
+the list of previously set
+.Cm AgentEnv
+variable names the special name
+.Pa -
+may be used. To ignore all further set names use the special name
+.Pa # .
+To ask the agent for a list of names to send use
+.Pa auto
+as the first and only item.
+.Pp
+The default is not to send any environment variables to the agent.
.It Cm BatchMode
If set to
.Cm yes ,
diff --git a/sshconnect.c b/sshconnect.c
index 616ee37e..adce5d80 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1718,6 +1718,12 @@ maybe_add_key_to_agent(const char *authfile, struct sshkey *private,
}
if (sshkey_is_sk(private))
skprovider = options.sk_provider;
+ if ((r = ssh_send_agent_env (auth_sock, options.agent_env,
+ options.num_agent_env)) != 0) {
+ debug("agent does not support AgentEnv: (%d)", r);
+ close(auth_sock);
+ return;
+ }
if ((r = ssh_add_identity_constrained(auth_sock, private,
comment == NULL ? authfile : comment,
options.add_keys_to_agent_lifespan,
diff --git a/sshconnect2.c b/sshconnect2.c
index de89b761..39302829 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1623,6 +1623,29 @@ key_type_allowed_by_config(struct sshkey *key)
}
+/* Helper for pubkey_prepare. */
+static int
+authentication_socket(int *fdp)
+{
+ int r;
+ int sock;
+
+ if ((r = ssh_get_authentication_socket(&sock)) == 0) {
+ if ((r = ssh_send_agent_env (sock, options.agent_env,
+ options.num_agent_env)) != 0) {
+ debug("agent does not support AgentEnv: (%d)", r);
+ close(sock);
+ *fdp = -1;
+ }
+ }
+
+ if (!r) {
+ *fdp = sock;
+ }
+
+ return r;
+}
+
/*
* try keys in the following order:
* 1. certificates listed in the config file
@@ -1694,7 +1717,7 @@ pubkey_prepare(Authctxt *authctxt)
TAILQ_INSERT_TAIL(preferred, id, next);
}
/* list of keys supported by the agent */
- if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) {
+ if ((r = authentication_socket(&agent_fd)) != 0) {
if (r != SSH_ERR_AGENT_NOT_PRESENT)
debug_fr(r, "ssh_get_authentication_socket");
} else if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
--
2.20.1
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1353009
Attached To
E844: Weekly Standup
Event Timeline
Log In to Comment