krb5 commit: Use kadmin script mode in Python tests

Greg Hudson ghudson at mit.edu
Thu Feb 19 12:46:24 EST 2015


https://github.com/krb5/krb5/commit/60516bb111ac68ce0d809043d46c0c1f815a7b30
commit 60516bb111ac68ce0d809043d46c0c1f815a7b30
Author: Greg Hudson <ghudson at mit.edu>
Date:   Sat Jan 31 00:29:59 2015 -0500

    Use kadmin script mode in Python tests
    
    In k5test, rename kadmin_local to kadminl and remove the run_kadminl()
    K5Realm method.  Update all scripts to use realm.run([kadminl, 'cmd',
    ...]).  run_kadmin() still exists but takes an argument array instead
    of a query string.
    
    Where we touch test code, rename "output" to "out" (since "output" is
    a function name exported by k5test.py), elide ":normal" from salt
    strings, and use expressions like realm.krbtgt_princ instead of
    manually composed principal names where appropriate.  In
    t_kadmin_acl.py, get rid of the delprinc() helper since the equivalent
    is now concise enough to be written out each time.  In t_policy.py,
    remove some inoperative getprinc invocations and reorder some tests
    which didn't correspond to their comment headers.

 src/lib/krb5/krb/t_expire_warn.py       |   10 +-
 src/lib/krb5/krb/t_in_ccache_patypes.py |    4 +-
 src/lib/krb5/krb/t_vfy_increds.py       |   14 +-
 src/tests/gssapi/t_enctypes.py          |    2 +-
 src/tests/gssapi/t_gssapi.py            |   22 ++--
 src/tests/gssapi/t_s4u.py               |    2 +-
 src/tests/t_audit.py                    |    2 +-
 src/tests/t_changepw.py                 |    4 +-
 src/tests/t_dump.py                     |   24 ++--
 src/tests/t_general.py                  |    5 +-
 src/tests/t_iprop.py                    |   54 +++---
 src/tests/t_kadm5_hook.py               |    2 +-
 src/tests/t_kadmin_acl.py               |  286 +++++++++++++------------------
 src/tests/t_kdb.py                      |  102 ++++++-----
 src/tests/t_kdb_locking.py              |    2 +-
 src/tests/t_keydata.py                  |   30 ++--
 src/tests/t_keyrollover.py              |   31 ++--
 src/tests/t_keytab.py                   |    6 +-
 src/tests/t_kprop.py                    |    2 +-
 src/tests/t_mkey.py                     |   25 ++--
 src/tests/t_otp.py                      |   22 ++-
 src/tests/t_pkinit.py                   |    8 +-
 src/tests/t_policy.py                   |  178 ++++++++------------
 src/tests/t_pwqual.py                   |   21 +--
 src/tests/t_rdreq.py                    |   10 +-
 src/tests/t_referral.py                 |    1 -
 src/tests/t_renew.py                    |   22 ++-
 src/tests/t_renprinc.py                 |    8 +-
 src/tests/t_salt.py                     |   20 +-
 src/tests/t_sesskeynego.py              |   24 ++-
 src/tests/t_skew.py                     |    4 +-
 src/tests/t_stringattr.py               |   28 +--
 src/util/k5test.py                      |   27 +--
 33 files changed, 459 insertions(+), 543 deletions(-)

diff --git a/src/lib/krb5/krb/t_expire_warn.py b/src/lib/krb5/krb/t_expire_warn.py
index 4c9b5cc..e021379 100644
--- a/src/lib/krb5/krb/t_expire_warn.py
+++ b/src/lib/krb5/krb/t_expire_warn.py
@@ -28,10 +28,12 @@ from k5test import *
 realm = K5Realm(create_user=False, create_host=False)
 
 # Create principals with various password expirations.
-realm.run_kadminl('addprinc -pw pass noexpire')
-realm.run_kadminl('addprinc -pw pass -pwexpire "30 minutes" minutes')
-realm.run_kadminl('addprinc -pw pass -pwexpire "12 hours" hours')
-realm.run_kadminl('addprinc -pw pass -pwexpire "3 days" days')
+realm.run([kadminl, 'addprinc', '-pw', 'pass', 'noexpire'])
+realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '30 minutes',
+           'minutes'])
+realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '12 hours',
+           'hours'])
+realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '3 days', 'days'])
 
 # Check for expected prompter warnings when no expire callback is used.
 output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0'])
diff --git a/src/lib/krb5/krb/t_in_ccache_patypes.py b/src/lib/krb5/krb/t_in_ccache_patypes.py
index 7e3c7b0..c042340 100644
--- a/src/lib/krb5/krb/t_in_ccache_patypes.py
+++ b/src/lib/krb5/krb/t_in_ccache_patypes.py
@@ -28,8 +28,8 @@ from k5test import *
 realm = K5Realm(create_user=False, create_host=False)
 
 # Create principals with various password expirations.
-realm.run_kadminl('addprinc -pw pass nopreauth')
-realm.run_kadminl('addprinc -pw pass +requires_preauth preauth')
+realm.run([kadminl, 'addprinc', '-pw', 'pass', 'nopreauth'])
+realm.run([kadminl, 'addprinc', '-pw', 'pass', '+requires_preauth', 'preauth'])
 
 # Check that we can get creds without preauth without an in_ccache.  This is
 # the default behavior for kinit.
diff --git a/src/lib/krb5/krb/t_vfy_increds.py b/src/lib/krb5/krb/t_vfy_increds.py
index a17b478..c820cc6 100644
--- a/src/lib/krb5/krb/t_vfy_increds.py
+++ b/src/lib/krb5/krb/t_vfy_increds.py
@@ -32,13 +32,13 @@ realm.run(['./t_vfy_increds', '-n'])
 
 # Verify after updating the keytab (so the keytab contains an outdated
 # version 1 key followed by an up-to-date version 2 key).
-realm.run_kadminl('ktadd ' + realm.host_princ)
+realm.run([kadminl, 'ktadd', realm.host_princ])
 realm.run(['./t_vfy_increds'])
 realm.run(['./t_vfy_increds', '-n'])
 
 # Bump the host key without updating the keytab and make sure that
 # verification fails as we expect it to.
-realm.run_kadminl('change_password -randkey ' + realm.host_princ)
+realm.run([kadminl, 'change_password', '-randkey', realm.host_princ])
 realm.run(['./t_vfy_increds'], expected_code=1)
 realm.run(['./t_vfy_increds', '-n'], expected_code=1)
 
@@ -47,8 +47,8 @@ realm.run(['./t_vfy_increds', '-n'], expected_code=1)
 # matches.  Verify after updating the keytab with a host service
 # principal that has hostname that doesn't match the host running the
 # test.  Verify should succeed, with or without nofail.
-realm.run_kadminl('addprinc -randkey host/wrong.hostname')
-realm.run_kadminl('ktadd host/wrong.hostname')
+realm.run([kadminl, 'addprinc', '-randkey', 'host/wrong.hostname'])
+realm.run([kadminl, 'ktadd', 'host/wrong.hostname'])
 realm.run(['./t_vfy_increds'])
 realm.run(['./t_vfy_increds', '-n'])
 
@@ -73,8 +73,8 @@ os.remove(realm.keytab)
 # Add an NFS service principal to keytab.  Verify should ignore it by
 # default (succeeding unless nofail is set), but should verify with it
 # when it is specifically requested.
-realm.run_kadminl('addprinc -randkey ' + realm.nfs_princ)
-realm.run_kadminl('ktadd ' + realm.nfs_princ)
+realm.run([kadminl, 'addprinc', '-randkey', realm.nfs_princ])
+realm.run([kadminl, 'ktadd', realm.nfs_princ])
 realm.run(['./t_vfy_increds'])
 realm.run(['./t_vfy_increds', '-n'], expected_code=1)
 realm.run(['./t_vfy_increds', realm.nfs_princ])
@@ -83,7 +83,7 @@ realm.run(['./t_vfy_increds', '-n', realm.nfs_princ])
 # Invalidating the NFS keys in the keytab.  We should get the same
 # results with the default principal argument, but verification should
 # now fail if we request it specifically.
-realm.run_kadminl('change_password -randkey ' + realm.nfs_princ)
+realm.run([kadminl, 'change_password', '-randkey', realm.nfs_princ])
 realm.run(['./t_vfy_increds'])
 realm.run(['./t_vfy_increds', '-n'], expected_code=1)
 realm.run(['./t_vfy_increds', realm.nfs_princ], expected_code=1)
diff --git a/src/tests/gssapi/t_enctypes.py b/src/tests/gssapi/t_enctypes.py
index d7577bf..862f229 100644
--- a/src/tests/gssapi/t_enctypes.py
+++ b/src/tests/gssapi/t_enctypes.py
@@ -99,7 +99,7 @@ test('init des3', 'des3', None,
 
 # Force the ticket session key to be rc4, so we can test some subkey
 # upgrade cases.  The ticket encryption key remains aes256.
-realm.run_kadminl('setstr %s session_enctypes rc4' % realm.host_princ)
+realm.run([kadminl, 'setstr', realm.host_princ, 'session_enctypes', 'rc4'])
 
 # With no arguments, the initiator should send an upgrade list of
 # [aes256 aes128 des3] and the acceptor should upgrade to an aes256
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
index adcaf36..4da7d62 100755
--- a/src/tests/gssapi/t_gssapi.py
+++ b/src/tests/gssapi/t_gssapi.py
@@ -16,15 +16,15 @@ realm = K5Realm()
 # Create some host-based principals and put most of them into the
 # keytab.  Rename one principal so that the keytab name matches the
 # key but not the client name.
-realm.run_kadminl('addprinc -randkey service1/abraham')
-realm.run_kadminl('addprinc -randkey service1/barack')
-realm.run_kadminl('addprinc -randkey service2/calvin')
-realm.run_kadminl('addprinc -randkey service2/dwight')
-realm.run_kadminl('addprinc -randkey host/-nomatch-')
-realm.run_kadminl('xst service1/abraham')
-realm.run_kadminl('xst service1/barack')
-realm.run_kadminl('xst service2/calvin')
-realm.run_kadminl('renprinc -force service1/abraham service1/andrew')
+realm.run([kadminl, 'addprinc', '-randkey', 'service1/abraham'])
+realm.run([kadminl, 'addprinc', '-randkey', 'service1/barack'])
+realm.run([kadminl, 'addprinc', '-randkey', 'service2/calvin'])
+realm.run([kadminl, 'addprinc', '-randkey', 'service2/dwight'])
+realm.run([kadminl, 'addprinc', '-randkey', 'host/-nomatch-'])
+realm.run([kadminl, 'xst', 'service1/abraham'])
+realm.run([kadminl, 'xst', 'service1/barack'])
+realm.run([kadminl, 'xst', 'service2/calvin'])
+realm.run([kadminl, 'renprinc', 'service1/abraham', 'service1/andrew'])
 
 # Test with no acceptor name, including client/keytab principal
 # mismatch (non-fatal) and missing keytab entry (fatal).
@@ -114,8 +114,8 @@ realm.stop()
 # and the principal for the mismatching hostname in the keytab.
 ignore_conf = {'libdefaults': {'ignore_acceptor_hostname': 'true'}}
 realm = K5Realm(krb5_conf=ignore_conf)
-realm.run_kadminl('addprinc -randkey host/-nomatch-')
-realm.run_kadminl('xst host/-nomatch-')
+realm.run([kadminl, 'addprinc', '-randkey', 'host/-nomatch-'])
+realm.run([kadminl, 'xst', 'host/-nomatch-'])
 output = realm.run(['./t_accname', 'p:host/-nomatch-',
                     'h:host@%s' % socket.gethostname()])
 if 'host/-nomatch-' not in output:
diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
index e4aa259..0e38429 100644
--- a/src/tests/gssapi/t_s4u.py
+++ b/src/tests/gssapi/t_s4u.py
@@ -60,7 +60,7 @@ if ('Warning: no delegated cred handle' not in output or
 
 # Correct that problem and try again.  As above, the S4U2Proxy step
 # won't actually succeed since we don't support that in DB2.
-realm.run_kadminl('modprinc +ok_to_auth_as_delegate ' + service1)
+realm.run([kadminl, 'modprinc', '+ok_to_auth_as_delegate', service1])
 output = realm.run(['./t_s4u', puser, pservice2], expected_code=1)
 if 'NOT_ALLOWED_TO_DELEGATE' not in output:
     fail('s4u2self')
diff --git a/src/tests/t_audit.py b/src/tests/t_audit.py
index 0cf5254..69c9251 100644
--- a/src/tests/t_audit.py
+++ b/src/tests/t_audit.py
@@ -6,7 +6,7 @@ conf = {'plugins': {'audit': {
 
 realm = K5Realm(krb5_conf=conf, get_creds=False)
 realm.addprinc('target')
-realm.run_kadminl('modprinc +ok_to_auth_as_delegate ' + realm.host_princ)
+realm.run([kadminl, 'modprinc', '+ok_to_auth_as_delegate', realm.host_princ])
 
 # Make normal AS and TGS requests so they will be audited.
 realm.kinit(realm.host_princ, flags=['-k', '-f'])
diff --git a/src/tests/t_changepw.py b/src/tests/t_changepw.py
index 0b98326..37fe4fc 100644
--- a/src/tests/t_changepw.py
+++ b/src/tests/t_changepw.py
@@ -7,12 +7,12 @@ from k5test import *
 realm = K5Realm(create_host=False, get_creds=False, start_kadmind=True)
 
 # Mark a principal as expired and change its password through kinit.
-realm.run_kadminl('modprinc -pwexpire "1 day ago" user')
+realm.run([kadminl, 'modprinc', '-pwexpire', '1 day ago', 'user'])
 pwinput = password('user') + '\nabcd\nabcd\n'
 realm.run([kinit, realm.user_princ], input=pwinput)
 
 # Do the same thing with FAST, with tracing turned on.
-realm.run_kadminl('modprinc -pwexpire "1 day ago" user')
+realm.run([kadminl, 'modprinc', '-pwexpire', '1 day ago', 'user'])
 pwinput = 'abcd\nefgh\nefgh\n'
 tracefile = os.path.join(realm.testdir, 'trace')
 realm.run(['env', 'KRB5_TRACE=' + tracefile, kinit, '-T', realm.ccache,
diff --git a/src/tests/t_dump.py b/src/tests/t_dump.py
index edf7a23..6ba0d35 100644
--- a/src/tests/t_dump.py
+++ b/src/tests/t_dump.py
@@ -6,7 +6,7 @@ from filecmp import cmp
 # principals and policies survive a dump/load cycle.
 
 realm = K5Realm(start_kdc=False)
-realm.run_kadminl('addpol fred')
+realm.run([kadminl, 'addpol', 'fred'])
 
 # Create a dump file.
 dumpfile = os.path.join(realm.testdir, 'dump')
@@ -24,26 +24,26 @@ f.close()
 # Spot-check principal and policy fields.
 realm.run([kdb5_util, 'destroy', '-f'])
 realm.run([kdb5_util, 'load', dumpfile])
-out = realm.run_kadminl('getprincs')
+out = realm.run([kadminl, 'getprincs'])
 if realm.user_princ not in out or realm.host_princ not in out:
     fail('Missing principal after load')
-out = realm.run_kadminl('getprinc %s' % realm.user_princ)
+out = realm.run([kadminl, 'getprinc', realm.user_princ])
 if 'Expiration date: [never]' not in out or 'MKey: vno 1' not in out:
     fail('Principal has wrong value after load')
-out = realm.run_kadminl('getpols')
+out = realm.run([kadminl, 'getpols'])
 if 'fred\n' not in out or 'barney\n' not in out:
     fail('Missing policy after load')
-out = realm.run_kadminl('getpol barney')
+out = realm.run([kadminl, 'getpol', 'barney'])
 if 'Number of old keys kept: 1' not in out:
     fail('Policy has wrong value after load')
 
 # Dump/load again, and make sure everything is still there.
 realm.run([kdb5_util, 'dump', dumpfile])
 realm.run([kdb5_util, 'load', dumpfile])
-out = realm.run_kadminl('getprincs')
+out = realm.run([kadminl, 'getprincs'])
 if realm.user_princ not in out or realm.host_princ not in out:
     fail('Missing principal after load')
-out = realm.run_kadminl('getpols')
+out = realm.run([kadminl, 'getpols'])
 if 'fred\n' not in out or 'barney\n' not in out:
     fail('Missing policy after second load')
 
@@ -75,13 +75,13 @@ dump_compare(realm, ['-ov'], srcdump_ov)
 def load_dump_check_compare(realm, opt, srcfile):
     realm.run([kdb5_util, 'destroy', '-f'])
     realm.run([kdb5_util, 'load'] + opt + [srcfile])
-    out = realm.run_kadminl('getprincs')
+    out = realm.run([kadminl, 'getprincs'])
     if 'user@' not in out:
         fail('Loaded dumpfile missing user principal')
-    out = realm.run_kadminl('getprinc nokeys')
+    out = realm.run([kadminl, 'getprinc', 'nokeys'])
     if 'Number of keys: 0' not in out:
         fail('Loading dumpfile did not process zero-key principal')
-    out = realm.run_kadminl('getpols')
+    out = realm.run([kadminl, 'getpols'])
     if 'testpol' not in out:
         fail('Loaded dumpfile missing test policy')
     dump_compare(realm, opt, srcfile)
@@ -93,11 +93,11 @@ load_dump_check_compare(realm, ['-b7'], srcdump_b7)
 
 # Loading the last (-b7 format) dump won't have loaded the
 # per-principal kadm data.  Load that incrementally with -ov.
-out = realm.run_kadminl('getprinc user')
+out = realm.run([kadminl, 'getprinc', 'user'])
 if 'Policy: [none]' not in out:
     fail('Loaded b7 dump unexpectedly contains user policy reference')
 realm.run([kdb5_util, 'load', '-update', '-ov', srcdump_ov])
-out = realm.run_kadminl('getprinc user')
+out = realm.run([kadminl, 'getprinc', 'user'])
 if 'Policy: testpol' not in out:
     fail('Loading ov dump did not add user policy reference')
 
diff --git a/src/tests/t_general.py b/src/tests/t_general.py
index 5349b05..c3629e6 100755
--- a/src/tests/t_general.py
+++ b/src/tests/t_general.py
@@ -14,7 +14,8 @@ for realm in multipass_realms(create_host=False):
 
     # Test FAST kinit.
     fastpw = password('fast')
-    realm.run_kadminl('ank -pw %s +requires_preauth user/fast' % fastpw)
+    realm.run([kadminl, 'ank', '-pw', fastpw, '+requires_preauth',
+               'user/fast'])
     realm.kinit('user/fast', fastpw)
     realm.kinit('user/fast', fastpw, flags=['-T', realm.ccache])
     realm.klist('user/fast@%s' % realm.realm)
@@ -27,7 +28,7 @@ for realm in multipass_realms(create_host=False):
 # principal with an empty password.  (Regression test for #7642.)
 conf={'plugins': {'pwqual': {'disable': 'empty'}}}
 realm = K5Realm(create_user=False, create_host=False, krb5_conf=conf)
-realm.run_kadminl('addprinc -pw "" user')
+realm.run([kadminl, 'addprinc', '-pw', '', 'user'])
 realm.run(['./t_init_creds', 'user', ''])
 realm.stop()
 
diff --git a/src/tests/t_iprop.py b/src/tests/t_iprop.py
index 51e18a8..aece8c2 100644
--- a/src/tests/t_iprop.py
+++ b/src/tests/t_iprop.py
@@ -170,25 +170,25 @@ check_ulog(0, 0, 0, [])
 realm.addprinc(pr1)
 realm.addprinc(pr3)
 realm.addprinc(pr2)
-realm.run_kadminl('modprinc -allow_tix ' + pr2)
-realm.run_kadminl('modprinc +allow_tix ' + pr2)
+realm.run([kadminl, 'modprinc', '-allow_tix', pr2])
+realm.run([kadminl, 'modprinc', '+allow_tix', pr2])
 check_ulog(5, 1, 5, [pr1, pr3, pr2, pr2, pr2])
 
 # Start kpropd for slave1 and get a full dump from master.
 kpropd1 = realm.start_kpropd(slave1, ['-d'])
 wait_for_prop(kpropd1, True, 0, 5)
-out = realm.run_kadminl('listprincs', slave1)
+out = realm.run([kadminl, 'listprincs'], env=slave1)
 if pr1 not in out or pr2 not in out or pr3 not in out:
     fail('slave1 does not have all principals from master')
 check_ulog(0, 0, 5, [], slave1)
 
 # Make a change and check that it propagates incrementally.
-realm.run_kadminl('modprinc -allow_tix ' + pr2)
+realm.run([kadminl, 'modprinc', '-allow_tix', pr2])
 check_ulog(6, 1, 6, [pr1, pr3, pr2, pr2, pr2, pr2])
 kpropd1.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd1, False, 5, 6)
 check_ulog(1, 6, 6, [pr2], slave1)
-out = realm.run_kadminl('getprinc ' + pr2, slave1)
+out = realm.run([kadminl, 'getprinc', pr2], env=slave1)
 if 'Attributes: DISALLOW_ALL_TIX' not in out:
     fail('slave1 does not have modification from master')
 
@@ -211,24 +211,24 @@ kpropd2 = realm.start_server([kpropd, '-d', '-D', '-P', slave2_kprop_port,
                               '-a', acl_file, '-A', hostname], 'ready', slave2)
 wait_for_prop(kpropd2, True, 0, 6)
 check_ulog(0, 0, 6, [], slave2)
-out = realm.run_kadminl('listprincs', slave1)
+out = realm.run([kadminl, 'listprincs'], env=slave1)
 if pr1 not in out or pr2 not in out or pr3 not in out:
     fail('slave2 does not have all principals from slave1')
 
 # Make another change and check that it propagates incrementally to
 # both slaves.
-realm.run_kadminl('modprinc -maxrenewlife "22 hours" ' + pr1)
+realm.run([kadminl, 'modprinc', '-maxrenewlife', '22 hours', pr1])
 check_ulog(7, 1, 7, [pr1, pr3, pr2, pr2, pr2, pr2, pr1])
 kpropd1.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd1, False, 6, 7)
 check_ulog(2, 6, 7, [pr2, pr1], slave1)
-out = realm.run_kadminl('getprinc ' + pr1, slave1)
+out = realm.run([kadminl, 'getprinc', pr1], env=slave1)
 if 'Maximum renewable life: 0 days 22:00:00\n' not in out:
     fail('slave1 does not have modification from master')
 kpropd2.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd2, False, 6, 7)
 check_ulog(1, 7, 7, [pr1], slave2)
-out = realm.run_kadminl('getprinc ' + pr1, slave2)
+out = realm.run([kadminl, 'getprinc', pr1], env=slave2)
 if 'Maximum renewable life: 0 days 22:00:00\n' not in out:
     fail('slave2 does not have modification from slave1')
 
@@ -247,66 +247,66 @@ check_ulog(1, 7, 7, [pr1], slave2)
 
 # Make another change and check that it propagates incrementally to
 # both slaves.
-realm.run_kadminl('modprinc +allow_tix w')
+realm.run([kadminl, 'modprinc', '+allow_tix', 'w'])
 check_ulog(8, 1, 8, [pr1, pr3, pr2, pr2, pr2, pr2, pr1, pr2])
 kpropd1.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd1, False, 7, 8)
 check_ulog(3, 6, 8, [pr2, pr1, pr2], slave1)
-out = realm.run_kadminl('getprinc ' + pr2, slave1)
+out = realm.run([kadminl, 'getprinc', pr2], env=slave1)
 if 'Attributes:\n' not in out:
     fail('slave1 does not have modification from master')
 kpropd2.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd2, False, 7, 8)
 check_ulog(2, 7, 8, [pr1, pr2], slave2)
-out = realm.run_kadminl('getprinc ' + pr2, slave2)
+out = realm.run([kadminl, 'getprinc', pr2], env=slave2)
 if 'Attributes:\n' not in out:
     fail('slave2 does not have modification from slave1')
 
 # Create a policy and check that it propagates via full resync.
-realm.run_kadminl('addpol -minclasses 2 testpol')
+realm.run([kadminl, 'addpol', '-minclasses', '2', 'testpol'])
 check_ulog(0, 0, 0, [])
 kpropd1.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd1, True, 8, 0)
 check_ulog(0, 0, 0, [], slave1)
-out = realm.run_kadminl('getpol testpol', slave1)
+out = realm.run([kadminl, 'getpol', 'testpol'], env=slave1)
 if 'Minimum number of password character classes: 2' not in out:
     fail('slave1 does not have policy from master')
 kpropd2.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd2, True, 8, 0)
 check_ulog(0, 0, 0, [], slave2)
-out = realm.run_kadminl('getpol testpol', slave2)
+out = realm.run([kadminl, 'getpol', 'testpol'], env=slave2)
 if 'Minimum number of password character classes: 2' not in out:
     fail('slave2 does not have policy from slave1')
 
 # Modify the policy and test that it also propagates via full resync.
-realm.run_kadminl('modpol -minlength 17 testpol')
+realm.run([kadminl, 'modpol', '-minlength', '17', 'testpol'])
 check_ulog(0, 0, 0, [])
 kpropd1.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd1, True, 0, 0)
 check_ulog(0, 0, 0, [], slave1)
-out = realm.run_kadminl('getpol testpol', slave1)
+out = realm.run([kadminl, 'getpol', 'testpol'], env=slave1)
 if 'Minimum password length: 17' not in out:
     fail('slave1 does not have policy change from master')
 kpropd2.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd2, True, 0, 0)
 check_ulog(0, 0, 0, [], slave2)
-out = realm.run_kadminl('getpol testpol', slave2)
+out = realm.run([kadminl, 'getpol', 'testpol'], env=slave2)
 if 'Minimum password length: 17' not in out:
     fail('slave2 does not have policy change from slave1')
 
 # Delete the policy and test that it propagates via full resync.
-realm.run_kadminl('delpol -force testpol')
+realm.run([kadminl, 'delpol', 'testpol'])
 check_ulog(0, 0, 0, [])
 kpropd1.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd1, True, 0, 0)
 check_ulog(0, 0, 0, [], slave1)
-out = realm.run_kadminl('getpol testpol', slave1)
+out = realm.run([kadminl, 'getpol', 'testpol'], env=slave1, expected_code=1)
 if 'Policy does not exist' not in out:
     fail('slave1 did not get policy deletion from master')
 kpropd2.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd2, True, 0, 0)
 check_ulog(0, 0, 0, [], slave2)
-out = realm.run_kadminl('getpol testpol', slave2)
+out = realm.run([kadminl, 'getpol', 'testpol'], env=slave2, expected_code=1)
 if 'Policy does not exist' not in out:
     fail('slave2 did not get policy deletion from slave1')
 
@@ -314,18 +314,18 @@ if 'Policy does not exist' not in out:
 # full resync.  (The master's ulog does not remember the timestamp it
 # had at serial number 0, so it does not know that an incremental
 # propagation is possible.)
-realm.run_kadminl('modprinc -maxlife "10 minutes" ' + pr1)
+realm.run([kadminl, 'modprinc', '-maxlife', '10 minutes', pr1])
 check_ulog(1, 1, 1, [pr1])
 kpropd1.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd1, True, 0, 1)
 check_ulog(0, 0, 1, [], slave1)
-out = realm.run_kadminl('getprinc ' + pr1, slave1)
+out = realm.run([kadminl, 'getprinc', pr1], env=slave1)
 if 'Maximum ticket life: 0 days 00:10:00' not in out:
     fail('slave1 does not have modification from master')
 kpropd2.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd2, True, 0, 1)
 check_ulog(0, 0, 1, [], slave2)
-out = realm.run_kadminl('getprinc ' + pr1, slave2)
+out = realm.run([kadminl, 'getprinc', pr1], env=slave2)
 if 'Maximum ticket life: 0 days 00:10:00' not in out:
     fail('slave2 does not have modification from slave1')
 
@@ -333,18 +333,18 @@ if 'Maximum ticket life: 0 days 00:10:00' not in out:
 # slave1.  slave2 needs another full resync because slave1 no longer
 # has serial number 1 in its ulog after processing its first
 # incremental update.
-realm.run_kadminl('delprinc -force ' + pr3)
+realm.run([kadminl, 'delprinc', pr3])
 check_ulog(2, 1, 2, [pr1, pr3])
 kpropd1.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd1, False, 1, 2)
 check_ulog(1, 2, 2, [pr3], slave1)
-out = realm.run_kadminl('getprinc ' + pr3, slave1)
+out = realm.run([kadminl, 'getprinc', pr3], env=slave1, expected_code=1)
 if 'Principal does not exist' not in out:
     fail('slave1 does not have principal deletion from master')
 kpropd2.send_signal(signal.SIGUSR1)
 wait_for_prop(kpropd2, True, 1, 2)
 check_ulog(0, 0, 2, [], slave2)
-out = realm.run_kadminl('getprinc ' + pr3, slave2)
+out = realm.run([kadminl, 'getprinc', pr3], env=slave2, expected_code=1)
 if 'Principal does not exist' not in out:
     fail('slave2 does not have principal deletion from slave1')
 
diff --git a/src/tests/t_kadm5_hook.py b/src/tests/t_kadm5_hook.py
index 1f023ea..b0de25c 100644
--- a/src/tests/t_kadm5_hook.py
+++ b/src/tests/t_kadm5_hook.py
@@ -7,7 +7,7 @@ plugin = os.path.join(buildtop, "plugins", "kadm5_hook", "test",
 hook_krb5_conf = {'plugins': {'kadm5_hook': { 'module': 'test:' + plugin}}}
 
 realm = K5Realm(krb5_conf=hook_krb5_conf, create_user=False, create_host=False)
-output = realm.run_kadminl ('addprinc -randkey test')
+output = realm.run([kadminl, 'addprinc', '-randkey', 'test'])
 if "create: stage precommit" not in output:
     fail('kadm5_hook test output not found')
 
diff --git a/src/tests/t_kadmin_acl.py b/src/tests/t_kadmin_acl.py
index c4b8465..9ccc80b 100644
--- a/src/tests/t_kadmin_acl.py
+++ b/src/tests/t_kadmin_acl.py
@@ -12,13 +12,9 @@ def make_client(name):
                 flags=['-S', 'kadmin/admin', '-c', ccache])
     return ccache
 
-def kadmin_as(client, query):
+def kadmin_as(client, query, **kwargs):
     global realm
-    return realm.run([kadmin, '-c', client, '-q', query])
-
-def delprinc(name):
-    global realm
-    realm.run_kadminl('delprinc -force ' + name)
+    return realm.run([kadmin, '-c', client] + query, **kwargs)
 
 all_add = make_client('all_add')
 all_changepw = make_client('all_changepw')
@@ -42,7 +38,7 @@ none = make_client('none')
 restrictions = make_client('restrictions')
 onetwothreefour = make_client('one/two/three/four')
 
-realm.run_kadminl('addpol -minlife "1 day" minlife')
+realm.run([kadminl, 'addpol', '-minlife', '1 day', 'minlife'])
 
 f = open(os.path.join(realm.testdir, 'acl'), 'w')
 f.write('''
@@ -79,280 +75,244 @@ realm.start_kadmind()
 # cpw can generate four different RPC calls depending on options.
 realm.addprinc('selected', 'oldpw')
 realm.addprinc('unselected', 'oldpw')
-for pw in ('-pw newpw', '-randkey'):
-    for ks in ('', '-e aes256-cts:normal'):
-        args = pw + ' ' + ks
-        out = kadmin_as(all_changepw, 'cpw %s unselected' % args)
-        if ('Password for "unselected at KRBTEST.COM" changed.' not in out and
-            'Key for "unselected at KRBTEST.COM" randomized.' not in out):
-            fail('cpw success (acl)')
-        out = kadmin_as(some_changepw, 'cpw %s selected' % args)
-        if ('Password for "selected at KRBTEST.COM" changed.' not in out and
-            'Key for "selected at KRBTEST.COM" randomized.' not in out):
-            fail('cpw success (target)')
-        out = kadmin_as(none, 'cpw %s selected' % args)
+for pw in (['-pw', 'newpw'], ['-randkey']):
+    for ks in ([], ['-e', 'aes256-cts']):
+        args = pw + ks
+        kadmin_as(all_changepw, ['cpw'] + args + ['unselected'])
+        kadmin_as(some_changepw, ['cpw'] + args + ['selected'])
+        out = kadmin_as(none, ['cpw'] + args + ['selected'], expected_code=1)
         if 'Operation requires ``change-password\'\' privilege' not in out:
             fail('cpw failure (no perms)')
-        out = kadmin_as(some_changepw, 'cpw %s unselected' % args)
+        out = kadmin_as(some_changepw, ['cpw'] + args + ['unselected'],
+                        expected_code=1)
         if 'Operation requires ``change-password\'\' privilege' not in out:
             fail('cpw failure (target)')
-        out = kadmin_as(none, 'cpw %s none' % args)
-        if ('Password for "none at KRBTEST.COM" changed.' not in out and
-            'Key for "none at KRBTEST.COM" randomized.' not in out):
-            fail('cpw success (self exemption)')
-        realm.run_kadminl('modprinc -policy minlife none')
-        out = kadmin_as(none, 'cpw %s none' % args)
+        out = kadmin_as(none, ['cpw'] + args + ['none'])
+        realm.run([kadminl, 'modprinc', '-policy', 'minlife', 'none'])
+        out = kadmin_as(none, ['cpw'] + args + ['none'], expected_code=1)
         if 'Current password\'s minimum life has not expired' not in out:
             fail('cpw failure (minimum life)')
-        realm.run_kadminl('modprinc -clearpolicy none')
-delprinc('selected')
-delprinc('unselected')
+        realm.run([kadminl, 'modprinc', '-clearpolicy', 'none'])
+realm.run([kadminl, 'delprinc', 'selected'])
+realm.run([kadminl, 'delprinc', 'unselected'])
 
-out = kadmin_as(all_add, 'addpol policy')
-realm.run_kadminl('delpol -force policy')
-if 'Operation requires' in out:
-    fail('addpol success (acl)')
-out = kadmin_as(none, 'addpol policy')
+kadmin_as(all_add, ['addpol', 'policy'])
+realm.run([kadminl, 'delpol', 'policy'])
+out = kadmin_as(none, ['addpol', 'policy'], expected_code=1)
 if 'Operation requires ``add\'\' privilege' not in out:
     fail('addpol failure (no perms)')
 
 # addprinc can generate two different RPC calls depending on options.
-for ks in ('', '-e aes256-cts:normal'):
-    args = '-pw pw ' + ks
-    out = kadmin_as(all_add, 'addprinc %s unselected' % args)
-    if 'Principal "unselected at KRBTEST.COM" created.' not in out:
-        fail('addprinc success (acl)')
-    delprinc('unselected')
-    out = kadmin_as(some_add, 'addprinc %s selected' % args)
-    if 'Principal "selected at KRBTEST.COM" created.' not in out:
-        fail('addprinc success(target)')
-    delprinc('selected')
-    out = kadmin_as(restricted_add, 'addprinc %s unselected' % args)
-    if 'Principal "unselected at KRBTEST.COM" created.' not in out:
-        fail('addprinc success (restrictions) -- addprinc')
-    out = realm.run_kadminl('getprinc unselected')
+for ks in ([], ['-e', 'aes256-cts']):
+    args = ['-pw', 'pw'] + ks
+    kadmin_as(all_add, ['addprinc'] + args + ['unselected'])
+    realm.run([kadminl, 'delprinc', 'unselected'])
+    kadmin_as(some_add, ['addprinc'] + args + ['selected'])
+    realm.run([kadminl, 'delprinc', 'selected'])
+    kadmin_as(restricted_add, ['addprinc'] + args + ['unselected'])
+    out = realm.run([kadminl, 'getprinc', 'unselected'])
     if 'REQUIRES_PRE_AUTH' not in out:
         fail('addprinc success (restrictions) -- restriction check')
-    delprinc('unselected')
-    out = kadmin_as(none, 'addprinc %s selected' % args)
+    realm.run([kadminl, 'delprinc', 'unselected'])
+    out = kadmin_as(none, ['addprinc'] + args + ['selected'], expected_code=1)
     if 'Operation requires ``add\'\' privilege' not in out:
         fail('addprinc failure (no perms)')
-    out = kadmin_as(some_add, 'addprinc %s unselected' % args)
+    out = kadmin_as(some_add, ['addprinc'] + args + ['unselected'],
+                    expected_code=1)
     if 'Operation requires ``add\'\' privilege' not in out:
         fail('addprinc failure (target)')
 
 realm.addprinc('unselected', 'pw')
-out = kadmin_as(all_delete, 'delprinc -force unselected')
-if 'Principal "unselected at KRBTEST.COM" deleted.' not in out:
-    fail('delprinc success (acl)')
+kadmin_as(all_delete, ['delprinc', 'unselected'])
 realm.addprinc('selected', 'pw')
-out = kadmin_as(some_delete, 'delprinc -force selected')
-if 'Principal "selected at KRBTEST.COM" deleted.' not in out:
-    fail('delprinc success (target)')
+kadmin_as(some_delete, ['delprinc', 'selected'])
 realm.addprinc('unselected', 'pw')
-out = kadmin_as(none, 'delprinc -force unselected')
+out = kadmin_as(none, ['delprinc', 'unselected'], expected_code=1)
 if 'Operation requires ``delete\'\' privilege' not in out:
     fail('delprinc failure (no perms)')
-out = kadmin_as(some_delete, 'delprinc -force unselected')
+out = kadmin_as(some_delete, ['delprinc', 'unselected'], expected_code=1)
 if 'Operation requires ``delete\'\' privilege' not in out:
     fail('delprinc failure (no target)')
+realm.run([kadminl, 'delprinc', 'unselected'])
 
-out = kadmin_as(all_inquire, 'getpol minlife')
+out = kadmin_as(all_inquire, ['getpol', 'minlife'])
 if 'Policy: minlife' not in out:
     fail('getpol success (acl)')
-out = kadmin_as(none, 'getpol minlife')
+out = kadmin_as(none, ['getpol', 'minlife'], expected_code=1)
 if 'Operation requires ``get\'\' privilege' not in out:
     fail('getpol failure (no perms)')
-realm.run_kadminl('modprinc -policy minlife none')
-out = kadmin_as(none, 'getpol minlife')
+realm.run([kadminl, 'modprinc', '-policy', 'minlife', 'none'])
+out = kadmin_as(none, ['getpol', 'minlife'])
 if 'Policy: minlife' not in out:
     fail('getpol success (self policy exemption)')
-realm.run_kadminl('modprinc -clearpolicy none')
+realm.run([kadminl, 'modprinc', '-clearpolicy', 'none'])
 
 realm.addprinc('selected', 'pw')
 realm.addprinc('unselected', 'pw')
-out = kadmin_as(all_inquire, 'getprinc unselected')
+out = kadmin_as(all_inquire, ['getprinc', 'unselected'])
 if 'Principal: unselected at KRBTEST.COM' not in out:
     fail('getprinc success (acl)')
-out = kadmin_as(some_inquire, 'getprinc selected')
+out = kadmin_as(some_inquire, ['getprinc', 'selected'])
 if 'Principal: selected at KRBTEST.COM' not in out:
     fail('getprinc success (target)')
-out = kadmin_as(none, 'getprinc selected')
+out = kadmin_as(none, ['getprinc', 'selected'], expected_code=1)
 if 'Operation requires ``get\'\' privilege' not in out:
     fail('getprinc failure (no perms)')
-out = kadmin_as(some_inquire, 'getprinc unselected')
+out = kadmin_as(some_inquire, ['getprinc', 'unselected'], expected_code=1)
 if 'Operation requires ``get\'\' privilege' not in out:
     fail('getprinc failure (target)')
-out = kadmin_as(none, 'getprinc none')
+out = kadmin_as(none, ['getprinc', 'none'])
 if 'Principal: none at KRBTEST.COM' not in out:
     fail('getprinc success (self exemption)')
-delprinc('selected')
-delprinc('unselected')
+realm.run([kadminl, 'delprinc', 'selected'])
+realm.run([kadminl, 'delprinc', 'unselected'])
 
-out = kadmin_as(all_list, 'listprincs')
+out = kadmin_as(all_list, ['listprincs'])
 if 'K/M at KRBTEST.COM' not in out:
     fail('listprincs success (acl)')
-out = kadmin_as(none, 'listprincs')
+out = kadmin_as(none, ['listprincs'], expected_code=1)
 if 'Operation requires ``list\'\' privilege' not in out:
     fail('listprincs failure (no perms)')
 
 realm.addprinc('selected', 'pw')
 realm.addprinc('unselected', 'pw')
-realm.run_kadminl('setstr selected key value')
-realm.run_kadminl('setstr unselected key value')
-out = kadmin_as(all_inquire, 'getstrs unselected')
+realm.run([kadminl, 'setstr', 'selected', 'key', 'value'])
+realm.run([kadminl, 'setstr', 'unselected', 'key', 'value'])
+out = kadmin_as(all_inquire, ['getstrs', 'unselected'])
 if 'key: value' not in out:
     fail('getstrs success (acl)')
-out = kadmin_as(some_inquire, 'getstrs selected')
+out = kadmin_as(some_inquire, ['getstrs', 'selected'])
 if 'key: value' not in out:
     fail('getstrs success (target)')
-out = kadmin_as(none, 'getstrs selected')
+out = kadmin_as(none, ['getstrs', 'selected'], expected_code=1)
 if 'Operation requires ``get\'\' privilege' not in out:
     fail('getstrs failure (no perms)')
-out = kadmin_as(some_inquire, 'getstrs unselected')
+out = kadmin_as(some_inquire, ['getstrs', 'unselected'], expected_code=1)
 if 'Operation requires ``get\'\' privilege' not in out:
     fail('getstrs failure (target)')
-out = kadmin_as(none, 'getstrs none')
+out = kadmin_as(none, ['getstrs', 'none'])
 if '(No string attributes.)' not in out:
     fail('getstrs success (self exemption)')
-delprinc('selected')
-delprinc('unselected')
+realm.run([kadminl, 'delprinc', 'selected'])
+realm.run([kadminl, 'delprinc', 'unselected'])
 
-out = kadmin_as(all_modify, 'modpol -maxlife "1 hour" policy')
+out = kadmin_as(all_modify, ['modpol', '-maxlife', '1 hour', 'policy'],
+                expected_code=1)
 if 'Operation requires' in out:
     fail('modpol success (acl)')
-out = kadmin_as(none, 'modpol -maxlife "1 hour" policy')
+out = kadmin_as(none, ['modpol', '-maxlife', '1 hour', 'policy'],
+                expected_code=1)
 if 'Operation requires ``modify\'\' privilege' not in out:
     fail('modpol failure (no perms)')
 
 realm.addprinc('selected', 'pw')
 realm.addprinc('unselected', 'pw')
-out = kadmin_as(all_modify, 'modprinc -maxlife "1 hour" unselected')
-if 'Principal "unselected at KRBTEST.COM" modified.' not in out:
-    fail('modprinc success (acl)')
-out = kadmin_as(some_modify, 'modprinc -maxlife "1 hour" selected')
-if 'Principal "selected at KRBTEST.COM" modified.' not in out:
-    fail('modprinc success (target)')
-out = kadmin_as(restricted_modify, 'modprinc -maxlife "1 hour" unselected')
-if 'Principal "unselected at KRBTEST.COM" modified.' not in out:
-    fail('modprinc success (restrictions) -- modprinc')
-out = realm.run_kadminl('getprinc unselected')
+kadmin_as(all_modify, ['modprinc', '-maxlife', '1 hour',  'unselected'])
+kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'selected'])
+kadmin_as(restricted_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'])
+out = realm.run([kadminl, 'getprinc', 'unselected'])
 if 'REQUIRES_PRE_AUTH' not in out:
     fail('addprinc success (restrictions) -- restriction check')
-out = kadmin_as(all_inquire, 'modprinc -maxlife "1 hour" selected')
+out = kadmin_as(all_inquire, ['modprinc', '-maxlife', '1 hour', 'selected'],
+                expected_code=1)
 if 'Operation requires ``modify\'\' privilege' not in out:
     fail('addprinc failure (no perms)')
-out = kadmin_as(some_modify, 'modprinc -maxlife "1 hour" unselected')
+out = kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'],
+                expected_code=1)
 if 'Operation requires' not in out:
     fail('modprinc failure (target)')
-delprinc('selected')
-delprinc('unselected')
+realm.run([kadminl, 'delprinc', 'selected'])
+realm.run([kadminl, 'delprinc', 'unselected'])
 
 realm.addprinc('selected', 'pw')
 realm.addprinc('unselected', 'pw')
-out = kadmin_as(all_modify, 'purgekeys unselected')
-if 'Old keys for principal "unselected at KRBTEST.COM" purged' not in out:
-    fail('purgekeys success (acl)')
-out = kadmin_as(some_modify, 'purgekeys selected')
-if 'Old keys for principal "selected at KRBTEST.COM" purged' not in out:
-    fail('purgekeys success (target)')
-out = kadmin_as(none, 'purgekeys selected')
+kadmin_as(all_modify, ['purgekeys', 'unselected'])
+kadmin_as(some_modify, ['purgekeys', 'selected'])
+out = kadmin_as(none, ['purgekeys', 'selected'], expected_code=1)
 if 'Operation requires ``modify\'\' privilege' not in out:
     fail('purgekeys failure (no perms)')
-out = kadmin_as(some_modify, 'purgekeys unselected')
+out = kadmin_as(some_modify, ['purgekeys', 'unselected'], expected_code=1)
 if 'Operation requires ``modify\'\' privilege' not in out:
     fail('purgekeys failure (target)')
-out = kadmin_as(none, 'purgekeys none')
-if 'Old keys for principal "none at KRBTEST.COM" purged' not in out:
-    fail('purgekeys success (self exemption)')
-delprinc('selected')
-delprinc('unselected')
+kadmin_as(none, ['purgekeys', 'none'])
+realm.run([kadminl, 'delprinc', 'selected'])
+realm.run([kadminl, 'delprinc', 'unselected'])
 
 realm.addprinc('from', 'pw')
-out = kadmin_as(all_rename, 'renprinc -force from to')
-if 'Principal "from at KRBTEST.COM" renamed to "to at KRBTEST.COM".' not in out:
-    fail('renprinc success (acl)')
-realm.run_kadminl('renprinc -force to from')
-out = kadmin_as(some_rename, 'renprinc -force from to')
-if 'Principal "from at KRBTEST.COM" renamed to "to at KRBTEST.COM".' not in out:
-    fail('renprinc success (target)')
-realm.run_kadminl('renprinc -force to from')
-out = kadmin_as(all_add, 'renprinc -force from to')
+kadmin_as(all_rename, ['renprinc', 'from', 'to'])
+realm.run([kadminl, 'renprinc', 'to', 'from'])
+kadmin_as(some_rename, ['renprinc', 'from', 'to'])
+realm.run([kadminl, 'renprinc', 'to', 'from'])
+out = kadmin_as(all_add, ['renprinc', 'from', 'to'], expected_code=1)
 if 'Operation requires ``delete\'\' privilege' not in out:
     fail('renprinc failure (no delete perms)')
-out = kadmin_as(all_delete, 'renprinc -force from to')
+out = kadmin_as(all_delete, ['renprinc', 'from', 'to'], expected_code=1)
 if 'Operation requires ``add\'\' privilege' not in out:
     fail('renprinc failure (no add perms)')
-out = kadmin_as(some_rename, 'renprinc -force from notto')
+out = kadmin_as(some_rename, ['renprinc', 'from', 'notto'], expected_code=1)
 if 'Operation requires ``add\'\' privilege' not in out:
     fail('renprinc failure (new target)')
-realm.run_kadminl('renprinc -force from notfrom')
-out = kadmin_as(some_rename, 'renprinc -force notfrom to')
+realm.run([kadminl, 'renprinc', 'from', 'notfrom'])
+out = kadmin_as(some_rename, ['renprinc', 'notfrom', 'to'], expected_code=1)
 if 'Operation requires ``delete\'\' privilege' not in out:
     fail('renprinc failure (old target)')
-out = kadmin_as(restricted_rename, 'renprinc -force notfrom to')
+out = kadmin_as(restricted_rename, ['renprinc', 'notfrom', 'to'],
+                expected_code=1)
 if 'Operation requires ``add\'\' privilege' not in out:
     fail('renprinc failure (restrictions)')
-delprinc('notfrom')
+realm.run([kadminl, 'delprinc', 'notfrom'])
 
 realm.addprinc('selected', 'pw')
 realm.addprinc('unselected', 'pw')
-out = kadmin_as(all_modify, 'setstr unselected key value')
-if 'Attribute set for principal "unselected at KRBTEST.COM".' not in out:
-    fail('modprinc success (acl)')
-out = kadmin_as(some_modify, 'setstr selected key value')
-if 'Attribute set for principal "selected at KRBTEST.COM".' not in out:
-    fail('modprinc success (target)')
-out = kadmin_as(none, 'setstr selected key value')
+kadmin_as(all_modify, ['setstr', 'unselected', 'key', 'value'])
+kadmin_as(some_modify, ['setstr', 'selected', 'key', 'value'])
+out = kadmin_as(none, ['setstr', 'selected',  'key', 'value'], expected_code=1)
 if 'Operation requires ``modify\'\' privilege' not in out:
     fail('addprinc failure (no perms)')
-out = kadmin_as(some_modify, 'setstr unselected key value')
+out = kadmin_as(some_modify, ['setstr', 'unselected', 'key', 'value'],
+                expected_code=1)
 if 'Operation requires' not in out:
     fail('modprinc failure (target)')
-delprinc('selected')
-delprinc('unselected')
+realm.run([kadminl, 'delprinc', 'selected'])
+realm.run([kadminl, 'delprinc', 'unselected'])
 
-out = kadmin_as(admin, 'addprinc -pw pw anytarget')
-if 'Principal "anytarget at KRBTEST.COM" created.' not in out:
-    fail('addprinc success (client wildcard)')
-delprinc('anytarget')
-out = kadmin_as(wctarget, 'addprinc -pw pw wild/card')
-if 'Principal "wild/card at KRBTEST.COM" created.' not in out:
-    fail('addprinc sucess (target wildcard)')
-delprinc('wild/card')
-out = kadmin_as(wctarget, 'addprinc -pw pw wild/card/extra')
+kadmin_as(admin, ['addprinc', '-pw', 'pw', 'anytarget'])
+realm.run([kadminl, 'delprinc', 'anytarget'])
+kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card'])
+realm.run([kadminl, 'delprinc', 'wild/card'])
+out = kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card/extra'],
+                expected_code=1)
 if 'Operation requires' not in out:
     fail('addprinc failure (target wildcard extra component)')
 realm.addprinc('admin/user', 'pw')
-out = kadmin_as(admin, 'delprinc -force admin/user')
-if 'Principal "admin/user at KRBTEST.COM" deleted.' not in out:
-    fail('delprinc success (wildcard backreferences)')
-out = kadmin_as(admin, 'delprinc -force none')
+kadmin_as(admin, ['delprinc', 'admin/user'])
+out = kadmin_as(admin, ['delprinc', 'none'], expected_code=1)
 if 'Operation requires' not in out:
     fail('delprinc failure (wildcard backreferences not matched)')
 realm.addprinc('four/one/three', 'pw')
-out = kadmin_as(onetwothreefour, 'delprinc -force four/one/three')
-if 'Principal "four/one/three at KRBTEST.COM" deleted.' not in out:
-    fail('delprinc success (wildcard backreferences 2)')
+kadmin_as(onetwothreefour, ['delprinc', 'four/one/three'])
 
-kadmin_as(restrictions, 'addprinc -pw pw type1')
-out = realm.run_kadminl('getprinc type1')
+kadmin_as(restrictions, ['addprinc', '-pw', 'pw', 'type1'])
+out = realm.run([kadminl, 'getprinc', 'type1'])
 if 'Policy: minlife' not in out:
     fail('restriction (policy)')
-delprinc('type1')
-kadmin_as(restrictions, 'addprinc -pw pw -policy minlife type2')
-out = realm.run_kadminl('getprinc type2')
+realm.run([kadminl, 'delprinc', 'type1'])
+kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-policy', 'minlife',
+                         'type2'])
+out = realm.run([kadminl, 'getprinc', 'type2'])
 if 'Policy: [none]' not in out:
     fail('restriction (clearpolicy)')
-delprinc('type2')
-kadmin_as(restrictions, 'addprinc -pw pw -maxlife "1 minute" type3')
-out = realm.run_kadminl('getprinc type3')
+realm.run([kadminl, 'delprinc', 'type2'])
+kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-maxlife', '1 minute',
+                         'type3'])
+out = realm.run([kadminl, 'getprinc', 'type3'])
 if ('Maximum ticket life: 0 days 00:01:00' not in out or
     'Maximum renewable life: 0 days 02:00:00' not in out):
     fail('restriction (maxlife low, maxrenewlife unspec)')
-delprinc('type3')
-kadmin_as(restrictions, 'addprinc -pw pw -maxrenewlife "1 day" type3')
-out = realm.run_kadminl('getprinc type3')
+realm.run([kadminl, 'delprinc', 'type3'])
+kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-maxrenewlife', '1 day',
+                         'type3'])
+out = realm.run([kadminl, 'getprinc', 'type3'])
 if 'Maximum renewable life: 0 days 02:00:00' not in out:
     fail('restriction (maxrenewlife high)')
 
diff --git a/src/tests/t_kdb.py b/src/tests/t_kdb.py
index a52a49d..56595db 100644
--- a/src/tests/t_kdb.py
+++ b/src/tests/t_kdb.py
@@ -152,43 +152,45 @@ if out != 'KRBTEST.COM\n':
 # because we're sticking a krbPrincipalAux objectclass onto a subtree
 # krbContainer, but it works and it avoids having to load core.schema
 # in the test LDAP server.
-out = realm.run_kadminl('ank -randkey -x dn=cn=krb5 princ1')
+out = realm.run([kadminl, 'ank', '-randkey', '-x', 'dn=cn=krb5', 'princ1'],
+                expected_code=1)
 if 'DN is out of the realm subtree' not in out:
     fail('Unexpected kadmin.local output for out-of-realm dn')
-out = realm.run_kadminl('ank -randkey -x dn=cn=t2,cn=krb5 princ1')
-if 'Principal "princ1 at KRBTEST.COM" created.\n' not in  out:
-    fail('Unexpected kadmin.local output for specified dn')
-out = realm.run_kadminl('getprinc princ1')
+realm.run([kadminl, 'ank', '-randkey', '-x', 'dn=cn=t2,cn=krb5', 'princ1'])
+out = realm.run([kadminl, 'getprinc', 'princ1'])
 if 'Principal: princ1' not in out:
     fail('Unexpected kadmin.local output after creating princ1')
-out = realm.run_kadminl('ank -randkey -x dn=cn=t2,cn=krb5 again')
+out = realm.run([kadminl, 'ank', '-randkey', '-x', 'dn=cn=t2,cn=krb5',
+                 'again'], expected_code=1)
 if 'ldap object is already kerberized' not in out:
     fail('Unexpected kadmin.local output trying to re-kerberize DN')
 # Check that we can't set linkdn on a non-standalone object.
-out = realm.run_kadminl('modprinc -x linkdn=cn=t1,cn=krb5 princ1')
+out = realm.run([kadminl, 'modprinc', '-x', 'linkdn=cn=t1,cn=krb5', 'princ1'],
+                expected_code=1)
 if 'link information can not be set' not in out:
     fail('Unexpected kadmin.local output trying to set linkdn on princ1')
 
 # Create a principal with a specified linkdn.
-out = realm.run_kadminl('ank -randkey -x linkdn=cn=krb5 princ2')
+out = realm.run([kadminl, 'ank', '-randkey', '-x', 'linkdn=cn=krb5', 'princ2'],
+                expected_code=1)
 if 'DN is out of the realm subtree' not in out:
     fail('Unexpected kadmin.local output for out-of-realm linkdn')
-out = realm.run_kadminl('ank -randkey -x linkdn=cn=t1,cn=krb5 princ2')
-if 'Principal "princ2 at KRBTEST.COM" created.\n' not in out:
-    fail('Unexpected kadmin.local output for specified linkdn')
+realm.run([kadminl, 'ank', '-randkey', '-x', 'linkdn=cn=t1,cn=krb5', 'princ2'])
 # Check that we can't reset linkdn.
-out = realm.run_kadminl('modprinc -x linkdn=cn=t2,cn=krb5 princ2')
+out = realm.run([kadminl, 'modprinc', '-x', 'linkdn=cn=t2,cn=krb5', 'princ2'],
+                expected_code=1)
 if 'kerberos principal is already linked' not in out:
     fail('Unexpected kadmin.local output for re-specified linkdn')
 
 # Create a principal with a specified containerdn.
-out = realm.run_kadminl('ank -randkey -x containerdn=cn=krb5 princ3')
+out = realm.run([kadminl, 'ank', '-randkey', '-x', 'containerdn=cn=krb5',
+                 'princ3'], expected_code=1)
 if 'DN is out of the realm subtree' not in out:
     fail('Unexpected kadmin.local output for out-of-realm containerdn')
-out = realm.run_kadminl('ank -randkey -x containerdn=cn=t1,cn=krb5 princ3')
-if 'Principal "princ3 at KRBTEST.COM" created.\n' not in out:
-    fail('Unexpected kadmin.local output for specified containerdn')
-out = realm.run_kadminl('modprinc -x containerdn=cn=t2,cn=krb5 princ3')
+realm.run([kadminl, 'ank', '-randkey', '-x', 'containerdn=cn=t1,cn=krb5',
+           'princ3'])
+out = realm.run([kadminl, 'modprinc', '-x', 'containerdn=cn=t2,cn=krb5',
+                 'princ3'], expected_code=1)
 if 'containerdn option not supported' not in out:
     fail('Unexpected kadmin.local output trying to reset containerdn')
 
@@ -209,8 +211,8 @@ if out != 'tktpol\n':
     fail('Unexpected kdb5_ldap_util list_policy output')
 
 # Associate the ticket policy to a principal.
-realm.run_kadminl('ank -randkey -x tktpolicy=tktpol princ4')
-out = realm.run_kadminl('getprinc princ4')
+realm.run([kadminl, 'ank', '-randkey', '-x', 'tktpolicy=tktpol', 'princ4'])
+out = realm.run([kadminl, 'getprinc', 'princ4'])
 if ('Maximum ticket life: 0 days 04:00:00\n' not in out or
     'Maximum renewable life: 0 days 08:00:00\n' not in out or
     'Attributes: DISALLOW_FORWARDABLE REQUIRES_PRE_AUTH\n' not in out):
@@ -220,8 +222,8 @@ if ('Maximum ticket life: 0 days 04:00:00\n' not in out or
 kldaputil(['destroy_policy', '-force', 'tktpol'], expected_code=1)
 
 # Dissociate the ticket policy from the principal.
-realm.run_kadminl('modprinc -x tktpolicy= princ4')
-out = realm.run_kadminl('getprinc princ4')
+realm.run([kadminl, 'modprinc', '-x', 'tktpolicy=', 'princ4'])
+out = realm.run([kadminl, 'getprinc', 'princ4'])
 if ('Maximum ticket life: 0 days 05:00:00\n' not in out or
     'Maximum renewable life: 0 days 10:00:00\n' not in out or
     'Attributes:\n' not in out):
@@ -238,23 +240,25 @@ if out:
 kldaputil(['create_policy', 'tktpol2'])
 
 # Try to create a password policy conflicting with a ticket policy.
-out = realm.run_kadminl('addpol tktpol2')
+out = realm.run([kadminl, 'addpol', 'tktpol2'], expected_code=1)
 if 'Already exists while creating policy "tktpol2"' not in out:
     fail('Expected error not seen in kadmin.local output')
 
 # Try to create a ticket policy conflicting with a password policy.
-realm.run_kadminl('addpol pwpol')
+realm.run([kadminl, 'addpol', 'pwpol'])
 out = kldaputil(['create_policy', 'pwpol'], expected_code=1)
 if 'Already exists while creating policy object' not in out:
     fail('Expected error not seen in kdb5_ldap_util output')
 
 # Try to use a password policy as a ticket policy.
-out = realm.run_kadminl('modprinc -x tktpolicy=pwpol princ4')
+out = realm.run([kadminl, 'modprinc', '-x', 'tktpolicy=pwpol', 'princ4'],
+                expected_code=1)
 if 'Object class violation' not in out:
     fail('Expected error not seem in kadmin.local output')
 
-# Try to use a ticket policy as a password policy (CVE-2014-5353).
-out = realm.run_kadminl('modprinc -policy tktpol2 princ4')
+# Use a ticket policy as a password policy (CVE-2014-5353).  This
+# works with a warning; use kadmin.local -q so the warning is shown.
+out = realm.run([kadminl, '-q', 'modprinc -policy tktpol2 princ4'])
 if 'WARNING: policy "tktpol2" does not exist' not in out:
     fail('Expected error not seen in kadmin.local output')
 
@@ -278,10 +282,10 @@ ldap_modify('dn: krbPrincipalName=canon at KRBTEST.COM,cn=t1,cn=krb5\n'
             '-\n'
             'add: krbCanonicalName\n'
             'krbCanonicalName: canon at KRBTEST.COM\n')
-out = realm.run_kadminl('getprinc alias')
+out = realm.run([kadminl, 'getprinc', 'alias'])
 if 'Principal: canon at KRBTEST.COM\n' not in out:
     fail('Could not fetch canon through alias')
-out = realm.run_kadminl('getprinc canon')
+out = realm.run([kadminl, 'getprinc', 'canon'])
 if 'Principal: canon at KRBTEST.COM\n' not in out:
     fail('Could not fetch canon through canon')
 realm.run([kvno, 'alias'])
@@ -299,7 +303,7 @@ ldap_modify('dn: krbPrincipalName=krbtgt/KRBTEST.COM at KRBTEST.COM,'
             '-\n'
             'add: krbCanonicalName\n'
             'krbCanonicalName: krbtgt/KRBTEST.COM at KRBTEST.COM\n')
-out = realm.run_kadminl('getprinc tgtalias')
+out = realm.run([kadminl, 'getprinc', 'tgtalias'])
 if 'Principal: krbtgt/KRBTEST.COM at KRBTEST.COM' not in out:
     fail('Could not fetch krbtgt through tgtalias')
 realm.run([kvno, 'tgtalias'])
@@ -308,38 +312,42 @@ if 'tgtalias at KRBTEST.COM\n' not in out:
     fail('After fetching tgtalias, klist is missing it')
 
 # Make sure aliases work in header tickets.
-realm.run_kadminl('modprinc -maxrenewlife "3 hours" user')
-realm.run_kadminl('modprinc -maxrenewlife "3 hours" krbtgt/KRBTEST.COM')
+realm.run([kadminl, 'modprinc', '-maxrenewlife', '3 hours', 'user'])
+realm.run([kadminl, 'modprinc', '-maxrenewlife', '3 hours',
+           'krbtgt/KRBTEST.COM'])
 realm.kinit(realm.user_princ, password('user'), ['-l', '1h', '-r', '2h'])
 realm.run([kvno, 'alias'])
 realm.kinit(realm.user_princ, flags=['-R', '-S', 'alias'])
 realm.klist(realm.user_princ, 'alias at KRBTEST.COM')
 
 # Regression test for #7980 (fencepost when dividing keys up by kvno).
-realm.run_kadminl('addprinc -randkey -e aes256-cts,aes128-cts kvnoprinc')
-realm.run_kadminl('cpw -randkey -keepold -e aes256-cts,aes128-cts kvnoprinc')
-out = realm.run_kadminl('getprinc kvnoprinc')
+realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts,aes128-cts',
+           'kvnoprinc'])
+realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e',
+           'aes256-cts,aes128-cts', 'kvnoprinc'])
+out = realm.run([kadminl, 'getprinc', 'kvnoprinc'])
 if 'Number of keys: 4' not in out:
     fail('After cpw -keepold, wrong number of keys')
-realm.run_kadminl('cpw -randkey -keepold -e aes256-cts,aes128-cts kvnoprinc')
-out = realm.run_kadminl('getprinc kvnoprinc')
+realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e',
+           'aes256-cts,aes128-cts', 'kvnoprinc'])
+out = realm.run([kadminl, 'getprinc', 'kvnoprinc'])
 if 'Number of keys: 6' not in out:
     fail('After cpw -keepold, wrong number of keys')
 
 # Regression test for #8041 (NULL dereference on keyless principals).
-out = realm.run_kadminl('addprinc -nokey keylessprinc')
-if 'Principal "keylessprinc at KRBTEST.COM" created' not in out:
-    fail('Failed to create keyless principal')
-out = realm.run_kadminl('getprinc keylessprinc')
+realm.run([kadminl, 'addprinc', '-nokey', 'keylessprinc'])
+out = realm.run([kadminl, 'getprinc', 'keylessprinc'])
 if 'Number of keys: 0' not in out:
     fail('Failed to create a principal with no keys')
-realm.run_kadminl('cpw -randkey -e aes256-cts,aes128-cts keylessprinc')
-realm.run_kadminl('cpw -randkey -keepold -e aes256-cts,aes128-cts keylessprinc')
-out = realm.run_kadminl('getprinc keylessprinc')
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes256-cts,aes128-cts',
+           'keylessprinc'])
+realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e',
+           'aes256-cts,aes128-cts', 'keylessprinc'])
+out = realm.run([kadminl, 'getprinc', 'keylessprinc'])
 if 'Number of keys: 4' not in out:
     fail('Failed to add keys to keylessprinc')
-realm.run_kadminl('purgekeys -all keylessprinc')
-out = realm.run_kadminl('getprinc keylessprinc')
+realm.run([kadminl, 'purgekeys', '-all', 'keylessprinc'])
+out = realm.run([kadminl, 'getprinc', 'keylessprinc'])
 if 'Number of keys: 0' not in out:
     fail('After purgekeys -all, keys remain')
 
@@ -398,11 +406,11 @@ realm.addprinc(realm.user_princ, password('user'))
 realm.kinit(realm.user_princ, password('user'))
 realm.stop()
 # Exercise DB options, which should cause binding to fail.
-out = realm.run([kadmin_local, '-x', 'sasl_authcid=ab', '-q', 'getprinc user'],
+out = realm.run([kadminl, '-x', 'sasl_authcid=ab', 'getprinc', 'user'],
                 expected_code=1)
 if 'Cannot bind to LDAP server' not in out:
     fail('Expected error not seen in kadmin.local output')
-out = realm.run([kadmin_local, '-x', 'bindpwd=wrong', '-q', 'getprinc user'],
+out = realm.run([kadminl, '-x', 'bindpwd=wrong', 'getprinc', 'user'],
                 expected_code=1)
 if 'Cannot bind to LDAP server' not in out:
     fail('Expected error not seen in kadmin.local output')
diff --git a/src/tests/t_kdb_locking.py b/src/tests/t_kdb_locking.py
index 7c0755e..e8d86e0 100644
--- a/src/tests/t_kdb_locking.py
+++ b/src/tests/t_kdb_locking.py
@@ -28,7 +28,7 @@ if 'A service is not available' not in output:
 f = open(kadm5_lock, 'w')
 f.close()
 
-output = realm.run_kadminl('modprinc -allow_tix ' + p)
+output = realm.run([kadminl, 'modprinc', '-allow_tix', p])
 if 'Cannot lock database' in output:
     fail('krb5kdc still holds a lock on the principal db')
 
diff --git a/src/tests/t_keydata.py b/src/tests/t_keydata.py
index ad8c909..686e543 100644
--- a/src/tests/t_keydata.py
+++ b/src/tests/t_keydata.py
@@ -4,34 +4,26 @@ from k5test import *
 realm = K5Realm(create_user=False, create_host=False)
 
 # Create a principal with no keys.
-out = realm.run_kadminl('addprinc -nokey user')
-if 'created.' not in out:
-    fail('addprinc -nokey')
-out = realm.run_kadminl('getprinc user')
+realm.run([kadminl, 'addprinc', '-nokey', 'user'])
+out = realm.run([kadminl, 'getprinc', 'user'])
 if 'Number of keys: 0' not in out:
     fail('getprinc (addprinc -nokey)')
 
 # Change its password and check the resulting kvno.
-out = realm.run_kadminl('cpw -pw password user')
-if 'changed.' not in out:
-    fail('cpw -pw')
-out = realm.run_kadminl('getprinc user')
+realm.run([kadminl, 'cpw', '-pw', 'password', 'user'])
+out = realm.run([kadminl, 'getprinc', 'user'])
 if 'vno 1' not in out:
     fail('getprinc (cpw -pw)')
 
 # Delete all of its keys.
-out = realm.run_kadminl('purgekeys -all user')
-if 'All keys' not in out or 'removed.' not in out:
-    fail('purgekeys')
-out = realm.run_kadminl('getprinc user')
+realm.run([kadminl, 'purgekeys', '-all', 'user'])
+out = realm.run([kadminl, 'getprinc', 'user'])
 if 'Number of keys: 0' not in out:
     fail('getprinc (purgekeys)')
 
 # Randomize its keys and check the resulting kvno.
-out = realm.run_kadminl('cpw -randkey user')
-if 'randomized.' not in out:
-    fail('cpw -randkey')
-out = realm.run_kadminl('getprinc user')
+realm.run([kadminl, 'cpw', '-randkey', 'user'])
+out = realm.run([kadminl, 'getprinc', 'user'])
 if 'vno 1' not in out:
     fail('getprinc (cpw -randkey)')
 
@@ -52,14 +44,14 @@ def preauth_type_received(fname, patype):
 # Make sure the KDC doesn't offer encrypted timestamp for a principal
 # with no keys.
 tracefile = os.path.join(realm.testdir, 'trace')
-realm.run_kadminl('purgekeys -all user')
-realm.run_kadminl('modprinc +requires_preauth user')
+realm.run([kadminl, 'purgekeys', '-all', 'user'])
+realm.run([kadminl, 'modprinc', '+requires_preauth', 'user'])
 realm.run(['env', 'KRB5_TRACE=' + tracefile, kinit, 'user'], expected_code=1)
 if preauth_type_received(tracefile, 2):
     fail('encrypted timestamp')
 
 # Make sure it doesn't offer encrypted challenge either.
-realm.run_kadminl('addprinc -pw fast armor')
+realm.run([kadminl, 'addprinc', '-pw', 'fast', 'armor'])
 realm.kinit('armor', 'fast')
 os.remove(tracefile)
 realm.run(['env', 'KRB5_TRACE=' + tracefile, kinit, '-T', realm.ccache,
diff --git a/src/tests/t_keyrollover.py b/src/tests/t_keyrollover.py
index 29d1291..35d0b61 100644
--- a/src/tests/t_keyrollover.py
+++ b/src/tests/t_keyrollover.py
@@ -14,13 +14,13 @@ realm.addprinc(princ2)
 realm.run([kvno, realm.host_princ])
 
 # Change key for TGS, keeping old key.
-realm.run_kadminl('cpw -randkey -e aes256-cts:normal -keepold krbtgt/%s@%s' %
-                  (realm.realm, realm.realm))
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes256-cts', '-keepold',
+           realm.krbtgt_princ])
 
 # Ensure that kvno still works with an old TGT.
 realm.run([kvno, princ1])
 
-realm.run_kadminl('purgekeys krbtgt/%s@%s' % (realm.realm, realm.realm))
+realm.run([kadminl, 'purgekeys', realm.krbtgt_princ])
 # Make sure an old TGT fails after purging old TGS key.
 realm.run([kvno, princ2], expected_code=1)
 output = realm.run([klist, '-e'])
@@ -47,17 +47,17 @@ if expected not in output:
 # local-realm TGS request.  To set this up, we abuse an edge-case
 # behavior of modprinc -kvno.  First, set up a DES3 krbtgt entry at
 # kvno 1 and cache a krbtgt ticket.
-realm.run_kadminl('cpw -randkey -e des3-cbc-sha1:normal krbtgt/%s' %
-                  realm.realm)
-realm.run_kadminl('modprinc -kvno 1 krbtgt/%s' % realm.realm)
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'des3-cbc-sha1',
+           realm.krbtgt_princ])
+realm.run([kadminl, 'modprinc', '-kvno', '1', realm.krbtgt_princ])
 realm.kinit(realm.user_princ, password('user'))
 # Add an AES krbtgt entry at kvno 2, and then reset it to kvno 1
 # (modprinc -kvno sets the kvno on all entries without deleting any).
-realm.run_kadminl('cpw -randkey -keepold -e aes256-cts:normal krbtgt/%s' %
-                  realm.realm)
-realm.run_kadminl('modprinc -kvno 1 krbtgt/%s' % realm.realm)
-output = realm.run_kadminl('getprinc krbtgt/%s' % realm.realm)
-if 'vno 1, aes256' not in output or 'vno 1, des3' not in output:
+realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'aes256-cts',
+           realm.krbtgt_princ])
+realm.run([kadminl, 'modprinc', '-kvno', '1', realm.krbtgt_princ])
+out = realm.run([kadminl, 'getprinc', realm.krbtgt_princ])
+if 'vno 1, aes256' not in out or 'vno 1, des3' not in out:
     fail('keyrollover: setup for TGS enctype test failed')
 # Now present the DES3 ticket to the KDC and make sure it's rejected.
 realm.run([kvno, realm.host_princ], expected_code=1)
@@ -71,11 +71,12 @@ realm.stop()
 # r2's KDC with no kvno to identify it, forcing the KDC to try
 # multiple keys.
 r1, r2 = cross_realms(2)
-r1.run_kadminl('modprinc -kvno 0 krbtgt/%s' % r2.realm)
+crosstgt_princ = 'krbtgt/%s@%s' % (r2.realm, r1.realm)
+r1.run([kadminl, 'modprinc', '-kvno', '0', crosstgt_princ])
 r1.run([kvno, r2.host_princ])
-r2.run_kadminl('cpw -pw newcross -keepold krbtgt/%s@%s' % (r2.realm, r1.realm))
-r1.run_kadminl('cpw -pw newcross krbtgt/%s' % r2.realm)
-r1.run_kadminl('modprinc -kvno 0 krbtgt/%s' % r2.realm)
+r2.run([kadminl, 'cpw', '-pw', 'newcross', '-keepold', crosstgt_princ])
+r1.run([kadminl, 'cpw', '-pw', 'newcross', crosstgt_princ])
+r1.run([kadminl, 'modprinc', '-kvno', '0', crosstgt_princ])
 r1.run([kvno, r2.user_princ])
 
 success('keyrollover')
diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py
index 8e2cd23..7e35460 100644
--- a/src/tests/t_keytab.py
+++ b/src/tests/t_keytab.py
@@ -45,13 +45,13 @@ realm.klist(realm.user_princ)
 princ = 'foo/bar@%s' % realm.realm
 realm.addprinc(princ)
 os.remove(realm.keytab)
-realm.run_kadminl('modprinc -kvno 252 %s' % princ)
+realm.run([kadminl, 'modprinc', '-kvno', '252', princ])
 for kvno in range(253, 259):
-    realm.run_kadminl('ktadd -k %s %s' % (realm.keytab, princ))
+    realm.run([kadminl, 'ktadd', '-k', realm.keytab, princ])
     realm.kinit(princ, flags=['-k'])
     realm.klist_keytab(princ)
     os.remove(realm.keytab)
-output = realm.run_kadminl('getprinc %s' % princ)
+output = realm.run([kadminl, 'getprinc', princ])
 if 'Key: vno 258,' not in output:
     fail('Expected vno not seen in kadmin.local output')
 
diff --git a/src/tests/t_kprop.py b/src/tests/t_kprop.py
index ff62902..e2026c8 100644
--- a/src/tests/t_kprop.py
+++ b/src/tests/t_kprop.py
@@ -37,7 +37,7 @@ for realm in multipass_realms(create_user=False):
         if 'Rejected connection' in line:
             fail('kpropd rejected connection from kprop')
 
-            out = realm.run_kadminl('listprincs', slave)
+            out = realm.run([kadminl, 'listprincs', slave])
             if 'wakawaka' not in out:
                 fail('Slave does not have all principals from master')
 
diff --git a/src/tests/t_mkey.py b/src/tests/t_mkey.py
index 8a5b84e..572b2ad 100644
--- a/src/tests/t_mkey.py
+++ b/src/tests/t_mkey.py
@@ -16,7 +16,7 @@ realm.prep_kadmin()
 stash_file = os.path.join(realm.testdir, 'stash')
 
 # Count the number of principals in the realm.
-nprincs = len(realm.run_kadminl('listprincs').splitlines()) - 1
+nprincs = len(realm.run([kadminl, 'listprincs']).splitlines())
 
 # List the currently active mkeys and compare against expected
 # results.  Each argument must be a sequence of four elements: an
@@ -51,7 +51,7 @@ def check_mkey_list(*expected):
 # key version and an expected enctype.
 keyline_re = re.compile(r'^Key: vno (\d+), (\S+)$')
 def check_master_dbent(expected_mkvno, *expected_keys):
-    outlines = realm.run_kadminl('getprinc K/M').splitlines()
+    outlines = realm.run([kadminl, 'getprinc', 'K/M']).splitlines()
     mkeyline = [l for l in outlines if l.startswith('MKey: vno ')]
     if len(mkeyline) != 1 or mkeyline[0] != ('MKey: vno %d' % expected_mkvno):
         fail('Unexpected mkvno in K/M DB entry')
@@ -92,7 +92,7 @@ def check_stash(*expected):
 
 # Verify that the user principal has the expected mkvno.
 def check_mkvno(princ, expected_mkvno):
-    out = realm.run_kadminl('getprinc ' + princ)
+    out = realm.run([kadminl, 'getprinc', princ])
     if ('MKey: vno %d\n' % expected_mkvno) not in out:
         fail('Unexpected mkvno in user DB entry')
 
@@ -101,10 +101,11 @@ def check_mkvno(princ, expected_mkvno):
 # the mkvno of the principal against expected_mkvno and verify that
 # the running KDC can access the new key.
 def change_password_check_mkvno(local, princ, password, expected_mkvno):
-    cmd = 'cpw -pw %s %s' % (password, princ)
-    out = local and realm.run_kadminl(cmd) or realm.run_kadmin(cmd)
-    if 'changed.' not in out:
-        fail('Failed to change password')
+    cmd = ['cpw', '-pw', password, princ]
+    if local:
+        realm.run([kadminl] + cmd)
+    else:
+        realm.run_kadmin(cmd)
     check_mkvno(princ, expected_mkvno)
     realm.kinit(princ, password)
 
@@ -252,7 +253,7 @@ check_mkey_list((2, defetype, True, True))
 check_master_dbent(2, (2, defetype))
 os.rename(stash_file, stash_file + '.save')
 os.rename(stash_file + '.old', stash_file)
-out = realm.run([kadmin_local, '-q', 'getprinc user'], expected_code=1)
+out = realm.run([kadminl, 'getprinc', 'user'], expected_code=1)
 if 'Unable to decrypt latest master key' not in out:
     fail('Unexpected error from kadmin.local with old stash file')
 os.rename(stash_file + '.save', stash_file)
@@ -283,13 +284,13 @@ check_mkvno(realm.user_princ, 3)
 # and #7995 (-keepold does not re-encrypt old keys).
 add_mkey(['-s'])
 realm.run([kdb5_util, 'use_mkey', '4', 'now-1day'])
-realm.run_kadminl('cpw -randkey -keepold %s' % realm.user_princ)
+realm.run([kadminl, 'cpw', '-randkey', '-keepold', realm.user_princ])
 # With #7994 unfixed, mkvno of user will still be 3.
 check_mkvno(realm.user_princ, 4)
 # With #7995 unfixed, old keys are still encrypted with mkvno 3.
 update_princ_encryption(False, 4, nprincs - 2, 1)
 realm.run([kdb5_util, 'purge_mkeys', '-f'])
-out = realm.run_kadminl('xst -norandkey %s' % realm.user_princ)
+out = realm.run([kadminl, 'xst', '-norandkey', realm.user_princ])
 if 'Decrypt integrity check failed' in out or 'added to keytab' not in out:
     fail('Preserved old key data not updated to new master key')
 
@@ -310,7 +311,7 @@ f.write(struct.pack('=HL24s', 16, 24,
                     '\x94\xAD\x6D\x86\xB5\x16\x37\xEC\x7C\x8A\xBC\x86'))
 f.close()
 realm.run([kdb5_util, 'load', dumpfile])
-nprincs = len(realm.run_kadminl('listprincs').splitlines()) - 1
+nprincs = len(realm.run([kadminl, 'listprincs']).splitlines())
 check_mkvno('K/M', 1)
 check_mkey_list((1, des3, True, True))
 
@@ -322,7 +323,7 @@ check_mkey_list((1, des3, True, True))
 add_mkey([])
 check_mkey_list((2, defetype, False, False), (1, des3, True, True))
 update_princ_encryption(False, 1, 0, nprincs - 1)
-realm.run_kadminl('addprinc -randkey ' + realm.user_princ)
+realm.run([kadminl, 'addprinc', '-randkey', realm.user_princ])
 check_mkvno(realm.user_princ, 1)
 realm.run([kdb5_util, 'use_mkey', '2', 'now-1day'])
 check_mkey_list((2, defetype, True, True), (1, des3, True, False))
diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
index defe5c7..1a90a70 100644
--- a/src/tests/t_otp.py
+++ b/src/tests/t_otp.py
@@ -149,13 +149,13 @@ def verify(daemon, queue, reply, usernm, passwd):
     assert data['pass'] == [passwd]
     daemon.join()
 
-def setstr(princ, type, username=None):
-    cmd = 'setstr %s otp "[{""type"": ""%s""' % (princ, type)
+def otpconfig(toktype, username=None):
+    val = '[{"type": "%s"' % toktype
     if username is None:
-        cmd += '}]"'
+        val += '}]'
     else:
-        cmd += ', ""username"": ""%s""}]"' % username
-    return cmd
+        val += ', "username": "%s"}]' % username
+    return val
 
 prefix = "/tmp/%d" % os.getpid()
 secret_file = prefix + ".secret"
@@ -174,7 +174,7 @@ conf = {'plugins': {'kdcpreauth': {'enable_only': 'otp'}},
 queue = Queue()
 
 realm = K5Realm(kdc_conf=conf)
-realm.run_kadminl('modprinc +requires_preauth %s' % realm.user_princ)
+realm.run([kadminl, 'modprinc', '+requires_preauth', realm.user_princ])
 flags = ['-T', realm.ccache]
 server_addr = '127.0.0.1:' + str(realm.portbase + 9)
 
@@ -182,7 +182,8 @@ server_addr = '127.0.0.1:' + str(realm.portbase + 9)
 daemon = UDPRadiusDaemon(args=(server_addr, secret_file, 'accept', queue))
 daemon.start()
 queue.get()
-realm.run_kadminl(setstr(realm.user_princ, 'udp', 'custom'))
+realm.run([kadminl, 'setstr', realm.user_princ, 'otp',
+           otpconfig('udp', 'custom')])
 realm.kinit(realm.user_princ, 'reject', flags=flags, expected_code=1)
 verify(daemon, queue, False, 'custom', 'reject')
 
@@ -190,7 +191,7 @@ verify(daemon, queue, False, 'custom', 'reject')
 daemon = UDPRadiusDaemon(args=(server_addr, secret_file, 'accept', queue))
 daemon.start()
 queue.get()
-realm.run_kadminl(setstr(realm.user_princ, 'udp'))
+realm.run([kadminl, 'setstr', realm.user_princ, 'otp', otpconfig('udp')])
 realm.kinit(realm.user_princ, 'accept', flags=flags)
 verify(daemon, queue, True, realm.user_princ.split('@')[0], 'accept')
 
@@ -206,7 +207,8 @@ except AssertionError:
 daemon = UnixRadiusDaemon(args=(socket_file, '', 'accept', queue))
 daemon.start()
 queue.get()
-realm.run_kadminl(setstr(realm.user_princ, 'unix', 'custom'))
+realm.run([kadminl, 'setstr', realm.user_princ, 'otp',
+           otpconfig('unix', 'custom')])
 realm.kinit(realm.user_princ, 'reject', flags=flags, expected_code=1)
 verify(daemon, queue, False, 'custom', 'reject')
 
@@ -214,7 +216,7 @@ verify(daemon, queue, False, 'custom', 'reject')
 daemon = UnixRadiusDaemon(args=(socket_file, '', 'accept', queue))
 daemon.start()
 queue.get()
-realm.run_kadminl(setstr(realm.user_princ, 'unix'))
+realm.run([kadminl, 'setstr', realm.user_princ, 'otp', otpconfig('unix')])
 realm.kinit(realm.user_princ, 'accept', flags=flags)
 verify(daemon, queue, True, realm.user_princ, 'accept')
 
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
index 52123e1..e1cc514 100644
--- a/src/tests/t_pkinit.py
+++ b/src/tests/t_pkinit.py
@@ -73,10 +73,8 @@ f = open(os.path.join(realm.testdir, 'acl'), 'a')
 f.write('WELLKNOWN/ANONYMOUS at WELLKNOWN:ANONYMOUS a *')
 f.close()
 realm.start_kadmind()
-out = realm.run([kadmin, '-n', '-q', 'addprinc -pw test testadd'])
-if 'created.' not in out:
-    fail('Could not create principal with anonymous kadmin')
-out = realm.run([kadmin, '-n', '-q', 'getprinc testadd'])
+realm.run([kadmin, '-n', 'addprinc', '-pw', 'test', 'testadd'])
+out = realm.run([kadmin, '-n', 'getprinc', 'testadd'], expected_code=1)
 if "Operation requires ``get'' privilege" not in out:
     fail('Anonymous kadmin has too much privilege')
 realm.stop_kadmind()
@@ -94,7 +92,7 @@ if 'KDC policy rejects request' not in out:
 # Go back to a normal KDC and disable anonymous PKINIT.
 realm.stop_kdc()
 realm.start_kdc()
-realm.run_kadminl('delprinc -force WELLKNOWN/ANONYMOUS')
+realm.run([kadminl, 'delprinc', 'WELLKNOWN/ANONYMOUS'])
 
 # Run the basic test - PKINIT with FILE: identity, with no password on the key.
 realm.run(['./responder', '-x', 'pkinit=',
diff --git a/src/tests/t_policy.py b/src/tests/t_policy.py
index f4cb4b4..1fa5106 100644
--- a/src/tests/t_policy.py
+++ b/src/tests/t_policy.py
@@ -5,82 +5,74 @@ import re
 realm = K5Realm(create_host=False)
 
 # Test password quality enforcement.
-realm.run_kadminl('addpol -minlength 6 -minclasses 2 pwpol')
-realm.run_kadminl('addprinc -randkey -policy pwpol pwuser')
-out = realm.run_kadminl('cpw -pw sh0rt pwuser')
+realm.run([kadminl, 'addpol', '-minlength', '6', '-minclasses', '2', 'pwpol'])
+realm.run([kadminl, 'addprinc', '-randkey', '-policy', 'pwpol', 'pwuser'])
+out = realm.run([kadminl, 'cpw', '-pw', 'sh0rt', 'pwuser'], expected_code=1)
 if 'Password is too short' not in out:
     fail('short password')
-out = realm.run_kadminl('cpw -pw longenough pwuser')
+out = realm.run([kadminl, 'cpw', '-pw', 'longenough', 'pwuser'],
+                expected_code=1)
 if 'Password does not contain enough character classes' not in out:
     fail('insufficient character classes')
-out = realm.run_kadminl('cpw -pw l0ngenough pwuser')
-if ' changed.' not in out:
-    fail('acceptable password')
+realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'])
 
 # Test some password history enforcement.  Even with no history value,
 # the current password should be denied.
-out = realm.run_kadminl('cpw -pw l0ngenough pwuser')
+out = realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'],
+                expected_code=1)
 if 'Cannot reuse password' not in out:
     fail('reuse of current password')
-realm.run_kadminl('modpol -history 2 pwpol')
-realm.run_kadminl('cpw -pw an0therpw pwuser')
-out = realm.run_kadminl('cpw -pw l0ngenough pwuser')
+realm.run([kadminl, 'modpol', '-history', '2', 'pwpol'])
+realm.run([kadminl, 'cpw', '-pw', 'an0therpw', 'pwuser'])
+out = realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'],
+                expected_code=1)
 if 'Cannot reuse password' not in out:
     fail('reuse of old password')
-realm.run_kadminl('cpw -pw 3rdpassword pwuser')
-out = realm.run_kadminl('cpw -pw l0ngenough pwuser')
-if ' changed.' not in out:
-    fail('reuse of third-oldest password with history 2')
+realm.run([kadminl, 'cpw', '-pw', '3rdpassword', 'pwuser'])
+realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'])
 
 # Test references to nonexistent policies.
-out = realm.run_kadminl('addprinc -randkey -policy newpol newuser')
-if ('WARNING: policy "newpol" does not exist' not in out or
-    ' created.' not in out):
-    fail('creation with nonexistent policy')
-out = realm.run_kadminl('getprinc newuser')
+realm.run([kadminl, 'addprinc', '-randkey', '-policy', 'newpol', 'newuser'])
+out = realm.run([kadminl, 'getprinc', 'newuser'])
 if 'Policy: newpol [does not exist]\n' not in out:
     fail('getprinc output for principal referencing nonexistent policy')
-out = realm.run_kadminl('modprinc -policy newpol pwuser')
-if ('WARNING: policy "newpol" does not exist' not in out or
-    ' modified.' not in out):
-    fail('modification to nonexistent policy')
+realm.run([kadminl, 'modprinc', '-policy', 'newpol', 'pwuser'])
 # pwuser should allow reuse of the current password since newpol doesn't exist.
-out = realm.run_kadminl('cpw -pw 3rdpassword pwuser')
-if ' changed.' not in out:
-    fail('reuse of current password with nonexistent policy')
+realm.run([kadminl, 'cpw', '-pw', '3rdpassword', 'pwuser'])
 
 # Create newpol and verify that it is enforced.
-realm.run_kadminl('addpol -minlength 3 newpol')
-out = realm.run_kadminl('getprinc pwuser')
+realm.run([kadminl, 'addpol', '-minlength', '3', 'newpol'])
+out = realm.run([kadminl, 'getprinc', 'pwuser'])
 if 'Policy: newpol\n' not in out:
     fail('getprinc after creating policy (pwuser)')
-out = realm.run_kadminl('cpw -pw aa pwuser')
+out = realm.run([kadminl, 'cpw', '-pw', 'aa', 'pwuser'], expected_code=1)
 if 'Password is too short' not in out:
     fail('short password after creating policy (pwuser)')
-out = realm.run_kadminl('cpw -pw 3rdpassword pwuser')
+out = realm.run([kadminl, 'cpw', '-pw', '3rdpassword', 'pwuser'],
+                expected_code=1)
 if 'Cannot reuse password' not in out:
     fail('reuse of current password after creating policy')
 
-out = realm.run_kadminl('getprinc newuser')
+out = realm.run([kadminl, 'getprinc', 'newuser'])
 if 'Policy: newpol\n' not in out:
     fail('getprinc after creating policy (newuser)')
-out = realm.run_kadminl('cpw -pw aa newuser')
+out = realm.run([kadminl, 'cpw', '-pw', 'aa', 'newuser'], expected_code=1)
 if 'Password is too short' not in out:
     fail('short password after creating policy (newuser)')
 
 # Delete the policy and verify that it is no longer enforced.
-realm.run_kadminl('delpol -force newpol')
-out = realm.run_kadminl('getpol newpol')
+realm.run([kadminl, 'delpol', 'newpol'])
+out = realm.run([kadminl, 'getpol', 'newpol'], expected_code=1)
 if 'Policy does not exist' not in out:
     fail('deletion of referenced policy')
-out = realm.run_kadminl('cpw -pw aa pwuser')
-if ' changed.' not in out:
-    fail('short password after deleting policy')
+realm.run([kadminl, 'cpw', '-pw', 'aa', 'pwuser'])
 
 # Test basic password lockout support.
 
-realm.run_kadminl('addpol -maxfailure 2 -failurecountinterval 5m lockout')
-realm.run_kadminl('modprinc +requires_preauth -policy lockout user')
+realm.run([kadminl, 'addpol', '-maxfailure', '2', '-failurecountinterval',
+           '5m', 'lockout'])
+realm.run([kadminl, 'modprinc', '+requires_preauth', '-policy', 'lockout',
+           'user'])
 
 # kinit twice with the wrong password.
 output = realm.run([kinit, realm.user_princ], input='wrong\n', expected_code=1)
@@ -97,11 +89,11 @@ if 'Clients credentials have been revoked while getting initial credentials' \
     fail('Expected lockout error message not seen in kinit output')
 
 # Check that modprinc -unlock allows a further attempt.
-output = realm.run_kadminl('modprinc -unlock user')
+realm.run([kadminl, 'modprinc', '-unlock', 'user'])
 realm.kinit(realm.user_princ, password('user'))
 
 # Make sure a nonexistent policy reference doesn't prevent authentication.
-realm.run_kadminl('delpol -force lockout')
+realm.run([kadminl, 'delpol', 'lockout'])
 realm.kinit(realm.user_princ, password('user'))
 
 # Regression test for issue #7099: databases created prior to krb5 1.3 have
@@ -112,14 +104,15 @@ realm.stop()
 realm = K5Realm(start_kdc=False)
 # Create a history principal with two keys.
 realm.run(['./hist', 'make'])
-realm.run_kadminl('addpol -history 2 pol')
-realm.run_kadminl('modprinc -policy pol user')
-realm.run_kadminl('cpw -pw pw2 user')
+realm.run([kadminl, 'addpol', '-history', '2', 'pol'])
+realm.run([kadminl, 'modprinc', '-policy', 'pol', 'user'])
+realm.run([kadminl, 'cpw', '-pw', 'pw2', 'user'])
 # Swap the keys, simulating older kadmin having chosen the second entry.
 realm.run(['./hist', 'swap'])
 # Make sure we can read the history entry.
-output = realm.run_kadminl('cpw -pw %s user' % password('user'))
-if 'Cannot reuse password' not in output:
+out = realm.run([kadminl, 'cpw', '-pw', password('user'), 'user'],
+                expected_code=1)
+if 'Cannot reuse password' not in out:
     fail('Expected error not seen in output')
 
 # Test key/salt constraints.
@@ -129,84 +122,53 @@ krb5_conf1 = {'libdefaults': {'supported_enctypes': 'aes256-cts'}}
 realm = K5Realm(krb5_conf=krb5_conf1, create_host=False, get_creds=False)
 
 # Add policy.
-realm.run_kadminl('addpol -allowedkeysalts aes256-cts:normal ak')
-realm.run_kadminl('addprinc -randkey -e aes256-cts:normal server')
+realm.run([kadminl, 'addpol', '-allowedkeysalts', 'aes256-cts', 'ak'])
+realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts', 'server'])
 
 # Test with one-enctype allowed_keysalts.
-realm.run_kadminl('modprinc -policy ak server')
-realm.run_kadminl('getprinc server')
-output = realm.run_kadminl('cpw -randkey -e aes128-cts:normal server')
-if not 'Invalid key/salt tuples' in output:
-    fail('allowed_keysalts policy not applied properly')
-realm.run_kadminl('getprinc server')
-output = realm.run_kadminl('cpw -randkey -e aes256-cts:normal server')
-if 'Invalid key/salt tuples' in output:
+realm.run([kadminl, 'modprinc', '-policy', 'ak', 'server'])
+out = realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes128-cts', 'server'],
+                expected_code=1)
+if not 'Invalid key/salt tuples' in out:
     fail('allowed_keysalts policy not applied properly')
-realm.run_kadminl('getprinc server')
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes256-cts', 'server'])
 
 # Now test a multi-enctype allowed_keysalts.  Test that subsets are allowed,
 # the the complete set is allowed, that order doesn't matter, and that
 # enctypes outside the set are not allowed.
 
 # Test modpol.
-realm.run_kadminl('modpol -allowedkeysalts '
-                  'aes256-cts:normal,rc4-hmac:normal ak')
-output = realm.run_kadminl('getpol ak')
-if not 'Allowed key/salt types: aes256-cts:normal,rc4-hmac:normal' in output:
+realm.run([kadminl, 'modpol', '-allowedkeysalts', 'aes256-cts,rc4-hmac', 'ak'])
+out = realm.run([kadminl, 'getpol', 'ak'])
+if not 'Allowed key/salt types: aes256-cts,rc4-hmac' in out:
     fail('getpol does not implement allowedkeysalts?')
 
-# Test one subset.
-output = realm.run_kadminl('cpw -randkey -e rc4-hmac:normal server')
-if 'Invalid key/salt tuples' in output:
-    fail('allowed_keysalts policy not applied properly')
-realm.run_kadminl('getprinc server')
+# Test subsets and full set.
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'rc4-hmac', 'server'])
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes256-cts', 'server'])
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes256-cts,rc4-hmac', 'server'])
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'rc4-hmac,aes256-cts', 'server'])
 
-# Test another subset.
-output = realm.run_kadminl('cpw -randkey -e aes256-cts:normal server')
-if 'Invalid key/salt tuples' in output:
-    fail('allowed_keysalts policy not applied properly')
-realm.run_kadminl('getprinc server')
-output = realm.run_kadminl('cpw -randkey -e '
-                           'rc4-hmac:normal,aes256-cts:normal server')
-if 'Invalid key/salt tuples' in output:
-    fail('allowed_keysalts policy not applied properly')
-realm.run_kadminl('getprinc server')
-
-# Test full set.
-output = realm.run_kadminl('cpw -randkey -e aes256-cts:normal,rc4-hmac:normal '
-                           'server')
-if 'Invalid key/salt tuples' in output:
-    fail('allowed_keysalts policy not applied properly')
-realm.run_kadminl('getprinc server')
-output = realm.run_kadminl('cpw -randkey -e rc4-hmac:normal,aes128-cts:normal '
-                           'server')
-if not 'Invalid key/salt tuples' in output:
-    fail('allowed_keysalts policy not applied properly')
-realm.run_kadminl('getprinc server')
-output = realm.run_kadminl('getprinc -terse server')
-if not '2\t1\t6\t18\t0\t1\t6\t23\t0' in output:
+# Check that the order we got is the one from the policy.
+out = realm.run([kadminl, 'getprinc', '-terse', 'server'])
+if not '2\t1\t6\t18\t0\t1\t6\t23\t0' in out:
     fail('allowed_keysalts policy did not preserve order')
 
-# Test full set in opposite order.
-output = realm.run_kadminl('cpw -randkey -e rc4-hmac:normal,aes256-cts:normal,'
-                           'aes128-cts:normal server')
-if not 'Invalid key/salt tuples' in output:
+# Test partially intersecting sets.
+out = realm.run([kadminl, 'cpw', '-randkey', '-e', 'rc4-hmac,aes128-cts',
+                 'server'], expected_code=1)
+if not 'Invalid key/salt tuples' in out:
+    fail('allowed_keysalts policy not applied properly')
+out = realm.run([kadminl, 'cpw', '-randkey', '-e',
+                 'rc4-hmac,aes256-cts,aes128-cts', 'server'], expected_code=1)
+if not 'Invalid key/salt tuples' in out:
     fail('allowed_keysalts policy not applied properly')
-
-# Check that the order we got is the one from the policy.
-realm.run_kadminl('getprinc server')
-output = realm.run_kadminl('getprinc -terse server')
-if not '2\t1\t6\t18\t0\t1\t6\t23\t0' in output:
-    fail('allowed_keysalts policy did not preserve order')
 
 # Test reset of allowedkeysalts.
-realm.run_kadminl('modpol -allowedkeysalts - ak')
-output = realm.run_kadminl('getpol ak')
-if 'Allowed key/salt types' in output:
+realm.run([kadminl, 'modpol', '-allowedkeysalts', '-', 'ak'])
+out = realm.run([kadminl, 'getpol', 'ak'])
+if 'Allowed key/salt types' in out:
     fail('failed to clear allowedkeysalts')
-output = realm.run_kadminl('cpw -randkey -e aes128-cts:normal server')
-if 'Invalid key/salt tuples' in output:
-    fail('key change rejected that should have been permitted')
-realm.run_kadminl('getprinc server')
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes128-cts', 'server'])
 
 success('Policy tests')
diff --git a/src/tests/t_pwqual.py b/src/tests/t_pwqual.py
index b3a1698..0d1d387 100644
--- a/src/tests/t_pwqual.py
+++ b/src/tests/t_pwqual.py
@@ -15,31 +15,30 @@ f = open(dictfile, 'w')
 f.write('birds\nbees\napples\noranges\n')
 f.close()
 
-realm.run_kadminl('addpol pol')
+realm.run([kadminl, 'addpol', 'pol'])
 
 # The built-in "empty" module rejects empty passwords even without a policy.
-out = realm.run_kadminl('addprinc -pw "" p1')
+out = realm.run([kadminl, 'addprinc', '-pw', '', 'p1'], expected_code=1)
 if 'Empty passwords are not allowed' not in out:
     fail('Expected error not seen for empty password')
 
 # The built-in "dict" module rejects dictionary words, but only with a policy.
-out = realm.run_kadminl('addprinc -pw birds p2')
-if 'created.' not in out:
-    fail('Unexpected failure from dictionary password without policy')
-out = realm.run_kadminl('addprinc -pw birds -policy pol p3')
+realm.run([kadminl, 'addprinc', '-pw', 'birds', 'p2'])
+out = realm.run([kadminl, 'addprinc', '-pw', 'birds', '-policy', 'pol', 'p3'],
+                expected_code=1)
 if 'Password is in the password dictionary' not in out:
     fail('Expected error not seen from dictionary password')
 
 # The built-in "princ" module rejects principal components, only with a policy.
-out = realm.run_kadminl('addprinc -pw p4 p4')
-if 'created.' not in out:
-    fail('Unexpected failure from principal component without policy')
-out = realm.run_kadminl('addprinc -pw p5 -policy pol p5')
+realm.run([kadminl, 'addprinc', '-pw', 'p4', 'p4'])
+out = realm.run([kadminl, 'addprinc', '-pw', 'p5', '-policy', 'pol', 'p5'],
+                expected_code=1)
 if 'Password may not match principal name' not in out:
     fail('Expected error not seen from principal component')
 
 # The dynamic "combo" module rejects pairs of dictionary words.
-out = realm.run_kadminl('addprinc -pw birdsoranges p6')
+out = realm.run([kadminl, 'addprinc', '-pw', 'birdsoranges', 'p6'],
+                expected_code=1)
 if 'Password may not be a pair of dictionary words' not in out:
     fail('Expected error not seen from combo module')
 
diff --git a/src/tests/t_rdreq.py b/src/tests/t_rdreq.py
index 42c5e29..f67c348 100644
--- a/src/tests/t_rdreq.py
+++ b/src/tests/t_rdreq.py
@@ -66,7 +66,7 @@ test(princ3, matchprinc,
 
 # Service ticket is out of date.
 os.remove(realm.keytab)
-realm.run_kadminl('ktadd %s' % princ1)
+realm.run([kadminl, 'ktadd', princ1])
 test(princ1, None,
      '44 Request ticket server host/1 at KRBTEST.COM kvno 1 not found in keytab; '
      'ticket is likely out of date')
@@ -79,7 +79,7 @@ test(princ2, princ1,
      'ticket server host/2 at KRBTEST.COM)')
 
 # Keytab is out of date.
-realm.run_kadminl('cpw -randkey %s' % princ1)
+realm.run([kadminl, 'cpw', '-randkey', princ1])
 realm.kinit(realm.user_princ, password('user'))
 test(princ1, None,
      '44 Request ticket server host/1 at KRBTEST.COM kvno 3 not found in keytab; '
@@ -105,8 +105,8 @@ test(princ1, None,
 test(princ1, princ1, '45 No key table entry found for host/1 at KRBTEST.COM')
 
 # Ticket server, kvno, and enctype matched, but key does not work.
-realm.run_kadminl('cpw -randkey %s' % princ1)
-realm.run_kadminl('modprinc -kvno 3 %s' % princ1)
+realm.run([kadminl, 'cpw', '-randkey', princ1])
+realm.run([kadminl, 'modprinc', '-kvno', '3', princ1])
 os.remove(realm.keytab)
 realm.extract_keytab(princ1, realm.keytab)
 test(princ1, None,
@@ -118,7 +118,7 @@ test(princ1, princ1,
 
 # Test that aliases work.  The ticket server (princ4) isn't present in
 # keytab, but there is a usable princ1 entry with the same key.
-realm.run_kadminl('renprinc -force %s %s' % (princ1, princ4))
+realm.run([kadminl, 'renprinc', princ1, princ4])
 test(princ4, None, '0 success')
 test(princ4, princ1, '0 success')
 test(princ4, matchprinc, '0 success')
diff --git a/src/tests/t_referral.py b/src/tests/t_referral.py
index ff23073..415802e 100644
--- a/src/tests/t_referral.py
+++ b/src/tests/t_referral.py
@@ -9,7 +9,6 @@ realm, refrealm = cross_realms(2, xtgts=((0,1),),
                                      {'realm': 'REFREALM',
                                       'create_user': False}),
                                create_host=False)
-realm.addprinc('krbtgt/REFREALM')
 refrealm.addprinc('a/x.d')
 
 savefile = os.path.join(realm.testdir, 'ccache.copy')
diff --git a/src/tests/t_renew.py b/src/tests/t_renew.py
index acfdae6..cb32d1a 100644
--- a/src/tests/t_renew.py
+++ b/src/tests/t_renew.py
@@ -34,14 +34,14 @@ if "KDC can't fulfill requested option" not in out:
     fail('expected error not seen renewing non-renewable ticket')
 
 # Test that -allow_renewable on the client principal works.
-realm.run_kadminl('modprinc -allow_renewable user')
+realm.run([kadminl, 'modprinc', '-allow_renewable', 'user'])
 test('disallowed client', '1h', '2h', False)
-realm.run_kadminl('modprinc +allow_renewable user')
+realm.run([kadminl, 'modprinc', '+allow_renewable', 'user'])
 
 # Test that -allow_renewable on the server principal works.
-realm.run_kadminl('modprinc -allow_renewable %s' % realm.krbtgt_princ)
+realm.run([kadminl, 'modprinc', '-allow_renewable',  realm.krbtgt_princ])
 test('disallowed server', '1h', '2h', False)
-realm.run_kadminl('modprinc +allow_renewable %s' % realm.krbtgt_princ)
+realm.run([kadminl, 'modprinc', '+allow_renewable', realm.krbtgt_princ])
 
 # Test that non-renewable tickets are issued if renew_till < till.
 test('short', '2h', '1h', False)
@@ -50,24 +50,26 @@ test('short', '2h', '1h', False)
 # default, but not if we configure away the RENEWABLE-OK option.
 no_opts_conf = {'libdefaults': {'kdc_default_options': '0'}}
 no_opts = realm.special_env('no_opts', False, krb5_conf=no_opts_conf)
-realm.run_kadminl('modprinc -maxlife "10 hours" user')
+realm.run([kadminl, 'modprinc', '-maxlife', '10 hours', 'user'])
 test('long', '15h', None, True)
 test('long noopts', '15h', None, False, env=no_opts)
-realm.run_kadminl('modprinc -maxlife "20 hours" user')
+realm.run([kadminl, 'modprinc', '-maxlife', '20 hours', 'user'])
 
 # Test maximum renewable life on the client principal.
-realm.run_kadminl('modprinc -maxrenewlife "5 hours" user')
+realm.run([kadminl, 'modprinc', '-maxrenewlife', '5 hours', 'user'])
 test('maxrenewlife client yes', '4h', '5h', True)
 test('maxrenewlife client no', '6h', '10h', False)
 
 # Test maximum renewable life on the server principal.
-realm.run_kadminl('modprinc -maxrenewlife "3 hours" %s' % realm.krbtgt_princ)
+realm.run([kadminl, 'modprinc', '-maxrenewlife', '3 hours',
+           realm.krbtgt_princ])
 test('maxrenewlife server yes', '2h', '3h', True)
 test('maxrenewlife server no', '4h', '8h', False)
 
 # Test realm maximum life.
-realm.run_kadminl('modprinc -maxrenewlife "40 hours" user')
-realm.run_kadminl('modprinc -maxrenewlife "40 hours" %s' % realm.krbtgt_princ)
+realm.run([kadminl, 'modprinc', '-maxrenewlife', '40 hours', 'user'])
+realm.run([kadminl, 'modprinc', '-maxrenewlife', '40 hours',
+           realm.krbtgt_princ])
 test('maxrenewlife realm yes', '10h', '20h', True)
 test('maxrenewlife realm no', '21h', '40h', False)
 
diff --git a/src/tests/t_renprinc.py b/src/tests/t_renprinc.py
index 64c9be7..026a6f7 100644
--- a/src/tests/t_renprinc.py
+++ b/src/tests/t_renprinc.py
@@ -31,16 +31,16 @@ salttypes = ('normal', 'v4', 'norealm', 'onlyrealm')
 # For a variety of salt types, test that we can rename a principal and
 # still get tickets with the same password.
 for st in salttypes:
-    realm.run_kadminl('addprinc -e %s:%s -pw %s %s' %
-                      (enctype, st, password(st), st))
+    realm.run([kadminl, 'addprinc', '-e', enctype + ':' + st,
+               '-pw', password(st), st])
     realm.kinit(st, password(st))
     newprinc = 'new' + st
-    realm.run_kadminl('renprinc -force %s %s' % (st, newprinc))
+    realm.run([kadminl, 'renprinc', st, newprinc])
     realm.kinit(newprinc, password(st))
 
 # Rename the normal salt again to test renaming a principal with
 # special salt type (which it will have after the first rename).
-realm.run_kadminl('renprinc -force newnormal newnormal2')
+realm.run([kadminl, 'renprinc', 'newnormal', 'newnormal2'])
 realm.kinit('newnormal2', password('normal'))
 
 success('Principal renaming tests')
diff --git a/src/tests/t_salt.py b/src/tests/t_salt.py
index 4302ed2..e923c92 100755
--- a/src/tests/t_salt.py
+++ b/src/tests/t_salt.py
@@ -8,12 +8,12 @@ realm = K5Realm(create_user=False)
 # matched with and not to subsequent keys.  e1 and e2 are enctypes,
 # and salt is a non-default salt type.
 def test_salt(realm, e1, salt, e2):
-    query = 'ank -e %s:%s,%s -pw password user' % (e1, salt, e2)
-    realm.run_kadminl(query)
-    out = realm.run_kadminl('getprinc user')
+    keysalts = e1 + ':' + salt + ',' + e2
+    realm.run([kadminl, 'ank', '-e', keysalts, '-pw', 'password', 'user'])
+    out = realm.run([kadminl, 'getprinc', 'user'])
     if len(re.findall(':' + salt, out)) != 1:
         fail(salt + ' present in second enctype or not present')
-    realm.run_kadminl('delprinc -force user')
+    realm.run([kadminl, 'delprinc', 'user'])
 
 # Enctype/salt pairs chosen with non-default salt types.
 # The enctypes are mostly arbitrary, though afs3 must only be used with des.
@@ -36,16 +36,15 @@ for e1, string in salts:
         test_salt(realm, e1, string, e2)
 
 def test_dup(realm, ks):
-    query = 'ank -e ' + ks + ' -pw password ks_princ'
-    realm.run_kadminl(query)
-    out = realm.run_kadminl('getprinc ks_princ')
+    realm.run([kadminl, 'ank', '-e', ks, '-pw', 'password', 'ks_princ'])
+    out = realm.run([kadminl, 'getprinc', 'ks_princ'])
     lines = out.split('\n')
     keys = [l for l in lines if 'Key: ' in l]
     uniq = set(keys)
     # 'Key:' matches 'MKey:' as well so len(keys) has one extra
     if (len(uniq) != len(keys)) or len(keys) > len(ks.split(',')):
         fail('Duplicate keysalt detection failed for keysalt ' + ks)
-    realm.run_kadminl('delprinc -force ks_princ')
+    realm.run([kadminl, 'delprinc', 'ks_princ'])
 
 # All in-tree callers request duplicate suppression from
 # krb5_string_to_keysalts(); we should check that it works, respects
@@ -63,10 +62,11 @@ for ks in dup_kstypes:
 # fails.
 def test_reject_afs3(realm, etype):
     query = 'ank -e ' + etype + ':afs3 -pw password princ1'
-    out = realm.run_kadminl(query)
+    out = realm.run([kadminl, 'ank', '-e', etype + ':afs3', '-pw', 'password',
+                     'princ1'], expected_code=1)
     if 'Invalid key generation parameters from KDC' not in out:
         fail('Allowed afs3 salt for ' + etype)
-    out = realm.run_kadminl('getprinc princ1')
+    out = realm.run([kadminl, 'getprinc', 'princ1'], expected_code=1)
     if 'Principal does not exist' not in out:
         fail('Created principal with afs3 salt and enctype ' + etype)
 
diff --git a/src/tests/t_sesskeynego.py b/src/tests/t_sesskeynego.py
index 3a4a814..732c306 100644
--- a/src/tests/t_sesskeynego.py
+++ b/src/tests/t_sesskeynego.py
@@ -34,8 +34,9 @@ conf4 = {'libdefaults': {
 # Test with client request and session_enctypes preferring aes128, but
 # aes256 long-term key.
 realm = K5Realm(krb5_conf=conf1, create_host=False, get_creds=False)
-realm.run_kadminl('addprinc -randkey -e aes256-cts:normal server')
-realm.run_kadminl('setstr server session_enctypes aes128-cts,aes256-cts')
+realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts', 'server'])
+realm.run([kadminl, 'setstr', 'server', 'session_enctypes',
+           'aes128-cts,aes256-cts'])
 test_kvno(realm, 'aes128-cts-hmac-sha1-96', 'aes256-cts-hmac-sha1-96')
 realm.stop()
 
@@ -43,32 +44,35 @@ realm.stop()
 # because of the difference in default_tgs_enctypes order.  This tests that
 # session_enctypes doesn't change the order in which we negotiate.
 realm = K5Realm(krb5_conf=conf2, create_host=False, get_creds=False)
-realm.run_kadminl('addprinc -randkey -e aes256-cts:normal server')
-realm.run_kadminl('setstr server session_enctypes aes128-cts,aes256-cts')
+realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts', 'server'])
+realm.run([kadminl, 'setstr', 'server', 'session_enctypes',
+           'aes128-cts,aes256-cts'])
 test_kvno(realm, 'aes256-cts-hmac-sha1-96', 'aes256-cts-hmac-sha1-96')
 realm.stop()
 
 # Next we use conf3 and try various things.
 realm = K5Realm(krb5_conf=conf3, create_host=False, get_creds=False)
-realm.run_kadminl('addprinc -randkey -e aes256-cts:normal server')
+realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts:normal',
+           'server'])
 
 # 3a: Negotiate aes128 session key when principal only has aes256 long-term.
-realm.run_kadminl('setstr server session_enctypes aes128-cts,aes256-cts')
+realm.run([kadminl, 'setstr', 'server', 'session_enctypes',
+           'aes128-cts,aes256-cts'])
 test_kvno(realm, 'aes128-cts-hmac-sha1-96', 'aes256-cts-hmac-sha1-96')
 
 # 3b: Negotiate rc4-hmac session key when principal only has aes256 long-term.
-realm.run_kadminl('setstr server session_enctypes '
-                  'rc4-hmac,aes128-cts,aes256-cts')
+realm.run([kadminl, 'setstr', 'server', 'session_enctypes',
+           'rc4-hmac,aes128-cts,aes256-cts'])
 test_kvno(realm, 'arcfour-hmac', 'aes256-cts-hmac-sha1-96')
 
 # 3c: Test des-cbc-crc default assumption.
-realm.run_kadminl('delstr server session_enctypes')
+realm.run([kadminl, 'delstr', 'server', 'session_enctypes'])
 test_kvno(realm, 'des-cbc-crc', 'aes256-cts-hmac-sha1-96')
 realm.stop()
 
 # Last go: test that we can disable the des-cbc-crc assumption
 realm = K5Realm(krb5_conf=conf4, get_creds=False)
-realm.run_kadminl('addprinc -randkey -e aes256-cts:normal server')
+realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts', 'server'])
 test_kvno(realm, 'aes256-cts-hmac-sha1-96', 'aes256-cts-hmac-sha1-96')
 realm.stop()
 
diff --git a/src/tests/t_skew.py b/src/tests/t_skew.py
index 17649fc..b729710 100644
--- a/src/tests/t_skew.py
+++ b/src/tests/t_skew.py
@@ -14,7 +14,7 @@ realm.run([kvno, realm.host_princ])
 realm.run([kdestroy])
 
 # kinit (with preauth) should work, with or without FAST.
-realm.run_kadminl('modprinc +requires_preauth user')
+realm.run([kadminl, 'modprinc', '+requires_preauth', 'user'])
 realm.kinit(realm.user_princ, password('user'))
 realm.run([kvno, realm.host_princ])
 realm.kinit(realm.user_princ, password('user'), flags=['-T', realm.ccache])
@@ -46,7 +46,7 @@ if 'Clock skew too great while' not in out:
     fail('Expected error message not seen in kinit FAST skew case')
 
 # kinit (with preauth) should fail from the KDC, with or without FAST.
-realm.run_kadminl('modprinc +requires_preauth user')
+realm.run([kadminl, 'modprinc', '+requires_preauth', 'user'])
 out = realm.kinit(realm.user_princ, password('user'), expected_code=1)
 if 'Clock skew too great while' not in out:
     fail('Expected error message not seen in kinit skew case (preauth)')
diff --git a/src/tests/t_stringattr.py b/src/tests/t_stringattr.py
index 459151f..892d65a 100644
--- a/src/tests/t_stringattr.py
+++ b/src/tests/t_stringattr.py
@@ -27,26 +27,18 @@ realm = K5Realm(start_kadmind=True, create_host=False, get_creds=False)
 
 realm.prep_kadmin()
 
-output = realm.run_kadmin('getstrs user')
-if '(No string attributes.)' not in output:
+out = realm.run_kadmin(['getstrs', 'user'])
+if '(No string attributes.)' not in out:
     fail('Empty attribute query')
 
-output = realm.run_kadmin('setstr user attr1 value1')
-if 'Attribute set for principal' not in output:
-    fail('Setting attr1')
-output = realm.run_kadmin('setstr user attr2 value2')
-if 'Attribute set for principal' not in output:
-    fail('Setting attr2')
-output = realm.run_kadmin('delstr user attr1')
-if 'Attribute removed from principal' not in output:
-    fail('Deleting attr1')
-output = realm.run_kadmin('setstr user attr3 value3')
-if 'Attribute set for principal' not in output:
-    fail('Setting attr3')
-
-output = realm.run_kadmin('getstrs user')
-if 'attr2: value2' not in output or 'attr3: value3' not in output or \
-        'attr1:' in output:
+realm.run_kadmin(['setstr', 'user', 'attr1', 'value1'])
+realm.run_kadmin(['setstr', 'user', 'attr2', 'value2'])
+realm.run_kadmin(['delstr', 'user', 'attr1'])
+realm.run_kadmin(['setstr', 'user', 'attr3', 'value3'])
+
+out = realm.run_kadmin(['getstrs', 'user'])
+if ('attr2: value2' not in out or 'attr3: value3' not in out or
+    'attr1:' in out):
     fail('Final attribute query')
 
 success('KDB string attributes')
diff --git a/src/util/k5test.py b/src/util/k5test.py
index 13a00e9..935ec55 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -201,7 +201,7 @@ Scripts may use the following functions and variables:
   - krb5kdc
   - kadmind
   - kadmin
-  - kadmin_local
+  - kadminl (kadmin.local)
   - kdb5_ldap_util
   - kdb5_util
   - ktutil
@@ -287,14 +287,12 @@ Scripts may use the following realm methods and attributes:
   (must be a filename; self.keytab if not specified) and verify that
   the output shows the keytab name and principal name.
 
-* realm.run_kadminl(query): Run the specified query in kadmin.local.
-
 * realm.prep_kadmin(princname=None, password=None, flags=[]): Populate
   realm.kadmin_ccache with a ticket which can be used to run kadmin.
   If princname is not specified, realm.admin_princ and its default
   password will be used.
 
-* realm.run_kadmin(query, **keywords): Run the specified query in
+* realm.run_kadmin(args, **keywords): Run the specified query in
   kadmin, using realm.kadmin_ccache to authenticate.  Accepts the same
   keyword arguments as run.
 
@@ -773,8 +771,8 @@ class K5Realm(object):
         if create_kdb:
             self.create_kdb()
         if krbtgt_keysalt and create_kdb:
-            self.run_kadminl('cpw -randkey -e %s %s' %
-                             (krbtgt_keysalt, self.krbtgt_princ))
+            self.run([kadminl, 'cpw', '-randkey', '-e', krbtgt_keysalt,
+                      self.krbtgt_princ])
         if create_user and create_kdb:
             self.addprinc(self.user_princ, password('user'))
             self.addprinc(self.admin_princ, password('admin'))
@@ -948,12 +946,12 @@ class K5Realm(object):
 
     def addprinc(self, princname, password=None):
         if password:
-            self.run_kadminl('addprinc -pw %s %s' % (password, princname))
+            self.run([kadminl, 'addprinc', '-pw', password, princname])
         else:
-            self.run_kadminl('addprinc -randkey %s' % princname)
+            self.run([kadminl, 'addprinc', '-randkey', princname])
 
     def extract_keytab(self, princname, keytab):
-        self.run_kadminl('ktadd -k %s -norandkey %s' % (keytab, princname))
+        self.run([kadminl, 'ktadd', '-k', keytab, '-norandkey', princname])
 
     def kinit(self, princname, password=None, flags=[], **keywords):
         if password:
@@ -985,10 +983,6 @@ class K5Realm(object):
             princ not in output):
             fail('Unexpected klist output.')
 
-    def run_kadminl(self, query, env=None):
-        global kadmin_local
-        return self.run([kadmin_local, '-q', query], env=env)
-
     def prep_kadmin(self, princname=None, pw=None, flags=[]):
         if princname is None:
             princname = self.admin_princ
@@ -997,9 +991,8 @@ class K5Realm(object):
                           flags=['-S', 'kadmin/admin',
                                  '-c', self.kadmin_ccache] + flags)
 
-    def run_kadmin(self, query, **keywords):
-        return self.run([kadmin, '-c', self.kadmin_ccache, '-q', query],
-                        **keywords)
+    def run_kadmin(self, args, **keywords):
+        return self.run([kadmin, '-c', self.kadmin_ccache] + args, **keywords)
 
     def special_env(self, name, has_kdc_conf, krb5_conf=None, kdc_conf=None):
         krb5_conf_path = os.path.join(self.testdir, 'krb5.conf.%s' % name)
@@ -1208,7 +1201,7 @@ null_input = open(os.devnull, 'r')
 krb5kdc = os.path.join(buildtop, 'kdc', 'krb5kdc')
 kadmind = os.path.join(buildtop, 'kadmin', 'server', 'kadmind')
 kadmin = os.path.join(buildtop, 'kadmin', 'cli', 'kadmin')
-kadmin_local = os.path.join(buildtop, 'kadmin', 'cli', 'kadmin.local')
+kadminl = os.path.join(buildtop, 'kadmin', 'cli', 'kadmin.local')
 kdb5_ldap_util = os.path.join(buildtop, 'plugins', 'kdb', 'ldap', 'ldap_util',
                               'kdb5_ldap_util')
 kdb5_util = os.path.join(buildtop, 'kadmin', 'dbutil', 'kdb5_util')


More information about the cvs-krb5 mailing list