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 | ||||
| # https://bugzilla.mindrot.org/show_bug.cgi?id=2746 | ||||
| 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 | ||||
| Group: Applications/Internet | ||||
| @ -450,6 +453,7 @@ popd | ||||
| %patch953 -p1 -b .scp-ipv6 | ||||
| %patch808 -p1 -b .gsskex-method | ||||
| %patch954 -p1 -b .disable-sha1 | ||||
| %patch955 -p1 -b .match-final | ||||
| 
 | ||||
| %patch200 -p1 -b .audit | ||||
| %patch201 -p1 -b .audit-race | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user