vishalmishra434 / rpms / openssh

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