# Kerberos telnet test.
# This is a DejaGnu test script.
# This script tests Kerberos telnet.
# Written by Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>.

# Find the programs we need.  We use the binaries from the build tree
# if they exist.  If they do not, then they must be in PATH.  We
# expect $objdir to be .../kerberos/src.

if ![info exists TELNET] {
    set TELNET [findfile $objdir/../../appl/telnet/telnet/telnet]
}

if ![info exists TELNETD] {
    set TELNETD [findfile $objdir/../../appl/telnet/telnetd/telnetd]
}

if ![info exists LOGINKRB5] {
    set LOGINKRB5 [findfile $objdir/../../appl/bsd/login.krb5]
}

# Remove old wrapper script
    catch "exec rm -f $tmppwd/login.wrap"

# Start up a root shell.
if ![setup_root_shell telnet] {
    return
}

# Make sure .k5login is reasonable.
if ![check_k5login rlogin] {
    stop_root_shell
    return
}

# Set up the kerberos database.
if {![get_hostname] \
    || ![setup_kerberos_files] \
    || ![setup_kerberos_env] \
    || ![setup_kerberos_db 0]} {
    stop_root_shell
    return
}

# A procedure to start up the telnet daemon.

proc start_telnet_daemon { } {
    global REALMNAME
    global TELNETD
    global LOGINKRB5
    global ROOT_PROMPT
    global tmppwd
    global hostname
    global rlogin_spawn_id
    global telnetd_pid

    # Setup the shared library wrapper for login.krb5
    if ![file exists $tmppwd/login.wrap] {
	    setup_wrapper $tmppwd/login.wrap "$LOGINKRB5 $*"
    }

    # The -debug argument tells it to accept a single connection, so
    # we don't need to use inetd.  The 3023 is the port to listen at.
    # Note that tmppwd here is a shell variable, which is set in
    # setup_root_shell, not a TCL variable.
    send -i $rlogin_spawn_id "sh -c \"$TELNETD -debug -t \$tmppwd/srvtab -R $REALMNAME -L $tmppwd/login.wrap -X KERBEROS_V4 3023\" &\r"
    expect {
	-i $rlogin_spawn_id 
	-re "$ROOT_PROMPT" { }
	timeout {
	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
	    return
	}
	eof {
	    send_error "ERROR: eof from rlogin $hostname -l root\n"
	    return
	}
    }
    send -i $rlogin_spawn_id "echo \$!\r"
    expect {
	-i $rlogin_spawn_id
	-re "\[0-9\]+" {
	    set telnetd_pid $expect_out(0,string)
	    verbose "telnetd process ID is $telnetd_pid"
	}
	timeout {
	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
	    return
	}
	eof {
	    send_error "ERROR: eof from rlogin $hostname -l root\n"
	    return
	}
    }
    expect {
	-i $rlogin_spawn_id
	-re "$ROOT_PROMPT" { }
	timeout {
	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
	    return
	}
	eof {
	    send_error "ERROR: eof from rlogin $hostname -l root\n"
	    return
	}
    }

    # Give the telnet daemon a few seconds to get set up.
    catch "exec sleep 2"
}

# A procedure to stop the telnet daemon.

proc stop_telnet_daemon { } {
    global telnetd_pid

    if [info exists telnetd_pid] {
	catch "exec kill $telnetd_pid"
	unset telnetd_pid
    }
}

# Wrap the tests in a procedure, so that we can kill the daemons if
# we get some sort of error.

proc telnet_test { } {
    global REALMNAME
    global TELNET
    global BINSH
    global SHELL_PROMPT
    global KEY
    global hostname
    global localhostname
    global env

    # Start up the kerberos and kadmind daemons and get a srvtab and a
    # ticket file.
    if {![start_kerberos_daemons 0] \
        || ![add_kerberos_key host/$hostname 0] \
        || ![setup_srvtab 0] \
	|| ![add_kerberos_key $env(USER) 0] \
	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
	return
    }

    # Start up the telnet daemon.
    start_telnet_daemon

    # Start up our telnet connection.  We first try it without
    # authentication, so the daemon should prompt for a login.
    spawn $TELNET -- $hostname -3023
    set telnet_pid [exp_pid]

    expect_after {
	timeout {
	    fail "$testname (timeout)"
	    catch "expect_after"
	    return
	}
	eof {
	    fail "$testname (eof)"
	    catch "expect_after"
	    return
	}
    }

    set testname "simple telnet"
    expect {
	"ogin:" {
	    pass $testname
	}
    }

    # Move back to telnet command mode and make sure it seems
    # reasonable.
    set testname "telnet command mode"
    send "\035"
    expect {
	"telnet>" {
	    pass $testname
	}
    }

    set testname "telnet status"
    send "status\r"
    # use -nocase because telnet may output the fqdn in upper-case;
    # however, -nocase requires the whole pattern to be in lower case
    expect {
	-nocase -re "connected to $localhostname.*operating in single character mode.*catching signals locally.*remote character echo.*flow control.*escape character is '.\]'" {
	    pass $testname
	}
    }

    set testname "back to command mode"
    send "\035"
    expect {
	"telnet>" {
	    pass $testname
	}
    }

    set testname "quit"
    send "quit\r"
    expect {
	"Connection closed.\r" {
	    pass $testname
	}
    }

    expect_after

# on hpux 10.x, the child telnet will hang in an ioctl().  This will
# wait a while for an EOF, and kill the process if it doesn't exit by
# itself.  The hang doesn't happen when telnet is run at the shell.

    expect {
	eof { }
	timeout {
	    stop_telnet_daemon
	}
    }

    if ![check_exit_status "exit status"] {
	return
    }

    pass "exit status"

    # The telnet daemon should have stopped, but we have no easy way
    # of checking whether it actually did.  Kill it just in case.
    stop_telnet_daemon

    # Try an authenticated connection.
    start_telnet_daemon
    spawn $TELNET -a -k $REALMNAME -- $hostname -3023

    expect_after {
	timeout {
	    fail "$testname (timeout)"
	    catch "expect_after"
	    return
	}
	"Connection closed by foreign host.\r" {
	    fail "$testname (connection closed)"
	    catch "expect_after"
	    return
	}
	eof {
	    fail "$testname (eof)"
	    catch "expect_after"
	    return
	}
    }

    set testname "authenticated telnet"
    expect "Kerberos V5 accepts you"
    expect {
	-re "$SHELL_PROMPT" {
	    pass $testname
	}
    }

    # Switch to /bin/sh to try to avoid confusion from the shell
    # prompt.
    set testname "shell"
    send "$BINSH\r"
    expect -re "$SHELL_PROMPT"

    set testname "date"
    send "date\r"
    expect "date"
    expect {
	-re "\[A-Za-z0-9 :\]+\[\r\n\]+" {
	    if [check_date $expect_out(0,string)] {
		pass "date"
	    } else {
		fail "date"
	    }
	}
    }
    expect -re "$SHELL_PROMPT"

    set testname "exit"
    send "exit\r"
    expect -re "$SHELL_PROMPT"
    send "exit\r"
    expect {
	"Connection closed by foreign host.\r" {
	    pass $testname
	}
    }

    expect_after

    # We can't use check_exit_status, because we expect an exit status
    # of 1.
    set status_list [wait -i $spawn_id]
    verbose "wait -i $spawn_id returned $status_list (klist)"
    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 1 } {
	send_log "exit status: $status_list\n"
	verbose "exit status: $status_list"
	fail "exit status"
    } else {
	pass "exit status"
    }

    # The telnet daemon should have stopped, but we have no easy way
    # of checking whether it actually did.  Kill it just in case.
    stop_telnet_daemon

    # Try an authenticated encrypted connection.
    start_telnet_daemon
    spawn $TELNET -a -x -k $REALMNAME -- $hostname -3023

    expect_after {
	timeout {
	    fail $testname
	    catch "expect_after"
	    return
	}
	eof {
	    fail $testname
	    catch "expect_after"
	    return
	}
    }

    set testname "encrypted telnet"
    expect "Kerberos V5 accepts you"
    expect {
	-re "$SHELL_PROMPT" {
	    pass $testname
	}
    }

    # Make sure the encryption is not destroying the text.
    set testname "echo"
    send "echo hello\r"
    expect "echo hello"
    expect "hello"
    expect {
	-re "$SHELL_PROMPT" {
	    pass $testname
	}
    }

    # Move back to telnet command mode and check the encryption status.
    set testname "encryption status"
    send "\035"
    expect "telnet>"
    send "status\r"
    expect {
	-re "Currently encrypting output with DES_CFB64.*Currently decrypting input with DES_CFB64" {
	    pass $testname
	}
    }

    set testname "exit status"
    send "exit\r"
    expect "Connection closed by foreign host.\r"

    expect_after

    # We can't use check_exit_status, because we expect an exit status
    # of 1.
    set status_list [wait -i $spawn_id]
    verbose "wait -i $spawn_id returned $status_list (klist)"
    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 1 } {
	send_log "exit status: $status_list\n"
	verbose "exit status: $status_list"
	fail "exit status"
    } else {
	pass "exit status"
    }

    # The telnet daemon should have stopped, but we have no easy way
    # of checking whether it actually did.  Kill it just in case.
    stop_telnet_daemon
}

# Run the test.  Logging in sometimes takes a while, so increase the
# timeout.
set oldtimeout $timeout
set timeout 60
set status [catch telnet_test msg]
set timeout $oldtimeout

# Shut down the kerberos daemons, the telnet daemon, and the rlogin
# process.
stop_kerberos_daemons

stop_telnet_daemon

stop_root_shell

if { $status != 0 } {
    send_error "ERROR: error in telnet.exp\n"
    send_error "$msg\n"
    exit 1
}
