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:
parent
4da58d5873
commit
9e34e0c59a
44
readconf.c
44
readconf.c
|
@ -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>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* 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,
|
static int read_config_file_depth(const char *filename, struct passwd *pw,
|
||||||
const char *host, const char *original_host, Options *options,
|
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,
|
static int process_config_line_depth(Options *options, struct passwd *pw,
|
||||||
const char *host, const char *original_host, char *line,
|
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. */
|
/* Keyword tokens. */
|
||||||
|
|
||||||
|
@ -539,8 +540,8 @@ execute_in_shell(const char *cmd)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
match_cfg_line(Options *options, char **condition, struct passwd *pw,
|
match_cfg_line(Options *options, char **condition, struct passwd *pw,
|
||||||
const char *host_arg, const char *original_host, int post_canon,
|
const char *host_arg, const char *original_host, int final_pass,
|
||||||
const char *filename, int linenum)
|
int *want_final_pass, const char *filename, int linenum)
|
||||||
{
|
{
|
||||||
char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
|
char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria;
|
||||||
const char *ruser;
|
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;
|
port = options->port <= 0 ? default_ssh_port() : options->port;
|
||||||
ruser = options->user == NULL ? pw->pw_name : options->user;
|
ruser = options->user == NULL ? pw->pw_name : options->user;
|
||||||
if (post_canon) {
|
if (final_pass) {
|
||||||
host = xstrdup(options->hostname);
|
host = xstrdup(options->hostname);
|
||||||
} else if (options->hostname != NULL) {
|
} else if (options->hostname != NULL) {
|
||||||
/* NB. Please keep in sync with ssh.c:main() */
|
/* 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;
|
goto out;
|
||||||
}
|
}
|
||||||
attributes++;
|
attributes++;
|
||||||
if (strcasecmp(attrib, "canonical") == 0) {
|
if (strcasecmp(attrib, "canonical") == 0 ||
|
||||||
r = !!post_canon; /* force bitmask member to boolean */
|
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))
|
if (r == (negate ? 1 : 0))
|
||||||
this_result = result = 0;
|
this_result = result = 0;
|
||||||
debug3("%.200s line %d: %smatched '%s'",
|
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)
|
int linenum, int *activep, int flags)
|
||||||
{
|
{
|
||||||
return process_config_line_depth(options, pw, host, original_host,
|
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"
|
#define WHITESPACE " \t\r\n"
|
||||||
static int
|
static int
|
||||||
process_config_line_depth(Options *options, struct passwd *pw, const char *host,
|
process_config_line_depth(Options *options, struct passwd *pw, const char *host,
|
||||||
const char *original_host, char *line, const char *filename,
|
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 *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
|
||||||
char **cpptr, fwdarg[256];
|
char **cpptr, fwdarg[256];
|
||||||
|
@ -1339,7 +1348,8 @@ parse_keytypes:
|
||||||
fatal("Host directive not supported as a command-line "
|
fatal("Host directive not supported as a command-line "
|
||||||
"option");
|
"option");
|
||||||
value = match_cfg_line(options, &s, pw, host, original_host,
|
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)
|
if (value < 0)
|
||||||
fatal("%.200s line %d: Bad Match condition", filename,
|
fatal("%.200s line %d: Bad Match condition", filename,
|
||||||
linenum);
|
linenum);
|
||||||
|
@ -1548,7 +1558,7 @@ parse_keytypes:
|
||||||
pw, host, original_host, options,
|
pw, host, original_host, options,
|
||||||
flags | SSHCONF_CHECKPERM |
|
flags | SSHCONF_CHECKPERM |
|
||||||
(oactive ? 0 : SSHCONF_NEVERMATCH),
|
(oactive ? 0 : SSHCONF_NEVERMATCH),
|
||||||
activep, depth + 1);
|
activep, want_final_pass, depth + 1);
|
||||||
if (r != 1 && errno != ENOENT) {
|
if (r != 1 && errno != ENOENT) {
|
||||||
fatal("Can't open user config file "
|
fatal("Can't open user config file "
|
||||||
"%.100s: %.100s", gl.gl_pathv[i],
|
"%.100s: %.100s", gl.gl_pathv[i],
|
||||||
|
@ -1751,19 +1761,20 @@ parse_keytypes:
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
read_config_file(const char *filename, struct passwd *pw, const char *host,
|
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;
|
int active = 1;
|
||||||
|
|
||||||
return read_config_file_depth(filename, pw, host, original_host,
|
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
|
#define READCONF_MAX_DEPTH 16
|
||||||
static int
|
static int
|
||||||
read_config_file_depth(const char *filename, struct passwd *pw,
|
read_config_file_depth(const char *filename, struct passwd *pw,
|
||||||
const char *host, const char *original_host, Options *options,
|
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;
|
FILE *f;
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
|
@ -1798,7 +1809,8 @@ read_config_file_depth(const char *filename, struct passwd *pw,
|
||||||
/* Update line number counter. */
|
/* Update line number counter. */
|
||||||
linenum++;
|
linenum++;
|
||||||
if (process_config_line_depth(options, pw, host, original_host,
|
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++;
|
bad_options++;
|
||||||
}
|
}
|
||||||
free(line);
|
free(line);
|
||||||
|
|
|
@ -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>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
|
@ -185,7 +185,7 @@ typedef struct {
|
||||||
|
|
||||||
#define SSHCONF_CHECKPERM 1 /* check permissions on config file */
|
#define SSHCONF_CHECKPERM 1 /* check permissions on config file */
|
||||||
#define SSHCONF_USERCONF 2 /* user provided config file not system */
|
#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 SSHCONF_NEVERMATCH 8 /* Match/Host never matches; internal only */
|
||||||
|
|
||||||
#define SSH_UPDATE_HOSTKEYS_NO 0
|
#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 *,
|
int process_config_line(Options *, struct passwd *, const char *,
|
||||||
const char *, char *, const char *, int, int *, int);
|
const char *, char *, const char *, int, int *, int);
|
||||||
int read_config_file(const char *, struct passwd *, const char *,
|
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_forward(struct Forward *, const char *, int, int);
|
||||||
int parse_jump(const char *, Options *, int);
|
int parse_jump(const char *, Options *, int);
|
||||||
int parse_ssh_uri(const char *, char **, char **, int *);
|
int parse_ssh_uri(const char *, char **, char **, int *);
|
||||||
|
|
|
@ -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.
|
* 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 */
|
/* verify that ssh-keysign is enabled by the admin */
|
||||||
initialize_options(&options);
|
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);
|
fill_default_options(&options);
|
||||||
if (options.enable_ssh_keysign != 1)
|
if (options.enable_ssh_keysign != 1)
|
||||||
fatal("ssh-keysign not enabled in %s",
|
fatal("ssh-keysign not enabled in %s",
|
||||||
|
|
31
ssh.c
31
ssh.c
|
@ -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>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* 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.
|
* file if the user specifies a config file on the command line.
|
||||||
*/
|
*/
|
||||||
static void
|
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];
|
char buf[PATH_MAX];
|
||||||
int r;
|
int r;
|
||||||
|
@ -535,7 +536,8 @@ process_config_files(const char *host_name, struct passwd *pw, int post_canon)
|
||||||
if (config != NULL) {
|
if (config != NULL) {
|
||||||
if (strcasecmp(config, "none") != 0 &&
|
if (strcasecmp(config, "none") != 0 &&
|
||||||
!read_config_file(config, pw, host, host_name, &options,
|
!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: "
|
fatal("Can't open user config file %.100s: "
|
||||||
"%.100s", config, strerror(errno));
|
"%.100s", config, strerror(errno));
|
||||||
} else {
|
} 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))
|
if (r > 0 && (size_t)r < sizeof(buf))
|
||||||
(void)read_config_file(buf, pw, host, host_name,
|
(void)read_config_file(buf, pw, host, host_name,
|
||||||
&options, SSHCONF_CHECKPERM | SSHCONF_USERCONF |
|
&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. */
|
/* Read systemwide configuration file after user config. */
|
||||||
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw,
|
(void)read_config_file(_PATH_HOST_CONFIG_FILE, pw,
|
||||||
host, host_name, &options,
|
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;
|
struct ssh *ssh = NULL;
|
||||||
int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
|
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 *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile;
|
||||||
char cname[NI_MAXHOST];
|
char cname[NI_MAXHOST];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
@ -1089,7 +1091,9 @@ main(int ac, char **av)
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Parse the configuration files */
|
/* 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. */
|
/* Hostname canonicalisation needs a few options filled. */
|
||||||
fill_default_options_for_canonicalization(&options);
|
fill_default_options_for_canonicalization(&options);
|
||||||
|
@ -1146,12 +1150,17 @@ main(int ac, char **av)
|
||||||
* If canonicalisation is enabled then re-parse the configuration
|
* If canonicalisation is enabled then re-parse the configuration
|
||||||
* files as new stanzas may match.
|
* files as new stanzas may match.
|
||||||
*/
|
*/
|
||||||
if (options.canonicalize_hostname != 0) {
|
if (options.canonicalize_hostname != 0 && !want_final_pass) {
|
||||||
debug("Re-reading configuration after hostname "
|
debug("hostname canonicalisation enabled, "
|
||||||
"canonicalisation");
|
"will re-parse configuration");
|
||||||
|
want_final_pass = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (want_final_pass) {
|
||||||
|
debug("re-parsing configuration");
|
||||||
free(options.hostname);
|
free(options.hostname);
|
||||||
options.hostname = xstrdup(host);
|
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
|
* Address resolution happens early with canonicalisation
|
||||||
* enabled and the port number may have changed since, so
|
* enabled and the port number may have changed since, so
|
||||||
|
|
26
ssh_config.5
26
ssh_config.5
|
@ -33,8 +33,8 @@
|
||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" 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 $
|
.\" $OpenBSD: ssh_config.5,v 1.287 2018/11/23 05:08:07 djm Exp $
|
||||||
.Dd $Mdocdate: October 3 2018 $
|
.Dd $Mdocdate: November 23 2018 $
|
||||||
.Dt SSH_CONFIG 5
|
.Dt SSH_CONFIG 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -139,6 +139,7 @@ or the single token
|
||||||
which always matches.
|
which always matches.
|
||||||
The available criteria keywords are:
|
The available criteria keywords are:
|
||||||
.Cm canonical ,
|
.Cm canonical ,
|
||||||
|
.Cm final ,
|
||||||
.Cm exec ,
|
.Cm exec ,
|
||||||
.Cm host ,
|
.Cm host ,
|
||||||
.Cm originalhost ,
|
.Cm originalhost ,
|
||||||
|
@ -148,12 +149,15 @@ and
|
||||||
The
|
The
|
||||||
.Cm all
|
.Cm all
|
||||||
criteria must appear alone or immediately after
|
criteria must appear alone or immediately after
|
||||||
.Cm canonical .
|
.Cm canonical
|
||||||
|
or
|
||||||
|
.Cm final .
|
||||||
Other criteria may be combined arbitrarily.
|
Other criteria may be combined arbitrarily.
|
||||||
All criteria but
|
All criteria but
|
||||||
.Cm all
|
.Cm all
|
||||||
and
|
|
||||||
.Cm canonical
|
.Cm canonical
|
||||||
|
and
|
||||||
|
.Cm final
|
||||||
require an argument.
|
require an argument.
|
||||||
Criteria may be negated by prepending an exclamation mark
|
Criteria may be negated by prepending an exclamation mark
|
||||||
.Pq Sq !\& .
|
.Pq Sq !\& .
|
||||||
|
@ -166,6 +170,20 @@ after hostname canonicalization (see the
|
||||||
option.)
|
option.)
|
||||||
This may be useful to specify conditions that work with canonical host
|
This may be useful to specify conditions that work with canonical host
|
||||||
names only.
|
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
|
The
|
||||||
.Cm exec
|
.Cm exec
|
||||||
keyword executes the specified command under the user's shell.
|
keyword executes the specified command under the user's shell.
|
||||||
|
|
Loading…
Reference in New Issue