summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2020-01-31 22:42:45 +0000
committerDamien Miller <djm@mindrot.org>2020-02-01 10:20:24 +1100
commitc2bd7f74b0e0f3a3ee9d19ac549e6ba89013abaf (patch)
treef90d36f2501a863ff0c3d1041d93a2ef827c54d1
parentba261a1dd33266168ead4f8f40446dcece4d1600 (diff)
upstream: Add a sshd_config "Include" directive to allow inclusion
of files. This has sensible semantics wrt Match blocks and accepts glob(3) patterns to specify the included files. Based on patch by Jakub Jelen in bz2468; feedback and ok markus@ OpenBSD-Commit-ID: 36ed0e845b872e33f03355b936a4fff02d5794ff
-rw-r--r--auth.c5
-rw-r--r--servconf.c167
-rw-r--r--servconf.h20
-rw-r--r--sshd.c65
-rw-r--r--sshd_config.519
5 files changed, 232 insertions, 44 deletions
diff --git a/auth.c b/auth.c
index b42d7e76c..086b8ebb1 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth.c,v 1.145 2020/01/23 07:10:22 dtucker Exp $ */ 1/* $OpenBSD: auth.c,v 1.146 2020/01/31 22:42:45 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -79,6 +79,7 @@
79 79
80/* import */ 80/* import */
81extern ServerOptions options; 81extern ServerOptions options;
82extern struct include_list includes;
82extern int use_privsep; 83extern int use_privsep;
83extern struct sshbuf *loginmsg; 84extern struct sshbuf *loginmsg;
84extern struct passwd *privsep_pw; 85extern struct passwd *privsep_pw;
@@ -571,7 +572,7 @@ getpwnamallow(struct ssh *ssh, const char *user)
571 572
572 ci = get_connection_info(ssh, 1, options.use_dns); 573 ci = get_connection_info(ssh, 1, options.use_dns);
573 ci->user = user; 574 ci->user = user;
574 parse_server_match_config(&options, ci); 575 parse_server_match_config(&options, &includes, ci);
575 log_change_level(options.log_level); 576 log_change_level(options.log_level);
576 process_permitopen(ssh, &options); 577 process_permitopen(ssh, &options);
577 578
diff --git a/servconf.c b/servconf.c
index 1e0718139..70f5f73f0 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
1 1
2/* $OpenBSD: servconf.c,v 1.359 2020/01/23 10:24:29 dtucker Exp $ */ 2/* $OpenBSD: servconf.c,v 1.360 2020/01/31 22:42:45 djm Exp $ */
3/* 3/*
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved 5 * All rights reserved
@@ -40,6 +40,11 @@
40#ifdef HAVE_UTIL_H 40#ifdef HAVE_UTIL_H
41#include <util.h> 41#include <util.h>
42#endif 42#endif
43#ifdef USE_SYSTEM_GLOB
44# include <glob.h>
45#else
46# include "openbsd-compat/glob.h"
47#endif
43 48
44#include "openbsd-compat/sys-queue.h" 49#include "openbsd-compat/sys-queue.h"
45#include "xmalloc.h" 50#include "xmalloc.h"
@@ -69,6 +74,9 @@ static void add_listen_addr(ServerOptions *, const char *,
69 const char *, int); 74 const char *, int);
70static void add_one_listen_addr(ServerOptions *, const char *, 75static void add_one_listen_addr(ServerOptions *, const char *,
71 const char *, int); 76 const char *, int);
77void parse_server_config_depth(ServerOptions *options, const char *filename,
78 struct sshbuf *conf, struct include_list *includes,
79 struct connection_info *connectinfo, int flags, int *activep, int depth);
72 80
73/* Use of privilege separation or not */ 81/* Use of privilege separation or not */
74extern int use_privsep; 82extern int use_privsep;
@@ -526,7 +534,7 @@ typedef enum {
526 sAcceptEnv, sSetEnv, sPermitTunnel, 534 sAcceptEnv, sSetEnv, sPermitTunnel,
527 sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, 535 sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
528 sUsePrivilegeSeparation, sAllowAgentForwarding, 536 sUsePrivilegeSeparation, sAllowAgentForwarding,
529 sHostCertificate, 537 sHostCertificate, sInclude,
530 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, 538 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
531 sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, 539 sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
532 sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum, 540 sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
@@ -538,9 +546,10 @@ typedef enum {
538 sDeprecated, sIgnore, sUnsupported 546 sDeprecated, sIgnore, sUnsupported
539} ServerOpCodes; 547} ServerOpCodes;
540 548
541#define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */ 549#define SSHCFG_GLOBAL 0x01 /* allowed in main section of config */
542#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ 550#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
543#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) 551#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
552#define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */
544 553
545/* Textual representation of the tokens. */ 554/* Textual representation of the tokens. */
546static struct { 555static struct {
@@ -669,6 +678,7 @@ static struct {
669 { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, 678 { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
670 { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, 679 { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
671 { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, 680 { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
681 { "include", sInclude, SSHCFG_ALL },
672 { "ipqos", sIPQoS, SSHCFG_ALL }, 682 { "ipqos", sIPQoS, SSHCFG_ALL },
673 { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, 683 { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
674 { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, 684 { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
@@ -1240,13 +1250,14 @@ static const struct multistate multistate_tcpfwd[] = {
1240 { NULL, -1 } 1250 { NULL, -1 }
1241}; 1251};
1242 1252
1243int 1253static int
1244process_server_config_line(ServerOptions *options, char *line, 1254process_server_config_line_depth(ServerOptions *options, char *line,
1245 const char *filename, int linenum, int *activep, 1255 const char *filename, int linenum, int *activep,
1246 struct connection_info *connectinfo) 1256 struct connection_info *connectinfo, int inc_flags, int depth,
1257 struct include_list *includes)
1247{ 1258{
1248 char ch, *cp, ***chararrayptr, **charptr, *arg, *arg2, *p; 1259 char ch, *cp, ***chararrayptr, **charptr, *arg, *arg2, *p;
1249 int cmdline = 0, *intptr, value, value2, n, port; 1260 int cmdline = 0, *intptr, value, value2, n, port, oactive, r, found;
1250 SyslogFacility *log_facility_ptr; 1261 SyslogFacility *log_facility_ptr;
1251 LogLevel *log_level_ptr; 1262 LogLevel *log_level_ptr;
1252 ServerOpCodes opcode; 1263 ServerOpCodes opcode;
@@ -1255,6 +1266,8 @@ process_server_config_line(ServerOptions *options, char *line,
1255 long long val64; 1266 long long val64;
1256 const struct multistate *multistate_ptr; 1267 const struct multistate *multistate_ptr;
1257 const char *errstr; 1268 const char *errstr;
1269 struct include_item *item;
1270 glob_t gbuf;
1258 1271
1259 /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ 1272 /* Strip trailing whitespace. Allow \f (form feed) at EOL only */
1260 if ((len = strlen(line)) == 0) 1273 if ((len = strlen(line)) == 0)
@@ -1281,7 +1294,7 @@ process_server_config_line(ServerOptions *options, char *line,
1281 cmdline = 1; 1294 cmdline = 1;
1282 activep = &cmdline; 1295 activep = &cmdline;
1283 } 1296 }
1284 if (*activep && opcode != sMatch) 1297 if (*activep && opcode != sMatch && opcode != sInclude)
1285 debug3("%s:%d setting %s %s", filename, linenum, arg, cp); 1298 debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
1286 if (*activep == 0 && !(flags & SSHCFG_MATCH)) { 1299 if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
1287 if (connectinfo == NULL) { 1300 if (connectinfo == NULL) {
@@ -1954,6 +1967,96 @@ process_server_config_line(ServerOptions *options, char *line,
1954 *intptr = value; 1967 *intptr = value;
1955 break; 1968 break;
1956 1969
1970 case sInclude:
1971 if (cmdline) {
1972 fatal("Include directive not supported as a "
1973 "command-line option");
1974 }
1975 value = 0;
1976 while ((arg2 = strdelim(&cp)) != NULL && *arg2 != '\0') {
1977 value++;
1978 found = 0;
1979 if (*arg2 != '/' && *arg2 != '~') {
1980 xasprintf(&arg, "%s/%s", SSHDIR, arg);
1981 } else
1982 arg = xstrdup(arg2);
1983
1984 /*
1985 * Don't let included files clobber the containing
1986 * file's Match state.
1987 */
1988 oactive = *activep;
1989
1990 /* consult cache of include files */
1991 TAILQ_FOREACH(item, includes, entry) {
1992 if (strcmp(item->selector, arg) != 0)
1993 continue;
1994 if (item->filename != NULL) {
1995 parse_server_config_depth(options,
1996 item->filename, item->contents,
1997 includes, connectinfo,
1998 (oactive ? 0 : SSHCFG_NEVERMATCH),
1999 activep, depth + 1);
2000 }
2001 found = 1;
2002 *activep = oactive;
2003 }
2004 if (found != 0) {
2005 free(arg);
2006 continue;
2007 }
2008
2009 /* requested glob was not in cache */
2010 debug2("%s line %d: new include %s",
2011 filename, linenum, arg);
2012 if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
2013 if (r != GLOB_NOMATCH) {
2014 fatal("%s line %d: include \"%s\" "
2015 "glob failed", filename,
2016 linenum, arg);
2017 }
2018 /*
2019 * If no entry matched then record a
2020 * placeholder to skip later glob calls.
2021 */
2022 debug2("%s line %d: no match for %s",
2023 filename, linenum, arg);
2024 item = xcalloc(1, sizeof(*item));
2025 item->selector = strdup(arg);
2026 TAILQ_INSERT_TAIL(includes,
2027 item, entry);
2028 }
2029 if (gbuf.gl_pathc > INT_MAX)
2030 fatal("%s: too many glob results", __func__);
2031 for (n = 0; n < (int)gbuf.gl_pathc; n++) {
2032 debug2("%s line %d: including %s",
2033 filename, linenum, gbuf.gl_pathv[n]);
2034 item = xcalloc(1, sizeof(*item));
2035 item->selector = strdup(arg);
2036 item->filename = strdup(gbuf.gl_pathv[n]);
2037 if ((item->contents = sshbuf_new()) == NULL) {
2038 fatal("%s: sshbuf_new failed",
2039 __func__);
2040 }
2041 load_server_config(item->filename,
2042 item->contents);
2043 parse_server_config_depth(options,
2044 item->filename, item->contents,
2045 includes, connectinfo,
2046 (oactive ? 0 : SSHCFG_NEVERMATCH),
2047 activep, depth + 1);
2048 *activep = oactive;
2049 TAILQ_INSERT_TAIL(includes, item, entry);
2050 }
2051 globfree(&gbuf);
2052 free(arg);
2053 }
2054 if (value == 0) {
2055 fatal("%s line %d: Include missing filename argument",
2056 filename, linenum);
2057 }
2058 break;
2059
1957 case sMatch: 2060 case sMatch:
1958 if (cmdline) 2061 if (cmdline)
1959 fatal("Match directive not supported as a command-line " 2062 fatal("Match directive not supported as a command-line "
@@ -1962,7 +2065,7 @@ process_server_config_line(ServerOptions *options, char *line,
1962 if (value < 0) 2065 if (value < 0)
1963 fatal("%s line %d: Bad Match condition", filename, 2066 fatal("%s line %d: Bad Match condition", filename,
1964 linenum); 2067 linenum);
1965 *activep = value; 2068 *activep = (inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
1966 break; 2069 break;
1967 2070
1968 case sPermitListen: 2071 case sPermitListen:
@@ -2256,6 +2359,16 @@ process_server_config_line(ServerOptions *options, char *line,
2256 return 0; 2359 return 0;
2257} 2360}
2258 2361
2362int
2363process_server_config_line(ServerOptions *options, char *line,
2364 const char *filename, int linenum, int *activep,
2365 struct connection_info *connectinfo, struct include_list *includes)
2366{
2367 return process_server_config_line_depth(options, line, filename,
2368 linenum, activep, connectinfo, 0, 0, includes);
2369}
2370
2371
2259/* Reads the server configuration file. */ 2372/* Reads the server configuration file. */
2260 2373
2261void 2374void
@@ -2294,12 +2407,13 @@ load_server_config(const char *filename, struct sshbuf *conf)
2294 2407
2295void 2408void
2296parse_server_match_config(ServerOptions *options, 2409parse_server_match_config(ServerOptions *options,
2297 struct connection_info *connectinfo) 2410 struct include_list *includes, struct connection_info *connectinfo)
2298{ 2411{
2299 ServerOptions mo; 2412 ServerOptions mo;
2300 2413
2301 initialize_server_options(&mo); 2414 initialize_server_options(&mo);
2302 parse_server_config(&mo, "reprocess config", cfg, connectinfo); 2415 parse_server_config(&mo, "reprocess config", cfg, includes,
2416 connectinfo);
2303 copy_set_server_options(options, &mo, 0); 2417 copy_set_server_options(options, &mo, 0);
2304} 2418}
2305 2419
@@ -2443,22 +2557,27 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
2443#undef M_CP_STROPT 2557#undef M_CP_STROPT
2444#undef M_CP_STRARRAYOPT 2558#undef M_CP_STRARRAYOPT
2445 2559
2560#define SERVCONF_MAX_DEPTH 16
2446void 2561void
2447parse_server_config(ServerOptions *options, const char *filename, 2562parse_server_config_depth(ServerOptions *options, const char *filename,
2448 struct sshbuf *conf, struct connection_info *connectinfo) 2563 struct sshbuf *conf, struct include_list *includes,
2564 struct connection_info *connectinfo, int flags, int *activep, int depth)
2449{ 2565{
2450 int active, linenum, bad_options = 0; 2566 int linenum, bad_options = 0;
2451 char *cp, *obuf, *cbuf; 2567 char *cp, *obuf, *cbuf;
2452 2568
2569 if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
2570 fatal("Too many recursive configuration includes");
2571
2453 debug2("%s: config %s len %zu", __func__, filename, sshbuf_len(conf)); 2572 debug2("%s: config %s len %zu", __func__, filename, sshbuf_len(conf));
2454 2573
2455 if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL) 2574 if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
2456 fatal("%s: sshbuf_dup_string failed", __func__); 2575 fatal("%s: sshbuf_dup_string failed", __func__);
2457 active = connectinfo ? 0 : 1;
2458 linenum = 1; 2576 linenum = 1;
2459 while ((cp = strsep(&cbuf, "\n")) != NULL) { 2577 while ((cp = strsep(&cbuf, "\n")) != NULL) {
2460 if (process_server_config_line(options, cp, filename, 2578 if (process_server_config_line_depth(options, cp,
2461 linenum++, &active, connectinfo) != 0) 2579 filename, linenum++, activep, connectinfo, flags,
2580 depth, includes) != 0)
2462 bad_options++; 2581 bad_options++;
2463 } 2582 }
2464 free(obuf); 2583 free(obuf);
@@ -2468,6 +2587,16 @@ parse_server_config(ServerOptions *options, const char *filename,
2468 process_queued_listen_addrs(options); 2587 process_queued_listen_addrs(options);
2469} 2588}
2470 2589
2590void
2591parse_server_config(ServerOptions *options, const char *filename,
2592 struct sshbuf *conf, struct include_list *includes,
2593 struct connection_info *connectinfo)
2594{
2595 int active = connectinfo ? 0 : 1;
2596 parse_server_config_depth(options, filename, conf, includes,
2597 connectinfo, 0, &active, 0);
2598}
2599
2471static const char * 2600static const char *
2472fmt_multistate_int(int val, const struct multistate *m) 2601fmt_multistate_int(int val, const struct multistate *m)
2473{ 2602{
diff --git a/servconf.h b/servconf.h
index 6fc1efb2c..deda09d93 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.h,v 1.142 2019/12/15 18:57:30 djm Exp $ */ 1/* $OpenBSD: servconf.h,v 1.143 2020/01/31 22:42:45 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -16,6 +16,8 @@
16#ifndef SERVCONF_H 16#ifndef SERVCONF_H
17#define SERVCONF_H 17#define SERVCONF_H
18 18
19#include <sys/queue.h>
20
19#define MAX_PORTS 256 /* Max # ports. */ 21#define MAX_PORTS 256 /* Max # ports. */
20 22
21#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ 23#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
@@ -230,6 +232,15 @@ struct connection_info {
230 * unspecified */ 232 * unspecified */
231}; 233};
232 234
235/* List of included files for re-exec from the parsed configuration */
236struct include_item {
237 char *selector;
238 char *filename;
239 struct sshbuf *contents;
240 TAILQ_ENTRY(include_item) entry;
241};
242TAILQ_HEAD(include_list, include_item);
243
233 244
234/* 245/*
235 * These are string config options that must be copied between the 246 * These are string config options that must be copied between the
@@ -269,12 +280,13 @@ struct connection_info *get_connection_info(struct ssh *, int, int);
269void initialize_server_options(ServerOptions *); 280void initialize_server_options(ServerOptions *);
270void fill_default_server_options(ServerOptions *); 281void fill_default_server_options(ServerOptions *);
271int process_server_config_line(ServerOptions *, char *, const char *, int, 282int process_server_config_line(ServerOptions *, char *, const char *, int,
272 int *, struct connection_info *); 283 int *, struct connection_info *, struct include_list *includes);
273void process_permitopen(struct ssh *ssh, ServerOptions *options); 284void process_permitopen(struct ssh *ssh, ServerOptions *options);
274void load_server_config(const char *, struct sshbuf *); 285void load_server_config(const char *, struct sshbuf *);
275void parse_server_config(ServerOptions *, const char *, struct sshbuf *, 286void parse_server_config(ServerOptions *, const char *, struct sshbuf *,
276 struct connection_info *); 287 struct include_list *includes, struct connection_info *);
277void parse_server_match_config(ServerOptions *, struct connection_info *); 288void parse_server_match_config(ServerOptions *,
289 struct include_list *includes, struct connection_info *);
278int parse_server_match_testspec(struct connection_info *, char *); 290int parse_server_match_testspec(struct connection_info *, char *);
279int server_match_spec_complete(struct connection_info *); 291int server_match_spec_complete(struct connection_info *);
280void copy_set_server_options(ServerOptions *, ServerOptions *, int); 292void copy_set_server_options(ServerOptions *, ServerOptions *, int);
diff --git a/sshd.c b/sshd.c
index 46fdf7ee3..57fab0425 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshd.c,v 1.545 2020/01/24 23:56:01 djm Exp $ */ 1/* $OpenBSD: sshd.c,v 1.546 2020/01/31 22:42:45 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -251,6 +251,9 @@ struct sshauthopt *auth_opts = NULL;
251/* sshd_config buffer */ 251/* sshd_config buffer */
252struct sshbuf *cfg; 252struct sshbuf *cfg;
253 253
254/* Included files from the configuration file */
255struct include_list includes = TAILQ_HEAD_INITIALIZER(includes);
256
254/* message to be displayed after login */ 257/* message to be displayed after login */
255struct sshbuf *loginmsg; 258struct sshbuf *loginmsg;
256 259
@@ -870,30 +873,45 @@ usage(void)
870static void 873static void
871send_rexec_state(int fd, struct sshbuf *conf) 874send_rexec_state(int fd, struct sshbuf *conf)
872{ 875{
873 struct sshbuf *m; 876 struct sshbuf *m = NULL, *inc = NULL;
877 struct include_item *item = NULL;
874 int r; 878 int r;
875 879
876 debug3("%s: entering fd = %d config len %zu", __func__, fd, 880 debug3("%s: entering fd = %d config len %zu", __func__, fd,
877 sshbuf_len(conf)); 881 sshbuf_len(conf));
878 882
883 if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL)
884 fatal("%s: sshbuf_new failed", __func__);
885
886 /* pack includes into a string */
887 TAILQ_FOREACH(item, &includes, entry) {
888 if ((r = sshbuf_put_cstring(inc, item->selector)) != 0 ||
889 (r = sshbuf_put_cstring(inc, item->filename)) != 0 ||
890 (r = sshbuf_put_stringb(inc, item->contents)) != 0)
891 fatal("%s: buffer error: %s", __func__, ssh_err(r));
892 }
893
879 /* 894 /*
880 * Protocol from reexec master to child: 895 * Protocol from reexec master to child:
881 * string configuration 896 * string configuration
882 * string rngseed (only if OpenSSL is not self-seeded) 897 * string included_files[] {
898 * string selector
899 * string filename
900 * string contents
901 * }
902 * string rng_seed (if required)
883 */ 903 */
884 if ((m = sshbuf_new()) == NULL) 904 if ((r = sshbuf_put_stringb(m, conf)) != 0 ||
885 fatal("%s: sshbuf_new failed", __func__); 905 (r = sshbuf_put_stringb(m, inc)) != 0)
886 if ((r = sshbuf_put_stringb(m, conf)) != 0)
887 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 906 fatal("%s: buffer error: %s", __func__, ssh_err(r));
888
889#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY) 907#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY)
890 rexec_send_rng_seed(m); 908 rexec_send_rng_seed(m);
891#endif 909#endif
892
893 if (ssh_msg_send(fd, 0, m) == -1) 910 if (ssh_msg_send(fd, 0, m) == -1)
894 fatal("%s: ssh_msg_send failed", __func__); 911 fatal("%s: ssh_msg_send failed", __func__);
895 912
896 sshbuf_free(m); 913 sshbuf_free(m);
914 sshbuf_free(inc);
897 915
898 debug3("%s: done", __func__); 916 debug3("%s: done", __func__);
899} 917}
@@ -901,14 +919,15 @@ send_rexec_state(int fd, struct sshbuf *conf)
901static void 919static void
902recv_rexec_state(int fd, struct sshbuf *conf) 920recv_rexec_state(int fd, struct sshbuf *conf)
903{ 921{
904 struct sshbuf *m; 922 struct sshbuf *m, *inc;
905 u_char *cp, ver; 923 u_char *cp, ver;
906 size_t len; 924 size_t len;
907 int r; 925 int r;
926 struct include_item *item;
908 927
909 debug3("%s: entering fd = %d", __func__, fd); 928 debug3("%s: entering fd = %d", __func__, fd);
910 929
911 if ((m = sshbuf_new()) == NULL) 930 if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL)
912 fatal("%s: sshbuf_new failed", __func__); 931 fatal("%s: sshbuf_new failed", __func__);
913 if (ssh_msg_recv(fd, m) == -1) 932 if (ssh_msg_recv(fd, m) == -1)
914 fatal("%s: ssh_msg_recv failed", __func__); 933 fatal("%s: ssh_msg_recv failed", __func__);
@@ -916,14 +935,28 @@ recv_rexec_state(int fd, struct sshbuf *conf)
916 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 935 fatal("%s: buffer error: %s", __func__, ssh_err(r));
917 if (ver != 0) 936 if (ver != 0)
918 fatal("%s: rexec version mismatch", __func__); 937 fatal("%s: rexec version mismatch", __func__);
919 if ((r = sshbuf_get_string(m, &cp, &len)) != 0) 938 if ((r = sshbuf_get_string(m, &cp, &len)) != 0 ||
920 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 939 (r = sshbuf_get_stringb(m, inc)) != 0)
921 if (conf != NULL && (r = sshbuf_put(conf, cp, len)))
922 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 940 fatal("%s: buffer error: %s", __func__, ssh_err(r));
941
923#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY) 942#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY)
924 rexec_recv_rng_seed(m); 943 rexec_recv_rng_seed(m);
925#endif 944#endif
926 945
946 if (conf != NULL && (r = sshbuf_put(conf, cp, len)))
947 fatal("%s: buffer error: %s", __func__, ssh_err(r));
948
949 while (sshbuf_len(inc) != 0) {
950 item = xcalloc(1, sizeof(*item));
951 if ((item->contents = sshbuf_new()) == NULL)
952 fatal("%s: sshbuf_new failed", __func__);
953 if ((r = sshbuf_get_cstring(inc, &item->selector, NULL)) != 0 ||
954 (r = sshbuf_get_cstring(inc, &item->filename, NULL)) != 0 ||
955 (r = sshbuf_get_stringb(inc, item->contents)) != 0)
956 fatal("%s: buffer error: %s", __func__, ssh_err(r));
957 TAILQ_INSERT_TAIL(&includes, item, entry);
958 }
959
927 free(cp); 960 free(cp);
928 sshbuf_free(m); 961 sshbuf_free(m);
929 962
@@ -1600,7 +1633,7 @@ main(int ac, char **av)
1600 case 'o': 1633 case 'o':
1601 line = xstrdup(optarg); 1634 line = xstrdup(optarg);
1602 if (process_server_config_line(&options, line, 1635 if (process_server_config_line(&options, line,
1603 "command-line", 0, NULL, NULL) != 0) 1636 "command-line", 0, NULL, NULL, &includes) != 0)
1604 exit(1); 1637 exit(1);
1605 free(line); 1638 free(line);
1606 break; 1639 break;
@@ -1669,7 +1702,7 @@ main(int ac, char **av)
1669 load_server_config(config_file_name, cfg); 1702 load_server_config(config_file_name, cfg);
1670 1703
1671 parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, 1704 parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
1672 cfg, NULL); 1705 cfg, &includes, NULL);
1673 1706
1674 /* Fill in default values for those options not explicitly set. */ 1707 /* Fill in default values for those options not explicitly set. */
1675 fill_default_server_options(&options); 1708 fill_default_server_options(&options);
@@ -1895,7 +1928,7 @@ main(int ac, char **av)
1895 if (connection_info == NULL) 1928 if (connection_info == NULL)
1896 connection_info = get_connection_info(ssh, 0, 0); 1929 connection_info = get_connection_info(ssh, 0, 0);
1897 connection_info->test = 1; 1930 connection_info->test = 1;
1898 parse_server_match_config(&options, connection_info); 1931 parse_server_match_config(&options, &includes, connection_info);
1899 dump_config(&options); 1932 dump_config(&options);
1900 } 1933 }
1901 1934
diff --git a/sshd_config.5 b/sshd_config.5
index 1395a5e6d..6c3b5e5e0 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -33,8 +33,8 @@
33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35.\" 35.\"
36.\" $OpenBSD: sshd_config.5,v 1.303 2020/01/28 01:49:36 djm Exp $ 36.\" $OpenBSD: sshd_config.5,v 1.304 2020/01/31 22:42:45 djm Exp $
37.Dd $Mdocdate: January 28 2020 $ 37.Dd $Mdocdate: January 31 2020 $
38.Dt SSHD_CONFIG 5 38.Dt SSHD_CONFIG 5
39.Os 39.Os
40.Sh NAME 40.Sh NAME
@@ -801,7 +801,20 @@ during
801and use only the system-wide known hosts file 801and use only the system-wide known hosts file
802.Pa /etc/ssh/known_hosts . 802.Pa /etc/ssh/known_hosts .
803The default is 803The default is
804.Cm no . 804.Dq no .
805.It Cm Include
806Include the specified configuration file(s).
807Multiple path names may be specified and each pathname may contain
808.Xr glob 7
809wildcards.
810Files without absolute paths are assumed to be in
811.Pa /etc/ssh .
812A
813.Cm Include
814directive may appear inside a
815.Cm Match
816block
817to perform conditional inclusion.
805.It Cm IPQoS 818.It Cm IPQoS
806Specifies the IPv4 type-of-service or DSCP class for the connection. 819Specifies the IPv4 type-of-service or DSCP class for the connection.
807Accepted values are 820Accepted values are