summaryrefslogtreecommitdiffstats
path: root/bin/clogin
diff options
context:
space:
mode:
Diffstat (limited to 'bin/clogin')
-rwxr-xr-xbin/clogin181
1 files changed, 109 insertions, 72 deletions
diff --git a/bin/clogin b/bin/clogin
index b8b693e..cad94cd 100755
--- a/bin/clogin
+++ b/bin/clogin
@@ -7,7 +7,7 @@
## This software may be freely copied, modified and redistributed without
## fee for non-commerical purposes provided that this copyright notice is
## preserved intact on all copies and modified copies.
-##
+##
## There is no warranty or other guarantee of fitness of this software.
## It is provided solely "as is". The author(s) disclaim(s) all
## responsibility and liability with respect to this software's usage
@@ -29,8 +29,8 @@
# Usage line
set usage "Usage: $argv0 \[-u user\] \[-p user-password\] \[-v vty-password\] \
\[-w enable-username\] \[-e enable-password\] \[-noenable\] \
-\[-f cloginrc-file\] \[-c command\] \[-s script-file\] \[-autoenable\] \
-\[-t timeout\] router \[router...\]\n"
+\[-f cloginrc-file\] \[-y ssh_cypher_type\] \[-c command\] \[-s script-file\] \
+\[-x command-file\] \[-autoenable\] \[-t timeout\] router \[router...\]\n"
# env(CLOGIN) may contain:
# x == do not set xterm banner or name
@@ -53,8 +53,8 @@ set do_enapasswd 1
if {[ info exists env(CISCO_USER) ] } {
set default_user $env(CISCO_USER)
} else {
- # This uses "id" which I think is portable. At least it has existed
- # (without options) on all machines/OSes I've been on recently -
+ # This uses "id" which I think is portable. At least it has existed
+ # (without options) on all machines/OSes I've been on recently -
# unlike whoami or id -nu.
regexp {\(([^)]*)} [exec id] junk default_user
}
@@ -125,6 +125,13 @@ for {set i 0} {$i < $argc} {incr i} {
exit 1
}
set do_script 1
+ # cypher type
+ } -y* -
+ -Y* {
+ if {! [ regexp .\[eE\](.+) $arg ignore cypher]} {
+ incr i
+ set cypher [ lindex $argv $i ]
+ }
# alternate cloginrc file
} -f* -
-F* {
@@ -136,17 +143,17 @@ for {set i 0} {$i < $argc} {incr i} {
-T* {
incr i
set timeout [ lindex $argv $i ]
- } -x* -
- -X {
- if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {
- incr i
- set cmd_file [ lindex $argv $i ]
- }
- set cmd_fd [open $cmd_file r]
- set cmd_text [read $cmd_fd]
- close $cmd_fd
- set command [join [split $cmd_text \n] \;]
- set do_command 1
+ } -x* -
+ -X {
+ if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {
+ incr i
+ set cmd_file [ lindex $argv $i ]
+ }
+ set cmd_fd [open $cmd_file r]
+ set cmd_text [read $cmd_fd]
+ close $cmd_fd
+ set command [join [split $cmd_text \n] \;]
+ set do_command 1
# Do we enable?
} -noenable {
set enable 0
@@ -192,20 +199,20 @@ proc label { host } {
if [regexp \^(xterm|vs) $env(TERM) ignore ] {
send_user "\033]1;[lindex [split $host "."] 0]\a"
send_user "\033]2;$host\a"
- }
+ }
}
}
# This is a helper function to make the password file easier to
# maintain. Using this the password file has the form:
-# add password sl* pete cow
-# add password at* steve
+# add password sl* pete cow
+# add password at* steve
# add password * hanky-pie
-proc add {var args} { global $var ;lappend $var $args}
+proc add {var args} { global $var ;lappend $var $args}
proc find {var router} {
- source_password_file
- upvar $var list
- if { [info exists list] } {
+ source_password_file
+ upvar $var list
+ if { [info exists list] } {
foreach line $list {
if { [string match [lindex $line 0] $router ] } {
return [lrange $line 1 end]
@@ -219,11 +226,11 @@ proc find {var router} {
# it is sourced, the user better know what to put in there, as it
# could install more than just password info... I will assume however,
# that a "bad guy" could just as easy put such code in the clogin
-# script, so I will leave .cloginrc as just an extention of that script
+# script, so I will leave .cloginrc as just an extention of that script
proc source_password_file { } {
global env password_file read_password_file
if { [info exists read_password_file] } { return }
- if { [info exists password_file] == 0 } {
+ if { [info exists password_file] == 0 } {
set password_file $env(HOME)/.cloginrc
}
set read_password_file 1
@@ -236,9 +243,10 @@ proc source_password_file { } {
}
# Log into the router.
-proc login { router user userpswd passwd enapasswd prompt } {
+proc login { router user userpswd passwd enapasswd prompt cyphertype } {
global spawn_id in_proc do_command do_script
set in_proc 1
+ set tryssh 1
# Telnet to the router & try to login.
if [ catch {spawn telnet $router} reason ] {
@@ -253,19 +261,19 @@ proc login { router user userpswd passwd enapasswd prompt } {
send_user "\nError: TIMEOUT reached\n"
close; wait
if { $in_proc} {
- return 1
+ return 1
} else {
- continue
+ continue
}
- } eof {
+ } eof {
send_user "\nError: EOF received\n"
close; wait
if { $in_proc} {
- return 1
+ return 1
} else {
- continue
+ continue
}
- }
+ }
}
# Here we get a little tricky. There are several possibilities:
@@ -274,12 +282,24 @@ proc login { router user userpswd passwd enapasswd prompt } {
# TACACS server is not working, then it will use the enable
# passwd. Or, the router might not have TACACS turned on,
# then it will just send the passwd.
+ # if telnet fails with connection refused, try ssh
expect {
- eof { send_user "Error: Couldn't login\n"; wait; return 1 }
- "Connection refused" {
- expect eof
- send_user "Error: Connection Refused\n"; wait; return 1
- } "Unknown host\r\n" {
+ "Connection refused" {
+ close; wait
+ if { $tryssh } {
+ if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] {
+ send_user "Error: failed to ssh: $reason\n"
+ exit 1
+ }
+ set tryssh 0
+ sleep 0.3
+ exp_continue
+ } else {
+ expect eof
+ send_user "Error: Connection Refused\n"; wait; return 1
+ }
+ } eof { send_user "Error: Couldn't login\n"; wait; return 1
+ } "Unknown host\r\n" {
expect eof
send_user "Error: Unknown host\n"; wait; return 1
} "Host is unreachable" {
@@ -289,32 +309,40 @@ proc login { router user userpswd passwd enapasswd prompt } {
expect eof
send_user "Error: Unknown host\n"; wait; return 1
}
+ -re "Host key not found .* \(yes\/no\)\?" {
+ send "yes\r"
+ send_user "Host $router added to the list of known hosts.\n"
+ exp_continue }
+ -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" {
+ send "no\r"
+ send_user "Error: The host key for $router has changed. update the known_hosts file accordingly.\n"
+ return 1 }
-re "(Username|login):" { send "$user\r"
- expect {
- eof { send_user "Error: Couldn't login\n"; wait; return 1 }
+ expect {
+ eof { send_user "Error: Couldn't login\n"; wait; return 1 }
-re "\[Pp]assword:" { send "$userpswd\r" }
"$prompt" { set in_proc 0; return 0 }
}
exp_continue
}
- "Password:" { send "$passwd\r"
- expect {
- eof { send_user "Error: Couldn't login\n"; wait; return 1 }
+ "\[Pp]assword:" { send "$passwd\r"
+ expect {
+ eof { send_user "Error: Couldn't login\n"; wait; return 1 }
"Password:" { send "$enapasswd\r" }
- "$prompt" { set in_proc 0; return 0 }
+ "$prompt" { set in_proc 0; return 0 }
}
exp_continue
}
- "$prompt" { }
- denied { send_user "Error: Check your passwd for $router\n"
- if { $do_command || $do_script } {
+ "$prompt" { }
+ denied { send_user "Error: Check your passwd for $router\n"
+ if { $do_command || $do_script } {
send "quit"
wait
return 1
} else {
return 1
}
- }
+ }
"% Bad passwords" {send_user "Error: Check your passwd for $router\n"; return 1 }
}
set in_proc 0
@@ -358,17 +386,17 @@ proc run_commands { prompt command } {
for {set i 0} {$i < $num_commands} { incr i} {
send "[subst [lindex $commands $i]]\r"
expect {
- -re "^\[^\n\r]*$prompt." { exp_continue }
+ -re "^\[^\n\r]*$prompt." { exp_continue }
-re "^\[^\n\r *]*$prompt" {}
- "\n" { exp_continue }
- }
+ -re "\[\n\r]" { exp_continue }
+ }
}
} else {
send "[subst $command]\r"
expect {
-re "^\[^\n\r]*$prompt." { exp_continue }
-re "^\[^\n\r *]*$prompt" {}
- "\n" { exp_continue }
+ -re "\[\n\r]" { exp_continue }
}
}
send "exit\r"
@@ -410,49 +438,58 @@ foreach router [lrange $argv $i end] {
if { $do_passwd || $do_enapasswd } {
set pswd [find password $router]
if { [llength $pswd] == 0 } {
- send_user "Error - no password for $router in $password_file.\n"
- continue
- }
- if { $do_enapasswd && !$autoenable && [llength $pswd] < 2 } {
+ send_user "Error - no password for $router in $password_file.\n"
+ continue
+ }
+ if { $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } {
send_user "Error - no enable password for $router in $password_file.\n"
- continue
+ continue
}
- set passwd [lindex $pswd 0]
- set enapasswd [lindex $pswd 1]
+ set passwd [lindex $pswd 0]
+ set enapasswd [lindex $pswd 1]
}
# Figure out username
- if {[info exists username]} {
+ if {[info exists username]} {
# command line username
set ruser $username
} else {
- set ruser [find user $router]
+ set ruser [find user $router]
if { "$ruser" == "" } { set ruser $default_user }
- }
+ }
# Figure out username's password (if different from the vty password)
if {[info exists userpasswd]} {
# command line username
set userpswd $userpasswd
} else {
- set userpswd [find userpassword $router]
- if { "$userpswd" == "" } { set userpswd $passwd }
- }
-
+ set userpswd [find userpassword $router]
+ if { "$userpswd" == "" } { set userpswd $passwd }
+ }
+
# Figure out enable username
- if {[info exists enausername]} {
+ if {[info exists enausername]} {
# command line enausername
set enauser $enausername
} else {
- set enauser [find enauser $router]
- if { "$enauser" == "" } { set enauser $ruser }
- }
+ set enauser [find enauser $router]
+ if { "$enauser" == "" } { set enauser $ruser }
+ }
+
+ # Figure out cypher tpye
+ if {[info exists cypher]} {
+ # command line cypher type
+ set cyphertype $cypher
+ } else {
+ set cyphertype [find cyphertype $router]
+ if { "$cyphertype" == "" } { set cyphertype "3des" }
+ }
# Login to the router
- if {[login $router $ruser $userpswd $passwd $enapasswd $prompt]} {
+ if {[login $router $ruser $userpswd $passwd $enapasswd $prompt $cyphertype]} {
continue
}
- if { $enable } {
+ if { $enable } {
if {[do_enable $enauser $enapasswd]} {
if { $do_command || $do_script } {
close; wait
@@ -471,7 +508,7 @@ foreach router [lrange $argv $i end] {
source $sfile
close
} else {
- label $router
+ label $router
log_user 1
interact
}