Bugzilla – Attachment 3223 Details for
Bug 2468
Option to include external files to sshd_config
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Include server side (with same semantics as client) - updated for 7.9p1
0002_openssh-sshd_config-include-directive.patch (text/plain), 12.59 KB, created by
Patrick McLean
on 2019-01-12 05:37:46 AEDT
(
hide
)
Description:
Include server side (with same semantics as client) - updated for 7.9p1
Filename:
MIME Type:
Creator:
Patrick McLean
Created:
2019-01-12 05:37:46 AEDT
Size:
12.59 KB
patch
obsolete
>diff --git a/regress/Makefile b/regress/Makefile >index 7d50f9cf..89d93f8f 100644 >--- a/regress/Makefile >+++ b/regress/Makefile >@@ -79,6 +79,7 @@ LTESTS= connect \ > principals-command \ > cert-file \ > cfginclude \ >+ servcfginclude \ > allow-deny-users \ > authinfo > >@@ -111,6 +112,7 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \ > scp-ssh-wrapper.scp setuid-allowed sftp-server.log \ > sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \ > ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \ >+ sshd_config sshd_config.* \ > ssh_proxy_envpass sshd.log sshd_config sshd_config_minimal \ > sshd_config.orig sshd_proxy sshd_proxy.* sshd_proxy_bak \ > sshd_proxy_orig t10.out t10.out.pub t12.out t12.out.pub \ >diff --git a/regress/servcfginclude.sh b/regress/servcfginclude.sh >new file mode 100644 >index 00000000..6461b7c9 >--- /dev/null >+++ b/regress/servcfginclude.sh >@@ -0,0 +1,153 @@ >+# Placed in the Public Domain. >+ >+tid="server config include" >+ >+cat > $OBJ/sshd_config.i << _EOF >+ >+HostKey $OBJ/host.ed25519 >+ >+Match host a >+ Banner /aa >+ >+Match host b >+ Banner /bb >+ Include $OBJ/sshd_config.i.* >+ >+Match host c >+ Include $OBJ/sshd_config.i.* >+ Banner /cc >+ >+Match host m >+ Include $OBJ/sshd_config.i.* >+ >+Match Host d >+ Banner /dd >+ >+Match Host e >+ Banner /ee >+ Include $OBJ/sshd_config.i.* >+ >+Match Host f >+ Include $OBJ/sshd_config.i.* >+ Banner /ff >+ >+Match Host n >+ Include $OBJ/sshd_config.i.* >+_EOF >+ >+cat > $OBJ/sshd_config.i.0 << _EOF >+Match host xxxxxx >+_EOF >+ >+cat > $OBJ/sshd_config.i.1 << _EOF >+Match host a >+ Banner /aaa >+ >+Match host b >+ Banner /bbb >+ >+Match host c >+ Banner /ccc >+ >+Match Host d >+ Banner /ddd >+ >+Match Host e >+ Banner /eee >+ >+Match Host f >+ Banner /fff >+_EOF >+ >+cat > $OBJ/sshd_config.i.2 << _EOF >+Match host a >+ Banner /aaaa >+ >+Match host b >+ Banner /bbbb >+ >+Match host c >+ Banner /cccc >+ >+Match Host d >+ Banner /dddd >+ >+Match Host e >+ Banner /eeee >+ >+Match Host f >+ Banner /ffff >+ >+Match all >+ Banner /xxxx >+_EOF >+ >+trial() { >+ _host="$1" >+ _exp="$2" >+ ${REAL_SSHD} -f $OBJ/sshd_config.i -T -C "host=$_host,user=test,addr=127.0.0.1" > $OBJ/sshd_config.out || >+ fatal "ssh config parse failed" >+ _got=`grep -i '^banner ' $OBJ/sshd_config.out | awk '{print $2}'` >+ if test "x$_exp" != "x$_got" ; then >+ fail "host $_host include fail: expected $_exp got $_got" >+ fi >+} >+ >+trial a /aa >+trial b /bb >+trial c /ccc >+trial d /dd >+trial e /ee >+trial f /fff >+trial m /xxxx >+trial n /xxxx >+trial x >+ >+# Prepare an included config with an error. >+ >+cat > $OBJ/sshd_config.i.3 << _EOF >+Banner xxxx >+ Junk >+_EOF >+ >+${REAL_SSHD} -f $OBJ/sshd_config.i -C "host=a,user=test,addr=127.0.0.1" 2>/dev/null && \ >+ fail "sshd include allowed invalid config" >+ >+${REAL_SSHD} -f $OBJ/sshd_config.i -C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \ >+ fail "sshd include allowed invalid config" >+ >+rm -f $OBJ/sshd_config.i.* >+ >+# Ensure that a missing include is not fatal. >+cat > $OBJ/sshd_config.i << _EOF >+ >+HostKey $OBJ/host.ed25519 >+Include $OBJ/sshd_config.i.* >+Banner /aa >+_EOF >+ >+trial a /aa >+ >+# Ensure that Match/Host in an included config does not affect parent. >+cat > $OBJ/sshd_config.i.x << _EOF >+Match host x >+_EOF >+ >+trial a /aa >+ >+cat > $OBJ/sshd_config.i.x << _EOF >+Match Host x >+_EOF >+ >+trial a /aa >+ >+# Ensure the empty include directive is not accepted >+cat > $OBJ/sshd_config.i.x << _EOF >+Include >+_EOF >+ >+${REAL_SSHD} -f $OBJ/sshd_config.i.x -C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \ >+ fail "sshd allowed empty Include option" >+ >+# cleanup >+rm -f $OBJ/sshd_config.i $OBJ/sshd_config.i.* $OBJ/sshd_config.out >diff --git a/regress/test-exec.sh b/regress/test-exec.sh >index 68f010b7..cded6cb9 100644 >--- a/regress/test-exec.sh >+++ b/regress/test-exec.sh >@@ -217,6 +217,7 @@ echo "exec ${SSH} -E${TEST_SSH_LOGFILE} "'"$@"' >>$SSHLOGWRAP > > chmod a+rx $OBJ/ssh-log-wrapper.sh > REAL_SSH="$SSH" >+REAL_SSHD="$SSHD" > SSH="$SSHLOGWRAP" > > # Some test data. We make a copy because some tests will overwrite it. >diff --git a/servconf.c b/servconf.c >index 2c321a4a..bc1bf70f 100644 >--- a/servconf.c >+++ b/servconf.c >@@ -34,6 +34,11 @@ > #ifdef HAVE_UTIL_H > #include <util.h> > #endif >+#ifdef USE_SYSTEM_GLOB >+# include <glob.h> >+#else >+# include "openbsd-compat/glob.h" >+#endif > > #include "openbsd-compat/sys-queue.h" > #include "xmalloc.h" >@@ -64,6 +69,15 @@ static void add_one_listen_addr(ServerOptions *, char *, int); > /* Use of privilege separation or not */ > extern int use_privsep; > extern struct sshbuf *cfg; >+struct include_item *include_list = NULL, *include_last = NULL; >+ >+#define INCLUDE_LIST_APPEND(item) \ >+ (item)->next = NULL; \ >+ if (include_list == NULL) { \ >+ include_list = (item); \ >+ } else \ >+ include_last->next = (item); \ >+ include_last = (item); > > /* Initializes the server options to their default values. */ > >@@ -383,6 +397,13 @@ fill_default_server_options(ServerOptions *options) > > } > >+int process_server_config_line_depth(ServerOptions *options, char *line, >+ const char *filename, int linenum, int *activep, >+ struct connection_info *connectinfo, int inc_flags, int depth); >+void parse_server_config_depth(ServerOptions *options, const char *filename, >+ struct sshbuf *conf, struct connection_info *connectinfo, >+ int flags, int *activep, int depth); >+ > /* Keyword tokens. */ > typedef enum { > sBadOption, /* == unknown option */ >@@ -434,7 +455,7 @@ typedef enum { > sAcceptEnv, sPermitTunnel, > sMatch, sPermitOpen, sForceCommand, sChrootDirectory, > sUsePrivilegeSeparation, sAllowAgentForwarding, >- sHostCertificate, >+ sHostCertificate, sInclude, > sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, > sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, > sKexAlgorithms, sIPQoS, sVersionAddendum, >@@ -429,6 +450,8 @@ typedef enum { > #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ > #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) > >+#define SSHCFG_NEVERMATCH 0x04 /* Match/Host never matches; internal only */ >+ > /* Textual representation of the tokens. */ > static struct { > const char *name; >@@ -576,6 +599,7 @@ static struct { > { "noneenabled", sNoneEnabled, SSHCFG_ALL }, > { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, > { "disableMTAES", sDisableMTAES, SSHCFG_ALL }, >+ { "include", sInclude, SSHCFG_ALL }, > { "ipqos", sIPQoS, SSHCFG_ALL }, > { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, > { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, >@@ -991,9 +1015,18 @@ int > process_server_config_line(ServerOptions *options, char *line, > const char *filename, int linenum, int *activep, > struct connection_info *connectinfo) >+{ >+ return process_server_config_line_depth(options, line, filename, linenum, >+ activep, connectinfo, 0, 0); >+} >+ >+int >+process_server_config_line_depth(ServerOptions *options, char *line, >+ const char *filename, int linenum, int *activep, >+ struct connection_info *connectinfo, int inc_flags, int depth) > { > char *cp, ***chararrayptr, **charptr, *arg, *arg2, *p; >- int cmdline = 0, *intptr, value, value2, n, port; >+ int cmdline = 0, *intptr, value, value2, n, port, oactive; > SyslogFacility *log_facility_ptr; > LogLevel *log_level_ptr; > ServerOpCodes opcode; >@@ -1033,6 +1066,9 @@ process_server_config_line_depth(ServerOptions *options, char *line, > long long val64; > const struct multistate *multistate_ptr; > const char *errstr; >+ struct include_item *item; >+ int found = 0; >+ glob_t gbuf; > > /* Strip trailing whitespace. Allow \f (form feed) at EOL only */ > if ((len = strlen(line)) == 0) >@@ -1027,7 +1063,7 @@ process_server_config_line(ServerOptions *options, char *line, > cmdline = 1; > activep = &cmdline; > } >- if (*activep && opcode != sMatch) >+ if (*activep && opcode != sMatch && opcode != sInclude) > debug3("%s:%d setting %s %s", filename, linenum, arg, cp); > if (*activep == 0 && !(flags & SSHCFG_MATCH)) { > if (connectinfo == NULL) { >@@ -1647,6 +1683,80 @@ process_server_config_line(ServerOptions *options, char *line, > *intptr = value; > break; > >+ case sInclude: >+ if (cmdline) >+ fatal("Include directive not supported as a command-line " >+ "option"); >+ >+ value = 0; >+ while ((arg = strdelim(&cp)) != NULL && *arg != '\0') { >+ value++; >+ found = 0; >+ if (*arg != '/' && *arg != '~') { >+ xasprintf(&arg2, "%s/%s", >+ SSHDIR, arg); >+ } else >+ arg2 = xstrdup(arg); >+ >+ /* >+ * don't let the Match in Included clobber >+ * the containing file's Match state. >+ */ >+ oactive = *activep; >+ /* browse cached list of files */ >+ for (item = include_list; item != NULL; item = item->next) { >+ if (strcmp(item->selector, arg2) == 0) { >+ if (item->filename != NULL) >+ parse_server_config_depth(options, item->filename, >+ item->buffer, connectinfo, >+ (oactive ? 0 : SSHCFG_NEVERMATCH), >+ activep, depth + 1); >+ found = 1; >+ *activep = oactive; >+ } >+ } >+ if (found != 0) { >+ free(arg2); >+ continue; >+ } >+ >+ /* not in cache, a new glob */ >+ debug3("Glob configuration file to include %s", arg2); >+ if (glob(arg2, 0, NULL, &gbuf) == 0) { >+ for (i = 0; (int) i < gbuf.gl_pathc; i++) { >+ debug3("Including configuration file %s", >+ gbuf.gl_pathv[i]); >+ item = malloc(sizeof(struct include_item)); >+ item->selector = strdup(arg2); >+ item->filename = strdup(gbuf.gl_pathv[i]); >+ item->buffer = sshbuf_new(); >+ load_server_config(item->filename, item->buffer); >+ parse_server_config_depth(options, item->filename, >+ item->buffer, connectinfo, >+ (oactive ? 0 : SSHCFG_NEVERMATCH), >+ activep, depth + 1); >+ >+ // append item to the end of the list >+ INCLUDE_LIST_APPEND(item) >+ *activep = oactive; >+ } >+ } else { /* no match or other error */ >+ // store placeholder to avoid aditional empty globs >+ item = malloc(sizeof(struct include_item)); >+ item->selector = strdup(arg2); >+ item->filename = NULL; >+ item->buffer = sshbuf_new(); >+ // append item to the end of the list >+ INCLUDE_LIST_APPEND(item) >+ } >+ globfree(&gbuf); >+ free(arg2); >+ } >+ if (value == 0) >+ fatal("%s line %d: missing argument - file to include", >+ filename, linenum); >+ break; >+ > case sMatch: > if (cmdline) > fatal("Match directive not supported as a command-line " >@@ -1655,7 +1765,7 @@ process_server_config_line(ServerOptions *options, char *line, > if (value < 0) > fatal("%s line %d: Bad Match condition", filename, > linenum); >- *activep = value; >+ *activep = (inc_flags & SSHCFG_NEVERMATCH) ? 0 : value; > break; > > case sPermitOpen: >@@ -2106,18 +2216,32 @@ void > parse_server_config(ServerOptions *options, const char *filename, > struct sshbuf *conf, struct connection_info *connectinfo) > { >- int active, linenum, bad_options = 0; >+ int active = connectinfo ? 0 : 1; >+ parse_server_config_depth(options, filename, conf, connectinfo, >+ 0, &active, 0); >+} >+ >+#define SERVCONF_MAX_DEPTH 16 >+ >+void >+parse_server_config_depth(ServerOptions *options, const char *filename, >+ struct sshbuf *conf, struct connection_info *connectinfo, >+ int flags, int *activep, int depth) >+{ >+ int linenum, bad_options = 0; > char *cp, *obuf, *cbuf; > >+ if (depth < 0 || depth > SERVCONF_MAX_DEPTH) >+ fatal("Too many recursive configuration includes"); >+ > debug2("%s: config %s len %zu", __func__, filename, sshbuf_len(conf)); > > if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL) > fatal("%s: sshbuf_dup_string failed", __func__); >- active = connectinfo ? 0 : 1; > linenum = 1; > while ((cp = strsep(&cbuf, "\n")) != NULL) { >- if (process_server_config_line(options, cp, filename, >- linenum++, &active, connectinfo) != 0) >+ if (process_server_config_line_depth(options, cp, filename, >+ linenum++, activep, connectinfo, flags, depth) != 0) > bad_options++; > } > free(obuf); >diff --git a/servconf.h b/servconf.h >index 1dca702e..77b80bd1 100644 >--- a/servconf.h >+++ b/servconf.h >@@ -209,6 +209,13 @@ struct connection_info { > int lport; /* local port */ > }; > >+struct include_item { >+ const char *selector; >+ const char *filename; >+ struct sshbuf *buffer; >+ struct include_item *next; >+}; >+ > > /* > * These are string config options that must be copied between the >diff --git a/sshd_config.5 b/sshd_config.5 >index 251b7467..fee9ea82 100644 >--- a/sshd_config.5 >+++ b/sshd_config.5 >@@ -779,6 +779,18 @@ during > .Cm HostbasedAuthentication . > The default is > .Cm no . >+.It Cm Include >+Include the specified configuration file(s). >+Multiple path names may be specified and each pathname may contain >+.Xr glob 3 >+wildcards. >+Files without absolute paths are assumed to be in >+.Pa /etc/ssh . >+.Cm Include >+directive may appear inside a >+.Cm Match >+block >+to perform conditional inclusion. > .It Cm IPQoS > Specifies the IPv4 type-of-service or DSCP class for the connection. > Accepted values are
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2468
:
2706
|
2869
|
3223
|
3250
|
3333
|
3350
|
3351