mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-04 12:07:56 +00:00
Merge pull request #7726 from VersatusHPC/fix/remoteshell-sshd-config-drop-in
fix(remoteshell): stop rewriting the administrator's sshd_config
This commit is contained in:
@@ -0,0 +1,454 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Copy qw(copy);
|
||||
use File::Path qw(make_path);
|
||||
use File::Slurper qw(read_text write_text);
|
||||
use File::Temp qw(tempdir);
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use Test::More;
|
||||
|
||||
use XCAT::Test::File qw(repo_path);
|
||||
|
||||
my $postscripts = repo_path('xCAT/postscripts');
|
||||
my $remoteshell = "$postscripts/remoteshell";
|
||||
my $sshd_helper = "$postscripts/remoteshell-sshd-config";
|
||||
plan skip_all => 'remoteshell postscript not found' unless -r $remoteshell;
|
||||
plan skip_all => 'remoteshell sshd helper not found' unless -x $sshd_helper;
|
||||
# The postscript is written against GNU sed; sed -i means something else on BSD.
|
||||
plan skip_all => 'postscript targets Linux nodes' unless $^O eq 'linux';
|
||||
is( system( 'sh', '-n', $sshd_helper ), 0,
|
||||
'the sshd configuration helper has POSIX shell syntax' );
|
||||
|
||||
sub run_sshd_helper {
|
||||
my (%opt) = @_;
|
||||
|
||||
my ($root, $sshdir, $config);
|
||||
if ($opt{reuse}) {
|
||||
# A second deployment against the tree the first one left behind.
|
||||
($root, $sshdir, $config) = @{$opt{reuse}}{qw(root sshdir untouched)};
|
||||
}
|
||||
else {
|
||||
$root = tempdir(CLEANUP => 1);
|
||||
$sshdir = "$root/etc/ssh";
|
||||
make_path($sshdir);
|
||||
make_path("$root/bin");
|
||||
|
||||
# The fixtures name /etc/ssh so they read like a real config; point them
|
||||
# at the scratch tree along with the script itself.
|
||||
$config = $opt{sshd_config};
|
||||
$config =~ s{/etc/ssh}{$sshdir}g;
|
||||
write_text("$sshdir/sshd_config", $config);
|
||||
write_text("$sshdir/ssh_config", "Host *\n");
|
||||
make_path("$root$opt{dropin_dir}") if $opt{dropin_dir} && !$opt{skip_dropin_dir};
|
||||
|
||||
# Record logging in the scratch tree rather than the real syslog.
|
||||
write_text("$root/bin/logger",
|
||||
"#!/bin/sh\nprintf '%s\\n' \"\$*\" >> '$root/logger.log'\nexit 0\n");
|
||||
chmod 0755, "$root/bin/logger";
|
||||
}
|
||||
|
||||
my @args = (
|
||||
$opt{pcm} ? 1 : 0,
|
||||
defined $opt{osver} ? $opt{osver} : '',
|
||||
'xcat',
|
||||
);
|
||||
my $rc;
|
||||
my $output;
|
||||
{
|
||||
local $ENV{XCAT_SSH_ETC} = $sshdir;
|
||||
local $ENV{XCAT_LOGGER} = "$root/bin/logger";
|
||||
open(
|
||||
my $pipe,
|
||||
'-|', 'sh', '-c', 'exec "$@" 2>&1', 'sh',
|
||||
$sshd_helper, @args,
|
||||
) or die "Unable to run $sshd_helper: $!";
|
||||
$output = do { local $/; <$pipe> };
|
||||
close($pipe);
|
||||
$rc = $?;
|
||||
}
|
||||
|
||||
return {
|
||||
root => $root,
|
||||
sshdir => $sshdir,
|
||||
sshd_config => read_file("$sshdir/sshd_config"),
|
||||
ssh_config => read_file("$sshdir/ssh_config"),
|
||||
untouched => $config,
|
||||
orig => (-e "$sshdir/sshd_config.ORIG" ? 1 : 0),
|
||||
output => $output,
|
||||
rc => $rc,
|
||||
logged => read_file("$root/logger.log"),
|
||||
};
|
||||
}
|
||||
|
||||
sub read_file {
|
||||
my ($path) = @_;
|
||||
return '' unless -f $path;
|
||||
return read_text($path);
|
||||
}
|
||||
|
||||
sub run_remoteshell_wrapper {
|
||||
my (%opt) = @_;
|
||||
my $helper_contents = $opt{helper};
|
||||
my $root = tempdir(CLEANUP => 1);
|
||||
my $bin = "$root/bin";
|
||||
make_path($bin);
|
||||
|
||||
for my $name (qw(remoteshell xcatlib.sh)) {
|
||||
my $source = "$postscripts/$name";
|
||||
my $destination = "$bin/$name";
|
||||
copy($source, $destination)
|
||||
or die "Unable to stage $name: $!";
|
||||
chmod 0755, $destination or die "Unable to make $destination executable: $!";
|
||||
}
|
||||
if (defined $helper_contents) {
|
||||
write_text("$bin/remoteshell-sshd-config", $helper_contents);
|
||||
chmod 0755, "$bin/remoteshell-sshd-config"
|
||||
or die "Unable to make staged helper executable: $!";
|
||||
}
|
||||
write_text("$bin/logger", "#!/bin/sh\nprintf '%s\\n' \"\$*\" >>'$root/logger.log'\n");
|
||||
chmod 0755, "$bin/logger" or die "Unable to make logger executable: $!";
|
||||
|
||||
my $status;
|
||||
{
|
||||
local %ENV = (
|
||||
%ENV,
|
||||
PATH => "$bin:/usr/bin:/bin",
|
||||
OSVER => defined($opt{osver}) ? $opt{osver} : '',
|
||||
LOGLABEL => defined($opt{log_label}) ? $opt{log_label} : 'xcat',
|
||||
);
|
||||
$status = system( "$bin/remoteshell", @{ $opt{args} || [] } );
|
||||
}
|
||||
return ($status >> 8, read_file("$root/logger.log"));
|
||||
}
|
||||
|
||||
my $ADMIN_POLICY = <<'EOF';
|
||||
Port 22
|
||||
MaxStartups 3:30:3
|
||||
X11Forwarding no
|
||||
EOF
|
||||
|
||||
my $WITH_INCLUDE = "Include /etc/ssh/sshd_config.d/*.conf\n" . $ADMIN_POLICY;
|
||||
|
||||
SKIP: {
|
||||
skip 'the management-node marker bypasses remoteshell setup', 6
|
||||
if -e '/etc/xCATMN';
|
||||
|
||||
my ($missing_status, $missing_log) = run_remoteshell_wrapper();
|
||||
isnt($missing_status, 0, 'the wrapper fails when its sshd helper is missing');
|
||||
like($missing_log, qr/required sshd configuration helper not found/,
|
||||
'the wrapper reports the missing helper');
|
||||
|
||||
my ($failed_status, $failed_log) = run_remoteshell_wrapper(
|
||||
helper => "#!/bin/sh\nexit 42\n",
|
||||
);
|
||||
isnt($failed_status, 0, 'the wrapper fails when its sshd helper fails');
|
||||
like($failed_log, qr/failed to configure sshd/,
|
||||
'the wrapper reports the failed helper');
|
||||
|
||||
my $recording_helper = <<'SH';
|
||||
#!/bin/sh
|
||||
logger -t helper-args -p local4.info "$*"
|
||||
exit 42
|
||||
SH
|
||||
my ( undef, $plain_log ) = run_remoteshell_wrapper(
|
||||
helper => $recording_helper,
|
||||
osver => 'ubuntu24.04',
|
||||
log_label => 'wrapper-test',
|
||||
);
|
||||
like( $plain_log, qr/-t helper-args -p local4\.info 0 ubuntu24\.04 wrapper-test/m,
|
||||
'the wrapper passes the normal helper contract' );
|
||||
|
||||
my ( undef, $pcm_log ) = run_remoteshell_wrapper(
|
||||
helper => $recording_helper,
|
||||
osver => 'ubuntu24.04',
|
||||
log_label => 'wrapper-test',
|
||||
args => ['-p'],
|
||||
);
|
||||
like( $pcm_log, qr/-t helper-args -p local4\.info 1 ubuntu24\.04 wrapper-test/m,
|
||||
'the wrapper maps -p to the PCM helper contract' );
|
||||
}
|
||||
|
||||
# --- sshd that reads a drop-in directory -----------------------------------
|
||||
{
|
||||
my $r = run_sshd_helper(sshd_config => $WITH_INCLUDE, dropin_dir => '/etc/ssh/sshd_config.d');
|
||||
my $dropin = read_file("$r->{sshdir}/sshd_config.d/01-xcat.conf");
|
||||
|
||||
is($r->{rc}, 0, 'the postscript exits cleanly');
|
||||
is($r->{sshd_config}, $r->{untouched}, 'sshd_config is left exactly as the administrator wrote it');
|
||||
is($r->{orig}, 0, 'no sshd_config.ORIG copy is made when a drop-in is used');
|
||||
like($dropin, qr/^X11Forwarding yes$/m, 'X11Forwarding is set in the drop-in');
|
||||
unlike($dropin, qr/MaxStartups/, 'the drop-in does not set MaxStartups');
|
||||
ok(!glob("$r->{sshdir}/sshd_config.d/*xcatnew*"), 'no scratch file is left behind');
|
||||
like($r->{ssh_config}, qr/^StrictHostKeyChecking no$/m,
|
||||
'the client SSH setting is configured by the same helper');
|
||||
}
|
||||
|
||||
# The directory has to come from the file, since an administrator is free to
|
||||
# point Include somewhere other than /etc/ssh/sshd_config.d.
|
||||
{
|
||||
my $config = "Include /etc/ssh/local.d/*.conf\n" . $ADMIN_POLICY;
|
||||
my $r = run_sshd_helper(sshd_config => $config, dropin_dir => '/etc/ssh/local.d');
|
||||
|
||||
ok(-e "$r->{sshdir}/local.d/01-xcat.conf", 'the drop-in follows the Include path in the file');
|
||||
ok(!-e "$r->{sshdir}/sshd_config.d/01-xcat.conf", 'no file is written to the assumed default path');
|
||||
is($r->{sshd_config}, $r->{untouched}, 'sshd_config is untouched for a custom Include path');
|
||||
}
|
||||
|
||||
# The directory may not exist yet on a freshly installed node.
|
||||
{
|
||||
my $r = run_sshd_helper(sshd_config => $WITH_INCLUDE, dropin_dir => '/etc/ssh/sshd_config.d', skip_dropin_dir => 1);
|
||||
|
||||
ok(-e "$r->{sshdir}/sshd_config.d/01-xcat.conf", 'the drop-in directory is created when missing');
|
||||
}
|
||||
|
||||
# sshd resolves a relative Include under /etc/ssh, so writing it relative to
|
||||
# wherever the postscript happens to be running would land nowhere useful.
|
||||
{
|
||||
my $config = "Include sshd_config.d/*.conf\n" . $ADMIN_POLICY;
|
||||
my $r = run_sshd_helper(sshd_config => $config, dropin_dir => '/etc/ssh/sshd_config.d');
|
||||
|
||||
ok(-e "$r->{sshdir}/sshd_config.d/01-xcat.conf", 'a relative Include is resolved under /etc/ssh');
|
||||
is($r->{sshd_config}, $r->{untouched}, 'sshd_config is untouched for a relative Include');
|
||||
}
|
||||
|
||||
# Configuration keywords are not case sensitive.
|
||||
for my $case (
|
||||
['lower case include', "include /etc/ssh/sshd_config.d/*.conf\n"],
|
||||
['upper case INCLUDE', "INCLUDE /etc/ssh/sshd_config.d/*.conf\n"],
|
||||
) {
|
||||
my ($name, $prefix) = @{$case};
|
||||
my $r = run_sshd_helper(sshd_config => $prefix . $ADMIN_POLICY, dropin_dir => '/etc/ssh/sshd_config.d');
|
||||
|
||||
ok(-e "$r->{sshdir}/sshd_config.d/01-xcat.conf", "$name: the keyword is recognised");
|
||||
}
|
||||
|
||||
# Forms that cannot be reduced to one directory have to fall back rather than
|
||||
# guess, and an Include inside a Match block does not apply to every connection.
|
||||
for my $case (
|
||||
['several patterns on one line', "Include /etc/ssh/sshd_config.d/*.conf /etc/ssh/other.d/*.conf\n"],
|
||||
['a quoted path', qq{Include "/etc/ssh/sshd_config.d/*.conf"\n}],
|
||||
['a single file, not a glob', "Include /etc/ssh/local.conf\n"],
|
||||
['an Include inside Match', "Match User admin\nInclude /etc/ssh/sshd_config.d/*.conf\n"],
|
||||
['an Include inside MATCH', "MATCH User admin\nInclude /etc/ssh/sshd_config.d/*.conf\n"],
|
||||
) {
|
||||
my ($name, $prefix) = @{$case};
|
||||
my $r = run_sshd_helper(sshd_config => $prefix . $ADMIN_POLICY, dropin_dir => '/etc/ssh/sshd_config.d');
|
||||
|
||||
ok(!-e "$r->{sshdir}/sshd_config.d/01-xcat.conf", "$name: no drop-in is guessed at");
|
||||
is($r->{orig}, 1, "$name: falls back to editing sshd_config in place");
|
||||
}
|
||||
|
||||
# A kernel-owned directory cannot accept the scratch file, even as root. The
|
||||
# failure must stay quiet and fall back to the main configuration.
|
||||
SKIP: {
|
||||
skip 'procfs is not mounted at /proc', 3 unless -d '/proc/self';
|
||||
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => "Include /proc/*.conf\n" . $ADMIN_POLICY,
|
||||
);
|
||||
|
||||
like($r->{sshd_config}, qr/^X11Forwarding yes$/m, 'an unwritable drop-in directory falls back to the in-place edit');
|
||||
is($r->{orig}, 1, 'the fallback still keeps a backup copy');
|
||||
is($r->{output}, '', 'the expected drop-in fallback does not leak a shell error');
|
||||
}
|
||||
|
||||
# SSH configuration is best effort. An unwritable client configuration must not
|
||||
# prevent the wrapper from continuing to install the root keys.
|
||||
{
|
||||
my $r = run_sshd_helper(sshd_config => $WITH_INCLUDE, dropin_dir => '/etc/ssh/sshd_config.d');
|
||||
unlink "$r->{sshdir}/ssh_config"
|
||||
or die "Unable to remove the client configuration: $!";
|
||||
mkdir "$r->{sshdir}/ssh_config"
|
||||
or die "Unable to create the unwritable client configuration: $!";
|
||||
my $again = run_sshd_helper(reuse => $r);
|
||||
|
||||
is($again->{rc}, 0, 'an unwritable client configuration remains best effort');
|
||||
}
|
||||
|
||||
# An administrator's own file at 01-xcat.conf must not be clobbered; xCAT
|
||||
# leaves it and edits sshd_config in place instead.
|
||||
{
|
||||
my $r = run_sshd_helper(sshd_config => $WITH_INCLUDE, dropin_dir => '/etc/ssh/sshd_config.d', skip_dropin_dir => 1);
|
||||
make_path("$r->{sshdir}/sshd_config.d");
|
||||
my $foreign = "$r->{sshdir}/sshd_config.d/01-xcat.conf";
|
||||
write_text($foreign, "# admin's own file\nX11Forwarding no\n");
|
||||
my $again = run_sshd_helper(reuse => $r);
|
||||
|
||||
is(read_file($foreign), "# admin's own file\nX11Forwarding no\n", 'a foreign 01-xcat.conf is left untouched');
|
||||
like($again->{sshd_config}, qr/^X11Forwarding yes$/m, 'the setting falls back to sshd_config when the name is taken');
|
||||
is($again->{orig}, 1, 'the fallback keeps a backup copy');
|
||||
like($again->{logged}, qr/01-xcat\.conf sets X11Forwarding before the fallback value/,
|
||||
'the fallback warns that the earlier fragment still controls X11Forwarding');
|
||||
}
|
||||
|
||||
# The same protection covers the PCM fragment: a foreign 02-xcat-pcm.conf is
|
||||
# not overwritten, and the PCM setting still lands via the in-place edit rather
|
||||
# than being silently dropped.
|
||||
{
|
||||
my $config = "Include /etc/ssh/sshd_config.d/*.conf\nPermitRootLogin prohibit-password\n";
|
||||
my $r = run_sshd_helper(sshd_config => $config, dropin_dir => '/etc/ssh/sshd_config.d', skip_dropin_dir => 1);
|
||||
make_path("$r->{sshdir}/sshd_config.d");
|
||||
my $foreign = "$r->{sshdir}/sshd_config.d/02-xcat-pcm.conf";
|
||||
write_text($foreign, "# admin's own file\nPermitRootLogin no\n");
|
||||
my $again = run_sshd_helper(reuse => $r, pcm => 1, osver => 'ubuntu24.04');
|
||||
|
||||
is(read_file($foreign), "# admin's own file\nPermitRootLogin no\n", 'a foreign 02-xcat-pcm.conf is left untouched');
|
||||
like($again->{sshd_config}, qr/^PermitRootLogin yes$/m, 'PCM falls back to the in-place edit when its fragment cannot be written');
|
||||
like($again->{logged}, qr/02-xcat-pcm\.conf sets PermitRootLogin before the fallback value/,
|
||||
'the PCM fallback warns that the earlier fragment still controls root login');
|
||||
}
|
||||
|
||||
{
|
||||
my $config = "Include /etc/ssh/sshd_config.d/*.conf\n#PermitRootLogin prohibit-password\n";
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => $config,
|
||||
dropin_dir => '/etc/ssh/sshd_config.d',
|
||||
pcm => 1,
|
||||
osver => 'ubuntu24.04',
|
||||
);
|
||||
|
||||
ok(!-e "$r->{sshdir}/sshd_config.d/02-xcat-pcm.conf",
|
||||
'Ubuntu PCM does not create a root-login setting when none was active');
|
||||
is($r->{sshd_config}, $r->{untouched},
|
||||
'Ubuntu PCM preserves a commented root-login default');
|
||||
}
|
||||
|
||||
# sshd allows glob metacharacters anywhere in an Include path. A parent that is
|
||||
# itself a pattern (sshd_config.[12].d) must not be written to literally.
|
||||
{
|
||||
my $config = "Include /etc/ssh/sshd_config.[12].d/*.conf\n" . $ADMIN_POLICY;
|
||||
my $r = run_sshd_helper(sshd_config => $config);
|
||||
|
||||
ok(!-e "$r->{sshdir}/sshd_config.[12].d", 'no literal directory is created for a glob parent');
|
||||
like($r->{sshd_config}, qr/^X11Forwarding yes$/m, 'a glob parent falls back to the in-place edit');
|
||||
is($r->{orig}, 1, 'the glob-parent fallback keeps a backup copy');
|
||||
}
|
||||
|
||||
# --- sshd without Include support ------------------------------------------
|
||||
for my $case (
|
||||
['no Include line at all', $ADMIN_POLICY],
|
||||
['Include commented out', "#Include /etc/ssh/sshd_config.d/*.conf\n" . $ADMIN_POLICY],
|
||||
) {
|
||||
my ($name, $config) = @{$case};
|
||||
my $r = run_sshd_helper(sshd_config => $config);
|
||||
|
||||
like($r->{sshd_config}, qr/^X11Forwarding yes$/m, "$name: X11Forwarding is set in sshd_config");
|
||||
unlike($r->{sshd_config}, qr/^X11Forwarding no$/m, "$name: the old X11Forwarding line is removed");
|
||||
is($r->{orig}, 1, "$name: sshd_config.ORIG is kept as a backup");
|
||||
ok(!-e "$r->{sshdir}/sshd_config.d/01-xcat.conf", "$name: no drop-in is written");
|
||||
}
|
||||
|
||||
# --- MaxStartups belongs to the administrator ------------------------------
|
||||
for my $case (
|
||||
['with a drop-in directory', $WITH_INCLUDE, '/etc/ssh/sshd_config.d'],
|
||||
['editing in place', $ADMIN_POLICY, undef],
|
||||
) {
|
||||
my ($name, $config, $dir) = @{$case};
|
||||
my $r = run_sshd_helper(sshd_config => $config, dropin_dir => $dir);
|
||||
|
||||
like($r->{sshd_config}, qr/^MaxStartups 3:30:3$/m, "$name: the administrator's MaxStartups survives");
|
||||
}
|
||||
|
||||
# --- the PCM settings keep their own fragment ------------------------------
|
||||
# updatenode reruns remoteshell without -p, so anything the PCM setup wrote has
|
||||
# to survive a plain run.
|
||||
{
|
||||
my $config = "Include /etc/ssh/sshd_config.d/*.conf\nPermitRootLogin prohibit-password\n";
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => $config,
|
||||
dropin_dir => '/etc/ssh/sshd_config.d',
|
||||
pcm => 1,
|
||||
osver => 'ubuntu24.04',
|
||||
);
|
||||
|
||||
like(read_file("$r->{sshdir}/sshd_config.d/02-xcat-pcm.conf"), qr/^PermitRootLogin yes$/m,
|
||||
'PermitRootLogin goes to its own fragment on Ubuntu');
|
||||
unlike(read_file("$r->{sshdir}/sshd_config.d/01-xcat.conf"), qr/PermitRootLogin/,
|
||||
'the PCM setting is kept out of 01-xcat.conf');
|
||||
is($r->{sshd_config}, $r->{untouched}, 'sshd_config is untouched by the PCM setup');
|
||||
|
||||
my $again = run_sshd_helper(reuse => $r, osver => 'ubuntu24.04');
|
||||
like(read_file("$again->{sshdir}/sshd_config.d/02-xcat-pcm.conf"), qr/^PermitRootLogin yes$/m,
|
||||
'a later run without -p leaves the PCM setting alone');
|
||||
like(read_file("$again->{sshdir}/sshd_config.d/01-xcat.conf"), qr/^X11Forwarding yes$/m,
|
||||
'the later run still refreshes its own fragment');
|
||||
}
|
||||
|
||||
{
|
||||
my $config = "Include /etc/ssh/sshd_config.d/*.conf\nPasswordAuthentication no\n";
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => $config,
|
||||
dropin_dir => '/etc/ssh/sshd_config.d',
|
||||
pcm => 1,
|
||||
osver => 'sles15',
|
||||
);
|
||||
|
||||
like(read_file("$r->{sshdir}/sshd_config.d/02-xcat-pcm.conf"), qr/^PasswordAuthentication yes$/m,
|
||||
'PasswordAuthentication goes to its own fragment on SLES');
|
||||
|
||||
my $again = run_sshd_helper(reuse => $r, osver => 'sles15');
|
||||
like(read_file("$again->{sshdir}/sshd_config.d/02-xcat-pcm.conf"), qr/^PasswordAuthentication yes$/m,
|
||||
'a later run without -p leaves the SLES setting alone');
|
||||
}
|
||||
|
||||
# Without a drop-in directory the PCM settings are still edited in place.
|
||||
{
|
||||
my $r = run_sshd_helper(sshd_config => "PasswordAuthentication no\n", pcm => 1, osver => 'sles15');
|
||||
|
||||
like($r->{sshd_config}, qr/^PasswordAuthentication yes$/m, 'PasswordAuthentication is edited in place on SLES');
|
||||
unlike($r->{sshd_config}, qr/^PasswordAuthentication no$/m, 'the old PasswordAuthentication line is removed');
|
||||
}
|
||||
|
||||
# sshd keeps the first value it finds, so a keyword set ahead of the Include
|
||||
# line still wins over the drop-in. The postscript detects that and warns.
|
||||
{
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => "X11Forwarding no\nInclude /etc/ssh/sshd_config.d/*.conf\nPort 22\n" );
|
||||
|
||||
like( $r->{logged}, qr/X11Forwarding is set before the Include line/,
|
||||
'a keyword set before the Include line is reported' );
|
||||
like( $r->{logged}, qr{01-xcat\.conf},
|
||||
'the report names the fragment that is overridden' );
|
||||
}
|
||||
|
||||
# The same keyword after the Include line does not override the drop-in.
|
||||
{
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => "Include /etc/ssh/sshd_config.d/*.conf\nX11Forwarding no\nPort 22\n" );
|
||||
|
||||
unlike( $r->{logged}, qr/X11Forwarding is set before the Include line/,
|
||||
'a keyword set after the Include line is not reported' );
|
||||
}
|
||||
|
||||
# The Include keyword is matched whatever its case and leading spacing.
|
||||
{
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => "X11Forwarding no\n inClUdE /etc/ssh/sshd_config.d/*.conf\nPort 22\n" );
|
||||
|
||||
like( $r->{logged}, qr/X11Forwarding is set before the Include line/,
|
||||
'the Include line is recognised whatever its case and spacing' );
|
||||
}
|
||||
|
||||
# A keyword that merely starts with the Include name is not an Include line.
|
||||
{
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => "IncludeFoo bar\nX11Forwarding no\nInclude /etc/ssh/sshd_config.d/*.conf\n" );
|
||||
|
||||
like( $r->{logged}, qr/X11Forwarding is set before the Include line/,
|
||||
'a keyword that only begins with Include does not end the search' );
|
||||
}
|
||||
|
||||
# An earlier Include that is not the selected drop-in glob does not end the
|
||||
# precedence scan either.
|
||||
{
|
||||
my $r = run_sshd_helper(
|
||||
sshd_config => "Include /etc/ssh/local.conf\nX11Forwarding no\nInclude /etc/ssh/sshd_config.d/*.conf\n" );
|
||||
|
||||
like( $r->{logged}, qr/X11Forwarding is set before the Include line/,
|
||||
'an unrelated earlier Include does not hide an overriding keyword' );
|
||||
}
|
||||
|
||||
done_testing();
|
||||
@@ -54,31 +54,15 @@ if [ "$USEFLOWCONTROL" = "YES" ] || [ "$USEFLOWCONTROL" = "yes" ] || [ "$USEFLOW
|
||||
useflowcontrol=1
|
||||
fi
|
||||
|
||||
if [ -r /etc/ssh/sshd_config ]
|
||||
then
|
||||
logger -t $log_label -p local4.info "remoteshell: setup /etc/ssh/sshd_config and ssh_config"
|
||||
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.ORIG
|
||||
#delete all occurance of the attribute and then add xCAT settings
|
||||
sed -i '/X11Forwarding /'d /etc/ssh/sshd_config
|
||||
echo "X11Forwarding yes" >>/etc/ssh/sshd_config
|
||||
# delete all MaxStartups settings and use default value
|
||||
sed -i '/MaxStartups /'d /etc/ssh/sshd_config
|
||||
|
||||
if [ "$SETUPFORPCM" = "1" ]; then
|
||||
if [[ $OSVER == sle* ]];then
|
||||
sed -i '/PasswordAuthentication /'d /etc/ssh/sshd_config
|
||||
echo "PasswordAuthentication yes" >>/etc/ssh/sshd_config
|
||||
elif [[ $OSVER == ubuntu* ]];then
|
||||
sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
|
||||
fi
|
||||
sshd_config_helper="$(dirname "$0")/remoteshell-sshd-config"
|
||||
if [ -x "$sshd_config_helper" ]; then
|
||||
if ! "$sshd_config_helper" "${SETUPFORPCM:-0}" "${OSVER:-}" "$log_label"; then
|
||||
logger -t $log_label -p local4.err "remoteshell: failed to configure sshd with $sshd_config_helper"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -r /etc/ssh/ssh_config ]
|
||||
then
|
||||
sed -i '/StrictHostKeyChecking /'d /etc/ssh/ssh_config
|
||||
echo "StrictHostKeyChecking no" >> /etc/ssh/ssh_config
|
||||
|
||||
else
|
||||
logger -t $log_label -p local4.err "remoteshell: required sshd configuration helper not found: $sshd_config_helper"
|
||||
exit 1
|
||||
fi
|
||||
xcatpost="xcatpost"
|
||||
if [ -d /xcatpost/_ssh ]
|
||||
|
||||
Executable
+139
@@ -0,0 +1,139 @@
|
||||
#!/bin/sh
|
||||
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
||||
|
||||
setup_for_pcm=${1:-0}
|
||||
osver=${2:-}
|
||||
log_label=${3:-xcat}
|
||||
ssh_etc=${XCAT_SSH_ETC:-/etc/ssh}
|
||||
logger_command=${XCAT_LOGGER:-logger}
|
||||
sshd_config="$ssh_etc/sshd_config"
|
||||
ssh_config="$ssh_etc/ssh_config"
|
||||
|
||||
xcat_log() {
|
||||
priority=$1
|
||||
shift
|
||||
"$logger_command" -t "$log_label" -p "$priority" "$@"
|
||||
}
|
||||
|
||||
# Write a drop-in fragment atomically: scratch file then rename, the leading dot
|
||||
# keeping the scratch out of sshd's *.conf glob. Returns nonzero without
|
||||
# touching anything if the write fails or the file is not ours.
|
||||
XCATSSHDDROPINMARKER="# Written by the xCAT remoteshell postscript."
|
||||
xcat_write_dropin() {
|
||||
xcat_dir=$1
|
||||
xcat_file=$2
|
||||
shift 2
|
||||
xcat_dest="$xcat_dir/$xcat_file"
|
||||
if [ -e "$xcat_dest" ] && \
|
||||
! head -n 1 "$xcat_dest" 2>/dev/null | grep -qF "$XCATSSHDDROPINMARKER"; then
|
||||
return 1
|
||||
fi
|
||||
xcat_tmp="$xcat_dir/.$xcat_file.xcatnew.$$"
|
||||
mkdir -p "$xcat_dir" 2>/dev/null || return 1
|
||||
( : >"$xcat_tmp" ) 2>/dev/null || return 1
|
||||
chmod 600 "$xcat_tmp" 2>/dev/null
|
||||
(
|
||||
echo "$XCATSSHDDROPINMARKER Do not edit."
|
||||
for xcat_line in "$@"; do
|
||||
echo "$xcat_line"
|
||||
done
|
||||
) 2>/dev/null >>"$xcat_tmp" || { rm -f "$xcat_tmp"; return 1; }
|
||||
mv -f "$xcat_tmp" "$xcat_dest" 2>/dev/null || { rm -f "$xcat_tmp"; return 1; }
|
||||
return 0
|
||||
}
|
||||
|
||||
# sshd keeps the first value it finds for a keyword, so a setting ahead of the
|
||||
# Include line or in an earlier fragment still wins over ours; log it.
|
||||
xcat_warn_if_overridden() {
|
||||
xcat_kw=$1
|
||||
xcat_own="$XCATSSHDDROPINDIR/$2"
|
||||
if sed -n '/^[[:space:]]*[Mm][Aa][Tt][Cc][Hh][[:space:]]/q; /^[[:space:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:space:]]\{1,\}[^[:space:]]\{1,\}\/\*\.conf[[:space:]]*$/q; p' "$sshd_config" 2>/dev/null | \
|
||||
grep -i "^[[:space:]]*${xcat_kw}[[:space:]]" >/dev/null 2>&1; then
|
||||
xcat_log local4.warning "remoteshell: $xcat_kw is set before the Include line in $sshd_config and overrides $xcat_own"
|
||||
fi
|
||||
for xcat_frag in "$XCATSSHDDROPINDIR"/*.conf; do
|
||||
[ "$xcat_frag" = "$xcat_own" ] && break
|
||||
[ -r "$xcat_frag" ] || continue
|
||||
if grep -i "^[[:space:]]*${xcat_kw}[[:space:]]" "$xcat_frag" >/dev/null 2>&1; then
|
||||
xcat_log local4.warning "remoteshell: $xcat_frag sets $xcat_kw and is read before $xcat_own"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
xcat_warn_if_fragment_overrides_fallback() {
|
||||
xcat_kw=$1
|
||||
[ -n "$XCATSSHDDIR" ] || return 0
|
||||
for xcat_frag in "$XCATSSHDDIR"/*.conf; do
|
||||
[ -r "$xcat_frag" ] || continue
|
||||
if grep -i "^[[:space:]]*${xcat_kw}[[:space:]]" "$xcat_frag" >/dev/null 2>&1; then
|
||||
xcat_log local4.warning "remoteshell: $xcat_frag sets $xcat_kw before the fallback value appended to $sshd_config"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
if [ -r "$sshd_config" ]; then
|
||||
xcat_log local4.info "remoteshell: setup $sshd_config and ssh_config"
|
||||
|
||||
# Take a single *.conf Include ahead of the first Match block. An Include
|
||||
# inside Match does not apply to every connection.
|
||||
XCATSSHDDIR=`sed -n '/^[[:space:]]*[Mm][Aa][Tt][Cc][Hh][[:space:]]/q; s|^[[:space:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:space:]]\{1,\}\([^[:space:]]\{1,\}\)/\*\.conf[[:space:]]*$|\1|p' "$sshd_config" | head -n 1`
|
||||
case "$XCATSSHDDIR" in
|
||||
""|/*) ;;
|
||||
*) XCATSSHDDIR="$ssh_etc/$XCATSSHDDIR" ;;
|
||||
esac
|
||||
case "$XCATSSHDDIR" in
|
||||
*[][*?]*) XCATSSHDDIR="" ;;
|
||||
esac
|
||||
|
||||
XCATSSHDDROPINDIR=""
|
||||
if [ -n "$XCATSSHDDIR" ]; then
|
||||
if xcat_write_dropin "$XCATSSHDDIR" "01-xcat.conf" "X11Forwarding yes"; then
|
||||
XCATSSHDDROPINDIR="$XCATSSHDDIR"
|
||||
xcat_warn_if_overridden "X11Forwarding" "01-xcat.conf"
|
||||
else
|
||||
xcat_log local4.err "remoteshell: could not write $XCATSSHDDIR/01-xcat.conf, editing $sshd_config instead"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$XCATSSHDDROPINDIR" ]; then
|
||||
cp "$sshd_config" "$sshd_config.ORIG"
|
||||
sed -i '/X11Forwarding /'d "$sshd_config"
|
||||
echo "X11Forwarding yes" >>"$sshd_config"
|
||||
xcat_warn_if_fragment_overrides_fallback "X11Forwarding"
|
||||
fi
|
||||
|
||||
if [ "$setup_for_pcm" = "1" ]; then
|
||||
case "$osver" in
|
||||
sle*)
|
||||
if [ -n "$XCATSSHDDROPINDIR" ] && \
|
||||
xcat_write_dropin "$XCATSSHDDROPINDIR" "02-xcat-pcm.conf" "PasswordAuthentication yes"; then
|
||||
xcat_warn_if_overridden "PasswordAuthentication" "02-xcat-pcm.conf"
|
||||
else
|
||||
[ -e "$sshd_config.ORIG" ] || cp "$sshd_config" "$sshd_config.ORIG"
|
||||
sed -i '/PasswordAuthentication /'d "$sshd_config"
|
||||
echo "PasswordAuthentication yes" >>"$sshd_config"
|
||||
xcat_warn_if_fragment_overrides_fallback "PasswordAuthentication"
|
||||
fi
|
||||
;;
|
||||
ubuntu*)
|
||||
if grep -q '^PermitRootLogin' "$sshd_config"; then
|
||||
if [ -n "$XCATSSHDDROPINDIR" ] && \
|
||||
xcat_write_dropin "$XCATSSHDDROPINDIR" "02-xcat-pcm.conf" "PermitRootLogin yes"; then
|
||||
xcat_warn_if_overridden "PermitRootLogin" "02-xcat-pcm.conf"
|
||||
else
|
||||
[ -e "$sshd_config.ORIG" ] || cp "$sshd_config" "$sshd_config.ORIG"
|
||||
sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' "$sshd_config"
|
||||
xcat_warn_if_fragment_overrides_fallback "PermitRootLogin"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -r "$ssh_config" ]; then
|
||||
sed -i '/StrictHostKeyChecking /'d "$ssh_config"
|
||||
echo "StrictHostKeyChecking no" >>"$ssh_config"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user