aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/servconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/servconf.c')
-rw-r--r--crypto/openssh/servconf.c400
1 files changed, 311 insertions, 89 deletions
diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c
index 6eaf9c2876ff..6d8b791ffa4c 100644
--- a/crypto/openssh/servconf.c
+++ b/crypto/openssh/servconf.c
@@ -1,5 +1,4 @@
-
-/* $OpenBSD: servconf.c,v 1.384 2022/03/18 04:04:11 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.405 2024/03/04 02:16:11 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -54,7 +53,6 @@
#include "sshbuf.h"
#include "misc.h"
#include "servconf.h"
-#include "compat.h"
#include "pathnames.h"
#include "cipher.h"
#include "sshkey.h"
@@ -196,6 +194,10 @@ initialize_server_options(ServerOptions *options)
options->fingerprint_hash = -1;
options->disable_forwarding = -1;
options->expose_userauth_info = -1;
+ options->required_rsa_size = -1;
+ options->channel_timeouts = NULL;
+ options->num_channel_timeouts = 0;
+ options->unused_connection_timeout = -1;
options->use_blacklist = -1;
}
@@ -327,7 +329,7 @@ fill_default_server_options(ServerOptions *options)
if (options->print_lastlog == -1)
options->print_lastlog = 1;
if (options->x11_forwarding == -1)
- options->x11_forwarding = 1;
+ options->x11_forwarding = 0;
if (options->x11_display_offset == -1)
options->x11_display_offset = 10;
if (options->x11_use_localhost == -1)
@@ -449,6 +451,10 @@ fill_default_server_options(ServerOptions *options)
options->expose_userauth_info = 0;
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("internal");
+ if (options->required_rsa_size == -1)
+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
+ if (options->unused_connection_timeout == -1)
+ options->unused_connection_timeout = 0;
if (options->use_blacklist == -1)
options->use_blacklist = 0;
@@ -465,6 +471,16 @@ fill_default_server_options(ServerOptions *options)
v = NULL; \
} \
} while(0)
+#define CLEAR_ON_NONE_ARRAY(v, nv, none) \
+ do { \
+ if (options->nv == 1 && \
+ strcasecmp(options->v[0], none) == 0) { \
+ free(options->v[0]); \
+ free(options->v); \
+ options->v = NULL; \
+ options->nv = 0; \
+ } \
+ } while (0)
CLEAR_ON_NONE(options->pid_file);
CLEAR_ON_NONE(options->xauth_location);
CLEAR_ON_NONE(options->banner);
@@ -476,19 +492,16 @@ fill_default_server_options(ServerOptions *options)
CLEAR_ON_NONE(options->chroot_directory);
CLEAR_ON_NONE(options->routing_domain);
CLEAR_ON_NONE(options->host_key_agent);
+
for (i = 0; i < options->num_host_key_files; i++)
CLEAR_ON_NONE(options->host_key_files[i]);
for (i = 0; i < options->num_host_cert_files; i++)
CLEAR_ON_NONE(options->host_cert_files[i]);
-#undef CLEAR_ON_NONE
- /* Similar handling for AuthenticationMethods=any */
- if (options->num_auth_methods == 1 &&
- strcmp(options->auth_methods[0], "any") == 0) {
- free(options->auth_methods[0]);
- options->auth_methods[0] = NULL;
- options->num_auth_methods = 0;
- }
+ CLEAR_ON_NONE_ARRAY(channel_timeouts, num_channel_timeouts, "none");
+ CLEAR_ON_NONE_ARRAY(auth_methods, num_auth_methods, "any");
+#undef CLEAR_ON_NONE
+#undef CLEAR_ON_NONE_ARRAY
}
/* Keyword tokens. */
@@ -527,6 +540,7 @@ typedef enum {
sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
+ sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout,
sUseBlacklist,
sDeprecated, sIgnore, sUnsupported
} ServerOpCodes;
@@ -640,7 +654,7 @@ static struct {
{ "macs", sMacs, SSHCFG_GLOBAL },
{ "protocol", sIgnore, SSHCFG_GLOBAL },
{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
- { "subsystem", sSubsystem, SSHCFG_GLOBAL },
+ { "subsystem", sSubsystem, SSHCFG_ALL },
{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
{ "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
{ "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
@@ -687,12 +701,12 @@ static struct {
{ "rdomain", sRDomain, SSHCFG_ALL },
{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
+ { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
+ { "channeltimeout", sChannelTimeout, SSHCFG_ALL },
+ { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL },
{ "useblacklist", sUseBlacklist, SSHCFG_GLOBAL },
{ "useblocklist", sUseBlacklist, SSHCFG_GLOBAL }, /* alias */
- { "noneenabled", sUnsupported, SSHCFG_ALL },
- { "hpndisabled", sDeprecated, SSHCFG_ALL },
- { "hpnbuffersize", sDeprecated, SSHCFG_ALL },
- { "tcprcvbufpoll", sDeprecated, SSHCFG_ALL },
+
{ NULL, sBadOption, 0 }
};
@@ -956,6 +970,26 @@ process_permitopen(struct ssh *ssh, ServerOptions *options)
options->num_permitted_listens);
}
+void
+process_channel_timeouts(struct ssh *ssh, ServerOptions *options)
+{
+ int secs;
+ u_int i;
+ char *type;
+
+ debug3_f("setting %u timeouts", options->num_channel_timeouts);
+ channel_clear_timeouts(ssh);
+ for (i = 0; i < options->num_channel_timeouts; i++) {
+ if (parse_pattern_interval(options->channel_timeouts[i],
+ &type, &secs) != 0) {
+ fatal_f("internal error: bad timeout %s",
+ options->channel_timeouts[i]);
+ }
+ channel_add_timeout(ssh, type, secs);
+ free(type);
+ }
+}
+
struct connection_info *
get_connection_info(struct ssh *ssh, int populate, int use_dns)
{
@@ -1278,11 +1312,12 @@ process_server_config_line_depth(ServerOptions *options, char *line,
struct include_list *includes)
{
char *str, ***chararrayptr, **charptr, *arg, *arg2, *p, *keyword;
- int cmdline = 0, *intptr, value, value2, n, port, oactive, r, found;
+ int cmdline = 0, *intptr, value, value2, n, port, oactive, r;
+ int ca_only = 0, found = 0;
SyslogFacility *log_facility_ptr;
LogLevel *log_level_ptr;
ServerOpCodes opcode;
- u_int i, *uintptr, uvalue, flags = 0;
+ u_int i, *uintptr, flags = 0;
size_t len;
long long val64;
const struct multistate *multistate_ptr;
@@ -1292,6 +1327,8 @@ process_server_config_line_depth(ServerOptions *options, char *line,
char **oav = NULL, **av;
int oac = 0, ac;
int ret = -1;
+ char **strs = NULL; /* string array arguments; freed implicitly */
+ u_int nstrs = 0;
/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
if ((len = strlen(line)) == 0)
@@ -1520,6 +1557,7 @@ process_server_config_line_depth(ServerOptions *options, char *line,
case sHostbasedAcceptedAlgorithms:
charptr = &options->hostbased_accepted_algos;
+ ca_only = 0;
parse_pubkey_algos:
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
@@ -1527,7 +1565,7 @@ process_server_config_line_depth(ServerOptions *options, char *line,
filename, linenum);
if (*arg != '-' &&
!sshkey_names_valid2(*arg == '+' || *arg == '^' ?
- arg + 1 : arg, 1))
+ arg + 1 : arg, 1, ca_only))
fatal("%s line %d: Bad key types '%s'.",
filename, linenum, arg ? arg : "<NONE>");
if (*activep && *charptr == NULL)
@@ -1536,18 +1574,22 @@ process_server_config_line_depth(ServerOptions *options, char *line,
case sHostKeyAlgorithms:
charptr = &options->hostkeyalgorithms;
+ ca_only = 0;
goto parse_pubkey_algos;
case sCASignatureAlgorithms:
charptr = &options->ca_sign_algorithms;
+ ca_only = 1;
goto parse_pubkey_algos;
case sPubkeyAuthentication:
intptr = &options->pubkey_authentication;
+ ca_only = 0;
goto parse_flag;
case sPubkeyAcceptedAlgorithms:
charptr = &options->pubkey_accepted_algos;
+ ca_only = 0;
goto parse_pubkey_algos;
case sPubkeyAuthOptions:
@@ -1749,7 +1791,6 @@ process_server_config_line_depth(ServerOptions *options, char *line,
case sLogVerbose:
found = options->num_log_verbose == 0;
- i = 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
@@ -1758,19 +1799,25 @@ process_server_config_line_depth(ServerOptions *options, char *line,
}
/* Allow "none" only in first position */
if (strcasecmp(arg, "none") == 0) {
- if (i > 0 || ac > 0) {
+ if (nstrs > 0 || ac > 0) {
error("%s line %d: keyword %s \"none\" "
"argument must appear alone.",
filename, linenum, keyword);
goto out;
}
}
- i++;
- if (!found || !*activep)
- continue;
opt_array_append(filename, linenum, keyword,
- &options->log_verbose, &options->num_log_verbose,
- arg);
+ &strs, &nstrs, arg);
+ }
+ if (nstrs == 0) {
+ fatal("%s line %d: no %s specified",
+ filename, linenum, keyword);
+ }
+ if (found && *activep) {
+ options->log_verbose = strs;
+ options->num_log_verbose = nstrs;
+ strs = NULL; /* transferred */
+ nstrs = 0;
}
break;
@@ -1796,16 +1843,22 @@ process_server_config_line_depth(ServerOptions *options, char *line,
chararrayptr = &options->allow_users;
uintptr = &options->num_allow_users;
parse_allowdenyusers:
+ /* XXX appends to list; doesn't respect first-match-wins */
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0' ||
match_user(NULL, NULL, NULL, arg) == -1)
fatal("%s line %d: invalid %s pattern: \"%s\"",
filename, linenum, keyword, arg);
+ found = 1;
if (!*activep)
continue;
opt_array_append(filename, linenum, keyword,
chararrayptr, uintptr, arg);
}
+ if (!found) {
+ fatal("%s line %d: no %s specified",
+ filename, linenum, keyword);
+ }
break;
case sDenyUsers:
@@ -1816,16 +1869,22 @@ process_server_config_line_depth(ServerOptions *options, char *line,
case sAllowGroups:
chararrayptr = &options->allow_groups;
uintptr = &options->num_allow_groups;
+ /* XXX appends to list; doesn't respect first-match-wins */
parse_allowdenygroups:
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0')
fatal("%s line %d: empty %s pattern",
filename, linenum, keyword);
+ found = 1;
if (!*activep)
continue;
opt_array_append(filename, linenum, keyword,
chararrayptr, uintptr, arg);
}
+ if (!found) {
+ fatal("%s line %d: no %s specified",
+ filename, linenum, keyword);
+ }
break;
case sDenyGroups:
@@ -1874,39 +1933,54 @@ process_server_config_line_depth(ServerOptions *options, char *line,
break;
case sSubsystem:
- if (options->num_subsystems >= MAX_SUBSYSTEMS) {
- fatal("%s line %d: too many subsystems defined.",
- filename, linenum);
- }
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
if (!*activep) {
- arg = argv_next(&ac, &av);
+ argv_consume(&ac);
break;
}
- for (i = 0; i < options->num_subsystems; i++)
- if (strcmp(arg, options->subsystem_name[i]) == 0)
- fatal("%s line %d: Subsystem '%s' "
- "already defined.", filename, linenum, arg);
+ found = 0;
+ for (i = 0; i < options->num_subsystems; i++) {
+ if (strcmp(arg, options->subsystem_name[i]) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ debug("%s line %d: Subsystem '%s' already defined.",
+ filename, linenum, arg);
+ argv_consume(&ac);
+ break;
+ }
+ options->subsystem_name = xrecallocarray(
+ options->subsystem_name, options->num_subsystems,
+ options->num_subsystems + 1,
+ sizeof(*options->subsystem_name));
+ options->subsystem_command = xrecallocarray(
+ options->subsystem_command, options->num_subsystems,
+ options->num_subsystems + 1,
+ sizeof(*options->subsystem_command));
+ options->subsystem_args = xrecallocarray(
+ options->subsystem_args, options->num_subsystems,
+ options->num_subsystems + 1,
+ sizeof(*options->subsystem_args));
options->subsystem_name[options->num_subsystems] = xstrdup(arg);
arg = argv_next(&ac, &av);
- if (!arg || *arg == '\0')
+ if (!arg || *arg == '\0') {
fatal("%s line %d: Missing subsystem command.",
filename, linenum);
- options->subsystem_command[options->num_subsystems] = xstrdup(arg);
-
- /* Collect arguments (separate to executable) */
- p = xstrdup(arg);
- len = strlen(p) + 1;
- while ((arg = argv_next(&ac, &av)) != NULL) {
- len += 1 + strlen(arg);
- p = xreallocarray(p, 1, len);
- strlcat(p, " ", len);
- strlcat(p, arg, len);
}
- options->subsystem_args[options->num_subsystems] = p;
+ options->subsystem_command[options->num_subsystems] =
+ xstrdup(arg);
+ /* Collect arguments (separate to executable) */
+ arg = argv_assemble(1, &arg); /* quote command correctly */
+ arg2 = argv_assemble(ac, av); /* rest of command */
+ xasprintf(&options->subsystem_args[options->num_subsystems],
+ "%s%s%s", arg, *arg2 == '\0' ? "" : " ", arg2);
+ free(arg2);
+ argv_consume(&ac);
options->num_subsystems++;
break;
@@ -1930,6 +2004,10 @@ process_server_config_line_depth(ServerOptions *options, char *line,
filename, linenum, keyword);
else
options->max_startups = options->max_startups_begin;
+ if (options->max_startups <= 0 ||
+ options->max_startups_begin <= 0)
+ fatal("%s line %d: Invalid %s spec.",
+ filename, linenum, keyword);
break;
case sPerSourceNetBlockSize:
@@ -1967,7 +2045,7 @@ process_server_config_line_depth(ServerOptions *options, char *line,
fatal("%s line %d: %s integer value %s.",
filename, linenum, keyword, errstr);
}
- if (*activep)
+ if (*activep && options->per_source_max_startups == -1)
options->per_source_max_startups = value;
break;
@@ -1990,7 +2068,7 @@ process_server_config_line_depth(ServerOptions *options, char *line,
* AuthorizedKeysFile /etc/ssh_keys/%u
*/
case sAuthorizedKeysFile:
- uvalue = options->num_authkeys_files;
+ found = options->num_authkeys_files == 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
@@ -1998,13 +2076,20 @@ process_server_config_line_depth(ServerOptions *options, char *line,
goto out;
}
arg2 = tilde_expand_filename(arg, getuid());
- if (*activep && uvalue == 0) {
- opt_array_append(filename, linenum, keyword,
- &options->authorized_keys_files,
- &options->num_authkeys_files, arg2);
- }
+ opt_array_append(filename, linenum, keyword,
+ &strs, &nstrs, arg2);
free(arg2);
}
+ if (nstrs == 0) {
+ fatal("%s line %d: no %s specified",
+ filename, linenum, keyword);
+ }
+ if (found && *activep) {
+ options->authorized_keys_files = strs;
+ options->num_authkeys_files = nstrs;
+ strs = NULL; /* transferred */
+ nstrs = 0;
+ }
break;
case sAuthorizedPrincipalsFile:
@@ -2030,28 +2115,47 @@ process_server_config_line_depth(ServerOptions *options, char *line,
goto parse_int;
case sAcceptEnv:
+ /* XXX appends to list; doesn't respect first-match-wins */
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0' || strchr(arg, '=') != NULL)
fatal("%s line %d: Invalid environment name.",
filename, linenum);
+ found = 1;
if (!*activep)
continue;
opt_array_append(filename, linenum, keyword,
&options->accept_env, &options->num_accept_env,
arg);
}
+ if (!found) {
+ fatal("%s line %d: no %s specified",
+ filename, linenum, keyword);
+ }
break;
case sSetEnv:
- uvalue = options->num_setenv;
+ found = options->num_setenv == 0;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0' || strchr(arg, '=') == NULL)
fatal("%s line %d: Invalid environment.",
filename, linenum);
- if (!*activep || uvalue != 0)
+ if (lookup_setenv_in_list(arg, strs, nstrs) != NULL) {
+ debug2("%s line %d: ignoring duplicate env "
+ "name \"%.64s\"", filename, linenum, arg);
continue;
+ }
opt_array_append(filename, linenum, keyword,
- &options->setenv, &options->num_setenv, arg);
+ &strs, &nstrs, arg);
+ }
+ if (nstrs == 0) {
+ fatal("%s line %d: no %s specified",
+ filename, linenum, keyword);
+ }
+ if (found && *activep) {
+ options->setenv = strs;
+ options->num_setenv = nstrs;
+ strs = NULL; /* transferred */
+ nstrs = 0;
}
break;
@@ -2202,21 +2306,20 @@ process_server_config_line_depth(ServerOptions *options, char *line,
uintptr = &options->num_permitted_opens;
chararrayptr = &options->permitted_opens;
}
- arg = argv_next(&ac, &av);
- if (!arg || *arg == '\0')
- fatal("%s line %d: %s missing argument.",
- filename, linenum, keyword);
- uvalue = *uintptr; /* modified later */
- if (strcmp(arg, "any") == 0 || strcmp(arg, "none") == 0) {
- if (*activep && uvalue == 0) {
- *uintptr = 1;
- *chararrayptr = xcalloc(1,
- sizeof(**chararrayptr));
- (*chararrayptr)[0] = xstrdup(arg);
+ found = *uintptr == 0;
+ while ((arg = argv_next(&ac, &av)) != NULL) {
+ if (strcmp(arg, "any") == 0 ||
+ strcmp(arg, "none") == 0) {
+ if (nstrs != 0) {
+ fatal("%s line %d: %s must appear "
+ "alone on a %s line.",
+ filename, linenum, arg, keyword);
+ }
+ opt_array_append(filename, linenum, keyword,
+ &strs, &nstrs, arg);
+ continue;
}
- break;
- }
- for (; arg != NULL && *arg != '\0'; arg = argv_next(&ac, &av)) {
+
if (opcode == sPermitListen &&
strchr(arg, ':') == NULL) {
/*
@@ -2238,12 +2341,20 @@ process_server_config_line_depth(ServerOptions *options, char *line,
fatal("%s line %d: %s bad port number",
filename, linenum, keyword);
}
- if (*activep && uvalue == 0) {
- opt_array_append(filename, linenum, keyword,
- chararrayptr, uintptr, arg2);
- }
+ opt_array_append(filename, linenum, keyword,
+ &strs, &nstrs, arg2);
free(arg2);
}
+ if (nstrs == 0) {
+ fatal("%s line %d: %s missing argument.",
+ filename, linenum, keyword);
+ }
+ if (found && *activep) {
+ *chararrayptr = strs;
+ *uintptr = nstrs;
+ strs = NULL; /* transferred */
+ nstrs = 0;
+ }
break;
case sForceCommand:
@@ -2340,7 +2451,7 @@ process_server_config_line_depth(ServerOptions *options, char *line,
fatal("%.200s line %d: %s must be an absolute path",
filename, linenum, keyword);
}
- if (*activep && options->authorized_keys_command == NULL)
+ if (*activep && *charptr == NULL)
*charptr = xstrdup(str + len);
argv_consume(&ac);
break;
@@ -2368,10 +2479,9 @@ process_server_config_line_depth(ServerOptions *options, char *line,
case sAuthenticationMethods:
found = options->num_auth_methods == 0;
value = 0; /* seen "any" pseudo-method */
- value2 = 0; /* successfully parsed any method */
while ((arg = argv_next(&ac, &av)) != NULL) {
if (strcmp(arg, "any") == 0) {
- if (options->num_auth_methods > 0) {
+ if (nstrs > 0) {
fatal("%s line %d: \"any\" must "
"appear alone in %s",
filename, linenum, keyword);
@@ -2384,17 +2494,19 @@ process_server_config_line_depth(ServerOptions *options, char *line,
fatal("%s line %d: invalid %s method list.",
filename, linenum, keyword);
}
- value2 = 1;
- if (!found || !*activep)
- continue;
opt_array_append(filename, linenum, keyword,
- &options->auth_methods,
- &options->num_auth_methods, arg);
+ &strs, &nstrs, arg);
}
- if (value2 == 0) {
+ if (nstrs == 0) {
fatal("%s line %d: no %s specified",
filename, linenum, keyword);
}
+ if (found && *activep) {
+ options->auth_methods = strs;
+ options->num_auth_methods = nstrs;
+ strs = NULL; /* transferred */
+ nstrs = 0;
+ }
break;
case sStreamLocalBindMask:
@@ -2449,6 +2561,52 @@ process_server_config_line_depth(ServerOptions *options, char *line,
*charptr = xstrdup(arg);
break;
+ case sRequiredRSASize:
+ intptr = &options->required_rsa_size;
+ goto parse_int;
+
+ case sChannelTimeout:
+ found = options->num_channel_timeouts == 0;
+ while ((arg = argv_next(&ac, &av)) != NULL) {
+ /* Allow "none" only in first position */
+ if (strcasecmp(arg, "none") == 0) {
+ if (nstrs > 0 || ac > 0) {
+ error("%s line %d: keyword %s \"none\" "
+ "argument must appear alone.",
+ filename, linenum, keyword);
+ goto out;
+ }
+ } else if (parse_pattern_interval(arg,
+ NULL, NULL) != 0) {
+ fatal("%s line %d: invalid channel timeout %s",
+ filename, linenum, arg);
+ }
+ opt_array_append(filename, linenum, keyword,
+ &strs, &nstrs, arg);
+ }
+ if (nstrs == 0) {
+ fatal("%s line %d: no %s specified",
+ filename, linenum, keyword);
+ }
+ if (found && *activep) {
+ options->channel_timeouts = strs;
+ options->num_channel_timeouts = nstrs;
+ strs = NULL; /* transferred */
+ nstrs = 0;
+ }
+ break;
+
+ case sUnusedConnectionTimeout:
+ intptr = &options->unused_connection_timeout;
+ /* peek at first arg for "none" so we can reuse parse_time */
+ if (av[0] != NULL && strcasecmp(av[0], "none") == 0) {
+ (void)argv_next(&ac, &av); /* consume arg */
+ if (*activep)
+ *intptr = 0;
+ break;
+ }
+ goto parse_time;
+
case sUseBlacklist:
intptr = &options->use_blacklist;
goto parse_flag;
@@ -2478,6 +2636,7 @@ process_server_config_line_depth(ServerOptions *options, char *line,
/* success */
ret = 0;
out:
+ opt_array_free2(strs, NULL, nstrs);
argv_free(oav, oac);
return ret;
}
@@ -2503,7 +2662,7 @@ load_server_config(const char *filename, struct sshbuf *conf)
char *line = NULL, *cp;
size_t linesize = 0;
FILE *f;
- int r, lineno = 0;
+ int r;
debug2_f("filename %s", filename);
if ((f = fopen(filename, "r")) == NULL) {
@@ -2516,7 +2675,6 @@ load_server_config(const char *filename, struct sshbuf *conf)
(r = sshbuf_allocate(conf, st.st_size)) != 0)
fatal_fr(r, "allocate");
while (getline(&line, &linesize, f) != -1) {
- lineno++;
/*
* Strip whitespace
* NB - preserve newlines, they are needed to reproduce
@@ -2576,6 +2734,47 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec)
return 0;
}
+void
+servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src)
+{
+ u_int i, j, found;
+
+ for (i = 0; i < src->num_subsystems; i++) {
+ found = 0;
+ for (j = 0; j < dst->num_subsystems; j++) {
+ if (strcmp(src->subsystem_name[i],
+ dst->subsystem_name[j]) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ debug_f("override \"%s\"", dst->subsystem_name[j]);
+ free(dst->subsystem_command[j]);
+ free(dst->subsystem_args[j]);
+ dst->subsystem_command[j] =
+ xstrdup(src->subsystem_command[i]);
+ dst->subsystem_args[j] =
+ xstrdup(src->subsystem_args[i]);
+ continue;
+ }
+ debug_f("add \"%s\"", src->subsystem_name[i]);
+ dst->subsystem_name = xrecallocarray(
+ dst->subsystem_name, dst->num_subsystems,
+ dst->num_subsystems + 1, sizeof(*dst->subsystem_name));
+ dst->subsystem_command = xrecallocarray(
+ dst->subsystem_command, dst->num_subsystems,
+ dst->num_subsystems + 1, sizeof(*dst->subsystem_command));
+ dst->subsystem_args = xrecallocarray(
+ dst->subsystem_args, dst->num_subsystems,
+ dst->num_subsystems + 1, sizeof(*dst->subsystem_args));
+ j = dst->num_subsystems++;
+ dst->subsystem_name[j] = xstrdup(src->subsystem_name[i]);
+ dst->subsystem_command[j] = xstrdup(src->subsystem_command[i]);
+ dst->subsystem_args[j] = xstrdup(src->subsystem_args[i]);
+ }
+}
+
/*
* Copy any supported values that are set.
*
@@ -2625,6 +2824,8 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
M_CP_INTOPT(rekey_limit);
M_CP_INTOPT(rekey_interval);
M_CP_INTOPT(log_level);
+ M_CP_INTOPT(required_rsa_size);
+ M_CP_INTOPT(unused_connection_timeout);
/*
* The bind_mask is a mode_t that may be unsigned, so we can't use
@@ -2680,6 +2881,9 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
free(dst->chroot_directory);
dst->chroot_directory = NULL;
}
+
+ /* Subsystems require merging. */
+ servconf_merge_subsystems(dst, src);
}
#undef M_CP_INTOPT
@@ -2777,6 +2981,10 @@ fmt_intarg(ServerOpCodes code, int val)
static void
dump_cfg_int(ServerOpCodes code, int val)
{
+ if (code == sUnusedConnectionTimeout && val == 0) {
+ printf("%s none\n", lookup_opcode_name(code));
+ return;
+ }
printf("%s %d\n", lookup_opcode_name(code), val);
}
@@ -2813,13 +3021,23 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals)
{
u_int i;
- if (count <= 0 && code != sAuthenticationMethods)
- return;
+ switch (code) {
+ case sAuthenticationMethods:
+ case sChannelTimeout:
+ break;
+ default:
+ if (count <= 0)
+ return;
+ break;
+ }
+
printf("%s", lookup_opcode_name(code));
for (i = 0; i < count; i++)
printf(" %s", vals[i]);
if (code == sAuthenticationMethods && count == 0)
printf(" any");
+ else if (code == sChannelTimeout && count == 0)
+ printf(" none");
printf("\n");
}
@@ -2889,7 +3107,9 @@ dump_config(ServerOptions *o)
dump_cfg_int(sMaxSessions, o->max_sessions);
dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
+ dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
+ dump_cfg_int(sUnusedConnectionTimeout, o->unused_connection_timeout);
/* formatted integer arguments */
dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
@@ -2988,6 +3208,8 @@ dump_config(ServerOptions *o)
o->num_auth_methods, o->auth_methods);
dump_cfg_strarray_oneline(sLogVerbose,
o->num_log_verbose, o->log_verbose);
+ dump_cfg_strarray_oneline(sChannelTimeout,
+ o->num_channel_timeouts, o->channel_timeouts);
/* other arguments */
for (i = 0; i < o->num_subsystems; i++)