diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index 5055f26..cc3682d 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -30,4 +30,4 @@ jobs: ssh-keygen -t ed25519 -f id_user ssh-keygen -t ed25519 -f id_root WANT_HTTP_PROXY=0 NO_SLEEP=1 user_pubkey=$(cat id_user.pub) root_pubkey=$(cat id_root.pub) TARGET_USER=user5000 /opt/bastion/tests/functional/docker/target_role.sh - /opt/bastion/tests/functional/launch_tests_on_instance.sh --module=500-http-proxy.sh --has-mfa=0 --has-mfa-password=1 --has-pamtester=1 --skip-consistency-check --remote-etc-bastion=/usr/local/etc/bastion 127.0.0.1 22 0 user5000 id_user id_root + /opt/bastion/tests/functional/launch_tests_on_instance.sh --has-mfa=0 --has-mfa-password=1 --has-pamtester=1 --skip-consistency-check --remote-etc-bastion=/usr/local/etc/bastion 127.0.0.1 22 0 user5000 id_user id_root diff --git a/README.md b/README.md index 02c9cb0..2fbcf33 100644 --- a/README.md +++ b/README.md @@ -86,10 +86,7 @@ The following OS are also tested with each release: \*\*: Note that these have partial MFA support, due to their reduced set of available `pam` plugins. Support for either an additional password or TOTP factor can be configured, but not both at the same time. The code is actually known to work on FreeBSD/HardenedBSD 10+, but it's only regularly tested under 13.0. -Other BSD variants partially work but are unsupported and discouraged as they have a severe limitation over the maximum number of supplementary groups (causing problems for group membership and restricted commands checks), no filesystem-level ACL support and missing MFA: - -- OpenBSD 5.4+ -- NetBSD 7+ +Other BSD variants, namely OpenBSD 5.4+ and NetBSD 7+ partially work but are unsupported and discouraged as they have a severe limitation over the maximum number of supplementary groups, causing problems for group membership and restricted commands checks, as well as no filesystem-level ACL support and missing PAM support (hence no MFA). ### Zero assumption on your environment diff --git a/bin/admin/install b/bin/admin/install index eca7925..b4f9232 100755 --- a/bin/admin/install +++ b/bin/admin/install @@ -219,7 +219,12 @@ if [ "$OS_FAMILY" = FreeBSD ]; then home_mp=/ fi if ! mount | awk '{ if($3=="'"$home_mp"'"){print;exit} }' | grep -q -w acls; then - action_error "No. Please modify your /etc/fstab accordingly, and run \`mount -u -o acls $home_mp' to apply the change on-the-fly." + if mount | awk '{ if($3=="'"$home_mp"'"){print;exit} }' | grep -q -w zfs; then + action_error "No. This is a ZFS mount, which might not be POSIX acls compliant (nfsv4acls supported only)." + action_error "You can still try to enable POSIX acls by running \`mount -u -o acls $home_mp' to apply the change on-the-fly." + else + action_error "No. Please modify your /etc/fstab accordingly, and run \`mount -u -o acls $home_mp' to apply the change on-the-fly." + fi exit 1 else action_done diff --git a/bin/shell/autologin b/bin/shell/autologin index 16dc331..c361f7d 100755 --- a/bin/shell/autologin +++ b/bin/shell/autologin @@ -1,11 +1,15 @@ -#!/usr/bin/expect -f +#!/usr/bin/env expect # vim: set filetype=expect ts=4 sw=4 sts=4 et: + +# To debug this script, you may want to uncomment the two following lines: +#exp_internal 1 #strace 2 + set ::env(TERM) "" # we need 6 arguments if { [llength $argv] < 8 } { - puts "BASTION SAYS: autologin usage error, expected 6 args: [passthrough arguments to ssh or telnet]" + puts {BASTION SAYS: autologin usage error, expected 6 args: [passthrough arguments to ssh or telnet]} exit 1 } @@ -81,17 +85,22 @@ proc attempt_to_login args { # send password expect { - -re "Password:|password:" { send -- "$pass" } + -re {[Pp]assword:|Password for [a-zA-Z0-9@._-]+:} { send -- "$pass" } eof { puts "BASTION SAYS: connection aborted"; exit 3 } timeout { puts "BASTION SAYS: timed out while waiting for password prompt"; exit 3 } } # do we have a login success with interactive prompt? expect { + # prompts "#" { interact; exit 0 } ">" { interact; exit 0 } + # 'enable' prompt on a network device "(enable)" { interact; exit 0 } - -re "Password:|password:|Authentication failed|Permission denied" { + # a successful login on a bastion (mainly for tests) + -exact "the-bastion-" { interact; exit 0 } + # login failure messages + -re {[Pp]assword:|Password for [a-zA-Z0-9@_-]+:|Authentication failed|Permission denied|UNIX authentication refused} { if { $tryid == 0 } { puts "BASTION SAYS: authentication failed!" } close wait diff --git a/lib/shell/install.inc b/lib/shell/install.inc index 4b2c337..6fbd654 100644 --- a/lib/shell/install.inc +++ b/lib/shell/install.inc @@ -183,11 +183,12 @@ action_auto() { *debian*) action_package deb;; *rhel*) action_package rpm;; *suse*) action_package rpm;; + freebsd) action_static;; *) if [ "$OS_FAMILY" = Linux ]; then action_static else - echo "This script doesn't support this OS yet ($DISTRO_LIKE)" >&2 + echo "This script doesn't support this OS yet ($OS_FAMILY/$DISTRO_LIKE)" >&2 exit 1 fi;; esac @@ -205,7 +206,7 @@ install_main() { d) action_package deb; exit 0;; r) action_package rpm; exit 0;; a) action_auto; exit 0;; - h) usage; exit 0;; + h) install_usage; exit 0;; ?) echo "Invalid option: -$OPTARG"; usage; exit 1;; esac done diff --git a/tests/functional/tests.d/325-accountinfo.sh b/tests/functional/tests.d/325-accountinfo.sh index 162951d..3687bca 100644 --- a/tests/functional/tests.d/325-accountinfo.sh +++ b/tests/functional/tests.d/325-accountinfo.sh @@ -36,12 +36,15 @@ testsuite_accountinfo() success a1_accountinfo_a2_detailed $a1 --osh accountInfo --account $account2 json .error_code OK .command accountInfo .value.always_active 1 .value.is_active 1 .value.allowed_commands "[]" json .value.ingress_piv_policy null .value.personal_egress_mfa_required none .value.pam_auth_bypass 0 - json .value.password.min_days 0 .value.password.warn_days 7 .value.password.user "$account2" .value.password.password locked - json .value.password.inactive_days -1 .value.password.date_disabled null .value.password.date_disabled_timestamp 0 .value.password.date_changed $(date +%Y-%m-%d) + json .value.password.min_days 0 .value.password.user "$account2" .value.password.password locked + json .value.password.inactive_days -1 .value.password.date_disabled null .value.password.date_disabled_timestamp 0 json .value.ingress_piv_enforced 0 .value.always_active 1 .value.creation_information.by "$account0" json .value.creation_information.comment "this is a comment" json .value.already_seen_before 0 .value.last_activity null json .value.max_inactive_days null + if [ "$OS_FAMILY" = Linux ]; then + .value.password.date_changed $(date +%Y-%m-%d) + fi # a2 connects, which will update already_seen_before success a2_connects $a2 --osh info diff --git a/tests/functional/tests.d/370-mfa.sh b/tests/functional/tests.d/370-mfa.sh index 27c98e9..ea9382d 100644 --- a/tests/functional/tests.d/370-mfa.sh +++ b/tests/functional/tests.d/370-mfa.sh @@ -145,21 +145,30 @@ testsuite_mfa() contain 'Permission denied' # test proactive mfa - script set_help_mfa $r0 "'"'echo \{\"mfa_required\":\ \"password\"\} > /etc/bastion/plugin.help.conf; chmod 644 /etc/bastion/plugin.help.conf'"'" + script set_help_mfa $r0 "'"'echo \{\"mfa_required\":\ \"password\"\} > '"$opt_remote_etc_bastion"'/plugin.help.conf; chmod 644 '"$opt_remote_etc_bastion"'/plugin.help.conf'"'" retvalshouldbe 0 - script a4_mfa_help_jitmfa "echo 'set timeout 30; \ - spawn $a4 --osh help; \ - expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \ - expect \"is required (password)\" { sleep 0.1; }; \ - expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \ - expect eof; \ - lassign [wait] pid spawnid value value; \ - exit \$value' | expect -f -" + if [ "$OS_FAMILY" = FreeBSD ]; then + script a4_mfa_help_jitmfa "echo 'set timeout 30; \ + spawn $a4 --osh help; \ + expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \ + expect eof; \ + lassign [wait] pid spawnid value value; \ + exit \$value' | expect -f -" + else + script a4_mfa_help_jitmfa "echo 'set timeout 30; \ + spawn $a4 --osh help; \ + expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \ + expect \"is required (password)\" { sleep 0.1; }; \ + expect \":\" { sleep 0.2; send \"$a4_password\\n\"; }; \ + expect eof; \ + lassign [wait] pid spawnid value value; \ + exit \$value' | expect -f -" + contain 'pamtester: successfully authenticated' + fi retvalshouldbe 0 contain 'Multi-Factor Authentication enabled, an additional authentication factor is required (password).' contain REGEX 'Password:|Password for' - contain 'pamtester: successfully authenticated' nocontain 'proactive MFA' script a4_proactive_mfa_help "echo 'set timeout 30; \ @@ -177,7 +186,7 @@ testsuite_mfa() contain 'proactive MFA' json .command help .error_code OK - script remove_help_mfa $r0 "'"'rm -f /etc/bastion/plugin.help.conf'"'" + script remove_help_mfa $r0 "'"'rm -f '"$opt_remote_etc_bastion"'/plugin.help.conf'"'" retvalshouldbe 0 # /proactive mfa