allow override of Sybsystem directives in sshd Match blocks
authordjm <djm@openbsd.org>
Wed, 6 Sep 2023 23:35:35 +0000 (23:35 +0000)
committerdjm <djm@openbsd.org>
Wed, 6 Sep 2023 23:35:35 +0000 (23:35 +0000)
usr.bin/ssh/servconf.c
usr.bin/ssh/servconf.h

index f0d0910..fea3bdf 100644 (file)
@@ -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 <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -599,7 +599,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 },
@@ -2633,6 +2633,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.
  *
@@ -2739,6 +2780,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
index 1a2411e..bff6f26 100644 (file)
@@ -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 <ylo@cs.hut.fi>
@@ -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;
@@ -292,6 +290,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);
@@ -308,6 +309,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 *);