krb5 commit: Move some dejagnu kadmin tests to Python tests

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/8027531caf6911bb07bf13de087da0e6bef5a348
commit 8027531caf6911bb07bf13de087da0e6bef5a348
Author: Greg Hudson <[email protected]>
Date:   Thu Apr 22 15:51:36 2021 -0400

    Move some dejagnu kadmin tests to Python tests
    
    Remove the dejagnu scripts kadmin.exp, pwchange.exp, and pwhist.exp.
    
    Add a new Python test script t_kadmin.py for the miscellaneous kadmin
    tests from kadmin.exp.
    
    In t_changepw.py, use modprinc +needchange for one of the kinit
    password change tests to gain the same coverage as pwchange.exp had,
    and add the "password changes are usable by kinit" tests from
    kadmin.exp.
    
    In t_policy.py, add the ticket 929 regression tests from kadmin.exp
    and the ticket 2841 regression tests from pwhist.exp.

 src/tests/Makefile.in                         |    1 +
 src/tests/dejagnu/krb-standalone/kadmin.exp   | 1133 -------------------------
 src/tests/dejagnu/krb-standalone/pwchange.exp |  145 ----
 src/tests/dejagnu/krb-standalone/pwhist.exp   |  217 -----
 src/tests/t_changepw.py                       |   34 +-
 src/tests/t_kadmin.py                         |   54 ++
 src/tests/t_policy.py                         |   62 ++
 7 files changed, 143 insertions(+), 1503 deletions(-)

diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 6b77491..ab416cc 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -147,6 +147,7 @@ check-pytests: unlockiter s4u2self
 	$(RUNPYTEST) $(srcdir)/t_referral.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_skew.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_keytab.py $(PYTESTFLAGS)
+	$(RUNPYTEST) $(srcdir)/t_kadmin.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_kadmin_acl.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_kadmin_parsing.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_kdb.py $(PYTESTFLAGS)
diff --git a/src/tests/dejagnu/krb-standalone/kadmin.exp b/src/tests/dejagnu/krb-standalone/kadmin.exp
deleted file mode 100644
index fa50a61..0000000
--- a/src/tests/dejagnu/krb-standalone/kadmin.exp
+++ /dev/null
@@ -1,1133 +0,0 @@
-# Kerberos kadmin test.
-# This is a DejaGnu test script.
-# This script tests Kerberos kadmin5 using kadmin.local as verification.
-
-#++
-# kadmin_add	- Test add new v5 principal function of kadmin.
-#
-# Adds principal $pname with password $password.  Returns 1 on success.
-#--
-proc kadmin_add { pname password } {
-    global REALMNAME
-    global KADMIN
-    global KADMIN_LOCAL
-    global KEY
-    global spawn_id
-    global tmppwd
-
-    set good 0
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin add $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin add $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin add $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*:" {
-	send "adminpass$KEY\r"
-    }
-    expect "Enter password for principal \"$pname@$REALMNAME\":" { send "$password\r" }
-    expect "Re-enter password for principal \"$pname@$REALMNAME\":" { send "$password\r" }
-    expect "Principal \"$pname@$REALMNAME\" created." { set good 1 }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin add)"
-    catch "close -i $spawn_id"
-    if { $good == 1 } {
-	#
-	# use kadmin.local to verify that a principal was created and that its
-	# salt types are 0 (normal).
-	#
-	envstack_push
-	setup_kerberos_env kdc
-	spawn $KADMIN_LOCAL -r $REALMNAME
-	envstack_pop
-	expect_after {
-	    -i $spawn_id
-	    timeout {
-		fail "kadmin add $pname"
-		catch "expect_after"
-		return 0
-	    }
-	    eof {
-		fail "kadmin add $pname"
-		catch "expect_after"
-		return 0
-	    }
-	}
-	set good 0
-	expect "kadmin.local: " { send "getprinc $pname\r" }
-	expect "Principal: $pname@$REALMNAME" { set good 1 }
-	expect "Expiration date:" { verbose "got expiration date" }
-	expect "Last password change:" { verbose "got last pwchange" }
-	expect "Password expiration date:" { verbose "got pwexpire date" }
-	expect "Maximum ticket life:" { verbose "got max life" }
-	expect "Maximum renewable life:" { verbose "got max rlife" }
-	expect "Last modified:" { verbose "got last modified" }
-	expect "Last successful authentication:" { verbose "last succ auth" }
-	expect "Last failed authentication:" { verbose "last pw failed" }
-	expect "Failed password attempts:" { verbose "num failed attempts" }
-	expect "Number of keys:" { verbose "num keys"} 
-	expect {
-		"Key: " { verbose "Key listed" 
-			exp_continue
-		}
-		"Attributes:" { verbose "attributes" }
-	}
-	expect "kadmin.local: " { send "q\r" }
-
-	expect_after
-	expect eof
-	set k_stat [wait -i $spawn_id]
-	verbose "wait -i $spawn_id returned $k_stat (kadmin.local show)"
-	catch "close -i $spawn_id"
-	if { $good == 1 } {
-	    pass "kadmin add $pname"
-	    return 1
-	}
-	else {
-	    fail "kadmin add $pname"
-	    return 0
-	}
-    }
-    else {
-	fail "kadmin add $pname"
-	return 0
-    }
-}
-
-#++
-# kadmin_add_rnd	- Test add new v5 principal with random key function.
-#
-# Adds principal $pname with random key.  Returns 1 on success.
-#--
-proc kadmin_add_rnd { pname { flags "" } } {
-    global REALMNAME
-    global KADMIN
-    global KADMIN_LOCAL
-    global KEY
-    global spawn_id
-    global tmppwd
-
-    set good 0
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $flags $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin add rnd $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin add_rnd $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin add_rnd $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    expect "Principal \"$pname@$REALMNAME\" created." { set good 1 }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin add_rnd)"
-    catch "close -i $spawn_id"
-    if { $good == 1 } {
-	#
-	# use kadmin.local to verify that a principal was created and that its
-	# salt types are 0 (normal).
-	#
-	envstack_push
-	setup_kerberos_env kdc
-	spawn $KADMIN_LOCAL -r $REALMNAME
-	envstack_pop
-	expect_after {
-	     -i $spawn_id
-	    timeout {
-		fail "kadmin add_rnd $pname"
-		catch "expect_after"
-		return 0
-	    }
-	    eof {
-		fail "kadmin add_rnd $pname"
-		catch "expect_after"
-		return 0
-	    }
-	}
-	set good 0
-	expect "kadmin.local:" { send "getprinc $pname\r" }
-	expect "Principal: $pname@$REALMNAME" { set good 1 }
-	expect "kadmin.local:" { send "q\r" }
-	expect_after
-	expect eof
-	set k_stat [wait -i $spawn_id]
-	verbose "wait -i $spawn_id returned $k_stat (kadmin.local show)"
-	catch "close -i $spawn_id"
-	if { $good == 1 } {
-	    pass "kadmin add_rnd $pname"
-	    return 1
-	}
-	else {
-	    fail "kadmin add_rnd $pname"
-	    return 0
-	}
-    }
-    else {
-	fail "kadmin add_rnd $pname"
-	return 0
-    }
-}
-
-#++
-# kadmin_show	- Test show principal function of kadmin.
-# 
-# Retrieves entry for $pname.  Returns 1 on success.
-#--
-proc kadmin_show { pname } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "get_principal $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin show $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin show $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin show $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *"
-    send "adminpass$KEY\r"
-    expect -re "\r.*Principal: $pname@$REALMNAME.*Key: .*Attributes:.*Policy: .*\r"
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin show)"
-    catch "close -i $spawn_id"
-    pass "kadmin show $pname"
-    return 1
-}
-
-#++
-# kadmin_cpw	- Test change password function of kadmin
-#
-# Change password of $pname to $password.  Returns 1 on success.
-#--
-proc kadmin_cpw { pname password } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "cpw $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin cpw $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin cpw $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin cpw $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-
-    expect "Enter password for principal \"$pname@$REALMNAME\":" { send "$password\r" }
-    expect "Re-enter password for principal \"$pname@$REALMNAME\":" { send "$password\r" }
-    # When in doubt, jam one of these in there.
-    expect "\r"
-    expect "Password for \"$pname@$REALMNAME\" changed."
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin cpw)"
-    catch "close -i $spawn_id"
-    pass "kadmin cpw $pname"
-    return 1
-}
-
-#++
-# kadmin_cpw_rnd	- Test change random key function of kadmin.
-#
-# Changes principal $pname's key to a new random key.  Returns 1 on success.
-#--
-proc kadmin_cpw_rnd { pname } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "cpw -randkey $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin cpw_rnd $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin cpw_rnd $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin cpw_rnd $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    # When in doubt, jam one of these in there.
-    expect "\r"
-    expect "Key for \"$pname@$REALMNAME\" randomized."
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin cpw_rnd)"
-    catch "close -i $spawn_id"
-    pass "kadmin cpw_rnd $pname"
-    return 1
-}
-
-#++
-# kadmin_modify	- Test modify principal function of kadmin.
-#
-# Modifies principal $pname with flags $flags.  Returns 1 on success.
-#--
-proc kadmin_modify { pname flags } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "modprinc $flags $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin modify $pname ($flags) lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin modify $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin modify $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *"
-    send "adminpass$KEY\r"
-    # When in doubt, jam one of these in there.
-    expect "\r"
-    expect "Principal \"$pname@$REALMNAME\" modified."
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin modify)"
-    catch "close -i $spawn_id"
-    pass "kadmin modify $pname"
-    return 1
-}
-
-
-#++
-# kadmin_list	- Test list database function of kadmin.
-#
-# Lists the database and verifies that output matches regular expression
-# "(.*@$REALMNAME)*".  Returns 1 on success.
-#--
-proc kadmin_list {  } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-
-    # "*" would match everything
-    # "*n" should match a few like kadmin/admin but see ticket 5667
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "get_principals *n"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin ldb lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	"Communication failure" {
-	    fail "kadmin ldb got RPC error"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin ldb"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin ldb"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    expect -re "\(.*@$REALMNAME\r\n\)+"
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin list)"
-    catch "close -i $spawn_id"
-    pass "kadmin ldb"
-    return 1
-}
-
-#++
-# kadmin_extract	- Test extract service key function of kadmin.
-#
-# Extracts service key for service name $name instance $instance.  Returns
-# 1 on success.
-#--
-proc kadmin_extract { instance name } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-    global tmppwd
-
-    catch "exec rm -f $tmppwd/keytab"
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "xst -k $tmppwd/keytab $name/$instance"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin xst $instance $name lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin xst $instance $name"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin xst $instance $name"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin xst)"
-    catch "close -i $spawn_id"
-    catch "exec rm -f $instance-new-keytab"
-    pass "kadmin xst $instance $name"
-    return 1
-}
-
-#++
-# kadmin_delete	- Test delete principal function of kadmin.
-#
-# Deletes principal $pname.  Returns 1 on success.
-#--
-proc kadmin_delete { pname } {
-    global REALMNAME
-    global KADMIN
-    global KADMIN_LOCAL
-    global KEY
-    global spawn_id
-    global tmppwd
-
-    set good 0
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "delprinc -force $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin_delete $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin delprinc $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin delprinc $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    expect "Principal \"$pname@$REALMNAME\" deleted." { set good 1 }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin delprinc)"
-    catch "close -i $spawn_id"
-    if { $good == 1 } {
-	#
-	# use kadmin.local to verify that the old principal is not present.
-	#
-	envstack_push
-	setup_kerberos_env kdc
-	spawn $KADMIN_LOCAL -r $REALMNAME
-	envstack_pop
-	expect_after {
-	    -i $spawn_id
-	    timeout {
-		fail "kadmin delprinc $pname"
-		catch "expect_after"
-		return 0
-	    }
-	    eof {
-		fail "kadmin delprinc $pname"
-		catch "expect_after"
-		return 0
-	    }
-	}
-	set good 0
-	expect "kadmin.local: " { send "getprinc $pname\r" }
-	expect "Principal does not exist while retrieving \"$pname@$REALMNAME\"." { set good 1 }
-	expect "kadmin.local: " { send "quit\r" }
-	expect_after
-	expect eof
-	set k_stat [wait -i $spawn_id]
-	verbose "wait -i $spawn_id returned $k_stat (kadmin.local show)"
-	catch "close -i $spawn_id"
-	if { $good == 1 } {
-	    pass "kadmin delprinc $pname"
-	    return 1
-	}
-	else {
-	    fail "kadmin delprinc $pname"
-	    return 0
-	}
-    }
-    else {
-	fail "kadmin delprinc $pname"
-	return 0
-    }
-}
-
-#++
-# kadmin_delete	- Test delete principal function of kadmin.
-#
-# Deletes principal $pname.  Returns 1 on success.
-#--
-proc kadmin_delete_locked_down { pname } {
-    global REALMNAME
-    global KADMIN
-    global KADMIN_LOCAL
-    global KEY
-    global spawn_id
-    global tmppwd
-
-    #
-    # First test that we fail, then unlock and retry
-    #
-
-    set good 0
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "delprinc -force $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin_delete $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin delprinc $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin delprinc $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    expect "delete_principal: Operation requires ``delete'' privilege while deleting principal \"$pname@$REALMNAME\"" { set good 1 }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin delprinc)"
-    catch "close -i $spawn_id"
-    if { $good == 1 } {
-	#
-	# use kadmin.local to remove lockdown.
-	#
-	envstack_push
-	setup_kerberos_env kdc
-	spawn $KADMIN_LOCAL -r $REALMNAME
-	envstack_pop
-	expect_after {
-	    -i $spawn_id
-	    timeout {
-		fail "kadmin delprinc $pname"
-		catch "expect_after"
-		return 0
-	    }
-	    eof {
-		fail "kadmin delprinc $pname"
-		catch "expect_after"
-		return 0
-	    }
-	}
-	set good 0
-	expect "kadmin.local: " { send "modprinc -lockdown_keys $pname\r" }
-	expect "Principal \"$pname@$REALMNAME\" modified." { set good 1 }
-	expect "kadmin.local: " { send "quit\r" }
-	expect_after
-	expect eof
-	set k_stat [wait -i $spawn_id]
-	verbose "wait -i $spawn_id returned $k_stat (kadmin.local show)"
-	catch "close -i $spawn_id"
-	if { $good == 1 } {
-            set good 0
-            if {[kadmin_delete $pname]} { set good 1 }
-        }
-	if { $good == 1 } {
-	    pass "kadmin delprinc $pname"
-	    return 1
-	}
-	else {
-	    fail "kadmin delprinc $pname"
-	    return 0
-	}
-    }
-    else {
-	fail "kadmin delprinc $pname"
-	return 0
-    }
-}
-
-#++
-# kpasswd_cpw	- Test password changing using kpasswd.
-#
-# Change $princ's password from $opw to $npw.  Returns 1 on success.
-#--
-proc kpasswd_cpw { princ opw npw } {
-    global KPASSWD
-    global REALMNAME
-
-    spawn $KPASSWD $princ
-    expect_after {
-	timeout {
-	    fail "kpasswd $princ $npw"
-#	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kpasswd $princ $npw"
-#	    catch "expect_after"
-	    return 0
-	}
-    }
-
-#    expect "Changing password for $princ."
-#    expect "Old password:" { send "$opw\r" }
-#    expect "New password:" { send "$npw\r" }
-#    expect "New password (again):" { send "$npw\r" }
-    expect "Password for $princ@$REALMNAME:" { send "$opw\r" }
-    expect "Enter new password:"  { send "$npw\r" }
-    expect "Enter it again:"      { send "$npw\r" }
-#    expect "Kerberos password changed."
-    expect "Password changed."
-    expect_after
-    expect eof
-
-    if ![check_exit_status "kpasswd"] {
-	fail "kpasswd $princ $npw"
-	return 0
-    }
-    pass "kpasswd $princ $npw"
-    return 1
-}
-
-#++
-# kadmin_addpol	- Test add new policy function of kadmin.
-#
-# Adds policy $pname.  Returns 1 on success.
-#--
-proc kadmin_addpol { pname } {
-    global REALMNAME
-    global KADMIN
-    global KADMIN_LOCAL
-    global KEY
-    global spawn_id
-    global tmppwd
-
-    set good 0
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "addpol $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin addpol $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin addpol $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin addpol $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin addpol)"
-    catch "close -i $spawn_id"
-    #
-    # use kadmin.local to verify that a policy was created
-    #
-    envstack_push
-    setup_kerberos_env kdc
-    spawn $KADMIN_LOCAL -r $REALMNAME
-    envstack_pop
-    expect_after {
-        -i $spawn_id
-        timeout {
-	    fail "kadmin addpol $pname"
-	    catch "expect_after"
-	    return 0
-        }
-        eof {
-	    fail "kadmin addpol $pname"
-	    catch "expect_after"
-	    return 0
-        }
-    }
-    set good 0
-    expect "kadmin.local: " { send "getpol $pname\r" }
-    expect "Policy: $pname" { set good 1 }
-    expect "Maximum password life:" { verbose "got max pw life" }
-    expect "Minimum password life:" { verbose "got min pw life" }
-    expect "Minimum password length:" { verbose "got min pw length" }
-    expect "Minimum number of password character classes:" {
-        verbose "got min pw character classes" }
-    expect "Number of old keys kept:" { verbose "got num old keys kept" }
-    expect "kadmin.local: " { send "q\r" }
-
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin.local showpol)"
-    catch "close -i $spawn_id"
-    if { $good == 1 } {
-        pass "kadmin addpol $pname"
-        return 1
-    }
-    else {
-        fail "kadmin addpol $pname"
-        return 0
-    }
-}
-
-#++
-# kadmin_delpol	- Test delete policy function of kadmin.
-#
-# Deletes policy $pname.  Returns 1 on success.
-#--
-proc kadmin_delpol { pname } {
-    global REALMNAME
-    global KADMIN
-    global KADMIN_LOCAL
-    global KEY
-    global spawn_id
-    global tmppwd
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "delpol -force $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin_delpol $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin delpol $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin delpol $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin delpol)"
-    catch "close -i $spawn_id"
-    #
-    # use kadmin.local to verify that the old policy is not present.
-    #
-    envstack_push
-    setup_kerberos_env kdc
-    spawn $KADMIN_LOCAL -r $REALMNAME
-    envstack_pop
-    expect_after {
-        -i $spawn_id
-        timeout {
-	    fail "kadmin delpol $pname"
-	    catch "expect_after"
-	    return 0
-        }
-        eof {
-	    fail "kadmin delpol $pname"
-	    catch "expect_after"
-	    return 0
-        }
-    }
-    set good 0
-    expect "kadmin.local: " { send "getpol $pname\r" }
-    expect "Policy does not exist while retrieving policy \"$pname\"." {
-	set good 1
-    }
-    expect "kadmin.local: " { send "quit\r" }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin.local showpol)"
-    catch "close -i $spawn_id"
-    if { $good == 1 } {
-        pass "kadmin delpol $pname"
-        return 1
-    }
-    else {
-        fail "kadmin delpol $pname"
-        return 0
-    }
-}
-
-#++
-# kadmin_listpols	- Test list policy database function of kadmin.
-#
-# Lists the policies.  Returns 1 on success.
-#--
-proc kadmin_listpols {  } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "get_policies *"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin lpols lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin lpols"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin lpols"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *" {
-	send "adminpass$KEY\r"
-    }
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin listpols)"
-    catch "close -i $spawn_id"
-    pass "kadmin lpols"
-    return 1
-}
-
-#++
-# kadmin_modpol	- Test modify policy function of kadmin.
-#
-# Modifies policy $pname with flags $flags.  Returns 1 on success.
-#--
-proc kadmin_modpol { pname flags } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "modpol $flags $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin modpol $pname ($flags) lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin modpol $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin modpol $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *"
-    send "adminpass$KEY\r"
-    # When in doubt, jam one of these in there.
-    expect "\r"
-    # Sadly, kadmin doesn't print a confirmation message for policy operations.
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin modpol)"
-    catch "close -i $spawn_id"
-    pass "kadmin modpol $pname"
-    return 1
-}
-
-#++
-# kadmin_showpol	- Test show policy function of kadmin.
-# 
-# Retrieves entry for $pname.  Returns 1 on success.
-#--
-proc kadmin_showpol { pname } {
-    global REALMNAME
-    global KADMIN
-    global KEY
-    global spawn_id
-
-    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "get_policy $pname"
-    expect_after {
-	"Cannot contact any KDC" {
-	    fail "kadmin showpol $pname lost KDC"
-	    catch "expect_after"
-	    return 0
-	}
-	timeout {
-	    fail "kadmin showpol $pname"
-	    catch "expect_after"
-	    return 0
-	}
-	eof {
-	    fail "kadmin showpol $pname"
-	    catch "expect_after"
-	    return 0
-	}
-    }
-    expect -re "assword\[^\r\n\]*: *"
-    send "adminpass$KEY\r"
-    expect -re "\r.*Policy: $pname.*Number of old keys kept: .*\r"
-    expect_after
-    expect eof
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin showpol)"
-    catch "close -i $spawn_id"
-    pass "kadmin showpol $pname"
-    return 1
-}
-
-#++
-# kdestroy
-#--
-proc kdestroy { } {
-    global KDESTROY
-
-    spawn $KDESTROY -5
-    if ![check_exit_status "kdestroy"] {
-	return 0
-    }
-    return 1
-}
-
-# Wrap the tests in a procedure, so that we can kill the daemons if
-# we get some sort of error.
-
-proc kadmin_test { } {
-    global hostname
-
-    # Start up the kerberos and kadmind daemons
-    if {![start_kerberos_daemons 0] } {
-	return
-    }
-
-    # Test basic kadmin functions.
-    if {![kadmin_add v5principal/instance1 v5principal] \
-	|| ![kadmin_addpol standardpol] \
-	|| ![kadmin_showpol standardpol] \
-	|| ![kadmin_listpols] \
-	|| ![kadmin_modpol standardpol "-minlength 5"] \
-	|| ![kadmin_add v4principal/instance2 v4principal] \
-	|| ![kadmin_add_rnd v5random] \
-	|| ![kadmin_show v5principal/instance1] \
-	|| ![kadmin_show v4principal/instance2] \
-	|| ![kadmin_show v5random] \
-	|| ![kadmin_cpw v5principal/instance1 faroutman] \
-	|| ![kadmin_cpw v4principal/instance2 honkydory] \
-	|| ![kadmin_cpw_rnd v5random] \
-	|| ![kadmin_modify v5random -allow_tix] \
-	|| ![kadmin_modify v5random +allow_tix] \
-	|| ![kadmin_modify v5random "-policy standardpol"] \
-	|| ![kadmin_list] \
-	|| ![kadmin_extract instance1 v5principal] \
-	|| ![kadmin_delete v5random] \
-	|| ![kadmin_delete v4principal/instance2] \
-	|| ![kadmin_delete v5principal/instance1] \
-	|| ![kadmin_delpol standardpol]} {
-	return
-    }
-
-# You cannot extract a v4 key...
-#	|| ![kadmin_extractv4 instance2 v4principal] \
-
-    # now test kpasswd
-    if {![kadmin_add testprinc/instance thisisatest] \
-	    || ![kpasswd_cpw testprinc/instance thisisatest anothertest] \
-	    || ![kpasswd_cpw testprinc/instance anothertest goredsox] \
-	    || ![kadmin_delete testprinc/instance]} {
-	return
-    }
-
-    # now test that we can kinit with principals/passwords.
-    # We defer kdestroying until after kpasswd at least once to test FAST automatic use in kpasswd
-    if {![kadmin_add testprinc1/instance thisisatest] \
-	    || ![kinit testprinc1/instance thisisatest 0] \
-	    || ![kpasswd_cpw testprinc1/instance thisisatest anothertest] \
-	    || ![kdestroy] \
-	    || ![kinit testprinc1/instance anothertest 0] \
-	    || ![kdestroy] \
-	    || ![kpasswd_cpw testprinc1/instance anothertest goredsox] \
-	    || ![kinit testprinc1/instance goredsox 0] \
-	    || ![kdestroy] \
-	    || ![kadmin_cpw testprinc1/instance betterwork] \
-	    || ![kinit testprinc1/instance betterwork 0] \
-	    || ![kdestroy] \
-	    || ![kadmin_delete testprinc1/instance]} {
-	return
-    }
-
-    # now test modify changes.
-    if {![kadmin_add testuser longtestpw] \
-	    || ![kinit testuser longtestpw 0] \
-	    || ![kdestroy] \
-	    || ![kadmin_modify testuser "-maxlife \"2500 seconds\""] \
-	    || ![kinit testuser longtestpw 0] \
-	    || ![kdestroy] \
-	    || ![kadmin_delete testuser]} {
-	return
-    }
-
-    # now test that reducing the history number doesn't make kadmind vulnerable.
-    if {![kadmin_addpol crashpol] \
-	    || ![kadmin_modpol crashpol "-history 5"] \
-	    || ![kadmin_add crash first] \
-	    || ![kadmin_modify crash "-policy crashpol"] \
-	    || ![kadmin_cpw crash second] \
-	    || ![kadmin_cpw crash third] \
-	    || ![kadmin_cpw crash fourth] \
-	    || ![kadmin_modpol crashpol "-history 3"] \
-	    || ![kadmin_cpw crash fifth] \
-	    || ![kadmin_delete crash] \
-	    || ![kadmin_delpol crashpol]} {
-	return
-    }
-
-    # test retrieval of large number of principals
-    # bug [2877]
-    for { set i 0 } { $i < 200 } { incr i } {
-	if { ![kadmin_add "foo$i" foopass] } {
-	    return
-	}
-    }
-
-    if { ![kadmin_list] } {
-	return
-    }
-
-    # test fallback to kadmin/hostname
-    if {![kadmin_add_rnd kadmin/$hostname] \
-	    || ![kadmin_delete_locked_down kadmin/admin] \
-	    || ![kadmin_list] \
-	    || ![kadmin_add_rnd kadmin/admin -allow_tgs_req] \
-	    || ![kadmin_list]} {
-	return
-    }
-
-    verbose "kadmin_test succeeded"
-}
-
-run_once kadmin {
-    # Set up the kerberos database.
-    if {![get_hostname] \
-	    || ![setup_kerberos_files] \
-	    || ![setup_kerberos_env] \
-	    || ![setup_kerberos_db 0]} {
-	return
-    }
-
-    # Run the test.
-    set status [catch kadmin_test msg]
-
-    # Shut down the kerberos daemons and the rsh daemon.
-    stop_kerberos_daemons
-
-    if { $status != 0 } {
-	send_error "ERROR: error in kadmin.exp\n"
-	send_error "$msg\n"
-	exit 1
-    }
-}
diff --git a/src/tests/dejagnu/krb-standalone/pwchange.exp b/src/tests/dejagnu/krb-standalone/pwchange.exp
deleted file mode 100644
index 010e834..0000000
--- a/src/tests/dejagnu/krb-standalone/pwchange.exp
+++ /dev/null
@@ -1,145 +0,0 @@
-# Password-changing Kerberos test.
-# This is a DejaGnu test script.
-
-# We are about to start up a couple of daemon processes.  We do all
-# the rest of the tests inside a proc, so that we can easily kill the
-# processes when the procedure ends.
-
-proc kinit_expecting_pwchange { name pass newpass } {
-    global REALMNAME
-    global KINIT
-    global spawn_id
-
-    # Use kinit to get a ticket.
-	#
-	# For now always get forwardable tickets. Later when we need to make
-	# tests that distinguish between forwardable tickets and otherwise
-	# we should but another option to this proc. --proven
-	#
-    spawn $KINIT -5 -f $name@$REALMNAME
-    expect {
-	"Password for $name@$REALMNAME:" {
-	    verbose "kinit started"
-	}
-	timeout {
-	    fail "kinit"
-	    return 0
-	}
-	eof {
-	    fail "kinit"
-	    return 0
-	}
-    }
-    send "$pass\r"
-    expect {
-	"Enter new password: " { }
-	timeout {
-	    fail "kinit (new password prompt)"
-	    return 0
-	}
-	eof {
-	    fail "kinit (new password prompt)"
-	    return 0
-	}
-    }
-    send "$newpass\r"
-    expect {
-	" again: " { }
-	timeout {
-	    fail "kinit (new password prompt2)"
-	    return 0
-	}
-	eof {
-	    fail "kinit (new password prompt2)"
-	    return 0
-	}
-    }
-    send "$newpass\r"
-    expect eof
-    if ![check_exit_status kinit] {
-	return 0
-    }
-
-    return 1
-}
-
-proc doit { } {
-    global REALMNAME
-    global KLIST
-    global KDESTROY
-    global KEY
-    global KADMIN_LOCAL
-    global KTUTIL
-    global hostname
-    global tmppwd
-    global spawn_id
-    global supported_enctypes
-    global KRBIV
-    global portbase
-    global mode
-
-    # Start up the kerberos and kadmind daemons.
-    if ![start_kerberos_daemons 0] {
-	return
-    }
-
-    # Use kadmin to add a key.
-    if ![add_kerberos_key pwchanger 0] {
-	return
-    }
-
-    setup_kerberos_env kdc
-    spawn $KADMIN_LOCAL -q "modprinc +needchange pwchanger"
-    catch expect_after
-    expect {
-	timeout {
-	    fail "kadmin.local modprinc +needchange"
-	}
-	eof {
-	    pass "kadmin.local modprinc +needchange"
-	}
-    }
-    set k_stat [wait -i $spawn_id]
-    verbose "wait -i $spawn_id returned $k_stat (kadmin modprinc +needchange)"
-    catch "close -i $spawn_id"
-
-    setup_kerberos_env client
-    if ![kinit_expecting_pwchange pwchanger pwchanger$KEY floople] {
-	return
-    }
-    pass "kinit (password change)"
-    if ![kinit pwchanger floople 0] {
-	return
-    }
-    pass "kinit (new password)"
-
-    # Destroy the ticket.
-    spawn $KDESTROY -5
-    if ![check_exit_status "kdestroy"] {
-	return
-    }
-    pass "kdestroy"
-}
-
-run_once pwchange {
-    # Set up the Kerberos files and environment.
-    if {![get_hostname] || ![setup_kerberos_files] || ![setup_kerberos_env]} {
-	return
-    }
-
-    # Initialize the Kerberos database.  The argument tells
-    # setup_kerberos_db that it is being called from here.
-    if ![setup_kerberos_db 0] {
-	return
-    }
-
-    set status [catch doit msg]
-
-    stop_kerberos_daemons
-
-    if { $status != 0 } {
-	send_error "ERROR: error in pwchange.exp\n"
-	send_error "$msg\n"
-	exit 1
-    }
-}
diff --git a/src/tests/dejagnu/krb-standalone/pwhist.exp b/src/tests/dejagnu/krb-standalone/pwhist.exp
deleted file mode 100644
index ed7a377..0000000
--- a/src/tests/dejagnu/krb-standalone/pwhist.exp
+++ /dev/null
@@ -1,217 +0,0 @@
-# password history tests
-
-# one *non-interactive* kadmin.local request
-proc onerq { rq pname str {flags ""} } {
-    global REALMNAME
-    global KADMIN_LOCAL
-
-    spawn $KADMIN_LOCAL -r $REALMNAME -q "$rq $flags $pname"
-    expect_after {
-	timeout {
-	    verbose "kadmin.local $rq $flags $pname timed out"
-	    catch expect_after
-	    kill [exp_pid]
-	    close
-	    expect eof
-	    wait
-	    return 0
-	} eof {
-	    verbose "kadmin.local $rq $flags $pname got EOF"
-	    catch expect_after
-	    wait
-	    return 0
-	}
-    }
-    expect $str
-    expect_after
-    expect eof
-    wait
-    return 1
-}
-
-proc addprinc { pname pw } {
-    global REALMNAME
-
-    return [onerq addprinc $pname \
-		"Principal \"$pname@$REALMNAME\" created." "-pw $pw"]
-}
-
-proc delprinc { pname } {
-    global REALMNAME
-    return [onerq delprinc $pname \
-		"Principal \"$pname@$REALMNAME\" deleted." "-force"]
-}
-
-proc cpw { pname pw } {
-    global REALMNAME
-
-    return [onerq cpw $pname \
-		"Password for \"$pname@$REALMNAME\" changed." "-pw $pw"]
-}
-
-proc modprinc { pname flags } {
-    global REALMNAME
-
-    return [onerq modprinc $pname \
-		"Principal \"$pname@$REALMNAME\" modified." $flags]
-}
-
-proc addpol { pname } {
-    if ![onerq addpol $pname ""] {
-	return 0
-    }
-    return [onerq getpol $pname "Policy: $pname"]
-}
-
-proc delpol { pname } {
-    onerq delpol $pname "" -force
-    return [onerq getpol $pname \
-		"Policy does not exist while retrieving policy \"$pname\"."]
-}
-
-proc modpol { pname flags } {
-    return [onerq modpol $pname "" $flags]
-}
-
-# Mandatory command must return true.
-# Issues a break in its parent on failure.
-proc mustrun { cmd } {
-    if ![eval $cmd] {
-	perror "mandatory command failed: $cmd"
-	uplevel break
-    }
-}
-
-# Fail test if command fails.
-# Issues a break in its parent on failure.
-proc chkpass { cmd } {
-    upvar test test
-    if ![eval $cmd] {
-	verbose "unexpected failure: $cmd"
-	fail $test
-	uplevel break
-    }
-}
-
-# Fail test if command succeeds.
-# Issues a break in its parent on failure.
-proc chkfail { cmd } {
-    upvar test test
-    if [eval $cmd] {
-	verbose "unexpected success: $cmd"
-	fail $test
-	uplevel break
-    }
-}
-
-# wrapper to run command (actually usually sequence of commands)
-#
-# If any part of CMD throws an exception, set failall, otherwise pass.
-# If failall is already true, report unresolved.
-proc wraptest { test cmd } {
-    upvar failall failall
-    if $failall {
-	unresolved $test
-	return
-    }
-    if [catch $cmd] {
-	set failall 1
-    } else {
-	pass $test
-    }
-}
-
-run_once pwhist {
-    # Set up the kerberos database.
-    if {![get_hostname] \
-	    || ![setup_kerberos_files] \
-	    || ![setup_kerberos_env kdc] \
-	    || ![setup_kerberos_db 0]} {
-	return
-    }
-
-    set failall 0
-    wraptest "nkeys=1, nhist=3" {
-	mustrun { addpol crashpol }
-	mustrun { modpol crashpol "-history 3"}
-	mustrun { addprinc crash 1111 }
-	mustrun { modprinc crash "-policy crashpol" }
-	chkpass { cpw crash 2222 }
-	chkfail { cpw crash 2222 }
-	chkfail { cpw crash 1111 }
-    }
-    verbose {old_keys [ 1111 ->[] ]}
-
-    # The following will result in reading/writing past array bounds if
-    # add_to_history() is not patched.
-    #
-    # NOTE: A pass from this test does not mean the bug isn't present;
-    # check with Purify, valgrind, etc.
-    wraptest "array bounds ok on nkeys=1, nhist 3->2" {
-	mustrun { modpol crashpol "-history 2" }
-	chkpass { cpw crash 3333 }
-    }
-    verbose {old_keys [ ->2222 ]}
-
-    wraptest "verify nhist=2" {
-	mustrun { delprinc crash }
-	mustrun { addprinc crash 1111 }
-	mustrun { modprinc crash "-policy crashpol" }
-	chkpass { cpw crash 2222 }
-	chkfail { cpw crash 2222 }
-	chkfail { cpw crash 1111 }
-    }
-    verbose {old_keys [ ->1111 ]}
-
-    # The following will fail if growing the history array causes an extra
-    # key to be lost due to failure to shift entries.
-    wraptest "grow nhist 2->3" {
-	mustrun { modpol crashpol "-history 3" }
-	chkpass { cpw crash 3333 }
-	chkfail { cpw crash 3333 }
-	chkfail { cpw crash 2222 }
-	chkfail { cpw crash 1111 }
-    }
-    verbose {old_keys [ 2222 ->1111 ]}
-
-    wraptest "grow nhist 3->4" {
-	mustrun { modpol crashpol "-history 4" }
-	chkfail { cpw crash 3333 }
-	chkfail { cpw crash 2222 }
-	chkfail { cpw crash 1111 }
-	chkpass { cpw crash 4444 }
-	chkfail { cpw crash 3333 }
-	chkfail { cpw crash 2222 }
-	chkfail { cpw crash 1111 }
-    }
-    verbose {old_keys [ 2222 3333 ->1111 ]}
-    wraptest "shrink nhist 4->3" {
-	mustrun { modpol crashpol "-history 3" }
-	chkfail { cpw crash 4444 }
-	chkfail { cpw crash 3333 }
-	chkfail { cpw crash 2222 }
-	chkfail { cpw crash 1111 }
-	chkpass { cpw crash 5555 }
-    }
-    verbose {old_keys [ 4444 ->3333 ]}
-    wraptest "verify nhist=3" {
-	chkfail { cpw crash 5555 }
-	chkfail { cpw crash 4444 }
-	chkfail { cpw crash 3333 }
-	chkpass { cpw crash 2222 }
-    }
-    verbose {old_keys [ ->4444 5555 ]}
-    wraptest "shrink nhist 3->2" {
-	mustrun { modpol crashpol "-history 2" }
-	chkfail { cpw crash 2222 }
-	chkfail { cpw crash 5555 }
-	chkfail { cpw crash 4444 }
-	chkpass { cpw crash 3333 }
-    }
-    verbose {old_keys [ ->2222 ]}
-
-    delprinc crash
-    delpol crashpol
-
-    stop_kerberos_daemons
-}
diff --git a/src/tests/t_changepw.py b/src/tests/t_changepw.py
index 573bdbd..bf8e3a9 100755
--- a/src/tests/t_changepw.py
+++ b/src/tests/t_changepw.py
@@ -1,23 +1,24 @@
 from k5test import *
 
-# This file is intended to cover any password-changing mechanism.  For
-# now it only contains a regression test for #7868.
-
 realm = K5Realm(create_host=False, get_creds=False, start_kadmind=True)
+realm.prep_kadmin()
 
 # Mark a principal as expired and change its password through kinit.
+mark('password change via kinit')
 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'])
+# Regression test for #7868 (preauth options ignored when
+# krb5_get_init_creds_password() initiates a password change).  This
+# time use the REQUIRES_PWCHANGE bit instead of the password
+# expiration time.
+mark('password change via kinit with FAST')
+realm.run([kadminl, 'modprinc', '+needchange', 'user'])
 pwinput = 'abcd\nefgh\nefgh\n'
 out, trace = realm.run([kinit, '-T', realm.ccache, realm.user_princ],
                        input=pwinput, return_trace=True)
-
-# Read the trace and check that FAST was used when getting the
-# kadmin/changepw ticket.
+# Check that FAST was used when getting the kadmin/changepw ticket.
 getting_changepw = fast_used_for_changepw = False
 for line in trace.splitlines():
     if 'Getting initial credentials for user@' in line:
@@ -29,4 +30,21 @@ for line in trace.splitlines():
 if not fast_used_for_changepw:
     fail('FAST was not used to get kadmin/changepw ticket')
 
+# Test that passwords specified via kadmin and kpasswd are usable with
+# kinit.
+mark('password change usability by kinit')
+realm.run([kadminl, 'addprinc', '-pw', 'pw1', 'testprinc'])
+# Run kpasswd with an active cache to exercise automatic FAST use.
+realm.kinit('testprinc', 'pw1')
+realm.run([kpasswd, 'testprinc'], input='pw1\npw2\npw2\n')
+realm.kinit('testprinc', 'pw2')
+realm.run([kdestroy])
+realm.run([kpasswd, 'testprinc'], input='pw2\npw3\npw3\n')
+realm.kinit('testprinc', 'pw3')
+realm.run([kdestroy])
+realm.run_kadmin(['cpw', '-pw', 'pw4', 'testprinc'])
+realm.kinit('testprinc', 'pw4')
+realm.run([kdestroy])
+realm.run([kadminl, 'delprinc', 'testprinc'])
+
 success('Password change tests')
diff --git a/src/tests/t_kadmin.py b/src/tests/t_kadmin.py
new file mode 100644
index 0000000..fe6a3cc
--- /dev/null
+++ b/src/tests/t_kadmin.py
@@ -0,0 +1,54 @@
+from k5test import *
+
+realm = K5Realm(start_kadmind=True)
+
+# Create a principal.  Test -q option and keyboard entry of the admin
+# password and principal password.  Verify creation with kadmin.local.
+realm.run([kadmin, '-q', 'addprinc princ/pw'],
+          input=password('admin') + '\npw1\npw1\n')
+realm.run([kadminl, 'getprinc', 'princ/pw'],
+          expected_msg='Principal: princ/[email protected]')
+
+# Run the remaining tests with a cache for efficiency.
+realm.prep_kadmin()
+
+realm.run_kadmin(['addpol', 'standardpol'])
+realm.run_kadmin(['listpols'], expected_msg='standardpol')
+realm.run_kadmin(['modpol', '-minlength', '5', 'standardpol'])
+realm.run_kadmin(['getpol', 'standardpol'],
+                 expected_msg='Minimum password length: 5')
+
+realm.run_kadmin(['addprinc', '-randkey', 'princ/random'])
+realm.run([kadminl, 'getprinc', 'princ/random'],
+          expected_msg='Principal: princ/[email protected]')
+
+realm.run_kadmin(['cpw', 'princ/pw'], input='newpw\nnewpw\n')
+realm.run_kadmin(['cpw', '-randkey', 'princ/random'])
+
+realm.run_kadmin(['modprinc', '-allow_tix', 'princ/random'])
+realm.run_kadmin(['modprinc', '+allow_tix', 'princ/random'])
+realm.run_kadmin(['modprinc', '-policy', 'standardpol', 'princ/random'])
+
+realm.run_kadmin(['listprincs'], expected_msg='princ/[email protected]')
+
+realm.run_kadmin(['ktadd', 'princ/pw'])
+
+realm.run_kadmin(['delprinc', 'princ/random'])
+realm.run([kadminl, 'getprinc', 'princ/random'], expected_code=1,
+          expected_msg='Principal does not exist')
+realm.run_kadmin(['delprinc', 'princ/pw'])
+realm.run([kadminl, 'getprinc', 'princ/pw'], expected_code=1,
+          expected_msg='Principal does not exist')
+
+realm.run_kadmin(['delpol', 'standardpol'])
+realm.run([kadminl, 'getpol', 'standardpol'], expected_code=1,
+          expected_msg='Policy does not exist')
+
+# Regression test for #2877 (fixed-sized GSSRPC buffers can't
+# accomodate large listprinc results).
+mark('large listprincs result')
+for i in range(200):
+    realm.run_kadmin(['addprinc', '-randkey', 'foo%d' % i])
+realm.run_kadmin(['listprincs'], expected_msg='foo199')
+
+success('kadmin and kpasswd tests')
diff --git a/src/tests/t_policy.py b/src/tests/t_policy.py
index 5a0c06b..2bb4f5f 100755
--- a/src/tests/t_policy.py
+++ b/src/tests/t_policy.py
@@ -25,6 +25,68 @@ realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'], expected_code=1,
 realm.run([kadminl, 'cpw', '-pw', '3rdpassword', 'pwuser'])
 realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'])
 
+# Regression test for #929 (kadmind crash with more historical
+# passwords in a principal entry than current policy history setting).
+mark('password history (policy value reduced below current array size)')
+realm.run([kadminl, 'addpol', '-history', '5', 'histpol'])
+realm.addprinc('histprinc', 'first')
+realm.run([kadminl, 'modprinc', '-policy', 'histpol', 'histprinc'])
+realm.run([kadminl, 'cpw', '-pw', 'second', 'histprinc'])
+realm.run([kadminl, 'cpw', '-pw', 'third', 'histprinc'])
+realm.run([kadminl, 'cpw', '-pw', 'fourth', 'histprinc'])
+realm.run([kadminl, 'modpol', '-history', '3', 'histpol'])
+realm.run([kadminl, 'cpw', '-pw', 'fifth', 'histprinc'])
+realm.run([kadminl, 'delprinc', 'histprinc'])
+
+# Regression test for #2841 (heap buffer overflow when policy history
+# value is reduced to match the number of historical passwords for a
+# principal).
+mark('password history (policy value reduced to current array size)')
+def histfail(*pwlist):
+    for pw in pwlist:
+        realm.run([kadminl, 'cpw', '-pw', pw, 'histprinc'], expected_code=1,
+                  expected_msg='Cannot reuse password')
+realm.run([kadminl, 'modpol', '-history', '3', 'histpol'])
+realm.addprinc('histprinc', '1111')
+realm.run([kadminl, 'modprinc', '-policy', 'histpol', 'histprinc'])
+realm.run([kadminl, 'cpw', '-pw', '2222', 'histprinc'])
+histfail('2222', '1111')
+realm.run([kadminl, 'modpol', '-history', '2', 'histpol'])
+realm.run([kadminl, 'cpw', '-pw', '3333', 'histprinc'])
+
+# Test that the history array is properly resized if the policy
+# history value is increased after the array is filled.
+mark('password history (policy value increase)')
+realm.run([kadminl, 'delprinc', 'histprinc'])
+realm.addprinc('histprinc', '1111')
+realm.run([kadminl, 'modprinc', '-policy', 'histpol', 'histprinc'])
+realm.run([kadminl, 'cpw', '-pw', '2222', 'histprinc'])
+histfail('2222', '1111')
+realm.run([kadminl, 'cpw', '-pw', '2222', 'histprinc'], expected_code=1,
+          expected_msg='Cannot reuse password')
+realm.run([kadminl, 'cpw', '-pw', '1111', 'histprinc'], expected_code=1,
+          expected_msg='Cannot reuse password')
+realm.run([kadminl, 'modpol', '-history', '3', 'histpol'])
+realm.run([kadminl, 'cpw', '-pw', '3333', 'histprinc'])
+histfail('3333', '2222', '1111')
+realm.run([kadminl, 'modpol', '-history', '4', 'histpol'])
+histfail('3333', '2222', '1111')
+realm.run([kadminl, 'cpw', '-pw', '4444', 'histprinc'])
+histfail('4444', '3333', '2222', '1111')
+
+# Test that when the policy history value is reduced, all currently
+# known old passwords still fail until the next password change, after
+# which the new number of old passwords fails (but no more).
+mark('password history (policy value reduction)')
+realm.run([kadminl, 'modpol', '-history', '3', 'histpol'])
+histfail('4444', '3333', '2222', '1111')
+realm.run([kadminl, 'cpw', '-pw', '5555', 'histprinc'])
+histfail('5555', '3333', '3333')
+realm.run([kadminl, 'cpw', '-pw', '2222', 'histprinc'])
+realm.run([kadminl, 'modpol', '-history', '2', 'histpol'])
+histfail('2222', '5555', '4444')
+realm.run([kadminl, 'cpw', '-pw', '3333', 'histprinc'])
+
 # Test references to nonexistent policies.
 mark('nonexistent policy references')
 realm.run([kadminl, 'addprinc', '-randkey', '-policy', 'newpol', 'newuser'])
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.