Backport Match final so the crypto-policies do not break canonicalization (#1630166)
This commit is contained in:
		
							parent
							
								
									a4c0a26cd4
								
							
						
					
					
						commit
						d6cc5f4740
					
				
							
								
								
									
										306
									
								
								openssh-7.9p1-match-final.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								openssh-7.9p1-match-final.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,306 @@ | |||||||
|  | commit 9e34e0c59ab04514f9de9934a772283f7f372afe | ||||||
|  | Author: djm@openbsd.org <djm@openbsd.org> | ||||||
|  | Date:   Fri Nov 23 05:08:07 2018 +0000 | ||||||
|  | 
 | ||||||
|  |     upstream: add a ssh_config "Match final" predicate | ||||||
|  |      | ||||||
|  |     Matches in same pass as "Match canonical" but doesn't require | ||||||
|  |     hostname canonicalisation be enabled. bz#2906 ok markus | ||||||
|  |      | ||||||
|  |     OpenBSD-Commit-ID: fba1dfe9f6e0cabcd0e2b3be13f7a434199beffa | ||||||
|  | 
 | ||||||
|  | diff --git a/readconf.c b/readconf.c
 | ||||||
|  | index 7850f2f5..7331ef5a 100644
 | ||||||
|  | --- a/readconf.c
 | ||||||
|  | +++ b/readconf.c
 | ||||||
|  | @@ -133,10 +133,11 @@
 | ||||||
|  |   | ||||||
|  |  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);
 | ||||||
|  | +    int flags, int *activep, int *want_final_pass, 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);
 | ||||||
|  | +    const char *filename, int linenum, int *activep, int flags,
 | ||||||
|  | +    int *want_final_pass, int depth);
 | ||||||
|  |   | ||||||
|  |  /* Keyword tokens. */ | ||||||
|  |   | ||||||
|  | @@ -539,8 +540,8 @@ execute_in_shell(const char *cmd)
 | ||||||
|  |   */ | ||||||
|  |  static int | ||||||
|  |  match_cfg_line(Options *options, char **condition, struct passwd *pw, | ||||||
|  | -    const char *host_arg, const char *original_host, int post_canon,
 | ||||||
|  | -    const char *filename, int linenum)
 | ||||||
|  | +    const char *host_arg, const char *original_host, int final_pass,
 | ||||||
|  | +    int *want_final_pass, const char *filename, int linenum)
 | ||||||
|  |  { | ||||||
|  |  	char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria; | ||||||
|  |  	const char *ruser; | ||||||
|  | @@ -554,7 +555,7 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
 | ||||||
|  |  	 */ | ||||||
|  |  	port = options->port <= 0 ? default_ssh_port() : options->port; | ||||||
|  |  	ruser = options->user == NULL ? pw->pw_name : options->user; | ||||||
|  | -	if (post_canon) {
 | ||||||
|  | +	if (final_pass) {
 | ||||||
|  |  		host = xstrdup(options->hostname); | ||||||
|  |  	} else if (options->hostname != NULL) { | ||||||
|  |  		/* NB. Please keep in sync with ssh.c:main() */ | ||||||
|  | @@ -586,8 +587,16 @@ match_cfg_line(Options *options, char **condition, struct passwd *pw,
 | ||||||
|  |  			goto out; | ||||||
|  |  		} | ||||||
|  |  		attributes++; | ||||||
|  | -		if (strcasecmp(attrib, "canonical") == 0) {
 | ||||||
|  | -			r = !!post_canon;  /* force bitmask member to boolean */
 | ||||||
|  | +		if (strcasecmp(attrib, "canonical") == 0 ||
 | ||||||
|  | +		    strcasecmp(attrib, "final") == 0) {
 | ||||||
|  | +			/*
 | ||||||
|  | +			 * If the config requests "Match final" then remember
 | ||||||
|  | +			 * this so we can perform a second pass later.
 | ||||||
|  | +			 */
 | ||||||
|  | +			if (strcasecmp(attrib, "final") == 0 &&
 | ||||||
|  | +			    want_final_pass != NULL)
 | ||||||
|  | +				*want_final_pass = 1;
 | ||||||
|  | +			r = !!final_pass;  /* force bitmask member to boolean */
 | ||||||
|  |  			if (r == (negate ? 1 : 0)) | ||||||
|  |  				this_result = result = 0; | ||||||
|  |  			debug3("%.200s line %d: %smatched '%s'", | ||||||
|  | @@ -824,14 +833,14 @@ process_config_line(Options *options, struct passwd *pw, const char *host,
 | ||||||
|  |      int linenum, int *activep, int flags) | ||||||
|  |  { | ||||||
|  |  	return process_config_line_depth(options, pw, host, original_host, | ||||||
|  | -	    line, filename, linenum, activep, flags, 0);
 | ||||||
|  | +	    line, filename, linenum, activep, flags, NULL, 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)
 | ||||||
|  | +    int linenum, int *activep, int flags, int *want_final_pass, int depth)
 | ||||||
|  |  { | ||||||
|  |  	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2; | ||||||
|  |  	char **cpptr, fwdarg[256]; | ||||||
|  | @@ -1339,7 +1348,8 @@ parse_keytypes:
 | ||||||
|  |  			fatal("Host directive not supported as a command-line " | ||||||
|  |  			    "option"); | ||||||
|  |  		value = match_cfg_line(options, &s, pw, host, original_host, | ||||||
|  | -		    flags & SSHCONF_POSTCANON, filename, linenum);
 | ||||||
|  | +		    flags & SSHCONF_FINAL, want_final_pass,
 | ||||||
|  | +		    filename, linenum);
 | ||||||
|  |  		if (value < 0) | ||||||
|  |  			fatal("%.200s line %d: Bad Match condition", filename, | ||||||
|  |  			    linenum); | ||||||
|  | @@ -1548,7 +1558,7 @@ parse_keytypes:
 | ||||||
|  |  				    pw, host, original_host, options, | ||||||
|  |  				    flags | SSHCONF_CHECKPERM | | ||||||
|  |  				    (oactive ? 0 : SSHCONF_NEVERMATCH), | ||||||
|  | -				    activep, depth + 1);
 | ||||||
|  | +				    activep, want_final_pass, depth + 1);
 | ||||||
|  |  				if (r != 1 && errno != ENOENT) { | ||||||
|  |  					fatal("Can't open user config file " | ||||||
|  |  					    "%.100s: %.100s", gl.gl_pathv[i], | ||||||
|  | @@ -1751,19 +1761,20 @@ parse_keytypes:
 | ||||||
|  |   */ | ||||||
|  |  int | ||||||
|  |  read_config_file(const char *filename, struct passwd *pw, const char *host, | ||||||
|  | -    const char *original_host, Options *options, int flags)
 | ||||||
|  | +    const char *original_host, Options *options, int flags,
 | ||||||
|  | +    int *want_final_pass)
 | ||||||
|  |  { | ||||||
|  |  	int active = 1; | ||||||
|  |   | ||||||
|  |  	return read_config_file_depth(filename, pw, host, original_host, | ||||||
|  | -	    options, flags, &active, 0);
 | ||||||
|  | +	    options, flags, &active, want_final_pass, 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)
 | ||||||
|  | +    int flags, int *activep, int *want_final_pass, int depth)
 | ||||||
|  |  { | ||||||
|  |  	FILE *f; | ||||||
|  |  	char *line = NULL; | ||||||
|  | @@ -1798,7 +1809,8 @@ read_config_file_depth(const char *filename, struct passwd *pw,
 | ||||||
|  |  		/* Update line number counter. */ | ||||||
|  |  		linenum++; | ||||||
|  |  		if (process_config_line_depth(options, pw, host, original_host, | ||||||
|  | -		    line, filename, linenum, activep, flags, depth) != 0)
 | ||||||
|  | +		    line, filename, linenum, activep, flags, want_final_pass,
 | ||||||
|  | +		    depth) != 0)
 | ||||||
|  |  			bad_options++; | ||||||
|  |  	} | ||||||
|  |  	free(line); | ||||||
|  | diff --git a/readconf.h b/readconf.h
 | ||||||
|  | index fc7e3825..8e36bf32 100644
 | ||||||
|  | --- a/readconf.h
 | ||||||
|  | +++ b/readconf.h
 | ||||||
|  | @@ -185,7 +185,7 @@ typedef struct {
 | ||||||
|  |   | ||||||
|  |  #define SSHCONF_CHECKPERM	1  /* check permissions on config file */ | ||||||
|  |  #define SSHCONF_USERCONF	2  /* user provided config file not system */ | ||||||
|  | -#define SSHCONF_POSTCANON	4  /* After hostname canonicalisation */
 | ||||||
|  | +#define SSHCONF_FINAL		4  /* Final pass over config, after canon. */
 | ||||||
|  |  #define SSHCONF_NEVERMATCH	8  /* Match/Host never matches; internal only */ | ||||||
|  |   | ||||||
|  |  #define SSH_UPDATE_HOSTKEYS_NO	0 | ||||||
|  | @@ -203,7 +203,7 @@ void	 fill_default_options_for_canonicalization(Options *);
 | ||||||
|  |  int	 process_config_line(Options *, struct passwd *, const char *, | ||||||
|  |      const char *, char *, const char *, int, int *, int); | ||||||
|  |  int	 read_config_file(const char *, struct passwd *, const char *, | ||||||
|  | -    const char *, Options *, int);
 | ||||||
|  | +    const char *, Options *, int, int *);
 | ||||||
|  |  int	 parse_forward(struct Forward *, const char *, int, int); | ||||||
|  |  int	 parse_jump(const char *, Options *, int); | ||||||
|  |  int	 parse_ssh_uri(const char *, char **, char **, int *); | ||||||
|  | diff --git a/ssh-keysign.c b/ssh-keysign.c
 | ||||||
|  | index 8f487b8c..7ea5ad0e 100644
 | ||||||
|  | --- a/ssh-keysign.c
 | ||||||
|  | +++ b/ssh-keysign.c
 | ||||||
|  | @@ -208,7 +208,8 @@ main(int argc, char **argv)
 | ||||||
|  |   | ||||||
|  |  	/* verify that ssh-keysign is enabled by the admin */ | ||||||
|  |  	initialize_options(&options); | ||||||
|  | -	(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "", &options, 0);
 | ||||||
|  | +	(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "",
 | ||||||
|  | +	    &options, 0, NULL);
 | ||||||
|  |  	fill_default_options(&options); | ||||||
|  |  	if (options.enable_ssh_keysign != 1) | ||||||
|  |  		fatal("ssh-keysign not enabled in %s", | ||||||
|  | diff --git a/ssh.c b/ssh.c
 | ||||||
|  | index 1ac903d1..c6cb7847 100644
 | ||||||
|  | --- a/ssh.c
 | ||||||
|  | +++ b/ssh.c
 | ||||||
|  | @@ -527,7 +527,8 @@ check_load(int r, const char *path, const char *message)
 | ||||||
|  |   * file if the user specifies a config file on the command line. | ||||||
|  |   */ | ||||||
|  |  static void | ||||||
|  | -process_config_files(const char *host_name, struct passwd *pw, int post_canon)
 | ||||||
|  | +process_config_files(const char *host_name, struct passwd *pw, int final_pass,
 | ||||||
|  | +    int *want_final_pass)
 | ||||||
|  |  { | ||||||
|  |  	char buf[PATH_MAX]; | ||||||
|  |  	int r; | ||||||
|  | @@ -535,7 +536,8 @@ process_config_files(const char *host_name, struct passwd *pw, int post_canon)
 | ||||||
|  |  	if (config != NULL) { | ||||||
|  |  		if (strcasecmp(config, "none") != 0 && | ||||||
|  |  		    !read_config_file(config, pw, host, host_name, &options, | ||||||
|  | -		    SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0)))
 | ||||||
|  | +		    SSHCONF_USERCONF | (final_pass ? SSHCONF_FINAL : 0),
 | ||||||
|  | +		    want_final_pass))
 | ||||||
|  |  			fatal("Can't open user config file %.100s: " | ||||||
|  |  			    "%.100s", config, strerror(errno)); | ||||||
|  |  	} else { | ||||||
|  | @@ -544,12 +546,12 @@ process_config_files(const char *host_name, struct passwd *pw, int post_canon)
 | ||||||
|  |  		if (r > 0 && (size_t)r < sizeof(buf)) | ||||||
|  |  			(void)read_config_file(buf, pw, host, host_name, | ||||||
|  |  			    &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | | ||||||
|  | -			    (post_canon ? SSHCONF_POSTCANON : 0));
 | ||||||
|  | +			    (final_pass ? SSHCONF_FINAL : 0), want_final_pass);
 | ||||||
|  |   | ||||||
|  |  		/* Read systemwide configuration file after user config. */ | ||||||
|  |  		(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, | ||||||
|  |  		    host, host_name, &options, | ||||||
|  | -		    post_canon ? SSHCONF_POSTCANON : 0);
 | ||||||
|  | +		    final_pass ? SSHCONF_FINAL : 0, want_final_pass);
 | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | @@ -581,7 +583,7 @@ main(int ac, char **av)
 | ||||||
|  |  { | ||||||
|  |  	struct ssh *ssh = NULL; | ||||||
|  |  	int i, r, opt, exit_status, use_syslog, direct, timeout_ms; | ||||||
|  | -	int was_addr, config_test = 0, opt_terminated = 0;
 | ||||||
|  | +	int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0;
 | ||||||
|  |  	char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile; | ||||||
|  |  	char cname[NI_MAXHOST]; | ||||||
|  |  	struct stat st; | ||||||
|  | @@ -1089,7 +1091,9 @@ main(int ac, char **av)
 | ||||||
|  |  		); | ||||||
|  |   | ||||||
|  |  	/* Parse the configuration files */ | ||||||
|  | -	process_config_files(host_arg, pw, 0);
 | ||||||
|  | +	process_config_files(host_arg, pw, 0, &want_final_pass);
 | ||||||
|  | +	if (want_final_pass)
 | ||||||
|  | +		debug("configuration requests final Match pass");
 | ||||||
|  |   | ||||||
|  |  	/* Hostname canonicalisation needs a few options filled. */ | ||||||
|  |  	fill_default_options_for_canonicalization(&options); | ||||||
|  | @@ -1146,12 +1150,17 @@ main(int ac, char **av)
 | ||||||
|  |  	 * If canonicalisation is enabled then re-parse the configuration | ||||||
|  |  	 * files as new stanzas may match. | ||||||
|  |  	 */ | ||||||
|  | -	if (options.canonicalize_hostname != 0) {
 | ||||||
|  | -		debug("Re-reading configuration after hostname "
 | ||||||
|  | -		    "canonicalisation");
 | ||||||
|  | +	if (options.canonicalize_hostname != 0 && !want_final_pass) {
 | ||||||
|  | +		debug("hostname canonicalisation enabled, "
 | ||||||
|  | +		    "will re-parse configuration");
 | ||||||
|  | +		want_final_pass = 1;
 | ||||||
|  | +	}
 | ||||||
|  | +
 | ||||||
|  | +	if (want_final_pass) {
 | ||||||
|  | +		debug("re-parsing configuration");
 | ||||||
|  |  		free(options.hostname); | ||||||
|  |  		options.hostname = xstrdup(host); | ||||||
|  | -		process_config_files(host_arg, pw, 1);
 | ||||||
|  | +		process_config_files(host_arg, pw, 1, NULL);
 | ||||||
|  |  		/* | ||||||
|  |  		 * Address resolution happens early with canonicalisation | ||||||
|  |  		 * enabled and the port number may have changed since, so | ||||||
|  | diff --git a/ssh_config.5 b/ssh_config.5
 | ||||||
|  | index 4d5b01d3..58a5fa1c 100644
 | ||||||
|  | --- a/ssh_config.5
 | ||||||
|  | +++ b/ssh_config.5
 | ||||||
|  | @@ -139,6 +139,7 @@ or the single token
 | ||||||
|  |  which always matches. | ||||||
|  |  The available criteria keywords are: | ||||||
|  |  .Cm canonical , | ||||||
|  | +.Cm final ,
 | ||||||
|  |  .Cm exec , | ||||||
|  |  .Cm host , | ||||||
|  |  .Cm originalhost , | ||||||
|  | @@ -148,12 +149,15 @@ and
 | ||||||
|  |  The | ||||||
|  |  .Cm all | ||||||
|  |  criteria must appear alone or immediately after | ||||||
|  | -.Cm canonical .
 | ||||||
|  | +.Cm canonical
 | ||||||
|  | +or
 | ||||||
|  | +.Cm final .
 | ||||||
|  |  Other criteria may be combined arbitrarily. | ||||||
|  |  All criteria but | ||||||
|  |  .Cm all | ||||||
|  | -and
 | ||||||
|  |  .Cm canonical | ||||||
|  | +and
 | ||||||
|  | +.Cm final
 | ||||||
|  |  require an argument. | ||||||
|  |  Criteria may be negated by prepending an exclamation mark | ||||||
|  |  .Pq Sq !\& . | ||||||
|  | @@ -166,6 +170,20 @@ after hostname canonicalization (see the
 | ||||||
|  |  option.) | ||||||
|  |  This may be useful to specify conditions that work with canonical host | ||||||
|  |  names only. | ||||||
|  | +.Pp
 | ||||||
|  | +The
 | ||||||
|  | +.Cm final
 | ||||||
|  | +keyword requests that the configuration be re-parsed (regardless of whether
 | ||||||
|  | +.Cm CanonicalizeHostname
 | ||||||
|  | +is enabled), and matches only during this final pass.
 | ||||||
|  | +If
 | ||||||
|  | +.Cm CanonicalizeHostname
 | ||||||
|  | +is enabled, then
 | ||||||
|  | +.Cm canonical
 | ||||||
|  | +and
 | ||||||
|  | +.Cm final
 | ||||||
|  | +match during the same pass.
 | ||||||
|  | +.Pp
 | ||||||
|  |  The | ||||||
|  |  .Cm exec | ||||||
|  |  keyword executes the specified command under the user's shell. | ||||||
| @ -226,6 +226,9 @@ Patch953: openssh-7.8p1-scp-ipv6.patch | |||||||
| # Allow to disable RSA signatures with SHA-1 in server | # Allow to disable RSA signatures with SHA-1 in server | ||||||
| # https://bugzilla.mindrot.org/show_bug.cgi?id=2746 | # https://bugzilla.mindrot.org/show_bug.cgi?id=2746 | ||||||
| Patch954: openssh-7.9p1-disable-sha1.patch | Patch954: openssh-7.9p1-disable-sha1.patch | ||||||
|  | # Backport Match final so the crypto-policies do not break canonicalization (#1630166) | ||||||
|  | # https://bugzilla.mindrot.org/show_bug.cgi?id=2906 | ||||||
|  | Patch955: openssh-7.9p1-match-final.patch | ||||||
| 
 | 
 | ||||||
| License: BSD | License: BSD | ||||||
| Group: Applications/Internet | Group: Applications/Internet | ||||||
| @ -450,6 +453,7 @@ popd | |||||||
| %patch953 -p1 -b .scp-ipv6 | %patch953 -p1 -b .scp-ipv6 | ||||||
| %patch808 -p1 -b .gsskex-method | %patch808 -p1 -b .gsskex-method | ||||||
| %patch954 -p1 -b .disable-sha1 | %patch954 -p1 -b .disable-sha1 | ||||||
|  | %patch955 -p1 -b .match-final | ||||||
| 
 | 
 | ||||||
| %patch200 -p1 -b .audit | %patch200 -p1 -b .audit | ||||||
| %patch201 -p1 -b .audit-race | %patch201 -p1 -b .audit-race | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user