# Test for the GSS-API.
# This is a DejaGnu test script.
# This script tests that the GSS-API tester functions correctly.

# This mostly just calls procedures in test/dejagnu/config/default.exp.

if ![info exists KDESTROY] {
    set KDESTROY [findfile $objdir/../../clients/kdestroy/kdestroy]
}

if ![info exists GSSCLIENT] {
    set GSSCLIENT [findfile $objdir/../../appl/gss-sample/gss-client]
}

if ![info exists GSSSERVER] {
    set GSSSERVER [findfile $objdir/../../appl/gss-sample/gss-server]
}

# 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
}

#
# Like kinit in default.exp, but allows us to specify a different ccache.
#
proc our_kinit { name pass ccache } {
    global REALMNAME
    global KINIT
    global spawn_id

    # Use kinit to get a ticket.
    spawn $KINIT -f -5 -c $ccache $name@$REALMNAME
    expect {
	"Password for $name@$REALMNAME:" {
	    verbose "kinit started"
	}
	timeout {
	    fail "kinit"
	    return 0
	}
	eof {
	    fail "kinit"
	    return 0
	}
    }
    send "$pass\r"
    # This last expect seems useless, but without it the test hangs on
    # AIX.
    expect {
        "\r" { }
    }
    expect eof
    if ![check_exit_status kinit] {
	return 0
    }

    return 1
}

#
# Destroys a particular ccache.
#
proc our_kdestroy { ccache } {
    global KDESTROY
    global spawn_id

    spawn $KDESTROY -c $ccache
    if ![check_exit_status "kdestroy"] {
	return 0
    }
    return 1
}

#
# Stops the gss-server.
#
proc stop_gss_server { } {
    global gss_server_pid
    global gss_server_spawn_id

    if [info exists gss_server_pid] {
	catch "close -i $gss_server_spawn_id"
	catch "exec kill $gss_server_pid"
	wait -i $gss_server_spawn_id
	unset gss_server_pid
    }
}

#
# Restore environment variables possibly set.
#
proc gss_restore_env { } {
    global env
    global gss_save_ccname
    global gss_save_ktname

    catch "unset env(KRB5CCNAME)"
    if [info exists gss_save_ccname] {
	set env(KRB5CCNAME) $gss_save_ccname
	unset gss_save_ccname
    }
    catch "unset env(KRB5_KTNAME)"
    if [info exists gss_save_ktname] {
	set env(KRB5_KTNAME) $gss_save_ktname
	unset gss_save_ktname
    }
}

proc run_client {test tkfile client} {
    global env
    global hostname
    global GSSCLIENT
    global spawn_id
    global gss_server_spawn_id
    global REALMNAME
    global portbase

    set env(KRB5CCNAME) $tkfile
    verbose "KRB5CCNAME=$env(KRB5CCNAME)"
    verbose "spawning gssclient, identity=$client"
    spawn $GSSCLIENT -d -port [expr 8 + $portbase] $hostname gssservice@$hostname "message from $client"
    set got_client 0
    set got_server 0
    expect_after {
	-i $spawn_id
	timeout {
	    if {!$got_client} {
		verbose -log "client timeout"
		fail $test
		catch "expect_after"
		return
	    }
	}
	eof {
	    if {!$got_client} {
		verbose -log "client eof"
		fail $test
		catch "expect_after"
		return
	    }
	}
	-i $gss_server_spawn_id
	timeout {
	    if {!$got_server} {
		verbose -log "server timeout"
		fail $test
		catch "expect_after"
		return
	    }
	}
	eof {
	    if {!$got_server} {
		verbose -log "server eof"
		fail $test
		catch "expect_after"
		return
	    }
	}
    }
    expect {
	-i $gss_server_spawn_id
	"Accepted connection: \"$client@$REALMNAME\"" exp_continue
	"Received message: \"message from $client\"" {
	    set got_server 1
	    if {!$got_client} {
		exp_continue
	    }
	}
	-i $spawn_id
	"Signature verified" {
	    set got_client 1
	    if {!$got_server} {
		exp_continue
	    }
	}
    }
    catch "expect_after"
    if ![check_exit_status $test] {
	# check_exit_staus already calls fail for us
	return
    }
    pass $test
}

proc doit { } {
    global REALMNAME
    global env
    global KLIST
    global KDESTROY
    global KEY
    global GSSTEST
    global GSSSERVER
    global GSSCLIENT
    global hostname
    global tmppwd
    global spawn_id
    global timeout
    global gss_server_pid
    global gss_server_spawn_id
    global gss_save_ccname
    global gss_save_ktname
    global portbase

    # Start up the kerberos and kadmind daemons.
    if ![start_kerberos_daemons 0] {
	perror "failed to start kerberos daemons"
    }

    # Use kadmin to add a key for us.
    if ![add_kerberos_key gsstest0 0] {
	perror "failed to set up gsstest0 key"
    }

    # Use kadmin to add a key for us.
    if ![add_kerberos_key gsstest1 0] {
	perror "failed to set up gsstest1 key"
    }

    # Use kadmin to add a key for us.
    if ![add_kerberos_key gsstest2 0] {
	perror "failed to set up gsstest2 key"
    }

    # Use kadmin to add a key for us.
    if ![add_kerberos_key gsstest3 0] {
	perror "failed to set up gsstest3 key"
    }

    # Use kadmin to add a service key for us.
    if ![add_random_key gssservice/$hostname 0] {
	perror "failed to set up gssservice/$hostname key"
    }

    # Use kdb5_edit to create a keytab entry for gssservice
    if ![setup_keytab 0 gssservice] {
	perror "failed to set up gssservice keytab"
    }

    catch "exec rm -f $tmppwd/gss_tk_0 $tmppwd/gss_tk_1 $tmppwd/gss_tk_2 $tmppwd/gss_tk_3"

    # Use kinit to get a ticket.
    if ![our_kinit gsstest0 gsstest0$KEY $tmppwd/gss_tk_0] {
	perror "failed to kinit gsstest0"
    }

    # Use kinit to get a ticket.
    if ![our_kinit gsstest1 gsstest1$KEY $tmppwd/gss_tk_1] {
	perror "failed to kinit gsstest1"
    }

    # Use kinit to get a ticket.
    if ![our_kinit gsstest2 gsstest2$KEY $tmppwd/gss_tk_2] {
	perror "failed to kinit gsstest2"
    }

    # Use kinit to get a ticket.
    if ![our_kinit gsstest3 gsstest3$KEY $tmppwd/gss_tk_3] {
	perror "failed to kinit gsstest3"
    }

    #
    # Save settings of KRB5CCNAME and KRB5_KTNAME
    #
    if [info exists env(KRB5CCNAME)] {
	set gss_save_ccname $env(KRB5CCNAME)
    }
    if [info exists env(KRB5_KTNAME)] {
	set gss_save_ktname $env(KRB5_KTNAME)
    }

    #
    # set KRB5CCNAME and KRB5_KTNAME
    #
    set env(KRB5_KTNAME) FILE:$tmppwd/keytab
    verbose "KRB5_KTNAME=$env(KRB5_KTNAME)"

    # Now start the gss-server.
    spawn $GSSSERVER -export -logfile $tmppwd/gss-server.log -verbose -port [expr 8 + $portbase] gssservice@$hostname
    set gss_server_pid [exp_pid]
    set gss_server_spawn_id $spawn_id

    expect {
	"starting" { }
	eof        { perror "gss-server failed to start" }
    }

    run_client gssclient0 $tmppwd/gss_tk_0 gssclient0
    run_client gssclient1 $tmppwd/gss_tk_1 gssclient1
    run_client gssclient2 $tmppwd/gss_tk_2 gssclient2
    run_client gssclient3 $tmppwd/gss_tk_3 gssclient3

    stop_gss_server
    gss_restore_env

    if ![our_kdestroy $tmppwd/gss_tk_0] {
	perror "failed kdestroy gss_tk_0" 0
    }

    if ![our_kdestroy $tmppwd/gss_tk_1] {
	perror "failed kdestroy gss_tk_1" 0
    }

    if ![our_kdestroy $tmppwd/gss_tk_2] {
	perror "failed kdestroy gss_tk_2" 0
    }

    if ![our_kdestroy $tmppwd/gss_tk_3] {
	perror "failed kdestroy gss_tk_3" 0
    }

    catch "exec rm -f $tmppwd/gss_tk_0 $tmppwd/gss_tk_1 $tmppwd/gss_tk_2 $tmppwd/gss_tk_3"

    return
}

set status [catch doit msg]

stop_gss_server
gss_restore_env
stop_kerberos_daemons

if { $status != 0 } {
    perror "error in gssapi.exp" 0
    perror $msg 0
}
