diff --git a/servconf.c b/servconf.c index 6650162be..3c2bf4827 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.400 2023/09/06 23:26:37 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.401 2023/09/06 23:35:35 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -643,7 +643,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 }, @@ -2694,6 +2694,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. * @@ -2800,6 +2841,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 diff --git a/servconf.h b/servconf.h index 7ad43de87..ed7b72e8e 100644 --- a/servconf.h +++ b/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.159 2023/01/17 09:44:48 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.160 2023/09/06 23:35:35 djm Exp $ */ /* * Author: Tatu Ylonen @@ -20,8 +20,6 @@ #define MAX_PORTS 256 /* Max # ports. */ -#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ - /* permit_root_login */ #define PERMIT_NOT_SET -1 #define PERMIT_NO 0 @@ -165,9 +163,9 @@ typedef struct { char **deny_groups; u_int num_subsystems; - char *subsystem_name[MAX_SUBSYSTEMS]; - char *subsystem_command[MAX_SUBSYSTEMS]; - char *subsystem_args[MAX_SUBSYSTEMS]; + char **subsystem_name; + char **subsystem_command; + char **subsystem_args; u_int num_accept_env; char **accept_env; @@ -294,6 +292,9 @@ TAILQ_HEAD(include_list, include_item); M_CP_STRARRAYOPT(permitted_listens, num_permitted_listens); \ M_CP_STRARRAYOPT(channel_timeouts, num_channel_timeouts); \ M_CP_STRARRAYOPT(log_verbose, num_log_verbose); \ + M_CP_STRARRAYOPT(subsystem_name, num_subsystems); \ + M_CP_STRARRAYOPT(subsystem_command, num_subsystems); \ + M_CP_STRARRAYOPT(subsystem_args, num_subsystems); \ } while (0) struct connection_info *get_connection_info(struct ssh *, int, int); @@ -310,6 +311,7 @@ void parse_server_match_config(ServerOptions *, struct include_list *includes, struct connection_info *); int parse_server_match_testspec(struct connection_info *, char *); int server_match_spec_complete(struct connection_info *); +void servconf_merge_subsystems(ServerOptions *, ServerOptions *); void copy_set_server_options(ServerOptions *, ServerOptions *, int); void dump_config(ServerOptions *); char *derelativise_path(const char *);