diff options
Diffstat (limited to 'servconf.c')
-rw-r--r-- | servconf.c | 85 |
1 files changed, 52 insertions, 33 deletions
diff --git a/servconf.c b/servconf.c index ba0a92c7b..f08e37477 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | /* $OpenBSD: servconf.c,v 1.363 2020/04/17 03:30:05 djm Exp $ */ | 2 | /* $OpenBSD: servconf.c,v 1.369 2020/08/28 03:15:52 dtucker 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 |
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <sys/types.h> | 16 | #include <sys/types.h> |
17 | #include <sys/socket.h> | 17 | #include <sys/socket.h> |
18 | #include <sys/stat.h> | ||
18 | #ifdef __OpenBSD__ | 19 | #ifdef __OpenBSD__ |
19 | #include <sys/sysctl.h> | 20 | #include <sys/sysctl.h> |
20 | #endif | 21 | #endif |
@@ -74,8 +75,8 @@ static void add_listen_addr(ServerOptions *, const char *, | |||
74 | const char *, int); | 75 | const char *, int); |
75 | static void add_one_listen_addr(ServerOptions *, const char *, | 76 | static void add_one_listen_addr(ServerOptions *, const char *, |
76 | const char *, int); | 77 | const char *, int); |
77 | void parse_server_config_depth(ServerOptions *options, const char *filename, | 78 | static void parse_server_config_depth(ServerOptions *options, |
78 | struct sshbuf *conf, struct include_list *includes, | 79 | const char *filename, struct sshbuf *conf, struct include_list *includes, |
79 | struct connection_info *connectinfo, int flags, int *activep, int depth); | 80 | struct connection_info *connectinfo, int flags, int *activep, int depth); |
80 | 81 | ||
81 | /* Use of privilege separation or not */ | 82 | /* Use of privilege separation or not */ |
@@ -140,7 +141,7 @@ initialize_server_options(ServerOptions *options) | |||
140 | options->challenge_response_authentication = -1; | 141 | options->challenge_response_authentication = -1; |
141 | options->permit_empty_passwd = -1; | 142 | options->permit_empty_passwd = -1; |
142 | options->permit_user_env = -1; | 143 | options->permit_user_env = -1; |
143 | options->permit_user_env_whitelist = NULL; | 144 | options->permit_user_env_allowlist = NULL; |
144 | options->compression = -1; | 145 | options->compression = -1; |
145 | options->rekey_limit = -1; | 146 | options->rekey_limit = -1; |
146 | options->rekey_interval = -1; | 147 | options->rekey_interval = -1; |
@@ -212,11 +213,11 @@ assemble_algorithms(ServerOptions *o) | |||
212 | all_key = sshkey_alg_list(0, 0, 1, ','); | 213 | all_key = sshkey_alg_list(0, 0, 1, ','); |
213 | all_sig = sshkey_alg_list(0, 1, 1, ','); | 214 | all_sig = sshkey_alg_list(0, 1, 1, ','); |
214 | /* remove unsupported algos from default lists */ | 215 | /* remove unsupported algos from default lists */ |
215 | def_cipher = match_filter_whitelist(KEX_SERVER_ENCRYPT, all_cipher); | 216 | def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher); |
216 | def_mac = match_filter_whitelist(KEX_SERVER_MAC, all_mac); | 217 | def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac); |
217 | def_kex = match_filter_whitelist(KEX_SERVER_KEX, all_kex); | 218 | def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex); |
218 | def_key = match_filter_whitelist(KEX_DEFAULT_PK_ALG, all_key); | 219 | def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); |
219 | def_sig = match_filter_whitelist(SSH_ALLOWED_CA_SIGALGS, all_sig); | 220 | def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); |
220 | #define ASSEMBLE(what, defaults, all) \ | 221 | #define ASSEMBLE(what, defaults, all) \ |
221 | do { \ | 222 | do { \ |
222 | if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \ | 223 | if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \ |
@@ -389,7 +390,7 @@ fill_default_server_options(ServerOptions *options) | |||
389 | options->permit_empty_passwd = 0; | 390 | options->permit_empty_passwd = 0; |
390 | if (options->permit_user_env == -1) { | 391 | if (options->permit_user_env == -1) { |
391 | options->permit_user_env = 0; | 392 | options->permit_user_env = 0; |
392 | options->permit_user_env_whitelist = NULL; | 393 | options->permit_user_env_allowlist = NULL; |
393 | } | 394 | } |
394 | if (options->compression == -1) | 395 | if (options->compression == -1) |
395 | #ifdef WITH_ZLIB | 396 | #ifdef WITH_ZLIB |
@@ -494,15 +495,6 @@ fill_default_server_options(ServerOptions *options) | |||
494 | options->auth_methods[0] = NULL; | 495 | options->auth_methods[0] = NULL; |
495 | options->num_auth_methods = 0; | 496 | options->num_auth_methods = 0; |
496 | } | 497 | } |
497 | |||
498 | #ifndef HAVE_MMAP | ||
499 | if (use_privsep && options->compression == 1) { | ||
500 | error("This platform does not support both privilege " | ||
501 | "separation and compression"); | ||
502 | error("Compression disabled"); | ||
503 | options->compression = 0; | ||
504 | } | ||
505 | #endif | ||
506 | } | 498 | } |
507 | 499 | ||
508 | /* Keyword tokens. */ | 500 | /* Keyword tokens. */ |
@@ -550,6 +542,7 @@ typedef enum { | |||
550 | #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ | 542 | #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ |
551 | #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) | 543 | #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) |
552 | #define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */ | 544 | #define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */ |
545 | #define SSHCFG_MATCH_ONLY 0x08 /* Match only in conditional blocks; internal only */ | ||
553 | 546 | ||
554 | /* Textual representation of the tokens. */ | 547 | /* Textual representation of the tokens. */ |
555 | static struct { | 548 | static struct { |
@@ -1117,6 +1110,9 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
1117 | "%.100s' at line %d", ci->host, arg, line); | 1110 | "%.100s' at line %d", ci->host, arg, line); |
1118 | } else if (strcasecmp(attrib, "address") == 0) { | 1111 | } else if (strcasecmp(attrib, "address") == 0) { |
1119 | if (ci == NULL || (ci->test && ci->address == NULL)) { | 1112 | if (ci == NULL || (ci->test && ci->address == NULL)) { |
1113 | if (addr_match_list(NULL, arg) != 0) | ||
1114 | fatal("Invalid Match address argument " | ||
1115 | "'%s' at line %d", arg, line); | ||
1120 | result = 0; | 1116 | result = 0; |
1121 | continue; | 1117 | continue; |
1122 | } | 1118 | } |
@@ -1136,6 +1132,10 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
1136 | } | 1132 | } |
1137 | } else if (strcasecmp(attrib, "localaddress") == 0){ | 1133 | } else if (strcasecmp(attrib, "localaddress") == 0){ |
1138 | if (ci == NULL || (ci->test && ci->laddress == NULL)) { | 1134 | if (ci == NULL || (ci->test && ci->laddress == NULL)) { |
1135 | if (addr_match_list(NULL, arg) != 0) | ||
1136 | fatal("Invalid Match localaddress " | ||
1137 | "argument '%s' at line %d", arg, | ||
1138 | line); | ||
1139 | result = 0; | 1139 | result = 0; |
1140 | continue; | 1140 | continue; |
1141 | } | 1141 | } |
@@ -1259,7 +1259,7 @@ static const struct multistate multistate_tcpfwd[] = { | |||
1259 | static int | 1259 | static int |
1260 | process_server_config_line_depth(ServerOptions *options, char *line, | 1260 | process_server_config_line_depth(ServerOptions *options, char *line, |
1261 | const char *filename, int linenum, int *activep, | 1261 | const char *filename, int linenum, int *activep, |
1262 | struct connection_info *connectinfo, int inc_flags, int depth, | 1262 | struct connection_info *connectinfo, int *inc_flags, int depth, |
1263 | struct include_list *includes) | 1263 | struct include_list *includes) |
1264 | { | 1264 | { |
1265 | char ch, *cp, ***chararrayptr, **charptr, *arg, *arg2, *p; | 1265 | char ch, *cp, ***chararrayptr, **charptr, *arg, *arg2, *p; |
@@ -1525,6 +1525,8 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
1525 | continue; | 1525 | continue; |
1526 | if (strcasecmp(arg, "touch-required") == 0) | 1526 | if (strcasecmp(arg, "touch-required") == 0) |
1527 | value |= PUBKEYAUTH_TOUCH_REQUIRED; | 1527 | value |= PUBKEYAUTH_TOUCH_REQUIRED; |
1528 | else if (strcasecmp(arg, "verify-required") == 0) | ||
1529 | value |= PUBKEYAUTH_VERIFY_REQUIRED; | ||
1528 | else { | 1530 | else { |
1529 | fatal("%s line %d: unsupported " | 1531 | fatal("%s line %d: unsupported " |
1530 | "PubkeyAuthOptions option %s", | 1532 | "PubkeyAuthOptions option %s", |
@@ -1628,7 +1630,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
1628 | 1630 | ||
1629 | case sPermitUserEnvironment: | 1631 | case sPermitUserEnvironment: |
1630 | intptr = &options->permit_user_env; | 1632 | intptr = &options->permit_user_env; |
1631 | charptr = &options->permit_user_env_whitelist; | 1633 | charptr = &options->permit_user_env_allowlist; |
1632 | arg = strdelim(&cp); | 1634 | arg = strdelim(&cp); |
1633 | if (!arg || *arg == '\0') | 1635 | if (!arg || *arg == '\0') |
1634 | fatal("%s line %d: missing argument.", | 1636 | fatal("%s line %d: missing argument.", |
@@ -2002,7 +2004,9 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
2002 | parse_server_config_depth(options, | 2004 | parse_server_config_depth(options, |
2003 | item->filename, item->contents, | 2005 | item->filename, item->contents, |
2004 | includes, connectinfo, | 2006 | includes, connectinfo, |
2005 | (oactive ? 0 : SSHCFG_NEVERMATCH), | 2007 | (*inc_flags & SSHCFG_MATCH_ONLY |
2008 | ? SSHCFG_MATCH_ONLY : (oactive | ||
2009 | ? 0 : SSHCFG_NEVERMATCH)), | ||
2006 | activep, depth + 1); | 2010 | activep, depth + 1); |
2007 | } | 2011 | } |
2008 | found = 1; | 2012 | found = 1; |
@@ -2050,7 +2054,9 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
2050 | parse_server_config_depth(options, | 2054 | parse_server_config_depth(options, |
2051 | item->filename, item->contents, | 2055 | item->filename, item->contents, |
2052 | includes, connectinfo, | 2056 | includes, connectinfo, |
2053 | (oactive ? 0 : SSHCFG_NEVERMATCH), | 2057 | (*inc_flags & SSHCFG_MATCH_ONLY |
2058 | ? SSHCFG_MATCH_ONLY : (oactive | ||
2059 | ? 0 : SSHCFG_NEVERMATCH)), | ||
2054 | activep, depth + 1); | 2060 | activep, depth + 1); |
2055 | *activep = oactive; | 2061 | *activep = oactive; |
2056 | TAILQ_INSERT_TAIL(includes, item, entry); | 2062 | TAILQ_INSERT_TAIL(includes, item, entry); |
@@ -2068,11 +2074,14 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
2068 | if (cmdline) | 2074 | if (cmdline) |
2069 | fatal("Match directive not supported as a command-line " | 2075 | fatal("Match directive not supported as a command-line " |
2070 | "option"); | 2076 | "option"); |
2071 | value = match_cfg_line(&cp, linenum, connectinfo); | 2077 | value = match_cfg_line(&cp, linenum, |
2078 | (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo)); | ||
2072 | if (value < 0) | 2079 | if (value < 0) |
2073 | fatal("%s line %d: Bad Match condition", filename, | 2080 | fatal("%s line %d: Bad Match condition", filename, |
2074 | linenum); | 2081 | linenum); |
2075 | *activep = (inc_flags & SSHCFG_NEVERMATCH) ? 0 : value; | 2082 | *activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value; |
2083 | /* The MATCH_ONLY is applicable only until the first match block */ | ||
2084 | *inc_flags &= ~SSHCFG_MATCH_ONLY; | ||
2076 | break; | 2085 | break; |
2077 | 2086 | ||
2078 | case sPermitListen: | 2087 | case sPermitListen: |
@@ -2375,8 +2384,10 @@ process_server_config_line(ServerOptions *options, char *line, | |||
2375 | const char *filename, int linenum, int *activep, | 2384 | const char *filename, int linenum, int *activep, |
2376 | struct connection_info *connectinfo, struct include_list *includes) | 2385 | struct connection_info *connectinfo, struct include_list *includes) |
2377 | { | 2386 | { |
2387 | int inc_flags = 0; | ||
2388 | |||
2378 | return process_server_config_line_depth(options, line, filename, | 2389 | return process_server_config_line_depth(options, line, filename, |
2379 | linenum, activep, connectinfo, 0, 0, includes); | 2390 | linenum, activep, connectinfo, &inc_flags, 0, includes); |
2380 | } | 2391 | } |
2381 | 2392 | ||
2382 | 2393 | ||
@@ -2385,6 +2396,7 @@ process_server_config_line(ServerOptions *options, char *line, | |||
2385 | void | 2396 | void |
2386 | load_server_config(const char *filename, struct sshbuf *conf) | 2397 | load_server_config(const char *filename, struct sshbuf *conf) |
2387 | { | 2398 | { |
2399 | struct stat st; | ||
2388 | char *line = NULL, *cp; | 2400 | char *line = NULL, *cp; |
2389 | size_t linesize = 0; | 2401 | size_t linesize = 0; |
2390 | FILE *f; | 2402 | FILE *f; |
@@ -2396,6 +2408,10 @@ load_server_config(const char *filename, struct sshbuf *conf) | |||
2396 | exit(1); | 2408 | exit(1); |
2397 | } | 2409 | } |
2398 | sshbuf_reset(conf); | 2410 | sshbuf_reset(conf); |
2411 | /* grow buffer, so realloc is avoided for large config files */ | ||
2412 | if (fstat(fileno(f), &st) == 0 && st.st_size > 0 && | ||
2413 | (r = sshbuf_allocate(conf, st.st_size)) != 0) | ||
2414 | fatal("%s: allocate failed: %s", __func__, ssh_err(r)); | ||
2399 | while (getline(&line, &linesize, f) != -1) { | 2415 | while (getline(&line, &linesize, f) != -1) { |
2400 | lineno++; | 2416 | lineno++; |
2401 | /* | 2417 | /* |
@@ -2570,7 +2586,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) | |||
2570 | #undef M_CP_STRARRAYOPT | 2586 | #undef M_CP_STRARRAYOPT |
2571 | 2587 | ||
2572 | #define SERVCONF_MAX_DEPTH 16 | 2588 | #define SERVCONF_MAX_DEPTH 16 |
2573 | void | 2589 | static void |
2574 | parse_server_config_depth(ServerOptions *options, const char *filename, | 2590 | parse_server_config_depth(ServerOptions *options, const char *filename, |
2575 | struct sshbuf *conf, struct include_list *includes, | 2591 | struct sshbuf *conf, struct include_list *includes, |
2576 | struct connection_info *connectinfo, int flags, int *activep, int depth) | 2592 | struct connection_info *connectinfo, int flags, int *activep, int depth) |
@@ -2581,14 +2597,15 @@ parse_server_config_depth(ServerOptions *options, const char *filename, | |||
2581 | if (depth < 0 || depth > SERVCONF_MAX_DEPTH) | 2597 | if (depth < 0 || depth > SERVCONF_MAX_DEPTH) |
2582 | fatal("Too many recursive configuration includes"); | 2598 | fatal("Too many recursive configuration includes"); |
2583 | 2599 | ||
2584 | debug2("%s: config %s len %zu", __func__, filename, sshbuf_len(conf)); | 2600 | debug2("%s: config %s len %zu%s", __func__, filename, sshbuf_len(conf), |
2601 | (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : "")); | ||
2585 | 2602 | ||
2586 | if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL) | 2603 | if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL) |
2587 | fatal("%s: sshbuf_dup_string failed", __func__); | 2604 | fatal("%s: sshbuf_dup_string failed", __func__); |
2588 | linenum = 1; | 2605 | linenum = 1; |
2589 | while ((cp = strsep(&cbuf, "\n")) != NULL) { | 2606 | while ((cp = strsep(&cbuf, "\n")) != NULL) { |
2590 | if (process_server_config_line_depth(options, cp, | 2607 | if (process_server_config_line_depth(options, cp, |
2591 | filename, linenum++, activep, connectinfo, flags, | 2608 | filename, linenum++, activep, connectinfo, &flags, |
2592 | depth, includes) != 0) | 2609 | depth, includes) != 0) |
2593 | bad_options++; | 2610 | bad_options++; |
2594 | } | 2611 | } |
@@ -2596,7 +2613,6 @@ parse_server_config_depth(ServerOptions *options, const char *filename, | |||
2596 | if (bad_options > 0) | 2613 | if (bad_options > 0) |
2597 | fatal("%s: terminating, %d bad configuration options", | 2614 | fatal("%s: terminating, %d bad configuration options", |
2598 | filename, bad_options); | 2615 | filename, bad_options); |
2599 | process_queued_listen_addrs(options); | ||
2600 | } | 2616 | } |
2601 | 2617 | ||
2602 | void | 2618 | void |
@@ -2606,7 +2622,8 @@ parse_server_config(ServerOptions *options, const char *filename, | |||
2606 | { | 2622 | { |
2607 | int active = connectinfo ? 0 : 1; | 2623 | int active = connectinfo ? 0 : 1; |
2608 | parse_server_config_depth(options, filename, conf, includes, | 2624 | parse_server_config_depth(options, filename, conf, includes, |
2609 | connectinfo, 0, &active, 0); | 2625 | connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0); |
2626 | process_queued_listen_addrs(options); | ||
2610 | } | 2627 | } |
2611 | 2628 | ||
2612 | static const char * | 2629 | static const char * |
@@ -2908,11 +2925,11 @@ dump_config(ServerOptions *o) | |||
2908 | } | 2925 | } |
2909 | printf("\n"); | 2926 | printf("\n"); |
2910 | 2927 | ||
2911 | if (o->permit_user_env_whitelist == NULL) { | 2928 | if (o->permit_user_env_allowlist == NULL) { |
2912 | dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); | 2929 | dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); |
2913 | } else { | 2930 | } else { |
2914 | printf("permituserenvironment %s\n", | 2931 | printf("permituserenvironment %s\n", |
2915 | o->permit_user_env_whitelist); | 2932 | o->permit_user_env_allowlist); |
2916 | } | 2933 | } |
2917 | 2934 | ||
2918 | printf("pubkeyauthoptions"); | 2935 | printf("pubkeyauthoptions"); |
@@ -2920,5 +2937,7 @@ dump_config(ServerOptions *o) | |||
2920 | printf(" none"); | 2937 | printf(" none"); |
2921 | if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED) | 2938 | if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED) |
2922 | printf(" touch-required"); | 2939 | printf(" touch-required"); |
2940 | if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED) | ||
2941 | printf(" verify-required"); | ||
2923 | printf("\n"); | 2942 | printf("\n"); |
2924 | } | 2943 | } |