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