diff options
author | des <des@FreeBSD.org> | 2017-09-02 14:25:20 +0000 |
---|---|---|
committer | des <des@FreeBSD.org> | 2017-09-02 14:25:20 +0000 |
commit | ce0d6faba2a9fd27ff0fc0942a4e51f5203bb88f (patch) | |
tree | e29bf4f30ea560420ac21b41c62cc53b42547a0b /crypto/openssh/readconf.c | |
parent | fa127d1375fbc969c65e8d8a5f9f2f8efe4e36fc (diff) | |
download | FreeBSD-src-ce0d6faba2a9fd27ff0fc0942a4e51f5203bb88f.zip FreeBSD-src-ce0d6faba2a9fd27ff0fc0942a4e51f5203bb88f.tar.gz |
MFH (r314527,r314576,r314601,r317998): Upgrade OpenSSH to 7.3p1.
Diffstat (limited to 'crypto/openssh/readconf.c')
-rw-r--r-- | crypto/openssh/readconf.c | 265 |
1 files changed, 241 insertions, 24 deletions
diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c index 4755473..170ae74 100644 --- a/crypto/openssh/readconf.c +++ b/crypto/openssh/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.250 2016/02/08 23:40:12 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.259 2016/07/22 03:35:11 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -41,6 +41,11 @@ __RCSID("$FreeBSD$"); #include <stdio.h> #include <string.h> #include <unistd.h> +#ifdef USE_SYSTEM_GLOB +# include <glob.h> +#else +# include "openbsd-compat/glob.h" +#endif #ifdef HAVE_UTIL_H #include <util.h> #endif @@ -128,18 +133,25 @@ __RCSID("$FreeBSD$"); */ +static int read_config_file_depth(const char *filename, struct passwd *pw, + const char *host, const char *original_host, Options *options, + int flags, int *activep, int depth); +static int process_config_line_depth(Options *options, struct passwd *pw, + const char *host, const char *original_host, char *line, + const char *filename, int linenum, int *activep, int flags, int depth); + /* Keyword tokens. */ typedef enum { oBadOption, oVersionAddendum, - oHost, oMatch, + oHost, oMatch, oInclude, oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout, oGatewayPorts, oExitOnForwardFailure, oPasswordAuthentication, oRSAAuthentication, oChallengeResponseAuthentication, oXAuthLocation, oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, - oCertificateFile, oAddKeysToAgent, + oCertificateFile, oAddKeysToAgent, oIdentityAgent, oUser, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, @@ -162,7 +174,7 @@ typedef enum { oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, - oPubkeyAcceptedKeyTypes, + oPubkeyAcceptedKeyTypes, oProxyJump, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -209,6 +221,7 @@ static struct { { "identitiesonly", oIdentitiesOnly }, { "certificatefile", oCertificateFile }, { "addkeystoagent", oAddKeysToAgent }, + { "identityagent", oIdentityAgent }, { "hostname", oHostName }, { "hostkeyalias", oHostKeyAlias }, { "proxycommand", oProxyCommand }, @@ -262,6 +275,7 @@ static struct { { "controlmaster", oControlMaster }, { "controlpersist", oControlPersist }, { "hashknownhosts", oHashKnownHosts }, + { "include", oInclude }, { "tunnel", oTunnel }, { "tunneldevice", oTunnelDevice }, { "localcommand", oLocalCommand }, @@ -285,6 +299,8 @@ static struct { { "hostbasedkeytypes", oHostbasedKeyTypes }, { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, { "ignoreunknown", oIgnoreUnknown }, + { "proxyjump", oProxyJump }, + { "hpndisabled", oDeprecated }, { "hpnbuffersize", oDeprecated }, { "tcprcvbufpoll", oDeprecated }, @@ -305,9 +321,8 @@ void add_local_forward(Options *options, const struct Forward *newfwd) { struct Forward *fwd; -#ifndef NO_IPPORT_RESERVED_CONCEPT extern uid_t original_real_uid; - int ipport_reserved; + int i, ipport_reserved; #ifdef __FreeBSD__ size_t len_ipport_reserved = sizeof(ipport_reserved); @@ -323,7 +338,11 @@ add_local_forward(Options *options, const struct Forward *newfwd) if (newfwd->listen_port < ipport_reserved && original_real_uid != 0 && newfwd->listen_path == NULL) fatal("Privileged ports can only be forwarded by root."); -#endif + /* Don't add duplicates */ + for (i = 0; i < options->num_local_forwards; i++) { + if (forward_equals(newfwd, options->local_forwards + i)) + return; + } options->local_forwards = xreallocarray(options->local_forwards, options->num_local_forwards + 1, sizeof(*options->local_forwards)); @@ -346,7 +365,13 @@ void add_remote_forward(Options *options, const struct Forward *newfwd) { struct Forward *fwd; + int i; + /* Don't add duplicates */ + for (i = 0; i < options->num_remote_forwards; i++) { + if (forward_equals(newfwd, options->remote_forwards + i)) + return; + } options->remote_forwards = xreallocarray(options->remote_forwards, options->num_remote_forwards + 1, sizeof(*options->remote_forwards)); @@ -796,22 +821,32 @@ static const struct multistate multistate_canonicalizehostname[] = { * Processes a single option line as used in the configuration files. This * only sets those values that have not already been set. */ -#define WHITESPACE " \t\r\n" int process_config_line(Options *options, struct passwd *pw, const char *host, const char *original_host, char *line, const char *filename, int linenum, int *activep, int flags) { + return process_config_line_depth(options, pw, host, original_host, + line, filename, linenum, activep, flags, 0); +} + +#define WHITESPACE " \t\r\n" +static int +process_config_line_depth(Options *options, struct passwd *pw, const char *host, + const char *original_host, char *line, const char *filename, + int linenum, int *activep, int flags, int depth) +{ char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; char **cpptr, fwdarg[256]; u_int i, *uintptr, max_entries = 0; - int negated, opcode, *intptr, value, value2, cmdline = 0; + int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0; LogLevel *log_level_ptr; long long val64; size_t len; struct Forward fwd; const struct multistate *multistate_ptr; struct allowed_cname *cname; + glob_t gl; if (activep == NULL) { /* We are processing a command line directive */ cmdline = 1; @@ -1110,6 +1145,9 @@ parse_char_array: case oProxyCommand: charptr = &options->proxy_command; + /* Ignore ProxyCommand if ProxyJump already specified */ + if (options->jump_host != NULL) + charptr = &options->jump_host; /* Skip below */ parse_command: if (s == NULL) fatal("%.200s line %d: Missing argument.", filename, linenum); @@ -1118,6 +1156,18 @@ parse_command: *charptr = xstrdup(s + len); return 0; + case oProxyJump: + if (s == NULL) { + fatal("%.200s line %d: Missing argument.", + filename, linenum); + } + len = strspn(s, WHITESPACE "="); + if (parse_jump(s + len, options, *activep) == -1) { + fatal("%.200s line %d: Invalid ProxyJump \"%s\"", + filename, linenum, s + len); + } + return 0; + case oPort: intptr = &options->port; parse_int: @@ -1271,6 +1321,8 @@ parse_keytypes: *activep = 0; arg2 = NULL; while ((arg = strdelim(&s)) != NULL && *arg != '\0') { + if ((flags & SSHCONF_NEVERMATCH) != 0) + break; negated = *arg == '!'; if (negated) arg++; @@ -1303,7 +1355,7 @@ parse_keytypes: if (value < 0) fatal("%.200s line %d: Bad Match condition", filename, linenum); - *activep = value; + *activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value; break; case oEscapeChar: @@ -1431,6 +1483,63 @@ parse_keytypes: intptr = &options->visual_host_key; goto parse_flag; + case oInclude: + if (cmdline) + fatal("Include directive not supported as a " + "command-line option"); + value = 0; + while ((arg = strdelim(&s)) != NULL && *arg != '\0') { + /* + * Ensure all paths are anchored. User configuration + * files may begin with '~/' but system configurations + * must not. If the path is relative, then treat it + * as living in ~/.ssh for user configurations or + * /etc/ssh for system ones. + */ + if (*arg == '~' && (flags & SSHCONF_USERCONF) == 0) + fatal("%.200s line %d: bad include path %s.", + filename, linenum, arg); + if (*arg != '/' && *arg != '~') { + xasprintf(&arg2, "%s/%s", + (flags & SSHCONF_USERCONF) ? + "~/" _PATH_SSH_USER_DIR : SSHDIR, arg); + } else + arg2 = xstrdup(arg); + memset(&gl, 0, sizeof(gl)); + r = glob(arg2, GLOB_TILDE, NULL, &gl); + if (r == GLOB_NOMATCH) { + debug("%.200s line %d: include %s matched no " + "files",filename, linenum, arg2); + continue; + } else if (r != 0 || gl.gl_pathc < 0) + fatal("%.200s line %d: glob failed for %s.", + filename, linenum, arg2); + free(arg2); + oactive = *activep; + for (i = 0; i < (u_int)gl.gl_pathc; i++) { + debug3("%.200s line %d: Including file %s " + "depth %d%s", filename, linenum, + gl.gl_pathv[i], depth, + oactive ? "" : " (parse only)"); + r = read_config_file_depth(gl.gl_pathv[i], + pw, host, original_host, options, + flags | SSHCONF_CHECKPERM | + (oactive ? 0 : SSHCONF_NEVERMATCH), + activep, depth + 1); + /* + * don't let Match in includes clobber the + * containing file's Match state. + */ + *activep = oactive; + if (r != 1) + value = -1; + } + globfree(&gl); + } + if (value != 0) + return value; + break; + case oIPQoS: arg = strdelim(&s); if ((value = parse_ipqos(arg)) == -1) @@ -1583,6 +1692,10 @@ parse_keytypes: multistate_ptr = multistate_yesnoaskconfirm; goto parse_multistate; + case oIdentityAgent: + charptr = &options->identity_agent; + goto parse_string; + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); @@ -1605,22 +1718,35 @@ parse_keytypes: return 0; } - /* * Reads the config file and modifies the options accordingly. Options * should already be initialized before this call. This never returns if * there is an error. If the file does not exist, this returns 0. */ - int read_config_file(const char *filename, struct passwd *pw, const char *host, const char *original_host, Options *options, int flags) { + int active = 1; + + return read_config_file_depth(filename, pw, host, original_host, + options, flags, &active, 0); +} + +#define READCONF_MAX_DEPTH 16 +static int +read_config_file_depth(const char *filename, struct passwd *pw, + const char *host, const char *original_host, Options *options, + int flags, int *activep, int depth) +{ FILE *f; char line[1024]; - int active, linenum; + int linenum; int bad_options = 0; + if (depth < 0 || depth > READCONF_MAX_DEPTH) + fatal("Too many recursive configuration includes"); + if ((f = fopen(filename, "r")) == NULL) return 0; @@ -1640,13 +1766,12 @@ read_config_file(const char *filename, struct passwd *pw, const char *host, * Mark that we are now processing the options. This flag is turned * on/off by Host specifications. */ - active = 1; linenum = 0; while (fgets(line, sizeof(line), f)) { /* Update line number counter. */ linenum++; - if (process_config_line(options, pw, host, original_host, - line, filename, linenum, &active, flags) != 0) + if (process_config_line_depth(options, pw, host, original_host, + line, filename, linenum, activep, flags, depth) != 0) bad_options++; } fclose(f); @@ -1679,6 +1804,9 @@ initialize_options(Options * options) options->forward_x11 = -1; options->forward_x11_trusted = -1; options->forward_x11_timeout = -1; + options->stdio_forward_host = NULL; + options->stdio_forward_port = 0; + options->clear_forwardings = -1; options->exit_on_forward_failure = -1; options->xauth_location = NULL; options->fwd_opts.gateway_ports = -1; @@ -1717,6 +1845,10 @@ initialize_options(Options * options) options->hostname = NULL; options->host_key_alias = NULL; options->proxy_command = NULL; + options->jump_user = NULL; + options->jump_host = NULL; + options->jump_port = -1; + options->jump_extra = NULL; options->user = NULL; options->escape_char = -1; options->num_system_hostfiles = 0; @@ -1725,7 +1857,6 @@ initialize_options(Options * options) options->num_local_forwards = 0; options->remote_forwards = NULL; options->num_remote_forwards = 0; - options->clear_forwardings = -1; options->log_level = SYSLOG_LEVEL_NOT_SET; options->preferred_authentications = NULL; options->bind_address = NULL; @@ -1750,6 +1881,7 @@ initialize_options(Options * options) options->local_command = NULL; options->permit_local_command = -1; options->add_keys_to_agent = -1; + options->identity_agent = NULL; options->visual_host_key = -1; options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; @@ -1798,8 +1930,19 @@ fill_default_options(Options * options) options->forward_x11_trusted = 0; if (options->forward_x11_timeout == -1) options->forward_x11_timeout = 1200; + /* + * stdio forwarding (-W) changes the default for these but we defer + * setting the values so they can be overridden. + */ if (options->exit_on_forward_failure == -1) - options->exit_on_forward_failure = 0; + options->exit_on_forward_failure = + options->stdio_forward_host != NULL ? 1 : 0; + if (options->clear_forwardings == -1) + options->clear_forwardings = + options->stdio_forward_host != NULL ? 1 : 0; + if (options->clear_forwardings == 1) + clear_forwardings(options); + if (options->xauth_location == NULL) options->xauth_location = _PATH_XAUTH; if (options->fwd_opts.gateway_ports == -1) @@ -1890,8 +2033,6 @@ fill_default_options(Options * options) } if (options->log_level == SYSLOG_LEVEL_NOT_SET) options->log_level = SYSLOG_LEVEL_INFO; - if (options->clear_forwardings == 1) - clear_forwardings(options); if (options->no_host_authentication_for_localhost == - 1) options->no_host_authentication_for_localhost = 0; if (options->identities_only == -1) @@ -1970,6 +2111,7 @@ fill_default_options(Options * options) CLEAR_ON_NONE(options->proxy_command); CLEAR_ON_NONE(options->control_path); CLEAR_ON_NONE(options->revoked_host_keys); + /* options->identity_agent distinguishes NULL from 'none' */ /* options->user will be set in the main program if appropriate */ /* options->hostname will be set in the main program if appropriate */ /* options->host_key_alias should not be set by default */ @@ -2187,6 +2329,54 @@ parse_forward(struct Forward *fwd, const char *fwdspec, int dynamicfwd, int remo return (0); } +int +parse_jump(const char *s, Options *o, int active) +{ + char *orig, *sdup, *cp; + char *host = NULL, *user = NULL; + int ret = -1, port = -1, first; + + active &= o->proxy_command == NULL && o->jump_host == NULL; + + orig = sdup = xstrdup(s); + first = active; + do { + if ((cp = strrchr(sdup, ',')) == NULL) + cp = sdup; /* last */ + else + *cp++ = '\0'; + + if (first) { + /* First argument and configuration is active */ + if (parse_user_host_port(cp, &user, &host, &port) != 0) + goto out; + } else { + /* Subsequent argument or inactive configuration */ + if (parse_user_host_port(cp, NULL, NULL, NULL) != 0) + goto out; + } + first = 0; /* only check syntax for subsequent hosts */ + } while (cp != sdup); + /* success */ + if (active) { + o->jump_user = user; + o->jump_host = host; + o->jump_port = port; + o->proxy_command = xstrdup("none"); + user = host = NULL; + if ((cp = strrchr(s, ',')) != NULL && cp != s) { + o->jump_extra = xstrdup(s); + o->jump_extra[cp - s] = '\0'; + } + } + ret = 0; + out: + free(orig); + free(user); + free(host); + return ret; +} + /* XXX the following is a near-vebatim copy from servconf.c; refactor */ static const char * fmt_multistate_int(int val, const struct multistate *m) @@ -2338,7 +2528,7 @@ void dump_client_config(Options *o, const char *host) { int i; - char vbuf[5]; + char buf[8]; /* This is normally prepared in ssh_kex2 */ if (kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->hostkeyalgorithms) != 0) @@ -2359,6 +2549,7 @@ dump_client_config(Options *o, const char *host) dump_cfg_fmtint(oCompression, o->compression); dump_cfg_fmtint(oControlMaster, o->control_master); dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); + dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings); dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash); dump_cfg_fmtint(oForwardAgent, o->forward_agent); @@ -2407,6 +2598,7 @@ dump_client_config(Options *o, const char *host) dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms); dump_cfg_string(oHostKeyAlias, o->host_key_alias); dump_cfg_string(oHostbasedKeyTypes, o->hostbased_key_types); + dump_cfg_string(oIdentityAgent, o->identity_agent); dump_cfg_string(oKbdInteractiveDevices, o->kbd_interactive_devices); dump_cfg_string(oKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_CLIENT_KEX); dump_cfg_string(oLocalCommand, o->local_command); @@ -2414,7 +2606,6 @@ dump_client_config(Options *o, const char *host) dump_cfg_string(oMacs, o->macs ? o->macs : KEX_CLIENT_MAC); dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); - dump_cfg_string(oProxyCommand, o->proxy_command); dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); dump_cfg_string(oXAuthLocation, o->xauth_location); @@ -2475,8 +2666,8 @@ dump_client_config(Options *o, const char *host) if (o->escape_char == SSH_ESCAPECHAR_NONE) printf("escapechar none\n"); else { - vis(vbuf, o->escape_char, VIS_WHITE, 0); - printf("escapechar %s\n", vbuf); + vis(buf, o->escape_char, VIS_WHITE, 0); + printf("escapechar %s\n", buf); } /* oIPQoS */ @@ -2490,4 +2681,30 @@ dump_client_config(Options *o, const char *host) /* oStreamLocalBindMask */ printf("streamlocalbindmask 0%o\n", o->fwd_opts.streamlocal_bind_mask); + + /* oProxyCommand / oProxyJump */ + if (o->jump_host == NULL) + dump_cfg_string(oProxyCommand, o->proxy_command); + else { + /* Check for numeric addresses */ + i = strchr(o->jump_host, ':') != NULL || + strspn(o->jump_host, "1234567890.") == strlen(o->jump_host); + snprintf(buf, sizeof(buf), "%d", o->jump_port); + printf("proxyjump %s%s%s%s%s%s%s%s%s\n", + /* optional additional jump spec */ + o->jump_extra == NULL ? "" : o->jump_extra, + o->jump_extra == NULL ? "" : ",", + /* optional user */ + o->jump_user == NULL ? "" : o->jump_user, + o->jump_user == NULL ? "" : "@", + /* opening [ if hostname is numeric */ + i ? "[" : "", + /* mandatory hostname */ + o->jump_host, + /* closing ] if hostname is numeric */ + i ? "]" : "", + /* optional port number */ + o->jump_port <= 0 ? "" : ":", + o->jump_port <= 0 ? "" : buf); + } } |