diff options
-rw-r--r-- | auth.c | 5 | ||||
-rw-r--r-- | servconf.c | 167 | ||||
-rw-r--r-- | servconf.h | 20 | ||||
-rw-r--r-- | sshd.c | 65 | ||||
-rw-r--r-- | sshd_config.5 | 19 |
5 files changed, 232 insertions, 44 deletions
@@ -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 */ |
81 | extern ServerOptions options; | 81 | extern ServerOptions options; |
82 | extern struct include_list includes; | ||
82 | extern int use_privsep; | 83 | extern int use_privsep; |
83 | extern struct sshbuf *loginmsg; | 84 | extern struct sshbuf *loginmsg; |
84 | extern struct passwd *privsep_pw; | 85 | extern 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); |
70 | static void add_one_listen_addr(ServerOptions *, const char *, | 75 | static void add_one_listen_addr(ServerOptions *, const char *, |
71 | const char *, int); | 76 | const char *, int); |
77 | void 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 */ |
74 | extern int use_privsep; | 82 | extern 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. */ |
546 | static struct { | 555 | static 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 | ||
1243 | int | 1253 | static int |
1244 | process_server_config_line(ServerOptions *options, char *line, | 1254 | process_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 | ||
2362 | int | ||
2363 | process_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 | ||
2261 | void | 2374 | void |
@@ -2294,12 +2407,13 @@ load_server_config(const char *filename, struct sshbuf *conf) | |||
2294 | 2407 | ||
2295 | void | 2408 | void |
2296 | parse_server_match_config(ServerOptions *options, | 2409 | parse_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 | ||
2446 | void | 2561 | void |
2447 | parse_server_config(ServerOptions *options, const char *filename, | 2562 | parse_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 | ||
2590 | void | ||
2591 | parse_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 | |||
2471 | static const char * | 2600 | static const char * |
2472 | fmt_multistate_int(int val, const struct multistate *m) | 2601 | fmt_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 */ | ||
236 | struct include_item { | ||
237 | char *selector; | ||
238 | char *filename; | ||
239 | struct sshbuf *contents; | ||
240 | TAILQ_ENTRY(include_item) entry; | ||
241 | }; | ||
242 | TAILQ_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); | |||
269 | void initialize_server_options(ServerOptions *); | 280 | void initialize_server_options(ServerOptions *); |
270 | void fill_default_server_options(ServerOptions *); | 281 | void fill_default_server_options(ServerOptions *); |
271 | int process_server_config_line(ServerOptions *, char *, const char *, int, | 282 | int process_server_config_line(ServerOptions *, char *, const char *, int, |
272 | int *, struct connection_info *); | 283 | int *, struct connection_info *, struct include_list *includes); |
273 | void process_permitopen(struct ssh *ssh, ServerOptions *options); | 284 | void process_permitopen(struct ssh *ssh, ServerOptions *options); |
274 | void load_server_config(const char *, struct sshbuf *); | 285 | void load_server_config(const char *, struct sshbuf *); |
275 | void parse_server_config(ServerOptions *, const char *, struct sshbuf *, | 286 | void parse_server_config(ServerOptions *, const char *, struct sshbuf *, |
276 | struct connection_info *); | 287 | struct include_list *includes, struct connection_info *); |
277 | void parse_server_match_config(ServerOptions *, struct connection_info *); | 288 | void parse_server_match_config(ServerOptions *, |
289 | struct include_list *includes, struct connection_info *); | ||
278 | int parse_server_match_testspec(struct connection_info *, char *); | 290 | int parse_server_match_testspec(struct connection_info *, char *); |
279 | int server_match_spec_complete(struct connection_info *); | 291 | int server_match_spec_complete(struct connection_info *); |
280 | void copy_set_server_options(ServerOptions *, ServerOptions *, int); | 292 | void copy_set_server_options(ServerOptions *, ServerOptions *, int); |
@@ -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 */ |
252 | struct sshbuf *cfg; | 252 | struct sshbuf *cfg; |
253 | 253 | ||
254 | /* Included files from the configuration file */ | ||
255 | struct include_list includes = TAILQ_HEAD_INITIALIZER(includes); | ||
256 | |||
254 | /* message to be displayed after login */ | 257 | /* message to be displayed after login */ |
255 | struct sshbuf *loginmsg; | 258 | struct sshbuf *loginmsg; |
256 | 259 | ||
@@ -870,30 +873,45 @@ usage(void) | |||
870 | static void | 873 | static void |
871 | send_rexec_state(int fd, struct sshbuf *conf) | 874 | send_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) | |||
901 | static void | 919 | static void |
902 | recv_rexec_state(int fd, struct sshbuf *conf) | 920 | recv_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 | |||
801 | and use only the system-wide known hosts file | 801 | and use only the system-wide known hosts file |
802 | .Pa /etc/ssh/known_hosts . | 802 | .Pa /etc/ssh/known_hosts . |
803 | The default is | 803 | The default is |
804 | .Cm no . | 804 | .Dq no . |
805 | .It Cm Include | ||
806 | Include the specified configuration file(s). | ||
807 | Multiple path names may be specified and each pathname may contain | ||
808 | .Xr glob 7 | ||
809 | wildcards. | ||
810 | Files without absolute paths are assumed to be in | ||
811 | .Pa /etc/ssh . | ||
812 | A | ||
813 | .Cm Include | ||
814 | directive may appear inside a | ||
815 | .Cm Match | ||
816 | block | ||
817 | to perform conditional inclusion. | ||
805 | .It Cm IPQoS | 818 | .It Cm IPQoS |
806 | Specifies the IPv4 type-of-service or DSCP class for the connection. | 819 | Specifies the IPv4 type-of-service or DSCP class for the connection. |
807 | Accepted values are | 820 | Accepted values are |