#!/usr/local/bin/expect -f
#
# Login on a remote host via Telnet.
# Handle S/Key challenges automatically by sending
# the corresponding response.

# procedure to read the user's password
proc read_password {} {
  send_user "Password:"
  stty -echo
  expect_user -re "(.*)\n" {send_user \n}
  stty echo
  return $expect_out(1,string)
}

# check the usage
if !$argc {
   puts stderr "Usage: $argv0 <target_host>"
   exit 1
}

# start telnet and wait for the login prompt
set target [lindex $argv 0]
spawn -noecho telnet $target
set timeout 30
expect {
   -re {.*login.*: *} {}
   timeout {
      send_user "Timeout - couldn't connect to $target\n"
      exit 1
   }
   eof {
      send_user "$expect_out(buffer)\n"
      exit 1
   }
}

# ask the user for her or his ID and send it over
expect_user {
   "*\n" {}
   eof { 
      close 
      exit 1 
   }
}
exp_send $expect_out(buffer)

# wait for a password request or an S/Key challenge
log_user 0
expect {
   -re {.*\[s/key ([^]]+)\].*Response: *} {
      set challenge $expect_out(1,string)
   }
   -re "Password:.*" {}
   default {
      send_user $expect_out(buffer)
      exit 1
   }
}

if [info exists challenge] {
   # is a new "keyinit" advisable ?
   # if so, give the user a hint
   set seqno [lindex $challenge 0]
   if {$seqno < 10} {
      send_user "\n\aThe sequence number of your current challenge is $seqno.\n"
      if !$seqno { 
         send_user "This is your last chance to"
         send_user " reinitialize your S/KEY sequence,\n"
         send_user "otherwise you are locked out!!\n"
      } else {
        send_user "You should'nt forget to reinitialize it.\n"
      }
   }
   
   # send telnet to the background
   set telnet_id $spawn_id
   
   # calculate the response with "key"
   eval spawn -noecho key $challenge
   
   # wait for the password request
   log_user 0
   expect {
     "*password: " {}
     default {
       send_user "No reaction from \"key\".\n"
       exit 1
     }
   }
}

# read the user's password
set password [read_password]

if [info exists challenge] {
   # there was a challenge ---> send the password to "key"
   exp_send $password\r 
   
   # wait for the response from "key"
   expect {
      timeout {
        send_user "Timeout - \"key\" didn't send a response.\n"
	exit 1
      }
      eof {
        regsub -all "\[\n\r\]" $expect_out(buffer) "" response
      }
   }

   # telnet back to the foreground
   set spawn_id $telnet_id

   # send the response to the remote host
   exp_send $response\n

   # wait for the echo
   expect {
     -re "$response\[\r\n\]*" {}
     timeout                  {}
     eof {
       send_user $expect_out(buffer)
       exit 1
     }
   }
} else {
   # there was no challenge ---> send the password in plain text
   exp_send $password\r
}

# normal interaction with the user
interact

