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

Collapse All | Expand All

(-)a/regress/Makefile (-1 / +3 lines)
Lines 77-83 LTESTS= connect \ Link Here
77
		hostkey-rotate \
77
		hostkey-rotate \
78
		principals-command \
78
		principals-command \
79
		cert-file \
79
		cert-file \
80
		cfginclude
80
		cfginclude \
81
		servcfginclude
81
82
82
83
83
#		dhgex \
84
#		dhgex \
Lines 105-110 CLEANFILES= *.core actual agent-key.* authorized_keys_${USER} \ Link Here
105
		scp-ssh-wrapper.scp setuid-allowed sftp-server.log \
106
		scp-ssh-wrapper.scp setuid-allowed sftp-server.log \
106
		sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
107
		sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
107
		ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \
108
		ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \
109
		sshd_config sshd_config.* \
108
		ssh_proxy_envpass sshd.log sshd_config sshd_config.orig \
110
		ssh_proxy_envpass sshd.log sshd_config sshd_config.orig \
109
		sshd_proxy sshd_proxy.* sshd_proxy_bak sshd_proxy_orig \
111
		sshd_proxy sshd_proxy.* sshd_proxy_bak sshd_proxy_orig \
110
		t10.out t10.out.pub t12.out t12.out.pub t2.out t3.out \
112
		t10.out t10.out.pub t12.out t12.out.pub t2.out t3.out \
(-)a/regress/servcfginclude.sh (+148 lines)
Line 0 Link Here
1
#	Placed in the Public Domain.
2
3
tid="server config include"
4
5
cat > $OBJ/sshd_config.i << _EOF
6
Match host a
7
	Banner /aa
8
9
Match host b
10
	Banner /bb
11
	Include $OBJ/sshd_config.i.*
12
13
Match host c
14
	Include $OBJ/sshd_config.i.*
15
	Banner /cc
16
17
Match host m
18
	Include $OBJ/sshd_config.i.*
19
20
Match Host d
21
	Banner /dd
22
23
Match Host e
24
	Banner /ee
25
	Include $OBJ/sshd_config.i.*
26
27
Match Host f
28
	Include $OBJ/sshd_config.i.*
29
	Banner /ff
30
31
Match Host n
32
	Include $OBJ/sshd_config.i.*
33
_EOF
34
35
cat > $OBJ/sshd_config.i.0 << _EOF
36
Match host xxxxxx
37
_EOF
38
39
cat > $OBJ/sshd_config.i.1 << _EOF
40
Match host a
41
	Banner /aaa
42
43
Match host b
44
	Banner /bbb
45
46
Match host c
47
	Banner /ccc
48
49
Match Host d
50
	Banner /ddd
51
52
Match Host e
53
	Banner /eee
54
55
Match Host f
56
	Banner /fff
57
_EOF
58
59
cat > $OBJ/sshd_config.i.2 << _EOF
60
Match host a
61
	Banner /aaaa
62
63
Match host b
64
	Banner /bbbb
65
66
Match host c
67
	Banner /cccc
68
69
Match Host d
70
	Banner /dddd
71
72
Match Host e
73
	Banner /eeee
74
75
Match Host f
76
	Banner /ffff
77
78
Match all
79
	Banner /xxxx
80
_EOF
81
82
trial() {
83
	_host="$1"
84
	_exp="$2"
85
	${REAL_SSHD} -f $OBJ/sshd_config.i -T -C "host=$_host,user=test,addr=127.0.0.1" > $OBJ/sshd_config.out ||
86
		fatal "ssh config parse failed"
87
	_got=`grep -i '^banner ' $OBJ/sshd_config.out | awk '{print $2}'`
88
	if test "x$_exp" != "x$_got" ; then
89
		fail "host $_host include fail: expected $_exp got $_got"
90
	fi
91
}
92
93
trial a /aa
94
trial b /bb
95
trial c /ccc
96
trial d /dd
97
trial e /ee
98
trial f /fff
99
trial m /xxxx
100
trial n /xxxx
101
trial x none
102
103
# Prepare an included config with an error.
104
105
cat > $OBJ/sshd_config.i.3 << _EOF
106
Banner xxxx
107
	Junk
108
_EOF
109
110
${REAL_SSHD} -f $OBJ/sshd_config.i -C "host=a,user=test,addr=127.0.0.1" 2>/dev/null && \
111
	fail "sshd include allowed invalid config"
112
113
${REAL_SSHD} -f $OBJ/sshd_config.i -C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \
114
	fail "sshd include allowed invalid config"
115
116
rm -f $OBJ/sshd_config.i.*
117
118
# Ensure that a missing include is not fatal.
119
cat > $OBJ/sshd_config.i << _EOF
120
Include $OBJ/sshd_config.i.*
121
Banner /aa
122
_EOF
123
124
trial a /aa
125
126
# Ensure that Match/Host in an included config does not affect parent.
127
cat > $OBJ/sshd_config.i.x << _EOF
128
Match host x
129
_EOF
130
131
trial a /aa
132
133
cat > $OBJ/sshd_config.i.x << _EOF
134
Match Host x
135
_EOF
136
137
trial a /aa
138
139
# Ensure the empty include directive is not accepted
140
cat > $OBJ/sshd_config.i.x << _EOF
141
Include
142
_EOF
143
144
${REAL_SSHD} -f $OBJ/sshd_config.i.x -C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \
145
	fail "sshd allowed empty Include option"
146
147
# cleanup
148
rm -f $OBJ/sshd_config.i $OBJ/sshd_config.i.* $OBJ/sshd_config.out
(-)a/regress/test-exec.sh (+1 lines)
Lines 223-228 echo "exec ${SSH} -E${TEST_SSH_LOGFILE} "'"$@"' >>$SSHLOGWRAP Link Here
223
223
224
chmod a+rx $OBJ/ssh-log-wrapper.sh
224
chmod a+rx $OBJ/ssh-log-wrapper.sh
225
REAL_SSH="$SSH"
225
REAL_SSH="$SSH"
226
REAL_SSHD="$SSHD"
226
SSH="$SSHLOGWRAP"
227
SSH="$SSHLOGWRAP"
227
228
228
# Some test data.  We make a copy because some tests will overwrite it.
229
# Some test data.  We make a copy because some tests will overwrite it.
(-)a/servconf.c (-9 / +134 lines)
Lines 34-39 Link Here
34
#ifdef HAVE_UTIL_H
34
#ifdef HAVE_UTIL_H
35
#include <util.h>
35
#include <util.h>
36
#endif
36
#endif
37
#ifdef USE_SYSTEM_GLOB
38
# include <glob.h>
39
#else
40
# include "openbsd-compat/glob.h"
41
#endif
37
42
38
#include "openbsd-compat/sys-queue.h"
43
#include "openbsd-compat/sys-queue.h"
39
#include "xmalloc.h"
44
#include "xmalloc.h"
Lines 64-69 static void add_one_listen_addr(ServerOptions *, char *, int); Link Here
64
/* Use of privilege separation or not */
69
/* Use of privilege separation or not */
65
extern int use_privsep;
70
extern int use_privsep;
66
extern Buffer cfg;
71
extern Buffer cfg;
72
struct include_item *include_list = NULL, *include_last = NULL;
73
74
#define INCLUDE_LIST_APPEND(item) \
75
	(item)->next = NULL; \
76
	if (include_list == NULL) { \
77
		include_list = (item); \
78
	} else \
79
		include_last->next = (item); \
80
	include_last = (item);
67
81
68
/* Initializes the server options to their default values. */
82
/* Initializes the server options to their default values. */
69
83
Lines 377-382 fill_default_server_options(ServerOptions *options) Link Here
377
391
378
}
392
}
379
393
394
int process_server_config_line_depth(ServerOptions *options, char *line,
395
    const char *filename, int linenum, int *activep,
396
    struct connection_info *connectinfo, int inc_flags, int depth);
397
void parse_server_config_depth(ServerOptions *options, const char *filename,
398
    Buffer *conf, struct connection_info *connectinfo,
399
    int flags, int *activep, int depth);
400
380
/* Keyword tokens. */
401
/* Keyword tokens. */
381
typedef enum {
402
typedef enum {
382
	sBadOption,		/* == unknown option */
403
	sBadOption,		/* == unknown option */
Lines 407-413 typedef enum { Link Here
407
	sAcceptEnv, sPermitTunnel,
428
	sAcceptEnv, sPermitTunnel,
408
	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
429
	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
409
	sUsePrivilegeSeparation, sAllowAgentForwarding,
430
	sUsePrivilegeSeparation, sAllowAgentForwarding,
410
	sHostCertificate,
431
	sHostCertificate, sInclude,
411
	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
432
	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
412
	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
433
	sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
413
	sKexAlgorithms, sIPQoS, sVersionAddendum,
434
	sKexAlgorithms, sIPQoS, sVersionAddendum,
Lines 422-427 typedef enum { Link Here
422
#define SSHCFG_MATCH	0x02	/* allowed inside a Match section */
443
#define SSHCFG_MATCH	0x02	/* allowed inside a Match section */
423
#define SSHCFG_ALL	(SSHCFG_GLOBAL|SSHCFG_MATCH)
444
#define SSHCFG_ALL	(SSHCFG_GLOBAL|SSHCFG_MATCH)
424
445
446
#define SSHCFG_NEVERMATCH 0x04  /* Match/Host never matches; internal only */
447
425
/* Textual representation of the tokens. */
448
/* Textual representation of the tokens. */
426
static struct {
449
static struct {
427
	const char *name;
450
	const char *name;
Lines 546-551 static struct { Link Here
546
	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
569
	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
547
	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
570
	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
548
	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
571
	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
572
	{ "include", sInclude, SSHCFG_ALL },
549
	{ "ipqos", sIPQoS, SSHCFG_ALL },
573
	{ "ipqos", sIPQoS, SSHCFG_ALL },
550
	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
574
	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
551
	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
575
	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
Lines 952-959 process_server_config_line(ServerOptions *options, char *line, Link Here
952
    const char *filename, int linenum, int *activep,
976
    const char *filename, int linenum, int *activep,
953
    struct connection_info *connectinfo)
977
    struct connection_info *connectinfo)
954
{
978
{
955
	char *cp, **charptr, *arg, *p;
979
	process_server_config_line_depth(options, line, filename, linenum,
956
	int cmdline = 0, *intptr, value, value2, n, port;
980
	    activep, connectinfo, 0, 0);
981
982
}
983
984
int
985
process_server_config_line_depth(ServerOptions *options, char *line,
986
    const char *filename, int linenum, int *activep,
987
    struct connection_info *connectinfo, int inc_flags, int depth)
988
{
989
	char *cp, **charptr, *arg, *arg2, *p;
990
	int cmdline = 0, *intptr, value, value2, n, port, oactive;
957
	SyslogFacility *log_facility_ptr;
991
	SyslogFacility *log_facility_ptr;
958
	LogLevel *log_level_ptr;
992
	LogLevel *log_level_ptr;
959
	ServerOpCodes opcode;
993
	ServerOpCodes opcode;
Lines 961-966 process_server_config_line(ServerOptions *options, char *line, Link Here
961
	size_t len;
995
	size_t len;
962
	long long val64;
996
	long long val64;
963
	const struct multistate *multistate_ptr;
997
	const struct multistate *multistate_ptr;
998
	struct include_item *item;
999
	int found = 0;
1000
	glob_t gbuf;
964
1001
965
	cp = line;
1002
	cp = line;
966
	if ((arg = strdelim(&cp)) == NULL)
1003
	if ((arg = strdelim(&cp)) == NULL)
Lines 978-984 process_server_config_line(ServerOptions *options, char *line, Link Here
978
		cmdline = 1;
1015
		cmdline = 1;
979
		activep = &cmdline;
1016
		activep = &cmdline;
980
	}
1017
	}
981
	if (*activep && opcode != sMatch)
1018
	if (*activep && opcode != sMatch && opcode != sInclude)
982
		debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
1019
		debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
983
	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1020
	if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
984
		if (connectinfo == NULL) {
1021
		if (connectinfo == NULL) {
Lines 1592-1597 process_server_config_line(ServerOptions *options, char *line, Link Here
1592
			*intptr = value;
1629
			*intptr = value;
1593
		break;
1630
		break;
1594
1631
1632
	case sInclude:
1633
		if (cmdline)
1634
			fatal("Include directive not supported as a command-line "
1635
			   "option");
1636
1637
		value = 0;
1638
		while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
1639
			value++;
1640
			found = 0;
1641
			if (*arg != '/' && *arg != '~') {
1642
				xasprintf(&arg2, "%s/%s",
1643
				    SSHDIR, arg);
1644
			} else
1645
				arg2 = xstrdup(arg);
1646
1647
			/*
1648
			 * don't let the Match in Included clobber
1649
			 * the containing file's Match state.
1650
			 */
1651
			oactive = *activep;
1652
			/* browse cached list of files */
1653
			for (item = include_list; item != NULL; item = item->next) {
1654
				if (strcmp(item->selector, arg2) == 0) {
1655
					if (item->filename != NULL)
1656
						parse_server_config_depth(options, item->filename,
1657
							&(item->buffer), connectinfo,
1658
						    (oactive ? 0 : SSHCFG_NEVERMATCH),
1659
						    activep, depth + 1);
1660
					found = 1;
1661
					*activep = oactive;
1662
				}
1663
			}
1664
			if (found != 0) {
1665
				free(arg2);
1666
				continue;
1667
			}
1668
1669
			/* not in cache, a new glob */
1670
			debug3("Glob configuration file to include %s", arg2);
1671
			if (glob(arg2, 0, NULL, &gbuf) == 0) {
1672
				for (i = 0; i < gbuf.gl_pathc; i++) {
1673
					debug3("Including configuration file %s",
1674
						gbuf.gl_pathv[i]);
1675
					item = malloc(sizeof(struct include_item));
1676
					item->selector = strdup(arg2);
1677
					item->filename = strdup(gbuf.gl_pathv[i]);
1678
					buffer_init(&(item->buffer));
1679
					load_server_config(item->filename, &(item->buffer));
1680
					parse_server_config_depth(options, item->filename,
1681
						&(item->buffer), connectinfo,
1682
					    (oactive ? 0 : SSHCFG_NEVERMATCH),
1683
					    activep, depth + 1);
1684
1685
					// append item to the end of the list
1686
					INCLUDE_LIST_APPEND(item)
1687
					*activep = oactive;
1688
				}
1689
			} else { /* no match or other error */
1690
				// store placeholder to avoid aditional empty globs
1691
				item = malloc(sizeof(struct include_item));
1692
				item->selector = strdup(arg2);
1693
				item->filename = NULL;
1694
				buffer_init(&(item->buffer));
1695
				// append item to the end of the list
1696
				INCLUDE_LIST_APPEND(item)
1697
			}
1698
			globfree(&gbuf);
1699
			free(arg2);
1700
		}
1701
		if (value == 0)
1702
			fatal("%s line %d: missing argument - file to include",
1703
			    filename, linenum);
1704
		break;
1705
1595
	case sMatch:
1706
	case sMatch:
1596
		if (cmdline)
1707
		if (cmdline)
1597
			fatal("Match directive not supported as a command-line "
1708
			fatal("Match directive not supported as a command-line "
Lines 1600-1606 process_server_config_line(ServerOptions *options, char *line, Link Here
1600
		if (value < 0)
1711
		if (value < 0)
1601
			fatal("%s line %d: Bad Match condition", filename,
1712
			fatal("%s line %d: Bad Match condition", filename,
1602
			    linenum);
1713
			    linenum);
1603
		*activep = value;
1714
		*activep = (inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
1604
		break;
1715
		break;
1605
1716
1606
	case sPermitOpen:
1717
	case sPermitOpen:
Lines 2033-2050 void Link Here
2033
parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
2144
parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
2034
    struct connection_info *connectinfo)
2145
    struct connection_info *connectinfo)
2035
{
2146
{
2036
	int active, linenum, bad_options = 0;
2147
	int active = connectinfo ? 0 : 1;
2148
	parse_server_config_depth(options, filename, conf, connectinfo,
2149
	    0, &active, 0);
2150
}
2151
2152
#define SERVCONF_MAX_DEPTH	16
2153
2154
void
2155
parse_server_config_depth(ServerOptions *options, const char *filename,
2156
    Buffer *conf, struct connection_info *connectinfo,
2157
    int flags, int *activep, int depth)
2158
{
2159
	int linenum, bad_options = 0;
2037
	char *cp, *obuf, *cbuf;
2160
	char *cp, *obuf, *cbuf;
2038
2161
2162
	if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
2163
		fatal("Too many recursive configuration includes");
2164
2039
	debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
2165
	debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
2040
2166
2041
	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
2167
	if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
2042
		fatal("%s: sshbuf_dup_string failed", __func__);
2168
		fatal("%s: sshbuf_dup_string failed", __func__);
2043
	active = connectinfo ? 0 : 1;
2044
	linenum = 1;
2169
	linenum = 1;
2045
	while ((cp = strsep(&cbuf, "\n")) != NULL) {
2170
	while ((cp = strsep(&cbuf, "\n")) != NULL) {
2046
		if (process_server_config_line(options, cp, filename,
2171
		if (process_server_config_line_depth(options, cp, filename,
2047
		    linenum++, &active, connectinfo) != 0)
2172
		    linenum++, activep, connectinfo, flags, depth) != 0)
2048
			bad_options++;
2173
			bad_options++;
2049
	}
2174
	}
2050
	free(obuf);
2175
	free(obuf);
(-)a/servconf.h (+7 lines)
Lines 199-204 struct connection_info { Link Here
199
	int lport;		/* local port */
199
	int lport;		/* local port */
200
};
200
};
201
201
202
struct include_item {
203
	const char *selector;
204
	const char *filename;
205
	Buffer buffer;
206
	struct include_item *next;
207
};
208
202
209
203
/*
210
/*
204
 * These are string config options that must be copied between the
211
 * These are string config options that must be copied between the
(-)a/sshd_config.5 (+12 lines)
Lines 778-783 during Link Here
778
.Cm HostbasedAuthentication .
778
.Cm HostbasedAuthentication .
779
The default is
779
The default is
780
.Dq no .
780
.Dq no .
781
.It Cm Include
782
Include the specified configuration file(s).
783
Multiple path names may be specified and each pathname may contain
784
.Xr glob 3
785
wildcards.
786
Files without absolute paths are assumed to be in
787
.Pa /etc/ssh .
788
.Cm Include
789
directive may appear inside a
790
.Cm Match
791
block
792
to perform conditional inclusion.
781
.It Cm IPQoS
793
.It Cm IPQoS
782
Specifies the IPv4 type-of-service or DSCP class for the connection.
794
Specifies the IPv4 type-of-service or DSCP class for the connection.
783
Accepted values are
795
Accepted values are

Return to bug 2468