diff options
Diffstat (limited to 'crypto/openssh/servconf.c')
-rw-r--r-- | crypto/openssh/servconf.c | 400 |
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++) |