# 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/admin
    if {![kadmin_delete_locked_down kadmin/$hostname] \
	    || ![kadmin_list] \
	    || ![kadmin_add_rnd kadmin/$hostname -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
    }
}
