1from k5test import * 2 3for realm in multipass_realms(create_user=False): 4 # Test kinit with a keytab. 5 realm.kinit(realm.host_princ, flags=['-k']) 6 7realm = K5Realm(get_creds=False, start_kadmind=True) 8 9# Test kinit with a partial keytab. 10mark('partial keytab') 11pkeytab = realm.keytab + '.partial' 12realm.run([ktutil], input=('rkt %s\ndelent 1\nwkt %s\n' % 13 (realm.keytab, pkeytab))) 14realm.kinit(realm.host_princ, flags=['-k', '-t', pkeytab]) 15 16# Test kinit with no keys for client in keytab. 17mark('no keys for client') 18realm.kinit(realm.user_princ, flags=['-k'], expected_code=1, 19 expected_msg='no suitable keys') 20 21# Test kinit and klist with client keytab defaults. 22mark('client keytab') 23realm.extract_keytab(realm.user_princ, realm.client_keytab); 24realm.run([kinit, '-k', '-i']) 25realm.klist(realm.user_princ) 26realm.run([kdestroy]) 27realm.kinit(realm.user_princ, flags=['-k', '-i']) 28realm.klist(realm.user_princ) 29out = realm.run([klist, '-k', '-i']) 30if realm.client_keytab not in out or realm.user_princ not in out: 31 fail('Expected output not seen from klist -k -i') 32 33# Test implicit request for keytab (-i or -t without -k) 34mark('implicit -k') 35realm.run([kdestroy]) 36realm.kinit(realm.host_princ, flags=['-t', realm.keytab], 37 expected_msg='keytab specified, forcing -k') 38realm.klist(realm.host_princ) 39realm.run([kdestroy]) 40realm.kinit(realm.user_princ, flags=['-i'], 41 expected_msg='keytab specified, forcing -k') 42realm.klist(realm.user_princ) 43 44# Test default principal for -k. This operation requires 45# canonicalization against the keytab in krb5_get_init_creds_keytab() 46# as the krb5_sname_to_principal() result won't have a realm. Try 47# with and without without fallback processing since the code paths 48# are different. 49mark('default principal for -k') 50realm.run([kinit, '-k']) 51realm.klist(realm.host_princ) 52no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}} 53no_canon = realm.special_env('no_canon', False, krb5_conf=no_canon_conf) 54realm.run([kinit, '-k'], env=no_canon) 55realm.klist(realm.host_princ) 56 57# Test extracting keys with multiple key versions present. 58mark('multi-kvno extract') 59os.remove(realm.keytab) 60realm.run([kadminl, 'cpw', '-randkey', '-keepold', realm.host_princ]) 61out = realm.run([kadminl, 'ktadd', '-norandkey', realm.host_princ]) 62if 'with kvno 1,' not in out or 'with kvno 2,' not in out: 63 fail('Expected output not seen from kadmin.local ktadd -norandkey') 64out = realm.run([klist, '-k', '-e']) 65if ' 1 host/' not in out or ' 2 host/' not in out: 66 fail('Expected output not seen from klist -k -e') 67 68# Test again using kadmin over the network. 69mark('multi-kvno extract (via kadmin)') 70realm.prep_kadmin() 71os.remove(realm.keytab) 72out = realm.run_kadmin(['ktadd', '-norandkey', realm.host_princ]) 73if 'with kvno 1,' not in out or 'with kvno 2,' not in out: 74 fail('Expected output not seen from kadmin.local ktadd -norandkey') 75out = realm.run([klist, '-k', '-e']) 76if ' 1 host/' not in out or ' 2 host/' not in out: 77 fail('Expected output not seen from klist -k -e') 78 79# Test handling of kvno values beyond 255. Use kadmin over the 80# network since we used to have an 8-bit limit on kvno marshalling. 81 82# Test one key rotation, verifying that the expected new kvno appears 83# in the keytab and in the principal entry. 84def test_key_rotate(realm, princ, expected_kvno): 85 realm.run_kadmin(['ktadd', '-k', realm.keytab, princ]) 86 realm.run([kadminl, 'ktrem', princ, 'old']) 87 realm.kinit(princ, flags=['-k']) 88 msg = '%d %s' % (expected_kvno, princ) 89 out = realm.run([klist, '-k'], expected_msg=msg) 90 msg = 'Key: vno %d,' % expected_kvno 91 out = realm.run_kadmin(['getprinc', princ], expected_msg=msg) 92 93mark('key rotation across boundaries') 94princ = 'foo/bar@%s' % realm.realm 95realm.addprinc(princ) 96os.remove(realm.keytab) 97realm.run([kadminl, 'modprinc', '-kvno', '253', princ]) 98test_key_rotate(realm, princ, 254) 99test_key_rotate(realm, princ, 255) 100test_key_rotate(realm, princ, 256) 101test_key_rotate(realm, princ, 257) 102realm.run([kadminl, 'modprinc', '-kvno', '32766', princ]) 103test_key_rotate(realm, princ, 32767) 104test_key_rotate(realm, princ, 32768) 105test_key_rotate(realm, princ, 32769) 106realm.run([kadminl, 'modprinc', '-kvno', '65534', princ]) 107test_key_rotate(realm, princ, 65535) 108test_key_rotate(realm, princ, 1) 109test_key_rotate(realm, princ, 2) 110 111mark('32-bit kvno') 112 113# Test that klist -k can read a keytab entry without a 32-bit kvno and 114# reports the 8-bit key version. 115record = b'\x00\x01' # principal component count 116record += b'\x00\x0bKRBTEST.COM' # realm 117record += b'\x00\x04user' # principal component 118record += b'\x00\x00\x00\x01' # name type (NT-PRINCIPAL) 119record += b'\x54\xf7\x4d\x35' # timestamp 120record += b'\x02' # key version 121record += b'\x00\x12' # enctype 122record += b'\x00\x20' # key length 123record += b'\x00' * 32 # key bytes 124f = open(realm.keytab, 'wb') 125f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record)])) 126f.write(record) 127f.close() 128msg = ' 2 %s' % realm.user_princ 129out = realm.run([klist, '-k'], expected_msg=msg) 130 131# Make sure zero-fill isn't treated as a 32-bit kvno. 132f = open(realm.keytab, 'wb') 133f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record) + 4])) 134f.write(record) 135f.write(b'\x00\x00\x00\x00') 136f.close() 137msg = ' 2 %s' % realm.user_princ 138out = realm.run([klist, '-k'], expected_msg=msg) 139 140# Make sure a hand-crafted 32-bit kvno is recognized. 141f = open(realm.keytab, 'wb') 142f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record) + 4])) 143f.write(record) 144f.write(b'\x00\x00\x00\x03') 145f.close() 146msg = ' 3 %s' % realm.user_princ 147out = realm.run([klist, '-k'], expected_msg=msg) 148 149# Test parameter expansion in profile variables 150mark('parameter expansion') 151realm.stop() 152conf = {'libdefaults': { 153 'default_keytab_name': 'testdir/%{null}abc%{uid}', 154 'default_client_keytab_name': 'testdir/%{null}xyz%{uid}'}} 155realm = K5Realm(krb5_conf=conf, create_kdb=False) 156del realm.env['KRB5_KTNAME'] 157del realm.env['KRB5_CLIENT_KTNAME'] 158uidstr = str(os.getuid()) 159msg = 'FILE:testdir/abc%s' % uidstr 160out = realm.run([klist, '-k'], expected_code=1, expected_msg=msg) 161msg = 'FILE:testdir/xyz%s' % uidstr 162out = realm.run([klist, '-ki'], expected_code=1, expected_msg=msg) 163 164conf = {'libdefaults': {'allow_weak_crypto': 'true'}} 165realm = K5Realm(create_user=False, create_host=False, krb5_conf=conf) 166 167realm.run([kadminl, 'ank', '-pw', 'pw', 'default']) 168realm.run([kadminl, 'ank', '-e', 'aes256-cts:special', '-pw', 'pw', 'exp']) 169realm.run([kadminl, 'ank', '-e', 'aes256-cts:special', '-pw', 'pw', '+preauth', 170 'pexp']) 171 172# Extract one of the explicit salt values from the database. 173out = realm.run([kdb5_util, 'tabdump', 'keyinfo']) 174salt_dict = {f[0]: f[5] for f in [l.split('\t') for l in out.splitlines()]} 175exp_salt = bytes.fromhex(salt_dict['exp@KRBTEST.COM']).decode('ascii') 176 177# Create a keytab using ktutil addent with the specified options and 178# password "pw". Test that we can use it to get initial tickets. 179# Remove the keytab afterwards. 180def test_addent(realm, princ, opts): 181 realm.run([ktutil], input=('addent -password -p %s -k 1 %s\npw\nwkt %s\n' % 182 (princ, opts, realm.keytab))) 183 realm.kinit(princ, flags=['-k']) 184 os.remove(realm.keytab) 185 186mark('ktutil addent') 187 188# Test with default salt. 189test_addent(realm, 'default', '-e aes128-cts') 190test_addent(realm, 'default', '-e aes256-cts') 191 192# Test with a salt specified to ktutil addent. 193test_addent(realm, 'exp', '-e aes256-cts -s %s' % exp_salt) 194 195# Test etype-info fetching. 196test_addent(realm, 'default', '-f') 197test_addent(realm, 'default', '-f -e aes128-cts') 198test_addent(realm, 'exp', '-f') 199test_addent(realm, 'pexp', '-f') 200 201# Regression test for #8914: INT32_MIN length can cause backwards seek 202mark('invalid record length') 203f = open(realm.keytab, 'wb') 204f.write(b'\x05\x02\x80\x00\x00\x00') 205f.close() 206msg = 'Bad format in keytab while scanning keytab' 207realm.run([klist, '-k'], expected_code=1, expected_msg=msg) 208 209success('Keytab-related tests') 210