diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index a7e749a..49f0b95 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -19,15 +19,15 @@ jobs: set -ex freebsd-version mount -o acls / - pkg install -y bash unzip rsync ca_root_nss jq fping screen flock + pkg install -y bash unzip rsync ca_root_nss jq fping screen flock gmake mkdir -p /opt/bastion rsync -a . /opt/bastion/ fetch https://github.com/ovh/ovh-ttyrec/archive/master.zip unzip master.zip cd ovh-ttyrec-master/ ./configure - make - make install + gmake + gmake install cd .. /opt/bastion/bin/admin/packages-check.sh -i /opt/bastion/bin/admin/install --new-install --no-wait diff --git a/bin/admin/install b/bin/admin/install index 63b2658..e9f7d38 100755 --- a/bin/admin/install +++ b/bin/admin/install @@ -202,8 +202,8 @@ fi if [ "${opt[install-fake-ttyrec]}" = 1 ]; then action_doing "Installing fake ttyrec (use this only for tests!)" - if [ ! -e "/usr/bin/ttyrec" ]; then - install -o "$UID0" -g "$GID0" -m 0755 "$basedir/tests/functional/fake_ttyrec.sh" "/usr/bin/ttyrec" + if [ ! -e "/usr/bin/ttyrec" ] && [ ! -e "/usr/local/bin/ttyrec" ]; then + install -o "$UID0" -g "$GID0" -m 0755 "$basedir/tests/functional/fake_ttyrec.sh" "/usr/local/bin/ttyrec" action_done else action_na diff --git a/bin/admin/install-ttyrec.sh b/bin/admin/install-ttyrec.sh index 3fa6233..993bad9 100755 --- a/bin/admin/install-ttyrec.sh +++ b/bin/admin/install-ttyrec.sh @@ -196,11 +196,6 @@ if [ "$OS_FAMILY" != "Linux" ]; then exit 1 fi -if [ "$OS_FAMILY" != "Linux" ]; then - echo "Sorry, your OS ($(uname -s)) is not supported." >&2 - exit 1 -fi - while getopts :sdrah arg; do case "$arg" in s) action_static; exit 0;; diff --git a/bin/shell/connect.pl b/bin/shell/connect.pl index 49011cf..1b60d45 100755 --- a/bin/shell/connect.pl +++ b/bin/shell/connect.pl @@ -100,7 +100,12 @@ else { } # in any case, force this -$command[0] = '/usr/bin/ttyrec'; +if (-e '/usr/local/bin/ttyrec') { + $command[0] = '/usr/local/bin/ttyrec'; +} +else { + $command[0] = '/usr/bin/ttyrec'; +} # then finally launch the command ! my $sysret = system(@command); diff --git a/bin/shell/osh.pl b/bin/shell/osh.pl index 945aab4..216e588 100755 --- a/bin/shell/osh.pl +++ b/bin/shell/osh.pl @@ -872,38 +872,8 @@ if ($osh_command) { if ($MFArequiredForPlugin ne 'none' && !$skipMFA) { print "As this is required to run this plugin, entering MFA phase.\n"; - # use system() instead of OVH::Bastion::execute() because we need it to grab the term - my $pamtries = 3; - while (1) { - my $pamsysret; - if (OVH::Bastion::is_freebsd()) { - $pamsysret = system('sudo', '-n', '-u', 'root', '--', '/usr/bin/env', 'pamtester', 'sshd', $sysself, 'authenticate'); - } - else { - $pamsysret = system('pamtester', 'sshd', $sysself, 'authenticate'); - } - if ($pamsysret < 0) { - main_exit(OVH::Bastion::EXIT_MFA_FAILED, 'mfa_failed', "MFA is required for this plugin, but this bastion is missing the `pamtester' tool, aborting"); - } - elsif ($pamsysret != 0) { - if (--$pamtries <= 0) { - main_exit(OVH::Bastion::EXIT_MFA_FAILED, 'mfa_failed', "Sorry, but Multi-Factor Authentication failed, aborting"); - } - next; - } - - # success, if we are configured to launch a external command on pamtester success, do it. - # see the bastion.conf.dist file for usage example. - my $MFAPostCommand = OVH::Bastion::config('MFAPostCommand')->value; - if (ref $MFAPostCommand eq 'ARRAY' && @$MFAPostCommand) { - s/%ACCOUNT%/$self/g for @$MFAPostCommand; - $fnret = OVH::Bastion::execute(cmd => $MFAPostCommand, must_succeed => 1); - if (!$fnret) { - warn_syslog("MFAPostCommand returned a non-zero value: " . $fnret->msg); - } - } - last; - } + $fnret = OVH::Bastion::do_pamtester(self => $self, sysself => $sysself); + $fnret or main_exit(OVH::Bastion::EXIT_MFA_FAILED, 'mfa_failed', $fnret->msg); } OVH::Bastion::set_terminal_mode_for_plugin(plugin => $osh_command, action => 'set'); @@ -1310,38 +1280,8 @@ if ($JITMFARequired) { print "... skipping as your account is exempt from MFA\n"; } else { - # use system() instead of OVH::Bastion::execute() because we need it to grab the term - my $pamtries = 3; - while (1) { - my $pamsysret; - if (OVH::Bastion::is_freebsd()) { - $pamsysret = system('sudo', '-n', '-u', 'root', '--', '/usr/bin/env', 'pamtester', 'sshd', $sysself, 'authenticate'); - } - else { - $pamsysret = system('pamtester', 'sshd', $sysself, 'authenticate'); - } - if ($pamsysret < 0) { - main_exit(OVH::Bastion::EXIT_MFA_FAILED, 'mfa_failed', "MFA is required for this host, but this bastion is missing the `pamtester' tool, aborting"); - } - elsif ($pamsysret != 0) { - if (--$pamtries <= 0) { - main_exit(OVH::Bastion::EXIT_MFA_FAILED, 'mfa_failed', "Sorry, but Multi-Factor Authentication failed, I can't connect you to this host"); - } - next; - } - - # success, if we are configured to launch a external command on pamtester success, do it. - # see the bastion.conf.dist file for usage example. - my $MFAPostCommand = OVH::Bastion::config('MFAPostCommand')->value; - if (ref $MFAPostCommand eq 'ARRAY' && @$MFAPostCommand) { - s/%ACCOUNT%/$self/g for @$MFAPostCommand; - $fnret = OVH::Bastion::execute(cmd => $MFAPostCommand, must_succeed => 1); - if (!$fnret) { - warn_syslog("MFAPostCommand returned a non-zero value: " . $fnret->msg); - } - } - last; - } + $fnret = OVH::Bastion::do_pamtester(self => $self, sysself => $sysself); + $fnret or main_exit(OVH::Bastion::EXIT_MFA_FAILED, 'mfa_failed', $fnret->msg); } } diff --git a/lib/perl/OVH/Bastion.pm b/lib/perl/OVH/Bastion.pm index 85d6696..1240fb2 100644 --- a/lib/perl/OVH/Bastion.pm +++ b/lib/perl/OVH/Bastion.pm @@ -920,4 +920,49 @@ sub build_ttyrec_cmdline { return R('OK', value => {saveFile => $saveFile, cmd => \@ttyrec}); } +sub do_pamtester { + my %params = @_; + my $sysself = $params{'sysself'}; + my $self = $params{'self'}; + my $fnret; + + if (!$sysself || !$self) { + return R('ERR_MISSING_PARAMETER', msg => "Missing mandatory arguments 'sysself' or 'self'"); + } + + # use system() instead of OVH::Bastion::execute() because we need it to grab the term + my $pamtries = 3; + while (1) { + my $pamsysret; + if (OVH::Bastion::is_freebsd()) { + $pamsysret = system('sudo', '-n', '-u', 'root', '--', '/usr/bin/env', 'pamtester', 'sshd', $sysself, 'authenticate'); + } + else { + $pamsysret = system('pamtester', 'sshd', $sysself, 'authenticate'); + } + if ($pamsysret < 0) { + return R('KO_MFA_FAILED', msg => "MFA is required for this host, but this bastion is missing the `pamtester' tool, aborting"); + } + elsif ($pamsysret != 0) { + if (--$pamtries <= 0) { + return R('KO_MFA_FAILED', msg => "Sorry, but Multi-Factor Authentication failed, I can't connect you to this host"); + } + next; + } + + # success, if we are configured to launch a external command on pamtester success, do it. + # see the bastion.conf.dist file for usage example. + my $MFAPostCommand = OVH::Bastion::config('MFAPostCommand')->value; + if (ref $MFAPostCommand eq 'ARRAY' && @$MFAPostCommand) { + s/%ACCOUNT%/$self/g for @$MFAPostCommand; + $fnret = OVH::Bastion::execute(cmd => $MFAPostCommand, must_succeed => 1); + if (!$fnret) { + warn_syslog("MFAPostCommand returned a non-zero value: " . $fnret->msg); + } + } + last; + } + return R('OK_MFA_SUCCESS'); +} + 1; diff --git a/tests/functional/docker/target_role.sh b/tests/functional/docker/target_role.sh index 6873b34..e81ed35 100755 --- a/tests/functional/docker/target_role.sh +++ b/tests/functional/docker/target_role.sh @@ -56,7 +56,7 @@ cat /home/"$TARGET_USER"/.ssh/id_*.pub > ~test-shell_/.ssh/authorized_keys add_user_to_group_compat test-shell_ bastion-nopam # install a fake ttyrec just so that our connection tests work -if [ ! -e /usr/bin/ttyrec ] ; then +if ! command -v ttyrec >/dev/null; then "$basedir"/bin/admin/install --nothing --no-wait --install-fake-ttyrec fi diff --git a/tests/functional/tests.d/350-groups.sh b/tests/functional/tests.d/350-groups.sh index 7f966c8..d30bfe7 100644 --- a/tests/functional/tests.d/350-groups.sh +++ b/tests/functional/tests.d/350-groups.sh @@ -883,6 +883,7 @@ EOS success groupModify guest_ttl_limit $a1 --osh groupModify --group $group1 --guest-ttl-limit 0 json .command groupModify .error_code OK + # if we're just counting the number of tests, don't sleep [ "$COUNTONLY" != 1 ] && sleep 1 # group1: a1(owner,aclkeeper,gatekeeper,member) a2() servers(127.0.0.10,127.0.0.11)