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
This commit is contained in:
djm@openbsd.org 2018-11-23 05:08:07 +00:00 committed by Damien Miller
parent 4da58d5873
commit 9e34e0c59a
5 changed files with 76 additions and 36 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.301 2018/11/16 03:26:01 djm Exp $ */
/* $OpenBSD: readconf.c,v 1.302 2018/11/23 05:08:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -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);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.128 2018/09/20 03:30:44 djm Exp $ */
/* $OpenBSD: readconf.h,v 1.129 2018/11/23 05:08:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -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 *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keysign.c,v 1.55 2018/07/27 05:34:42 dtucker Exp $ */
/* $OpenBSD: ssh-keysign.c,v 1.56 2018/11/23 05:08:07 djm Exp $ */
/*
* Copyright (c) 2002 Markus Friedl. All rights reserved.
*
@ -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",

31
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.495 2018/10/23 05:56:35 djm Exp $ */
/* $OpenBSD: ssh.c,v 1.496 2018/11/23 05:08:07 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -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

View File

@ -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.286 2018/10/03 06:38:35 djm Exp $
.Dd $Mdocdate: October 3 2018 $
.\" $OpenBSD: ssh_config.5,v 1.287 2018/11/23 05:08:07 djm Exp $
.Dd $Mdocdate: November 23 2018 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
@ -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.