Path: blob/main/crypto/krb5/src/clients/ksu/t_ksu.py
34890 views
from k5test import *1import pwd2import stat34krb5_conf = '/etc/krb5.conf'5krb5_conf_save = krb5_conf + '.save-ksutest'6krb5_conf_nosave = krb5_conf + '.nosave-ksutest'7ksu = './ksu.ksutest'8if 'SUDO_UID' not in os.environ or os.geteuid() != 0:9fail('this script must be run as root via sudo')10caller_uid = int(os.environ['SUDO_UID'])11if caller_uid == 0:12fail('the user invoking sudo must not be root')13caller_username = os.environ['SUDO_USER']14os.chown('testlog', caller_uid, -1)1516# Set the real and effective UIDs to the calling user, but preserve17# the ability to restore root privileges.18def be_caller():19os.setresuid(caller_uid, caller_uid, 0)202122# Restore root privileges.23def be_root():24os.setresuid(0, 0, 0)252627# Remove the ksutest account.28def cleanup_user():29# userdel commonly gives a warning about being unable to delete30# the mail spool; filter it out.31out = subprocess.check_output(['userdel', '-r', 'ksutest'],32stderr=subprocess.STDOUT)33if out.count(b'\n') > 1 or b'ksutest mail spool' not in out:34print(out)353637# Restore /etc/krb5.conf to the state it was in previously.38def cleanup_krb5_conf():39if os.path.exists(krb5_conf_save):40os.unlink(krb5_conf)41os.rename(krb5_conf_save, krb5_conf)42elif os.path.exists(krb5_conf_nosave):43os.unlink(krb5_conf)44os.unlink(krb5_conf_nosave)454647def onexit():48if len(sys.argv) >= 2 and sys.argv[1] == 'nocleanup':49return50be_root()51cleanup_user()52cleanup_krb5_conf()53if os.path.exists(ksu):54os.unlink(ksu)555657# Create a ksutest account and return its home directory.58def setup_user():59try:60ent = pwd.getpwnam('ksutest')61return ent.pw_dir62except KeyError:63subprocess.check_call(['useradd', '-m', '-r', 'ksutest'])64return pwd.getpwnam('ksutest').pw_dir656667# Make krb5.conf a copy of realm's krb5.conf file. Save the old68# contents in krb5_conf_save, or create krb5_conf_noexist to indicate69# that the file didn't previously exist.70def setup_krb5_conf(realm):71if not os.path.exists(krb5_conf):72open(krb5_conf_nosave, 'w').close()73elif not os.path.exists(krb5_conf_save):74os.rename(krb5_conf, krb5_conf_save)75shutil.copyfile(os.path.join(realm.testdir, 'krb5.conf'), krb5_conf)767778# Temporarily acting as root, write a file named fname in ksutest's79# home directory with the given contents. If wrong_owner is set, make80# the file owned by the caller uid in order to trip ksu's owner check.81def write_authz_file(fname, contents, wrong_owner=False):82be_root()83path = os.path.join(ksutest_home, fname)84with open(path, 'w') as f:85f.write('\n'.join(contents) + '\n')86if wrong_owner:87os.chown(path, caller_uid, -1)88be_caller()899091# Temporarily acting as root, remove fname from ksutest's home92# directory.93def remove_authz_file(fname):94be_root()95path = os.path.join(ksutest_home, fname)96if os.path.exists(path):97os.remove(path)98be_caller()99100101be_caller()102103# Set up a realm. Set default_keytab_name since ksu won't respect the104# KRB5_KTNAME environment variable.105keytab = os.path.join(os.getcwd(), 'testdir', 'keytab')106realm = K5Realm(create_user=False,107krb5_conf={'libdefaults': {'default_keytab_name': keytab}})108realm.addprinc('alice', 'pwalice')109realm.addprinc('ksutest', 'pwksutest')110realm.addprinc('ksutest/root', 'pwroot')111realm.addprinc(caller_username, 'pwcaller')112113# Root setup:114# - /etc/krb5.conf is a copy of the test realm krb5.conf115# - a newly created user named ksutest exists (with homedir ksutest_home)116# - a setuid copy of ksu exists in the build dir117# Register an atexit handler to undo these changes.118atexit.register(onexit)119be_root()120ksutest_home = setup_user()121setup_krb5_conf(realm)122if os.path.exists(ksu):123os.unlink(ksu)124shutil.copyfile('ksu', ksu)125os.chmod(ksu, 0o4755)126be_caller()127128mark('no authorization')129realm.kinit('alice', 'pwalice')130realm.run([ksu, 'ksutest', '-n', 'alice', '-a', '-c', klist], expected_code=1,131expected_msg='authorization of [email protected] failed')132133mark('an2ln authorization')134realm.kinit('ksutest', 'pwksutest')135realm.run([ksu, 'ksutest', '-a', '-c', klist],136expected_msg='authorization for [email protected] successful')137realm.run([ksu, 'ksutest', '-e', klist], expected_code=1,138expected_msg='account ksutest: authorization failed')139140mark('.k5login wrong owner')141write_authz_file('.k5login', ['[email protected]'], wrong_owner=True)142realm.run([ksu, 'ksutest', '-e', klist], expected_code=1,143expected_msg='account ksutest: authorization failed')144remove_authz_file('.k5login')145146mark('.k5users wrong owner')147write_authz_file('.k5users', ['[email protected]'], wrong_owner=True)148realm.run([ksu, 'ksutest', '-e', klist], expected_code=1,149expected_msg='account ksutest: authorization failed')150remove_authz_file('.k5users')151152mark('.k5login authorization')153realm.kinit('alice', 'pwalice')154write_authz_file('.k5login', ['[email protected]'])155realm.run([ksu, 'ksutest', '-a', '-c', klist],156expected_msg='authorization for [email protected] successful')157realm.run([ksu, 'ksutest', '-e', klist],158expected_msg='authorization for [email protected] for execution of')159write_authz_file('.k5login', ['[email protected]'])160realm.run([ksu, 'ksutest', '-a', '-c', klist], expected_code=1,161expected_msg='account ksutest: authorization failed')162remove_authz_file('.k5login')163164mark('.k5users authorization (no second field)')165write_authz_file('.k5users', ['[email protected]'])166realm.run([ksu, 'ksutest', '-a', '-c', klist],167expected_msg='authorization for [email protected] successful')168realm.run([ksu, 'ksutest', '-e', klist], expected_code=1,169expected_msg='account ksutest: authorization failed')170write_authz_file('.k5users', ['[email protected]'])171realm.run([ksu, 'ksutest', '-a', '-c', klist], expected_code=1,172expected_msg='account ksutest: authorization failed')173174mark('k5users authorization (wildcard)')175write_authz_file('.k5users', ['[email protected] *'])176realm.run([ksu, 'ksutest', '-a', '-c', klist],177expected_msg='authorization for [email protected] successful')178realm.run([ksu, 'ksutest', '-e', klist],179expected_msg='authorization for [email protected] for execution of')180181mark('k5users authorization (command list)')182write_authz_file('.k5users', ['[email protected] doesnotexist ' + klist])183realm.run([ksu, 'ksutest', '-a', '-c', klist], expected_code=1,184expected_msg='account ksutest: authorization failed')185realm.run([ksu, 'ksutest', '-e', klist],186expected_msg='authorization for [email protected] for execution of')187realm.run([ksu, 'ksutest', '-e', kvno], expected_code=1,188expected_msg='account ksutest: authorization failed')189realm.run([ksu, 'ksutest', '-e', 'doesnotexist'], expected_code=1,190expected_msg='Error: not found ->')191remove_authz_file('.k5users')192193mark('principal heuristic (no authz files)')194realm.run([ksu, 'ksutest', '-a', '-c', klist], input='pwksutest\n',195expected_msg='Authenticated [email protected]')196realm.run([ksu, 'ksutest', '-e', klist], expected_code=1,197expected_msg='account ksutest: authorization failed')198199mark('principal heuristic (empty authz files)')200write_authz_file('.k5login', [])201write_authz_file('.k5users', [])202realm.run([ksu, 'ksutest', '-e', klist], expected_code=1,203expected_msg='account ksutest: authorization failed')204remove_authz_file('.k5login')205remove_authz_file('.k5users')206207# Untested: if the ccache default principal is not authorized,208# get_best_princ_for_target() looks for a TGT or host service ticket209# for the target and source users (if authorized) or any other210# authorized user. This is not really useful because a ccache usually211# only contains tickets for its default client principal (aside from212# caches created for S4U2Proxy). If the heuristic is ever changed to213# search the cache collection instead of only the primary cache, we214# should add tests for that here.215216mark('principal heuristic (.k5login)')217write_authz_file('.k5login', ['[email protected]'])218realm.run([ksu, 'ksutest', '-a', '-c', klist], input='pwksutest\n',219expected_msg='Authenticated [email protected]')220realm.run([ksu, 'ksutest', '-e', klist], input='pwksutest\n',221expected_msg='Authenticated [email protected]')222write_authz_file('.k5login', [caller_username + '@KRBTEST.COM'])223realm.run([ksu, 'ksutest', '-e', klist], input='pwcaller\n',224expected_msg='Authenticated %[email protected]' % caller_username)225remove_authz_file('.k5login')226227mark('principal heuristic (.k5users)')228write_authz_file('.k5users', ['[email protected] ' + klist,229'[email protected]',230caller_username + '@KRBTEST.COM *'])231realm.run([ksu, 'ksutest', '-e', klist],232expected_msg='Authenticated [email protected]')233realm.run([ksu, 'ksutest', '-a', '-c', klist], input='pwksutest\n',234expected_msg='Authenticated [email protected]')235realm.run([ksu, 'ksutest', '-e', kvno, 'alice'], input='pwcaller\n',236expected_msg='Authenticated %[email protected]' % caller_username)237write_authz_file('.k5users', ['[email protected] ' + klist,238'ksutest/[email protected] ' + kvno])239realm.run([ksu, 'ksutest', '-e', kvno, 'alice'], input='pwroot\n',240expected_msg='Authenticated ksutest/[email protected]')241242mark('principal heuristic (no authorization)')243realm.run([ksu, '.', '-e', klist],244expected_msg='Default principal: [email protected]')245be_root()246realm.run([ksu, 'ksutest', '-e', klist], expected_code=1,247expected_msg='No credentials cache found')248be_caller()249realm.kinit('ksutest', 'pwksutest')250be_root()251realm.run([ksu, 'ksutest', '-e', klist],252expected_msg='Default principal: [email protected]')253be_caller()254realm.run([kdestroy])255realm.run([ksu, '.', '-e', klist], expected_code=1,256expected_msg='No credentials cache found')257258mark('authentication without authorization')259realm.run([ksu, '.', '-n', 'ksutest', '-e', klist], input='pwksutest\n',260expected_msg='Leaving uid as ' + caller_username)261262# It's hard to make this flag do anything detectable, but we can263# exercise the code.264mark('-z flag')265realm.kinit(caller_username, 'pwcaller')266realm.run([ksu, '.', '-z', '-e', klist],267expected_msg='Default principal: ' + caller_username)268269realm.run([ksu, '.', '-Z', '-e', klist], expected_code=1,270expected_msg='No credentials cache found')271272success('ksu tests')273274275