diff options
Diffstat (limited to 'servconf.c')
-rw-r--r-- | servconf.c | 77 |
1 files changed, 48 insertions, 29 deletions
diff --git a/servconf.c b/servconf.c index 5f3336365..98afcfcec 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | /* $OpenBSD: servconf.c,v 1.364 2020/05/27 21:59:11 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 |
@@ -144,7 +145,7 @@ initialize_server_options(ServerOptions *options) | |||
144 | options->challenge_response_authentication = -1; | 145 | options->challenge_response_authentication = -1; |
145 | options->permit_empty_passwd = -1; | 146 | options->permit_empty_passwd = -1; |
146 | options->permit_user_env = -1; | 147 | options->permit_user_env = -1; |
147 | options->permit_user_env_whitelist = NULL; | 148 | options->permit_user_env_allowlist = NULL; |
148 | options->compression = -1; | 149 | options->compression = -1; |
149 | options->rekey_limit = -1; | 150 | options->rekey_limit = -1; |
150 | options->rekey_interval = -1; | 151 | options->rekey_interval = -1; |
@@ -217,11 +218,11 @@ assemble_algorithms(ServerOptions *o) | |||
217 | all_key = sshkey_alg_list(0, 0, 1, ','); | 218 | all_key = sshkey_alg_list(0, 0, 1, ','); |
218 | all_sig = sshkey_alg_list(0, 1, 1, ','); | 219 | all_sig = sshkey_alg_list(0, 1, 1, ','); |
219 | /* remove unsupported algos from default lists */ | 220 | /* remove unsupported algos from default lists */ |
220 | def_cipher = match_filter_whitelist(KEX_SERVER_ENCRYPT, all_cipher); | 221 | def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher); |
221 | def_mac = match_filter_whitelist(KEX_SERVER_MAC, all_mac); | 222 | def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac); |
222 | def_kex = match_filter_whitelist(KEX_SERVER_KEX, all_kex); | 223 | def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex); |
223 | def_key = match_filter_whitelist(KEX_DEFAULT_PK_ALG, all_key); | 224 | def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); |
224 | def_sig = match_filter_whitelist(SSH_ALLOWED_CA_SIGALGS, all_sig); | 225 | def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); |
225 | #define ASSEMBLE(what, defaults, all) \ | 226 | #define ASSEMBLE(what, defaults, all) \ |
226 | do { \ | 227 | do { \ |
227 | if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \ | 228 | if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \ |
@@ -402,7 +403,7 @@ fill_default_server_options(ServerOptions *options) | |||
402 | options->permit_empty_passwd = 0; | 403 | options->permit_empty_passwd = 0; |
403 | if (options->permit_user_env == -1) { | 404 | if (options->permit_user_env == -1) { |
404 | options->permit_user_env = 0; | 405 | options->permit_user_env = 0; |
405 | options->permit_user_env_whitelist = NULL; | 406 | options->permit_user_env_allowlist = NULL; |
406 | } | 407 | } |
407 | if (options->compression == -1) | 408 | if (options->compression == -1) |
408 | #ifdef WITH_ZLIB | 409 | #ifdef WITH_ZLIB |
@@ -509,15 +510,6 @@ fill_default_server_options(ServerOptions *options) | |||
509 | options->auth_methods[0] = NULL; | 510 | options->auth_methods[0] = NULL; |
510 | options->num_auth_methods = 0; | 511 | options->num_auth_methods = 0; |
511 | } | 512 | } |
512 | |||
513 | #ifndef HAVE_MMAP | ||
514 | if (use_privsep && options->compression == 1) { | ||
515 | error("This platform does not support both privilege " | ||
516 | "separation and compression"); | ||
517 | error("Compression disabled"); | ||
518 | options->compression = 0; | ||
519 | } | ||
520 | #endif | ||
521 | } | 513 | } |
522 | 514 | ||
523 | /* Keyword tokens. */ | 515 | /* Keyword tokens. */ |
@@ -567,6 +559,7 @@ typedef enum { | |||
567 | #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ | 559 | #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ |
568 | #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) | 560 | #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) |
569 | #define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */ | 561 | #define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */ |
562 | #define SSHCFG_MATCH_ONLY 0x08 /* Match only in conditional blocks; internal only */ | ||
570 | 563 | ||
571 | /* Textual representation of the tokens. */ | 564 | /* Textual representation of the tokens. */ |
572 | static struct { | 565 | static struct { |
@@ -1146,6 +1139,9 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
1146 | "%.100s' at line %d", ci->host, arg, line); | 1139 | "%.100s' at line %d", ci->host, arg, line); |
1147 | } else if (strcasecmp(attrib, "address") == 0) { | 1140 | } else if (strcasecmp(attrib, "address") == 0) { |
1148 | if (ci == NULL || (ci->test && ci->address == NULL)) { | 1141 | if (ci == NULL || (ci->test && ci->address == NULL)) { |
1142 | if (addr_match_list(NULL, arg) != 0) | ||
1143 | fatal("Invalid Match address argument " | ||
1144 | "'%s' at line %d", arg, line); | ||
1149 | result = 0; | 1145 | result = 0; |
1150 | continue; | 1146 | continue; |
1151 | } | 1147 | } |
@@ -1165,6 +1161,10 @@ match_cfg_line(char **condition, int line, struct connection_info *ci) | |||
1165 | } | 1161 | } |
1166 | } else if (strcasecmp(attrib, "localaddress") == 0){ | 1162 | } else if (strcasecmp(attrib, "localaddress") == 0){ |
1167 | if (ci == NULL || (ci->test && ci->laddress == NULL)) { | 1163 | if (ci == NULL || (ci->test && ci->laddress == NULL)) { |
1164 | if (addr_match_list(NULL, arg) != 0) | ||
1165 | fatal("Invalid Match localaddress " | ||
1166 | "argument '%s' at line %d", arg, | ||
1167 | line); | ||
1168 | result = 0; | 1168 | result = 0; |
1169 | continue; | 1169 | continue; |
1170 | } | 1170 | } |
@@ -1288,7 +1288,7 @@ static const struct multistate multistate_tcpfwd[] = { | |||
1288 | static int | 1288 | static int |
1289 | process_server_config_line_depth(ServerOptions *options, char *line, | 1289 | process_server_config_line_depth(ServerOptions *options, char *line, |
1290 | const char *filename, int linenum, int *activep, | 1290 | const char *filename, int linenum, int *activep, |
1291 | struct connection_info *connectinfo, int inc_flags, int depth, | 1291 | struct connection_info *connectinfo, int *inc_flags, int depth, |
1292 | struct include_list *includes) | 1292 | struct include_list *includes) |
1293 | { | 1293 | { |
1294 | char ch, *cp, ***chararrayptr, **charptr, *arg, *arg2, *p; | 1294 | char ch, *cp, ***chararrayptr, **charptr, *arg, *arg2, *p; |
@@ -1554,6 +1554,8 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
1554 | continue; | 1554 | continue; |
1555 | if (strcasecmp(arg, "touch-required") == 0) | 1555 | if (strcasecmp(arg, "touch-required") == 0) |
1556 | value |= PUBKEYAUTH_TOUCH_REQUIRED; | 1556 | value |= PUBKEYAUTH_TOUCH_REQUIRED; |
1557 | else if (strcasecmp(arg, "verify-required") == 0) | ||
1558 | value |= PUBKEYAUTH_VERIFY_REQUIRED; | ||
1557 | else { | 1559 | else { |
1558 | fatal("%s line %d: unsupported " | 1560 | fatal("%s line %d: unsupported " |
1559 | "PubkeyAuthOptions option %s", | 1561 | "PubkeyAuthOptions option %s", |
@@ -1677,7 +1679,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
1677 | 1679 | ||
1678 | case sPermitUserEnvironment: | 1680 | case sPermitUserEnvironment: |
1679 | intptr = &options->permit_user_env; | 1681 | intptr = &options->permit_user_env; |
1680 | charptr = &options->permit_user_env_whitelist; | 1682 | charptr = &options->permit_user_env_allowlist; |
1681 | arg = strdelim(&cp); | 1683 | arg = strdelim(&cp); |
1682 | if (!arg || *arg == '\0') | 1684 | if (!arg || *arg == '\0') |
1683 | fatal("%s line %d: missing argument.", | 1685 | fatal("%s line %d: missing argument.", |
@@ -2051,7 +2053,9 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
2051 | parse_server_config_depth(options, | 2053 | parse_server_config_depth(options, |
2052 | item->filename, item->contents, | 2054 | item->filename, item->contents, |
2053 | includes, connectinfo, | 2055 | includes, connectinfo, |
2054 | (oactive ? 0 : SSHCFG_NEVERMATCH), | 2056 | (*inc_flags & SSHCFG_MATCH_ONLY |
2057 | ? SSHCFG_MATCH_ONLY : (oactive | ||
2058 | ? 0 : SSHCFG_NEVERMATCH)), | ||
2055 | activep, depth + 1); | 2059 | activep, depth + 1); |
2056 | } | 2060 | } |
2057 | found = 1; | 2061 | found = 1; |
@@ -2099,7 +2103,9 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
2099 | parse_server_config_depth(options, | 2103 | parse_server_config_depth(options, |
2100 | item->filename, item->contents, | 2104 | item->filename, item->contents, |
2101 | includes, connectinfo, | 2105 | includes, connectinfo, |
2102 | (oactive ? 0 : SSHCFG_NEVERMATCH), | 2106 | (*inc_flags & SSHCFG_MATCH_ONLY |
2107 | ? SSHCFG_MATCH_ONLY : (oactive | ||
2108 | ? 0 : SSHCFG_NEVERMATCH)), | ||
2103 | activep, depth + 1); | 2109 | activep, depth + 1); |
2104 | *activep = oactive; | 2110 | *activep = oactive; |
2105 | TAILQ_INSERT_TAIL(includes, item, entry); | 2111 | TAILQ_INSERT_TAIL(includes, item, entry); |
@@ -2117,11 +2123,14 @@ process_server_config_line_depth(ServerOptions *options, char *line, | |||
2117 | if (cmdline) | 2123 | if (cmdline) |
2118 | fatal("Match directive not supported as a command-line " | 2124 | fatal("Match directive not supported as a command-line " |
2119 | "option"); | 2125 | "option"); |
2120 | value = match_cfg_line(&cp, linenum, connectinfo); | 2126 | value = match_cfg_line(&cp, linenum, |
2127 | (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo)); | ||
2121 | if (value < 0) | 2128 | if (value < 0) |
2122 | fatal("%s line %d: Bad Match condition", filename, | 2129 | fatal("%s line %d: Bad Match condition", filename, |
2123 | linenum); | 2130 | linenum); |
2124 | *activep = (inc_flags & SSHCFG_NEVERMATCH) ? 0 : value; | 2131 | *activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value; |
2132 | /* The MATCH_ONLY is applicable only until the first match block */ | ||
2133 | *inc_flags &= ~SSHCFG_MATCH_ONLY; | ||
2125 | break; | 2134 | break; |
2126 | 2135 | ||
2127 | case sPermitListen: | 2136 | case sPermitListen: |
@@ -2428,8 +2437,10 @@ process_server_config_line(ServerOptions *options, char *line, | |||
2428 | const char *filename, int linenum, int *activep, | 2437 | const char *filename, int linenum, int *activep, |
2429 | struct connection_info *connectinfo, struct include_list *includes) | 2438 | struct connection_info *connectinfo, struct include_list *includes) |
2430 | { | 2439 | { |
2440 | int inc_flags = 0; | ||
2441 | |||
2431 | return process_server_config_line_depth(options, line, filename, | 2442 | return process_server_config_line_depth(options, line, filename, |
2432 | linenum, activep, connectinfo, 0, 0, includes); | 2443 | linenum, activep, connectinfo, &inc_flags, 0, includes); |
2433 | } | 2444 | } |
2434 | 2445 | ||
2435 | 2446 | ||
@@ -2438,6 +2449,7 @@ process_server_config_line(ServerOptions *options, char *line, | |||
2438 | void | 2449 | void |
2439 | load_server_config(const char *filename, struct sshbuf *conf) | 2450 | load_server_config(const char *filename, struct sshbuf *conf) |
2440 | { | 2451 | { |
2452 | struct stat st; | ||
2441 | char *line = NULL, *cp; | 2453 | char *line = NULL, *cp; |
2442 | size_t linesize = 0; | 2454 | size_t linesize = 0; |
2443 | FILE *f; | 2455 | FILE *f; |
@@ -2449,6 +2461,10 @@ load_server_config(const char *filename, struct sshbuf *conf) | |||
2449 | exit(1); | 2461 | exit(1); |
2450 | } | 2462 | } |
2451 | sshbuf_reset(conf); | 2463 | sshbuf_reset(conf); |
2464 | /* grow buffer, so realloc is avoided for large config files */ | ||
2465 | if (fstat(fileno(f), &st) == 0 && st.st_size > 0 && | ||
2466 | (r = sshbuf_allocate(conf, st.st_size)) != 0) | ||
2467 | fatal("%s: allocate failed: %s", __func__, ssh_err(r)); | ||
2452 | while (getline(&line, &linesize, f) != -1) { | 2468 | while (getline(&line, &linesize, f) != -1) { |
2453 | lineno++; | 2469 | lineno++; |
2454 | /* | 2470 | /* |
@@ -2634,14 +2650,15 @@ parse_server_config_depth(ServerOptions *options, const char *filename, | |||
2634 | if (depth < 0 || depth > SERVCONF_MAX_DEPTH) | 2650 | if (depth < 0 || depth > SERVCONF_MAX_DEPTH) |
2635 | fatal("Too many recursive configuration includes"); | 2651 | fatal("Too many recursive configuration includes"); |
2636 | 2652 | ||
2637 | debug2("%s: config %s len %zu", __func__, filename, sshbuf_len(conf)); | 2653 | debug2("%s: config %s len %zu%s", __func__, filename, sshbuf_len(conf), |
2654 | (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : "")); | ||
2638 | 2655 | ||
2639 | if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL) | 2656 | if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL) |
2640 | fatal("%s: sshbuf_dup_string failed", __func__); | 2657 | fatal("%s: sshbuf_dup_string failed", __func__); |
2641 | linenum = 1; | 2658 | linenum = 1; |
2642 | while ((cp = strsep(&cbuf, "\n")) != NULL) { | 2659 | while ((cp = strsep(&cbuf, "\n")) != NULL) { |
2643 | if (process_server_config_line_depth(options, cp, | 2660 | if (process_server_config_line_depth(options, cp, |
2644 | filename, linenum++, activep, connectinfo, flags, | 2661 | filename, linenum++, activep, connectinfo, &flags, |
2645 | depth, includes) != 0) | 2662 | depth, includes) != 0) |
2646 | bad_options++; | 2663 | bad_options++; |
2647 | } | 2664 | } |
@@ -2658,7 +2675,7 @@ parse_server_config(ServerOptions *options, const char *filename, | |||
2658 | { | 2675 | { |
2659 | int active = connectinfo ? 0 : 1; | 2676 | int active = connectinfo ? 0 : 1; |
2660 | parse_server_config_depth(options, filename, conf, includes, | 2677 | parse_server_config_depth(options, filename, conf, includes, |
2661 | connectinfo, 0, &active, 0); | 2678 | connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0); |
2662 | process_queued_listen_addrs(options); | 2679 | process_queued_listen_addrs(options); |
2663 | } | 2680 | } |
2664 | 2681 | ||
@@ -2965,11 +2982,11 @@ dump_config(ServerOptions *o) | |||
2965 | } | 2982 | } |
2966 | printf("\n"); | 2983 | printf("\n"); |
2967 | 2984 | ||
2968 | if (o->permit_user_env_whitelist == NULL) { | 2985 | if (o->permit_user_env_allowlist == NULL) { |
2969 | dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); | 2986 | dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); |
2970 | } else { | 2987 | } else { |
2971 | printf("permituserenvironment %s\n", | 2988 | printf("permituserenvironment %s\n", |
2972 | o->permit_user_env_whitelist); | 2989 | o->permit_user_env_allowlist); |
2973 | } | 2990 | } |
2974 | 2991 | ||
2975 | printf("pubkeyauthoptions"); | 2992 | printf("pubkeyauthoptions"); |
@@ -2977,5 +2994,7 @@ dump_config(ServerOptions *o) | |||
2977 | printf(" none"); | 2994 | printf(" none"); |
2978 | if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED) | 2995 | if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED) |
2979 | printf(" touch-required"); | 2996 | printf(" touch-required"); |
2997 | if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED) | ||
2998 | printf(" verify-required"); | ||
2980 | printf("\n"); | 2999 | printf("\n"); |
2981 | } | 3000 | } |