View | Details | Raw Unified | Return to bug 1585 | Differences between
and this patch

Collapse All | Expand All

(-)a/readconf.c (-9 / +84 lines)
Lines 45-50 Link Here
45
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
45
#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
46
# include <vis.h>
46
# include <vis.h>
47
#endif
47
#endif
48
#include <glob.h>
48
49
49
#include "xmalloc.h"
50
#include "xmalloc.h"
50
#include "ssh.h"
51
#include "ssh.h"
Lines 125-135 Link Here
125
126
126
*/
127
*/
127
128
129
static int read_config_file_depth(const char *filename, struct passwd *pw,
130
    const char *host, const char *original_host, Options *options,
131
    int flags, int *activep, int depth);
132
static int process_config_line_depth(Options *options, struct passwd *pw,
133
    const char *host, const char *original_host, char *line,
134
    const char *filename, int linenum, int *activep, int flags, int depth);
135
128
/* Keyword tokens. */
136
/* Keyword tokens. */
129
137
130
typedef enum {
138
typedef enum {
131
	oBadOption,
139
	oBadOption,
132
	oHost, oMatch,
140
	oHost, oMatch, oInclude,
133
	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
141
	oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
134
	oGatewayPorts, oExitOnForwardFailure,
142
	oGatewayPorts, oExitOnForwardFailure,
135
	oPasswordAuthentication, oRSAAuthentication,
143
	oPasswordAuthentication, oRSAAuthentication,
Lines 258-263 static struct { Link Here
258
	{ "controlmaster", oControlMaster },
266
	{ "controlmaster", oControlMaster },
259
	{ "controlpersist", oControlPersist },
267
	{ "controlpersist", oControlPersist },
260
	{ "hashknownhosts", oHashKnownHosts },
268
	{ "hashknownhosts", oHashKnownHosts },
269
	{ "include", oInclude },
261
	{ "tunnel", oTunnel },
270
	{ "tunnel", oTunnel },
262
	{ "tunneldevice", oTunnelDevice },
271
	{ "tunneldevice", oTunnelDevice },
263
	{ "localcommand", oLocalCommand },
272
	{ "localcommand", oLocalCommand },
Lines 772-793 static const struct multistate multistate_canonicalizehostname[] = { Link Here
772
 * Processes a single option line as used in the configuration files. This
781
 * Processes a single option line as used in the configuration files. This
773
 * only sets those values that have not already been set.
782
 * only sets those values that have not already been set.
774
 */
783
 */
775
#define WHITESPACE " \t\r\n"
776
int
784
int
777
process_config_line(Options *options, struct passwd *pw, const char *host,
785
process_config_line(Options *options, struct passwd *pw, const char *host,
778
    const char *original_host, char *line, const char *filename,
786
    const char *original_host, char *line, const char *filename,
779
    int linenum, int *activep, int flags)
787
    int linenum, int *activep, int flags)
780
{
788
{
789
	return process_config_line_depth(options, pw, host, original_host,
790
	    line, filename, linenum, activep, flags, 0);
791
}
792
793
#define WHITESPACE " \t\r\n"
794
static int
795
process_config_line_depth(Options *options, struct passwd *pw, const char *host,
796
    const char *original_host, char *line, const char *filename,
797
    int linenum, int *activep, int flags, int depth)
798
{
781
	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
799
	char *s, **charptr, *endofnumber, *keyword, *arg, *arg2;
782
	char **cpptr, fwdarg[256];
800
	char **cpptr, fwdarg[256];
783
	u_int i, *uintptr, max_entries = 0;
801
	u_int i, *uintptr, max_entries = 0;
784
	int negated, opcode, *intptr, value, value2, cmdline = 0;
802
	int r, oactive, negated, opcode, *intptr, value, value2, cmdline = 0;
785
	LogLevel *log_level_ptr;
803
	LogLevel *log_level_ptr;
786
	long long val64;
804
	long long val64;
787
	size_t len;
805
	size_t len;
788
	struct Forward fwd;
806
	struct Forward fwd;
789
	const struct multistate *multistate_ptr;
807
	const struct multistate *multistate_ptr;
790
	struct allowed_cname *cname;
808
	struct allowed_cname *cname;
809
	glob_t gl;
791
810
792
	if (activep == NULL) { /* We are processing a command line directive */
811
	if (activep == NULL) { /* We are processing a command line directive */
793
		cmdline = 1;
812
		cmdline = 1;
Lines 1247-1252 parse_keytypes: Link Here
1247
		*activep = 0;
1266
		*activep = 0;
1248
		arg2 = NULL;
1267
		arg2 = NULL;
1249
		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1268
		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1269
			if ((flags & SSHCONF_NEVERMATCH) != 0)
1270
				break;
1250
			negated = *arg == '!';
1271
			negated = *arg == '!';
1251
			if (negated)
1272
			if (negated)
1252
				arg++;
1273
				arg++;
Lines 1279-1285 parse_keytypes: Link Here
1279
		if (value < 0)
1300
		if (value < 0)
1280
			fatal("%.200s line %d: Bad Match condition", filename,
1301
			fatal("%.200s line %d: Bad Match condition", filename,
1281
			    linenum);
1302
			    linenum);
1282
		*activep = value;
1303
		*activep = (flags & SSHCONF_NEVERMATCH) ? 0 : value;
1283
		break;
1304
		break;
1284
1305
1285
	case oEscapeChar:
1306
	case oEscapeChar:
Lines 1407-1412 parse_keytypes: Link Here
1407
		intptr = &options->visual_host_key;
1428
		intptr = &options->visual_host_key;
1408
		goto parse_flag;
1429
		goto parse_flag;
1409
1430
1431
	case oInclude:
1432
		if (cmdline)
1433
			fatal("Include directive not supported as a "
1434
			    "command-line option");
1435
		value = 0;
1436
		while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
1437
			/* Ensure all paths are anchored */
1438
			if (*arg != '/' && *arg != '~') {
1439
				xasprintf(&arg2, "~/%s/%s",
1440
				    _PATH_SSH_USER_DIR, arg);
1441
			} else
1442
				arg2 = xstrdup(arg);
1443
			memset(&gl, 0, sizeof(gl));
1444
			r = glob(arg2, GLOB_TILDE, NULL, &gl);
1445
			if (r == GLOB_NOMATCH)
1446
				continue;
1447
			else if (r != 0)
1448
				fatal("%s: glob failed %s", __func__, arg2);
1449
			free(arg2);
1450
			oactive = *activep;
1451
			for (i = 0; i < gl.gl_pathc; i++) {
1452
				debug3("%.200s line %d: Including file %s%s",
1453
				    filename, linenum, gl.gl_pathv[i],
1454
				    oactive ? " (parse only)" : "");
1455
				r = read_config_file_depth(gl.gl_pathv[i],
1456
				    pw, host, original_host, options,
1457
				    flags | (oactive ? 0 : SSHCONF_NEVERMATCH),
1458
				    activep, depth + 1);
1459
				*activep = oactive;
1460
				if (r != 1)
1461
					value = -1;
1462
			}
1463
			globfree(&gl);
1464
			/*
1465
			 * don't let Match in includes clobber the
1466
			 * containing file's Match state.
1467
			 */
1468
		}
1469
		if (value != 0)
1470
			return value;
1471
		break;
1472
1410
	case oIPQoS:
1473
	case oIPQoS:
1411
		arg = strdelim(&s);
1474
		arg = strdelim(&s);
1412
		if ((value = parse_ipqos(arg)) == -1)
1475
		if ((value = parse_ipqos(arg)) == -1)
Lines 1565-1586 parse_keytypes: Link Here
1565
	return 0;
1628
	return 0;
1566
}
1629
}
1567
1630
1568
1569
/*
1631
/*
1570
 * Reads the config file and modifies the options accordingly.  Options
1632
 * Reads the config file and modifies the options accordingly.  Options
1571
 * should already be initialized before this call.  This never returns if
1633
 * should already be initialized before this call.  This never returns if
1572
 * there is an error.  If the file does not exist, this returns 0.
1634
 * there is an error.  If the file does not exist, this returns 0.
1573
 */
1635
 */
1574
1575
int
1636
int
1576
read_config_file(const char *filename, struct passwd *pw, const char *host,
1637
read_config_file(const char *filename, struct passwd *pw, const char *host,
1577
    const char *original_host, Options *options, int flags)
1638
    const char *original_host, Options *options, int flags)
1578
{
1639
{
1640
	int active = 1;
1641
1642
	return read_config_file_depth(filename, pw, host, original_host,
1643
	    options, flags, &active, 0);
1644
}
1645
1646
#define READCONF_MAX_DEPTH	16
1647
static int
1648
read_config_file_depth(const char *filename, struct passwd *pw,
1649
    const char *host, const char *original_host, Options *options,
1650
    int flags, int *activep, int depth)
1651
{
1579
	FILE *f;
1652
	FILE *f;
1580
	char line[1024];
1653
	char line[1024];
1581
	int active, linenum;
1654
	int linenum;
1582
	int bad_options = 0;
1655
	int bad_options = 0;
1583
1656
1657
	if (depth < 0 || depth > 16)
1658
		fatal("Too many recursive configuration includes");
1659
1584
	if ((f = fopen(filename, "r")) == NULL)
1660
	if ((f = fopen(filename, "r")) == NULL)
1585
		return 0;
1661
		return 0;
1586
1662
Lines 1600-1612 read_config_file(const char *filename, struct passwd *pw, const char *host, Link Here
1600
	 * Mark that we are now processing the options.  This flag is turned
1676
	 * Mark that we are now processing the options.  This flag is turned
1601
	 * on/off by Host specifications.
1677
	 * on/off by Host specifications.
1602
	 */
1678
	 */
1603
	active = 1;
1604
	linenum = 0;
1679
	linenum = 0;
1605
	while (fgets(line, sizeof(line), f)) {
1680
	while (fgets(line, sizeof(line), f)) {
1606
		/* Update line number counter. */
1681
		/* Update line number counter. */
1607
		linenum++;
1682
		linenum++;
1608
		if (process_config_line(options, pw, host, original_host,
1683
		if (process_config_line(options, pw, host, original_host,
1609
		    line, filename, linenum, &active, flags) != 0)
1684
		    line, filename, linenum, activep, flags) != 0)
1610
			bad_options++;
1685
			bad_options++;
1611
	}
1686
	}
1612
	fclose(f);
1687
	fclose(f);
(-)a/readconf.h (+1 lines)
Lines 179-184 typedef struct { Link Here
179
#define SSHCONF_CHECKPERM	1  /* check permissions on config file */
179
#define SSHCONF_CHECKPERM	1  /* check permissions on config file */
180
#define SSHCONF_USERCONF	2  /* user provided config file not system */
180
#define SSHCONF_USERCONF	2  /* user provided config file not system */
181
#define SSHCONF_POSTCANON	4  /* After hostname canonicalisation */
181
#define SSHCONF_POSTCANON	4  /* After hostname canonicalisation */
182
#define SSHCONF_NEVERMATCH	8  /* Match/Host never matches; internal only */
182
183
183
#define SSH_UPDATE_HOSTKEYS_NO	0
184
#define SSH_UPDATE_HOSTKEYS_NO	0
184
#define SSH_UPDATE_HOSTKEYS_YES	1
185
#define SSH_UPDATE_HOSTKEYS_YES	1
(-)a/regress/cfginclude.sh (+141 lines)
Line 0 Link Here
1
#	$OpenBSD$
2
#	Placed in the Public Domain.
3
4
tid="config include"
5
6
cat > $OBJ/ssh_config.i << _EOF
7
Match host a
8
	Hostname aa
9
10
Match host b
11
	Hostname bb
12
	Include $OBJ/ssh_config.i.*
13
14
Match host c
15
	Include $OBJ/ssh_config.i.*
16
	Hostname cc
17
18
Match host m
19
	Include $OBJ/ssh_config.i.*
20
21
Host d
22
	Hostname dd
23
24
Host e
25
	Hostname ee
26
	Include $OBJ/ssh_config.i.*
27
28
Host f
29
	Include $OBJ/ssh_config.i.*
30
	Hostname ff
31
32
Host n
33
	Include $OBJ/ssh_config.i.*
34
_EOF
35
36
cat > $OBJ/ssh_config.i.0 << _EOF
37
Match host xxxxxx
38
_EOF
39
40
cat > $OBJ/ssh_config.i.1 << _EOF
41
Match host a
42
	Hostname aaa
43
44
Match host b
45
	Hostname bbb
46
47
Match host c
48
	Hostname ccc
49
50
Host d
51
	Hostname ddd
52
53
Host e
54
	Hostname eee
55
56
Host f
57
	Hostname fff
58
_EOF
59
60
cat > $OBJ/ssh_config.i.2 << _EOF
61
Match host a
62
	Hostname aaaa
63
64
Match host b
65
	Hostname bbbb
66
67
Match host c
68
	Hostname cccc
69
70
Host d
71
	Hostname dddd
72
73
Host e
74
	Hostname eeee
75
76
Host f
77
	Hostname ffff
78
79
Match all
80
	Hostname xxxx
81
_EOF
82
83
trial() {
84
	_host="$1"
85
	_exp="$2"
86
	${REAL_SSH} -F $OBJ/ssh_config.i -G "$_host" > $OBJ/ssh_config.out ||
87
		fatal "ssh config parse failed"
88
	_got=`grep -i '^hostname ' $OBJ/ssh_config.out | awk '{print $2}'`
89
	if test "x$_exp" != "x$_got" ; then
90
		fail "host $_host include fail: expected $_exp got $_got"
91
	fi
92
}
93
94
trial a aa
95
trial b bb
96
trial c ccc
97
trial d dd
98
trial e ee
99
trial f fff
100
trial m xxxx
101
trial n xxxx
102
trial x x
103
104
# Prepare an included config with an error.
105
106
cat > $OBJ/ssh_config.i.3 << _EOF
107
Hostname xxxx
108
	Junk
109
_EOF
110
111
${REAL_SSH} -F $OBJ/ssh_config.i -G a 2>/dev/null && \
112
	fail "ssh include allowed invalid config"
113
114
${REAL_SSH} -F $OBJ/ssh_config.i -G x 2>/dev/null && \
115
	fail "ssh include allowed invalid config"
116
117
rm -f $OBJ/ssh_config.i.*
118
119
# Ensure that a missing include is not fatal.
120
cat > $OBJ/ssh_config.i << _EOF
121
#Include $OBJ/ssh_config.i.*
122
Hostname aa
123
_EOF
124
125
trial a aa
126
127
# Ensure that Match/Host in an included config does not affect parent.
128
cat > $OBJ/ssh_config.i.x << _EOF
129
Match host x
130
_EOF
131
132
trial a aa
133
134
cat > $OBJ/ssh_config.i.x << _EOF
135
Host x
136
_EOF
137
138
trial a aa
139
140
# cleanup
141
rm -f $OBJ/ssh_config.i $OBJ/ssh_config.i.* $OBJ/ssh_config.out
(-)a/regress/test-exec.sh (+1 lines)
Lines 221-226 echo "#!/bin/sh" > $SSHLOGWRAP Link Here
221
echo "exec ${SSH} -E${TEST_SSH_LOGFILE} "'"$@"' >>$SSHLOGWRAP
221
echo "exec ${SSH} -E${TEST_SSH_LOGFILE} "'"$@"' >>$SSHLOGWRAP
222
222
223
chmod a+rx $OBJ/ssh-log-wrapper.sh
223
chmod a+rx $OBJ/ssh-log-wrapper.sh
224
REAL_SSH="$SSH"
224
SSH="$SSHLOGWRAP"
225
SSH="$SSHLOGWRAP"
225
226
226
# Some test data.  We make a copy because some tests will overwrite it.
227
# Some test data.  We make a copy because some tests will overwrite it.
(-)a/ssh.1 (+1 lines)
Lines 505-510 For full details of the options listed below, and their possible values, see Link Here
505
.It HostName
505
.It HostName
506
.It IdentityFile
506
.It IdentityFile
507
.It IdentitiesOnly
507
.It IdentitiesOnly
508
.It Include
508
.It IPQoS
509
.It IPQoS
509
.It KbdInteractiveAuthentication
510
.It KbdInteractiveAuthentication
510
.It KbdInteractiveDevices
511
.It KbdInteractiveDevices
(-)a/ssh_config.5 (+17 lines)
Lines 1022-1027 It is recommended that Link Here
1022
.Cm IgnoreUnknown
1022
.Cm IgnoreUnknown
1023
be listed early in the configuration file as it will not be applied
1023
be listed early in the configuration file as it will not be applied
1024
to unknown options that appear before it.
1024
to unknown options that appear before it.
1025
.It Cm Include
1026
Include the specified configuration file(s).
1027
Multiple path names may be specified and each pathname may contain
1028
.Xr glob 3
1029
wildcards and shell-like
1030
.Dq ~
1031
references to user home directories.
1032
Files without absolute paths are assumed to be in
1033
.Pa ~/.ssh .
1034
An
1035
.Cm Include
1036
directive may appear inside a
1037
.Cm Match
1038
or
1039
.Cm Host
1040
block
1041
to perform conditional inclusion.
1025
.It Cm IPQoS
1042
.It Cm IPQoS
1026
Specifies the IPv4 type-of-service or DSCP class for connections.
1043
Specifies the IPv4 type-of-service or DSCP class for connections.
1027
Accepted values are
1044
Accepted values are

Return to bug 1585