2
0
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:
Daniel Hilst
2026-09-03 14:55:51 -03:00
committed by GitHub
3 changed files with 601 additions and 24 deletions
+454
View File
@@ -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();
+8 -24
View File
@@ -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 ]
+139
View File
@@ -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