Re: Sending envvars via ssh agent protocol

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



On 2021-01-29 at 00:06 +0100, Ángel wrote:
> (lots of notes about indentation on previos patch)
> 

I attach a revised version of the patch addressing the indentation
issues. It has only spacing changes from Werner's original patch.

Best regards


>From 3a9a092530396d66d91059efd3737f9dae5051be Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@xxxxxxxxx>
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@xxxxxxxxx"))!= 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@xxxxxxxxx")) != 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

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux