Blob Blame History Raw
From d467303bd7c5dba858b0af30349ce796cebd193f Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Thu, 22 Apr 2021 15:51:36 -0400
Subject: [PATCH] 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.

(cherry picked from commit 8027531caf6911bb07bf13de087da0e6bef5a348)
(cherry picked from commit 9b3d8b9c395bf1a889ea6d6439dc3543c680480d)
---
 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(-)
 delete mode 100644 src/tests/dejagnu/krb-standalone/kadmin.exp
 delete mode 100644 src/tests/dejagnu/krb-standalone/pwchange.exp
 delete mode 100644 src/tests/dejagnu/krb-standalone/pwhist.exp
 create mode 100644 src/tests/t_kadmin.py

diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 6b7749129..ab416cc5f 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 fa50a61fb..000000000
--- 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 010e8344a..000000000
--- 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 ed7a3771a..000000000
--- 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 573bdbd49..bf8e3a9eb 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 000000000..fe6a3cc2e
--- /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/pw@KRBTEST.COM')
+
+# 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/random@KRBTEST.COM')
+
+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/random@KRBTEST.COM')
+
+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 5a0c06b86..2bb4f5f18 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'])