Hi, does nobody have an opinion about this? Thanks, Thorsten On Fri, Jan 29, Thorsten Kukuk wrote: > > Hi, > > Distributors have one common problem: configuration files and updates. > > If a configuration file is modified by an user and the distributor mades > changes to it, the package manager needs to decide which version of the > configuration file should be used: the one of the admin or the one from > the distributor. Independent of the decission, in worst case the service > is broken until the admin merges the changes manually. Which is not that > problem with a single system, but could be a lot of work for big clusters. > > There is now the include statement, which solves already many cases as > the admin could put his changes in an extra file, but there are still > some bigger issues. > > As an example for sshd_config: most Linux distributions added meanwhile an > include statement to read at first files from /etc/ssh/sshd_config.d/* > This works fine for directives like 'PermitRootLogin', where the first entry > found wins. But you can have multiple AcceptEnv directives. And there is no > way for an admin to change the distributor default without editing the > config file itself, which again leads to update problems in the future. > > With ssh_config it's even more complicated: You can have multiple SendEnv > directives, and you can change them later. This leads now to the situation, > that you need two include directives: one on the beginning of the > configuration file, which sets variables which could only be set once, > and at the end, to remove and modify SendEnv. I don't know currently if > there are more directives you cannot modify, so that the admin still has > to modify the original file. > > I made a relativ small patch, which tries to follow the "systemd" behavior, > which is meanwhile used by many more projects: > > - There is a distributor/vendor default configuration file in /usr/share/ssh > - The admin can create his own configuration file in /etc/ssh > - There is still the possibility to use the include statement to only override > single directives. > > So if there is no admin provided configuration file, the vendor file from > /usr/share/ssh is used. If there is an admin provided configuration file > in /etc/ssh, this one will be used by default. > > Includes are only used from the configuration file which is really read. > And if a distribution does not like this, it can still only ship the > configuration files in /etc/ssh and there is no change in behavior. > > Attached is a patch which I'm using currently. I would like to see if > upstream openssh would support this. > > Thorsten > > -- > Thorsten Kukuk, Distinguished Engineer, Senior Architect SLES & MicroOS > SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nuernberg, Germany > Managing Director: Felix Imendoerffer (HRB 36809, AG Nürnberg) > diff -urN openssh-8.4p1/dh.c openssh-8.4p1-vendor/dh.c > --- openssh-8.4p1/dh.c 2020-09-27 09:25:01.000000000 +0200 > +++ openssh-8.4p1-vendor/dh.c 2021-01-29 11:49:40.968418136 +0100 > @@ -151,10 +151,18 @@ > size_t linesize = 0; > int best, bestcount, which, linenum; > struct dhgroup dhg; > + char *dh_moduli_path; > + struct stat st; > > - if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL) { > + if (stat(_PATH_VENDOR_DH_MODULI, &st) == 0 && > + stat(_PATH_DH_MODULI, &st) == -1) { > + dh_moduli_path = _PATH_VENDOR_DH_MODULI; > + } else { > + dh_moduli_path = _PATH_DH_MODULI; > + } > + if ((f = fopen(dh_moduli_path, "r")) == NULL) { > logit("WARNING: could not open %s (%s), using fixed modulus", > - _PATH_DH_MODULI, strerror(errno)); > + dh_moduli_path, strerror(errno)); > return (dh_new_group_fallback(max)); > } > > @@ -185,7 +193,7 @@ > > if (bestcount == 0) { > fclose(f); > - logit("WARNING: no suitable primes in %s", _PATH_DH_MODULI); > + logit("WARNING: no suitable primes in %s", dh_moduli_path); > return (dh_new_group_fallback(max)); > } > which = arc4random_uniform(bestcount); > @@ -210,7 +218,7 @@ > fclose(f); > if (bestcount != which + 1) { > logit("WARNING: selected prime disappeared in %s, giving up", > - _PATH_DH_MODULI); > + dh_moduli_path); > return (dh_new_group_fallback(max)); > } > > diff -urN openssh-8.4p1/pathnames.h openssh-8.4p1-vendor/pathnames.h > --- openssh-8.4p1/pathnames.h 2020-09-27 09:25:01.000000000 +0200 > +++ openssh-8.4p1-vendor/pathnames.h 2021-01-29 11:35:41.655599046 +0100 > @@ -18,6 +18,8 @@ > #define SSHDIR ETCDIR "/ssh" > #endif > > +#define VENDORDIR "/usr/share/ssh" > + > #ifndef _PATH_SSH_PIDDIR > #define _PATH_SSH_PIDDIR "/var/run" > #endif > @@ -35,13 +37,16 @@ > * should be world-readable. > */ > #define _PATH_SERVER_CONFIG_FILE SSHDIR "/sshd_config" > +#define _PATH_SERVER_VENDOR_CONFIG_FILE VENDORDIR "/sshd_config" > #define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config" > +#define _PATH_HOST_VENDOR_CONFIG_FILE VENDORDIR "/ssh_config" > #define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key" > #define _PATH_HOST_ECDSA_KEY_FILE SSHDIR "/ssh_host_ecdsa_key" > #define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" > #define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key" > #define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key" > #define _PATH_DH_MODULI SSHDIR "/moduli" > +#define _PATH_VENDOR_DH_MODULI VENDORDIR "/moduli" > > #ifndef _PATH_SSH_PROGRAM > #define _PATH_SSH_PROGRAM "/usr/bin/ssh" > diff -urN openssh-8.4p1/ssh.c openssh-8.4p1-vendor/ssh.c > --- openssh-8.4p1/ssh.c 2020-09-27 09:25:01.000000000 +0200 > +++ openssh-8.4p1-vendor/ssh.c 2021-01-27 18:22:52.322271681 +0100 > @@ -593,6 +593,7 @@ > process_config_files(const char *host_name, struct passwd *pw, int final_pass, > int *want_final_pass) > { > + struct stat st; > char buf[PATH_MAX]; > int r; > > @@ -611,10 +612,23 @@ > &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | > (final_pass ? SSHCONF_FINAL : 0), want_final_pass); > > - /* Read systemwide configuration file after user config. */ > - (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, > - host, host_name, &options, > - final_pass ? SSHCONF_FINAL : 0, want_final_pass); > + /* If only the vendor configuration file exists, use that. > + * Else use the standard configuration file. > + */ > + if (stat(_PATH_HOST_VENDOR_CONFIG_FILE, &st) == 0 && > + stat(_PATH_HOST_CONFIG_FILE, &st) == -1) { > + /* Read vendor distributed configuration file. */ > + (void)read_config_file(_PATH_HOST_VENDOR_CONFIG_FILE, > + pw, host, host_name, &options, > + final_pass ? SSHCONF_FINAL : 0, > + want_final_pass); > + } else { > + /* Read systemwide configuration file after user config. */ > + (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, > + host, host_name, &options, > + final_pass ? SSHCONF_FINAL : 0, > + want_final_pass); > + } > } > } > > diff -urN openssh-8.4p1/sshd.c openssh-8.4p1-vendor/sshd.c > --- openssh-8.4p1/sshd.c 2020-09-27 09:25:01.000000000 +0200 > +++ openssh-8.4p1-vendor/sshd.c 2021-01-27 18:25:38.370273280 +0100 > @@ -136,7 +136,7 @@ > ServerOptions options; > > /* Name of the server configuration file. */ > -char *config_file_name = _PATH_SERVER_CONFIG_FILE; > +char *config_file_name = NULL; > > /* > * Debug mode flag. This can be set on the command line. If debug > @@ -1526,6 +1526,7 @@ > int > main(int ac, char **av) > { > + struct stat st; > struct ssh *ssh = NULL; > extern char *optarg; > extern int optind; > @@ -1737,7 +1738,21 @@ > */ > (void)atomicio(vwrite, startup_pipe, "\0", 1); > } > + } else if (config_file_name == NULL) { > + /* If only the vendor configuration file exists, use that. > + * Else use the standard configuration file. > + */ > + if (stat(_PATH_SERVER_VENDOR_CONFIG_FILE, &st) == 0 && > + stat(_PATH_SERVER_CONFIG_FILE, &st) == -1) { > + /* fill with global distributor settings */ > + config_file_name = _PATH_SERVER_VENDOR_CONFIG_FILE; > + } else { > + /* load global admin settings */ > + config_file_name = _PATH_SERVER_CONFIG_FILE; > + } > + load_server_config(config_file_name, cfg); > } else if (strcasecmp(config_file_name, "none") != 0) > + /* load config specified on commandline */ > load_server_config(config_file_name, cfg); > > parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, > diff -urN openssh-8.4p1/ssh-keysign.c openssh-8.4p1-vendor/ssh-keysign.c > --- openssh-8.4p1/ssh-keysign.c 2020-09-27 09:25:01.000000000 +0200 > +++ openssh-8.4p1-vendor/ssh-keysign.c 2021-01-15 15:03:13.258901048 +0100 > @@ -207,6 +207,8 @@ > initialize_options(&options); > (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "", > &options, 0, NULL); > + (void)read_config_file(_PATH_HOST_VENDOR_CONFIG_FILE, pw, "", "", > + &options, 0, NULL); > fill_default_options(&options); > if (options.enable_ssh_keysign != 1) > fatal("ssh-keysign not enabled in %s", -- Thorsten Kukuk, Distinguished Engineer, Senior Architect SLES & MicroOS SUSE Software Solutions Germany GmbH, Maxfeldstr. 5, 90409 Nuernberg, Germany Managing Director: Felix Imendoerffer (HRB 36809, AG Nürnberg)
diff -urN openssh-8.4p1/dh.c openssh-8.4p1-vendor/dh.c --- openssh-8.4p1/dh.c 2020-09-27 09:25:01.000000000 +0200 +++ openssh-8.4p1-vendor/dh.c 2021-01-29 11:49:40.968418136 +0100 @@ -151,10 +151,18 @@ size_t linesize = 0; int best, bestcount, which, linenum; struct dhgroup dhg; + char *dh_moduli_path; + struct stat st; - if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL) { + if (stat(_PATH_VENDOR_DH_MODULI, &st) == 0 && + stat(_PATH_DH_MODULI, &st) == -1) { + dh_moduli_path = _PATH_VENDOR_DH_MODULI; + } else { + dh_moduli_path = _PATH_DH_MODULI; + } + if ((f = fopen(dh_moduli_path, "r")) == NULL) { logit("WARNING: could not open %s (%s), using fixed modulus", - _PATH_DH_MODULI, strerror(errno)); + dh_moduli_path, strerror(errno)); return (dh_new_group_fallback(max)); } @@ -185,7 +193,7 @@ if (bestcount == 0) { fclose(f); - logit("WARNING: no suitable primes in %s", _PATH_DH_MODULI); + logit("WARNING: no suitable primes in %s", dh_moduli_path); return (dh_new_group_fallback(max)); } which = arc4random_uniform(bestcount); @@ -210,7 +218,7 @@ fclose(f); if (bestcount != which + 1) { logit("WARNING: selected prime disappeared in %s, giving up", - _PATH_DH_MODULI); + dh_moduli_path); return (dh_new_group_fallback(max)); } diff -urN openssh-8.4p1/pathnames.h openssh-8.4p1-vendor/pathnames.h --- openssh-8.4p1/pathnames.h 2020-09-27 09:25:01.000000000 +0200 +++ openssh-8.4p1-vendor/pathnames.h 2021-01-29 11:35:41.655599046 +0100 @@ -18,6 +18,8 @@ #define SSHDIR ETCDIR "/ssh" #endif +#define VENDORDIR "/usr/share/ssh" + #ifndef _PATH_SSH_PIDDIR #define _PATH_SSH_PIDDIR "/var/run" #endif @@ -35,13 +37,16 @@ * should be world-readable. */ #define _PATH_SERVER_CONFIG_FILE SSHDIR "/sshd_config" +#define _PATH_SERVER_VENDOR_CONFIG_FILE VENDORDIR "/sshd_config" #define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config" +#define _PATH_HOST_VENDOR_CONFIG_FILE VENDORDIR "/ssh_config" #define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key" #define _PATH_HOST_ECDSA_KEY_FILE SSHDIR "/ssh_host_ecdsa_key" #define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" #define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key" #define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key" #define _PATH_DH_MODULI SSHDIR "/moduli" +#define _PATH_VENDOR_DH_MODULI VENDORDIR "/moduli" #ifndef _PATH_SSH_PROGRAM #define _PATH_SSH_PROGRAM "/usr/bin/ssh" diff -urN openssh-8.4p1/ssh.c openssh-8.4p1-vendor/ssh.c --- openssh-8.4p1/ssh.c 2020-09-27 09:25:01.000000000 +0200 +++ openssh-8.4p1-vendor/ssh.c 2021-01-27 18:22:52.322271681 +0100 @@ -593,6 +593,7 @@ process_config_files(const char *host_name, struct passwd *pw, int final_pass, int *want_final_pass) { + struct stat st; char buf[PATH_MAX]; int r; @@ -611,10 +612,23 @@ &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | (final_pass ? SSHCONF_FINAL : 0), want_final_pass); - /* Read systemwide configuration file after user config. */ - (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, - host, host_name, &options, - final_pass ? SSHCONF_FINAL : 0, want_final_pass); + /* If only the vendor configuration file exists, use that. + * Else use the standard configuration file. + */ + if (stat(_PATH_HOST_VENDOR_CONFIG_FILE, &st) == 0 && + stat(_PATH_HOST_CONFIG_FILE, &st) == -1) { + /* Read vendor distributed configuration file. */ + (void)read_config_file(_PATH_HOST_VENDOR_CONFIG_FILE, + pw, host, host_name, &options, + final_pass ? SSHCONF_FINAL : 0, + want_final_pass); + } else { + /* Read systemwide configuration file after user config. */ + (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, + host, host_name, &options, + final_pass ? SSHCONF_FINAL : 0, + want_final_pass); + } } } diff -urN openssh-8.4p1/sshd.c openssh-8.4p1-vendor/sshd.c --- openssh-8.4p1/sshd.c 2020-09-27 09:25:01.000000000 +0200 +++ openssh-8.4p1-vendor/sshd.c 2021-01-27 18:25:38.370273280 +0100 @@ -136,7 +136,7 @@ ServerOptions options; /* Name of the server configuration file. */ -char *config_file_name = _PATH_SERVER_CONFIG_FILE; +char *config_file_name = NULL; /* * Debug mode flag. This can be set on the command line. If debug @@ -1526,6 +1526,7 @@ int main(int ac, char **av) { + struct stat st; struct ssh *ssh = NULL; extern char *optarg; extern int optind; @@ -1737,7 +1738,21 @@ */ (void)atomicio(vwrite, startup_pipe, "\0", 1); } + } else if (config_file_name == NULL) { + /* If only the vendor configuration file exists, use that. + * Else use the standard configuration file. + */ + if (stat(_PATH_SERVER_VENDOR_CONFIG_FILE, &st) == 0 && + stat(_PATH_SERVER_CONFIG_FILE, &st) == -1) { + /* fill with global distributor settings */ + config_file_name = _PATH_SERVER_VENDOR_CONFIG_FILE; + } else { + /* load global admin settings */ + config_file_name = _PATH_SERVER_CONFIG_FILE; + } + load_server_config(config_file_name, cfg); } else if (strcasecmp(config_file_name, "none") != 0) + /* load config specified on commandline */ load_server_config(config_file_name, cfg); parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, diff -urN openssh-8.4p1/ssh-keysign.c openssh-8.4p1-vendor/ssh-keysign.c --- openssh-8.4p1/ssh-keysign.c 2020-09-27 09:25:01.000000000 +0200 +++ openssh-8.4p1-vendor/ssh-keysign.c 2021-01-15 15:03:13.258901048 +0100 @@ -207,6 +207,8 @@ initialize_options(&options); (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, "", "", &options, 0, NULL); + (void)read_config_file(_PATH_HOST_VENDOR_CONFIG_FILE, pw, "", "", + &options, 0, NULL); fill_default_options(&options); if (options.enable_ssh_keysign != 1) fatal("ssh-keysign not enabled in %s",
_______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev