|
| 1 | +tid="GSSAPI Authentication" |
| 2 | + |
| 3 | +# Skip the test if GSSAPI support is not configured |
| 4 | +if ! grep -E '^#define GSSAPI' "$BUILDDIR/config.h" >/dev/null 2>&1; then |
| 5 | + skip "GSSAPI not enabled" |
| 6 | +fi |
| 7 | + |
| 8 | +# We test with MIT Kerberos KDC, skip if not installed |
| 9 | +if ! which krb5kdc >/dev/null 2>&1; then |
| 10 | + skip "MIT Kerberos KDC not installed" |
| 11 | +fi |
| 12 | + |
| 13 | +# The test needs nss_wrapper to emulate gethostname() and /etc/hosts, |
| 14 | +# we skip if the shared library is not installed |
| 15 | +nss_wrapper="libnss_wrapper.so" |
| 16 | +if ! ldconfig -p | grep "$nss_wrapper" >/dev/null 2>&1; then |
| 17 | + skip "$nss_wrapper not installed" |
| 18 | +fi |
| 19 | + |
| 20 | +# Set up the username of the SSH client |
| 21 | +client="$LOGNAME" |
| 22 | +if [ "x$client" = "x" ]; then |
| 23 | + client="$(whoami)" |
| 24 | +fi |
| 25 | + |
| 26 | +# Set up SSHD and KDC hostnames and resolve both to localhost |
| 27 | +sshd_hostname="sshd.example.org" |
| 28 | +bad_hostname="bad.example.org" |
| 29 | +kdc_hostname="kdc.example.org" |
| 30 | +kdc_port=2088 |
| 31 | +hosts="$OBJ/hosts" |
| 32 | +echo "127.0.0.1 $sshd_hostname $kdc_hostname" > "$hosts" |
| 33 | + |
| 34 | +# Set up a directory to store Kerberos data |
| 35 | +# (configuration, ticket cache,...) |
| 36 | +gssdir="$OBJ/gss" |
| 37 | +mkdir -p "$gssdir" |
| 38 | +export KRB5CCNAME="$gssdir/cc" |
| 39 | +export KRB5_CONFIG="$gssdir/krb5.conf" |
| 40 | +export KRB5_KDC_PROFILE="$gssdir/kdc.conf" |
| 41 | +export KRB5_KTNAME="$gssdir/ssh.keytab" |
| 42 | +export KRB5RCACHETYPE="none" |
| 43 | +kdc_pidfile="$gssdir/pid" |
| 44 | + |
| 45 | +# Configure Kerberos |
| 46 | +cat<<EOF > "$KRB5_KDC_PROFILE" |
| 47 | +[realms] |
| 48 | + EXAMPLE.ORG = { |
| 49 | + database_name = $gssdir/principal |
| 50 | + key_stash_file = $gssdir/stash |
| 51 | + kdc_listen = $kdc_hostname:$kdc_port |
| 52 | + kdc_tcp_listen = $kdc_hostname:$kdc_port |
| 53 | + } |
| 54 | +[logging] |
| 55 | + kdc = FILE:$gssdir/kdc.log |
| 56 | + debug = true |
| 57 | +EOF |
| 58 | + |
| 59 | +cat<<EOF > "$KRB5_CONFIG" |
| 60 | +[libdefaults] |
| 61 | + default_realm = EXAMPLE.ORG |
| 62 | +[realms] |
| 63 | + EXAMPLE.ORG = { |
| 64 | + kdc = $kdc_hostname:$kdc_port |
| 65 | + } |
| 66 | +EOF |
| 67 | + |
| 68 | +# Back up the default sshd_config |
| 69 | +cp "$OBJ/sshd_config" "$OBJ/sshd_config.orig" |
| 70 | + |
| 71 | +setup_sshd() { |
| 72 | + mock_hostname="$1" |
| 73 | + strict_acceptor="$2" |
| 74 | + |
| 75 | + cp "$OBJ/sshd_config.orig" "$OBJ/sshd_config" |
| 76 | + |
| 77 | + cat<<EOF >> "$OBJ/sshd_config" |
| 78 | +PubkeyAuthentication No |
| 79 | +PasswordAuthentication No |
| 80 | +GSSAPIAuthentication Yes |
| 81 | +EOF |
| 82 | + |
| 83 | + if ! $strict_acceptor; then |
| 84 | + echo "GSSAPIStrictAcceptorCheck No" >> "$OBJ/sshd_config" |
| 85 | + fi |
| 86 | + |
| 87 | + test_ssh_sshd_env_backup="$TEST_SSH_SSHD_ENV" |
| 88 | + TEST_SSH_SSHD_ENV="$TEST_SSH_SSHD_ENV \ |
| 89 | + LD_PRELOAD=$nss_wrapper \ |
| 90 | + NSS_WRAPPER_HOSTS=$hosts \ |
| 91 | + NSS_WRAPPER_HOSTNAME=$mock_hostname \ |
| 92 | + KRB5_CONFIG=$KRB5_CONFIG \ |
| 93 | + KRB5_KDC_PROFILE=$KRB5_KDC_PROFILE \ |
| 94 | + KRB5CCNAME=$KRB5CCNAME \ |
| 95 | + KRB5_KTNAME=$KRB5_KTNAME \ |
| 96 | + KRB5RCACHETYPE=$KRB5RCACHETYPE" |
| 97 | + start_sshd |
| 98 | +} |
| 99 | + |
| 100 | +teardown_sshd() { |
| 101 | + TEST_SSH_SSHD_ENV="$test_ssh_sshd_env_backup" |
| 102 | + stop_sshd |
| 103 | +} |
| 104 | + |
| 105 | +setup_kdc() { |
| 106 | + kdb5_util create -P "foo" -s |
| 107 | + krb5kdc -w 1 -P "$kdc_pidfile" |
| 108 | + i=0; |
| 109 | + while [ ! -f "$kdc_pidfile" -a $i -lt 10 ]; do |
| 110 | + i=$((i + 1)) |
| 111 | + sleep 1 |
| 112 | + done |
| 113 | + test -f "$kdc_pidfile" || fatal "KDC failed to start" |
| 114 | +} |
| 115 | + |
| 116 | +teardown_kdc() { |
| 117 | + kill "$(cat "$kdc_pidfile")" |
| 118 | + kdestroy |
| 119 | + rm -f "$KRB5_KTNAME" "$kdc_pidfile" |
| 120 | + kdb5_util destroy -f |
| 121 | +} |
| 122 | + |
| 123 | +setup_nss_emulation() { |
| 124 | + export LD_PRELOAD="$nss_wrapper" |
| 125 | + export NSS_WRAPPER_HOSTS="$hosts" |
| 126 | +} |
| 127 | + |
| 128 | +teardown_nss_emulation() { |
| 129 | + unset LD_PRELOAD |
| 130 | + unset NSS_WRAPPER_HOSTS |
| 131 | +} |
| 132 | + |
| 133 | +setup_krb_principal_with_key() { |
| 134 | + name="$1" |
| 135 | + add_to_keytab="$2" |
| 136 | + kadmin.local add_principal -randkey "$name" |
| 137 | + if $add_to_keytab; then |
| 138 | + kadmin.local ktadd "$name" |
| 139 | + fi |
| 140 | +} |
| 141 | + |
| 142 | +setup_krb_principal_with_pw() { |
| 143 | + name="$1" |
| 144 | + password="$2" |
| 145 | + authenticate="$3" |
| 146 | + kadmin.local add_principal -pw "$password" "$name" |
| 147 | + if $authenticate; then |
| 148 | + echo "$password" | kinit "$name" |
| 149 | + fi |
| 150 | +} |
| 151 | + |
| 152 | +test_gss_auth() { |
| 153 | + sshd_mock_hostname="$1" # the name that gethostname() will return within sshd |
| 154 | + sshd_principal="$2" # the hostname for which a Kerberos principal will be created |
| 155 | + auth_sshd="$3" # whether sshd will be authenticated via a keytab |
| 156 | + auth_client="$4" # whether the client will be authenticated via kinit |
| 157 | + strict_acceptor="$5" # whether to be strict about the identity of the sshd server |
| 158 | + expect="$6" # the expected return value of the sshd command |
| 159 | + |
| 160 | + setup_sshd "$sshd_mock_hostname" "$strict_acceptor" |
| 161 | + setup_nss_emulation |
| 162 | + setup_kdc |
| 163 | + |
| 164 | + setup_krb_principal_with_key "host/$sshd_principal" "$auth_sshd" |
| 165 | + setup_krb_principal_with_pw "$client" "foo" "$auth_client" |
| 166 | + |
| 167 | + ${SSH} -F "$OBJ/ssh_config" -o "GSSAPIAuthentication Yes" "$client@$sshd_hostname" true |
| 168 | + status=$? |
| 169 | + |
| 170 | + teardown_kdc |
| 171 | + teardown_nss_emulation |
| 172 | + teardown_sshd |
| 173 | + |
| 174 | + [ $status -eq $expect ] |
| 175 | +} |
| 176 | + |
| 177 | +# sshd_mock_hostname sshd_principal auth_sshd auth_client strict_acceptor expect |
| 178 | +test_gss_auth $sshd_hostname $sshd_hostname true true true 0 \ |
| 179 | + || fail "valid authentication attempt failed" |
| 180 | +test_gss_auth $sshd_hostname $sshd_hostname false true true 255 \ |
| 181 | + || fail "authentication succeeded without a keytab entry for the host" |
| 182 | +test_gss_auth $sshd_hostname $sshd_hostname true false true 255 \ |
| 183 | + || fail "authentication succeeded without a ticket-granting ticket" |
| 184 | +test_gss_auth $bad_hostname $sshd_hostname true true true 255 \ |
| 185 | + || fail "authentication succeeded with a hostname/principal mismatch on server side" |
| 186 | +test_gss_auth $bad_hostname $sshd_hostname true true false 0 \ |
| 187 | + || fail "valid authentication without strict acceptor check failed" |
| 188 | +test_gss_auth $bad_hostname $bad_hostname true true true 255 \ |
| 189 | + || fail "authentication succeeded with a hostname/principal mismatch on client side" |
| 190 | + |
| 191 | +unset KRB5CCNAME |
| 192 | +unset KRB5_CONFIG |
| 193 | +unset KRB5_KDC_PROFILE |
| 194 | +unset KRB5_KTNAME |
| 195 | +unset KRB5RCACHETYPE |
| 196 | +rm -r "$gssdir" |
0 commit comments