=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/servconf.c,v retrieving revision 1.388 retrieving revision 1.389 diff -u -r1.388 -r1.389 --- src/usr.bin/ssh/servconf.c 2022/11/07 10:05:39 1.388 +++ src/usr.bin/ssh/servconf.c 2023/01/06 02:47:18 1.389 @@ -1,5 +1,5 @@ -/* $OpenBSD: servconf.c,v 1.388 2022/11/07 10:05:39 dtucker Exp $ */ +/* $OpenBSD: servconf.c,v 1.389 2023/01/06 02:47:18 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -178,6 +178,8 @@ options->disable_forwarding = -1; options->expose_userauth_info = -1; options->required_rsa_size = -1; + options->channel_timeouts = NULL; + options->num_channel_timeouts = 0; } /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ @@ -433,6 +435,16 @@ 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); @@ -444,19 +456,16 @@ 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. */ @@ -492,7 +501,7 @@ sStreamLocalBindMask, sStreamLocalBindUnlink, sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, - sRequiredRSASize, + sRequiredRSASize, sChannelTimeout, sDeprecated, sIgnore, sUnsupported } ServerOpCodes; @@ -637,6 +646,7 @@ { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, + { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -893,6 +903,58 @@ options->num_permitted_listens); } +/* Parse a ChannelTimeout clause "pattern=interval" */ +static int +parse_timeout(const char *s, char **typep, u_int *secsp) +{ + char *cp, *sdup; + int secs; + + if (typep != NULL) + *typep = NULL; + if (secsp != NULL) + *secsp = 0; + if (s == NULL) + return -1; + sdup = xstrdup(s); + + if ((cp = strchr(sdup, '=')) == NULL || cp == sdup) { + free(sdup); + return -1; + } + *cp++ = '\0'; + if ((secs = convtime(cp)) < 0) { + free(sdup); + return -1; + } + /* success */ + if (typep != NULL) + *typep = xstrdup(sdup); + if (secsp != NULL) + *secsp = (u_int)secs; + free(sdup); + return 0; +} + +void +process_channel_timeouts(struct ssh *ssh, ServerOptions *options) +{ + u_int i, secs; + 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_timeout(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) { @@ -2390,6 +2452,30 @@ intptr = &options->required_rsa_size; goto parse_int; + case sChannelTimeout: + uvalue = options->num_channel_timeouts; + i = 0; + while ((arg = argv_next(&ac, &av)) != NULL) { + /* Allow "none" only in first position */ + if (strcasecmp(arg, "none") == 0) { + if (i > 0 || ac > 0) { + error("%s line %d: keyword %s \"none\" " + "argument must appear alone.", + filename, linenum, keyword); + goto out; + } + } else if (parse_timeout(arg, NULL, NULL) != 0) { + fatal("%s line %d: invalid channel timeout %s", + filename, linenum, arg); + } + if (!*activep || uvalue != 0) + continue; + opt_array_append(filename, linenum, keyword, + &options->channel_timeouts, + &options->num_channel_timeouts, arg); + } + break; + case sDeprecated: case sIgnore: case sUnsupported: @@ -2757,6 +2843,8 @@ printf(" %s", vals[i]); if (code == sAuthenticationMethods && count == 0) printf(" any"); + else if (code == sChannelTimeout && count == 0) + printf(" none"); printf("\n"); } @@ -2916,6 +3004,8 @@ 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++)