#!/usr/local/bin/expect -- ## Program: stne, Version 0.6 ## Author: Samuel Abels ## File: stne ## Changelog: 30.08.02 S. Abels Version 0.01 ## Initial release ## 02.09.02 S. Abels Version 0.1 ## Bugfix: No error message when quitting (spawn_id) ## Set xterm title to hostname when logging in. ## 03.09.02 S. Abels Version 0.2 ## Allow multiple logins (e.g. multiple instances of routers). ## 04.09.02 S. Abels Version 0.3 ## Removed bug with multiple instances of routers. ## 09.09.02 S. Abels Version 0.4 ## Simplifing of the login process. ## Better handling when a wrong password has been typed in. ## The Script supports more prompts now. ## 10.09.02 S. Abels Version 0.5 ## Switching ciscos to enable mode again. ## Better error detection. ## Setting xterm title when logging in from one router to another. ## 13.09.02 Z.Can & J. Fro"hlich ## Version 0.6 ## 2 x carriage return after terminal monitor ## Description: ## Given a hostname, this script will log in. If it detects a cisco router, it will also ## switch to enable mode and execute a "terminal monitor". ## # ************************************************* # Supporting Functions # ************************************************* # # Get SKEY password # proc skey { key1 key2 password } { # Don't show any output to the user. log_user 0 # Spawn the S/Key program spawn -noecho /usr/local/bin/key $key1 $key2 # Send the passwort to the skey program and expect the response (= the encrypted password). expect -re "password:"; send "$password\r"; expect -re "\r\n(\[A-Z\ ]+)\r\n"; set response $expect_out(1,string); # Close the spawned program, and wait until it has quit. close; wait; # Enable logging to screen again log_user 1 # Return the encrypted password. return $response } # # Request password from user # proc GetPass { } { set pass "" set timeout -1 send_user "Please enter your S/KEY password: " stty -echo expect_user -re ".*\r" set pass $expect_out(0,string) set timeout 20 send_user "\n" return $pass } # # Extract an option from argv # proc GetOption { option } { global argv global argc set value "" # Search the flag in argv. If it is in there, we get its value. if { [lsearch $argv "$option"] >= 0 } { set pos [lsearch $argv "$option"] incr pos set value [lindex $argv $pos] if { $value != "" } { # Remove the option and its value from the option list lreplace $argv [lsearch $argv "$option"] $pos incr argc -2 } else { Usage exit } } return $value } # # Prompt the user for his username and password and login to a router. # Determines the router type automatically. # proc Login { host } { global prompt global hosttype set prompt "" # Request login information from user. send_user "Please enter your TACACS username: " expect_user -re "(.*)\n" set username $expect_out(1,string) send_user "Please enter your S/KEY password: " stty -echo expect_user -re "(.*)\n" set pass $expect_out(1,string) send_user "\n" # Connect to host set timeout 40 spawn -noecho telnet $host set telnet $spawn_id expect "login" { set hosttype "juniper" } "sername" { set hosttype "cisco" } timeout { send_user "Timeout..." close wait exit } send "$username\r" # expect the s/key id's expect -re "\[\r\n]s/key (\[0-9\]*) (\[A-Za-z0-9\]*).*Password: *$" { set key1 $expect_out(1,string) set key2 $expect_out(2,string) if { $key1 <= 10 } { send_user "Warning: only $key1 more logins possible\n"; send_user "Run keyinit -s as soon as possible\n"; { exit 1 } } # send s/key password send "[skey $key1 $key2 $pass]\r"; } -re "Password: *$" { # or send cleartext password send "$pass" } timeout { send_user "S/Key password prompt timeout!" close wait exit } # define the prompt expect -re "@(.+)> $" { set prompt "$expect_out(1,string)> " } -re "\n(.+)% *$" { set prompt "$expect_out(1,string)> " } -re "\n(.+)#$" { set prompt "$expect_out(1,string)#" } "Authentication failed" { close wait puts "" exit } "Login incorrect" { close wait puts "" exit } # expect -re "($prompt)" if { $prompt == "" } { send_user "Login to host failed!\n" close wait exit } if { $hosttype == "cisco" } { # switch to enable mode send "enable\r" expect -re "\[\r\n]s/key (\[0-9\]*) (\[A-Za-z0-9\]*).*Password: *$" { set key1 $expect_out(1,string) set key2 $expect_out(2,string) if { $key1 <= 10 } { send_user "Warning: only $key1 more logins possible\n"; send_user "Run keyinit -s as soon as possible\n"; { exit 1 } } send "[skey $key1 $key2 $pass]\r"; } timeout { send_user "S/Key password timeout!\n" } expect -re "($prompt)" { } timeout { send_user "Prompt timed out!\n" close wait exit } send "terminal monitor\r" expect -re "($prompt)" send "\r" expect -re "($prompt)" send "\r" expect -re "($prompt)" } return $telnet } # ************************************************* # End of Supporting Functions # ************************************************* # # Short usage info. # proc Usage { } { puts "(c)2002 by Samuel Abels (|spam| |debain| |org|)." puts "Given a hostname, this sript will log in. If it is a cisco router, it will enable and do a \"terminal monitor\", also." puts "Usage: stne hostname \[-l filename\]" puts "" puts "hostname The host on which to execute the command." puts "-l filename Log the session to filename." puts "" puts "Examples: stne isp-vix-gw20 -l log_supportinfo" puts " stne f-ea2" } # # Check the command line syntax # proc CheckSyntax { } { global argv global argc global filename global hosttype global hostname set filename [GetOption "-l"] set hosttype "auto" # Now, only the hostname should be left in argv if { $argc != 1 } { Usage exit } set hostname [ lindex $argv 0 ] } # ------------------------------------------------------- # # Init variables set hostname "" set hosttype "" set filename "" # Check syntax, usage info CheckSyntax # If the hostname can't be pinged, we'll append an "isp-" before. # If the given host is an IP-Address we skip that step. set erg [catch {exec ping -c 1 $hostname}] if { $erg != 0 } { if { ![ regexp "(\[0-9]+\.\[0-9]+\.\[0-9]+\.\[0-9]+)" $hostname ] } { send_user "Can't ping $hostname, trying isp-$hostname instead...\n" set hostname "isp-$hostname" } } # If the host still can't be pinged, send an error message and quit. if { [catch {exec ping -c 1 $hostname}] != 0 } { send_user "Can't ping $hostname! Quitting.\n" exit } else { send_user "Ping to $hostname was successful.\n" } # Login set spawn_id [ Login $hostname ] # set xterm title to current hostname system xterm_title "$hostname" # Empty out the tempfile, if it already exists if { $filename != "" } { if { [file exists "$filename"] } { system rm "$filename" exit } # Start logging log_file $filename } # interact with the user interact { -o -nobuffer -re "\[\n\r]*s/key +(\[0-9]+) +(..\[0-9]+)\[\n\r]+" { set key1 $interact_out(1,string) set key2 $interact_out(2,string) # send s/key password send "[ skey $key1 $key2 [ GetPass ] ]\r" if {$key1 <= 10} { send_user "Warning: only $key1 more logins possible\n"; send_user "Run keyinit -s as soon as possible\n"; } } -nobuffer -re ".*\[\n\r]*\[a-zA-Z0-9]+@(\[a-zA-Z0-9]+|\-+|\.+)>\[\n|\r]*" { set prompt "$interact_out(1,string)> " system xterm_title "\"$interact_out(1,string)\"" } -nobuffer -re ".*\[\r\n]+(\[\-\.a-zA-Z0-9]*)#$" { set prompt "$interact_out(0,string)#" system xterm_title "\"$interact_out(1,string)\"" } } log_file wait -i $spawn_id # set xterm title back to "xterm" system xterm_title "xterm" # -------------------------------------------------------