From ed833da176611a39d3376d62154eb88eb440d31c Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 3 Apr 2020 02:27:12 +0000 Subject: upstream: Make with config keywords support which percent_expansions more consistent. - %C is moved into its own function and added to Match Exec. - move the common (global) options into a macro. This is ugly but it's the least-ugly way I could come up with. - move IdentityAgent and ForwardAgent percent expansion to before the config dump to make it regression-testable. - document all of the above ok jmc@ for man page bits, "makes things less terrible" djm@ for the rest. OpenBSD-Commit-ID: 4b65664bd6d8ae2a9afaf1a2438ddd1b614b1d75 --- readconf.c | 26 ++++++++++++- readconf.h | 4 +- ssh.c | 120 ++++++++++++++++++++++++++--------------------------------- ssh_config.5 | 30 ++++++--------- 4 files changed, 92 insertions(+), 88 deletions(-) diff --git a/readconf.c b/readconf.c index f3cac6b3..1a3b2db2 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.326 2020/02/06 22:46:31 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.327 2020/04/03 02:27:12 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -324,6 +324,24 @@ kex_default_pk_alg(void) return kex_default_pk_alg_filtered; } +char * +ssh_connection_hash(const char *thishost, const char *host, const char *portstr, + const char *user) +{ + struct ssh_digest_ctx *md; + u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; + + if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || + ssh_digest_update(md, thishost, strlen(thishost)) < 0 || + ssh_digest_update(md, host, strlen(host)) < 0 || + ssh_digest_update(md, portstr, strlen(portstr)) < 0 || + ssh_digest_update(md, user, strlen(user)) < 0 || + ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0) + fatal("%s: mux digest failed", __func__); + ssh_digest_free(md); + return tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); +} + /* * Adds a local TCP/IP port forward to options. Never returns if there is an * error. @@ -646,6 +664,8 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw, if (r == (negate ? 1 : 0)) this_result = result = 0; } else if (strcasecmp(attrib, "exec") == 0) { + char *conn_hash_hex; + if (gethostname(thishost, sizeof(thishost)) == -1) fatal("gethostname: %s", strerror(errno)); strlcpy(shorthost, thishost, sizeof(shorthost)); @@ -653,8 +673,11 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw, snprintf(portstr, sizeof(portstr), "%d", port); snprintf(uidstr, sizeof(uidstr), "%llu", (unsigned long long)pw->pw_uid); + conn_hash_hex = ssh_connection_hash(thishost, host, + portstr, pw->pw_name); cmd = percent_expand(arg, + "C", conn_hash_hex, "L", shorthost, "d", pw->pw_dir, "h", host, @@ -665,6 +688,7 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw, "u", pw->pw_name, "i", uidstr, (char *)NULL); + free(conn_hash_hex); if (result != 1) { /* skip execution if prior predicate failed */ debug3("%.200s line %d: skipped exec " diff --git a/readconf.h b/readconf.h index feedb3d2..e143a108 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.132 2020/01/23 02:46:49 dtucker Exp $ */ +/* $OpenBSD: readconf.h,v 1.133 2020/04/03 02:27:12 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -200,6 +200,8 @@ typedef struct { #define SSH_STRICT_HOSTKEY_ASK 3 const char *kex_default_pk_alg(void); +char *ssh_connection_hash(const char *thishost, const char *host, + const char *portstr, const char *user); void initialize_options(Options *); void fill_default_options(Options *); void fill_default_options_for_canonicalization(Options *); diff --git a/ssh.c b/ssh.c index 9713b61e..470d9b7e 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.521 2020/03/06 18:20:02 markus Exp $ */ +/* $OpenBSD: ssh.c,v 1.522 2020/04/03 02:27:12 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -86,7 +86,6 @@ #include "canohost.h" #include "compat.h" #include "cipher.h" -#include "digest.h" #include "packet.h" #include "sshbuf.h" #include "channels.h" @@ -177,6 +176,13 @@ char *forward_agent_sock_path = NULL; /* Various strings used to to percent_expand() arguments */ static char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; static char uidstr[32], *host_arg, *conn_hash_hex; +#define DEFAULT_CLIENT_PERCENT_EXPAND_ARGS \ + "C", conn_hash_hex, \ + "L", shorthost, \ + "i", uidstr, \ + "l", thishost, \ + "n", host_arg, \ + "p", portstr /* socket address the host resolves to */ struct sockaddr_storage hostaddr; @@ -601,8 +607,6 @@ main(int ac, char **av) extern char *optarg; struct Forward fwd; struct addrinfo *addrs = NULL; - struct ssh_digest_ctx *md; - u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; size_t n, len; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ @@ -1330,15 +1334,8 @@ main(int ac, char **av) snprintf(uidstr, sizeof(uidstr), "%llu", (unsigned long long)pw->pw_uid); - if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL || - ssh_digest_update(md, thishost, strlen(thishost)) < 0 || - ssh_digest_update(md, host, strlen(host)) < 0 || - ssh_digest_update(md, portstr, strlen(portstr)) < 0 || - ssh_digest_update(md, options.user, strlen(options.user)) < 0 || - ssh_digest_final(md, conn_hash, sizeof(conn_hash)) < 0) - fatal("%s: mux digest failed", __func__); - ssh_digest_free(md); - conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); + conn_hash_hex = ssh_connection_hash(thishost, host, portstr, + options.user); /* * Expand tokens in arguments. NB. LocalCommand is expanded later, @@ -1349,14 +1346,9 @@ main(int ac, char **av) debug3("expanding RemoteCommand: %s", options.remote_command); cp = options.remote_command; options.remote_command = percent_expand(cp, - "C", conn_hash_hex, - "L", shorthost, + DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, "d", pw->pw_dir, "h", host, - "i", uidstr, - "l", thishost, - "n", host_arg, - "p", portstr, "r", options.user, "u", pw->pw_name, (char *)NULL); @@ -1371,20 +1363,44 @@ main(int ac, char **av) cp = tilde_expand_filename(options.control_path, getuid()); free(options.control_path); options.control_path = percent_expand(cp, - "C", conn_hash_hex, - "L", shorthost, + DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, + "d", pw->pw_dir, "h", host, - "i", uidstr, - "l", thishost, - "n", host_arg, - "p", portstr, "r", options.user, "u", pw->pw_name, - "i", uidstr, (char *)NULL); free(cp); } + if (options.identity_agent != NULL) { + p = tilde_expand_filename(options.identity_agent, getuid()); + cp = percent_expand(p, + DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, + "d", pw->pw_dir, + "h", host, + "r", options.user, + "u", pw->pw_name, + (char *)NULL); + free(p); + free(options.identity_agent); + options.identity_agent = cp; + } + + if (options.forward_agent_sock_path != NULL) { + p = tilde_expand_filename(options.forward_agent_sock_path, + getuid()); + cp = percent_expand(p, + DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, + "d", pw->pw_dir, + "h", host, + "r", options.user, + "u", pw->pw_name, + (char *)NULL); + free(p); + free(options.forward_agent_sock_path); + options.forward_agent_sock_path = cp; + } + if (config_test) { dump_client_config(&options, host); exit(0); @@ -1509,23 +1525,7 @@ main(int ac, char **av) if (strcmp(options.identity_agent, "none") == 0) { unsetenv(SSH_AUTHSOCKET_ENV_NAME); } else { - p = tilde_expand_filename(options.identity_agent, - getuid()); - cp = percent_expand(p, - "d", pw->pw_dir, - "h", host, - "i", uidstr, - "l", thishost, - "r", options.user, - "u", pw->pw_name, - (char *)NULL); - free(p); - /* - * If identity_agent represents an environment variable - * then recheck that it is valid (since processing with - * percent_expand() may have changed it) and substitute - * its value. - */ + cp = options.identity_agent; if (cp[0] == '$') { if (!valid_env_name(cp + 1)) { fatal("Invalid IdentityAgent " @@ -1539,22 +1539,10 @@ main(int ac, char **av) /* identity_agent specifies a path directly */ setenv(SSH_AUTHSOCKET_ENV_NAME, cp, 1); } - free(cp); } } - if (options.forward_agent && (options.forward_agent_sock_path != NULL)) { - p = tilde_expand_filename(options.forward_agent_sock_path, getuid()); - cp = percent_expand(p, - "d", pw->pw_dir, - "h", host, - "i", uidstr, - "l", thishost, - "r", options.user, - "u", pw->pw_name, - (char *)NULL); - free(p); - + if (options.forward_agent && options.forward_agent_sock_path != NULL) { if (cp[0] == '$') { if (!valid_env_name(cp + 1)) { fatal("Invalid ForwardAgent environment variable name %s", cp); @@ -1979,14 +1967,9 @@ ssh_session2(struct ssh *ssh, struct passwd *pw) debug3("expanding LocalCommand: %s", options.local_command); cp = options.local_command; options.local_command = percent_expand(cp, - "C", conn_hash_hex, - "L", shorthost, + DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, "d", pw->pw_dir, "h", host, - "i", uidstr, - "l", thishost, - "n", host_arg, - "p", portstr, "r", options.user, "u", pw->pw_name, "T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname, @@ -2143,9 +2126,13 @@ load_public_identity_files(struct passwd *pw) continue; } cp = tilde_expand_filename(options.identity_files[i], getuid()); - filename = percent_expand(cp, "d", pw->pw_dir, - "u", pw->pw_name, "l", thishost, "h", host, - "r", options.user, (char *)NULL); + filename = percent_expand(cp, + DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, + "d", pw->pw_dir, + "h", host, + "r", options.user, + "u", pw->pw_name, + (char *)NULL); free(cp); check_load(sshkey_load_public(filename, &public, NULL), filename, "pubkey"); @@ -2195,10 +2182,9 @@ load_public_identity_files(struct passwd *pw) cp = tilde_expand_filename(options.certificate_files[i], getuid()); filename = percent_expand(cp, + DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, "d", pw->pw_dir, "h", host, - "i", uidstr, - "l", thishost, "r", options.user, "u", pw->pw_name, (char *)NULL); diff --git a/ssh_config.5 b/ssh_config.5 index 06a32d31..9d89c13a 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.322 2020/02/07 03:54:44 dtucker Exp $ -.Dd $Mdocdate: February 7 2020 $ +.\" $OpenBSD: ssh_config.5,v 1.323 2020/04/03 02:27:12 dtucker Exp $ +.Dd $Mdocdate: April 3 2020 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -1845,31 +1845,23 @@ otherwise. The local username. .El .Pp -.Cm Match exec -accepts the tokens %%, %h, %i, %L, %l, %n, %p, %r, and %u. -.Pp -.Cm CertificateFile -accepts the tokens %%, %d, %h, %i, %l, %r, and %u. -.Pp -.Cm ControlPath -accepts the tokens %%, %C, %h, %i, %L, %l, %n, %p, %r, and %u. +.Cm Match exec , +.Cm CertificateFile , +.Cm ControlPath , +.Cm IdentityAgent , +.Cm IdentityFile , +and +.Cm RemoteCommand +accept the tokens %%, %C, %d, %h, %i, %L, %l, %n, %p, %r, and %u. .Pp .Cm Hostname accepts the tokens %% and %h. .Pp -.Cm IdentityAgent -and -.Cm IdentityFile -accept the tokens %%, %d, %h, %i, %l, %r, and %u. -.Pp .Cm LocalCommand -accepts the tokens %%, %C, %d, %h, %i, %l, %n, %p, %r, %T, and %u. +accepts all tokens. .Pp .Cm ProxyCommand accepts the tokens %%, %h, %n, %p, and %r. -.Pp -.Cm RemoteCommand -accepts the tokens %%, %C, %d, %h, %i, %l, %n, %p, %r, and %u. .Sh FILES .Bl -tag -width Ds .It Pa ~/.ssh/config -- cgit v1.2.3