1#! @EXPECT_PATH@ -- 2## 3## @PACKAGE@ @VERSION@ 4@copyright@ 5# 6# nslogin - Netscaler login 7# 8# Hacks from Anshuman Kanwar. 9 10# The default is to automatically enable 11set avenable 0 12# Sometimes routers take awhile to answer (the default is 10 sec) 13set timeoutdflt 45 14# Some CLIs having problems if we write too fast (Extreme, PIX, Cat) 15set send_human {.2 .1 .4 .2 1} 16 17@login_top@ 18 19# Log into the router. 20# returns: 0 on success, 1 on failure 21proc login { router user userpswd passwd enapasswd cmethod cyphertype } { 22 global spawn_id in_proc do_command do_script 23 global prompt u_prompt p_prompt e_prompt sshcmd 24 set in_proc 1 25 set uprompt_seen 0 26 27 # try each of the connection methods in $cmethod until one is successful 28 set progs [llength $cmethod] 29 foreach prog [lrange $cmethod 0 end] { 30 incr progs -1 31 if ![string compare $prog "ssh"] { 32 regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port 33 set cmd $sshcmd 34 if {"$port" != ""} { 35 set cmd "$cmd -p $port" 36 } 37 if {"$cyphertype" != ""} { 38 set cmd "$cmd -c $cyphertype" 39 } 40 set retval [ catch {eval spawn [split "$cmd -x -l $user $router" { }]} reason ] 41 if { $retval } { 42 send_user "\nError: $cmd failed: $reason\n" 43 return 1 44 } 45 } elseif ![string compare $prog "telnet"] { 46 send_error "\nError: unsupported method: telnet\n" 47 if { $progs == 0 } { 48 return 1 49 } 50 continue 51 } elseif ![string compare $prog "rsh"] { 52 send_error "\nError: unsupported method: rsh\n" 53 if { $progs == 0 } { 54 return 1 55 } 56 continue 57 } else { 58 send_user "\nError: unknown connection method: $prog\n" 59 return 1 60 } 61 sleep 0.3 62 63 # This helps cleanup each expect clause. 64 expect_after { 65 timeout { 66 global in_proc 67 send_user "\nError: TIMEOUT reached\n" 68 catch {close}; catch {wait}; 69 if {$in_proc} { 70 return 1 71 } else { 72 continue 73 } 74 } eof { 75 global in_proc 76 send_user "\nError: EOF received\n" 77 catch {close}; catch {wait}; 78 if {$in_proc} { 79 return 1 80 } else { 81 continue 82 } 83 } 84 } 85 86 # Here we get a little tricky. There are several possibilities: 87 # the router can ask for a username and passwd and then 88 # talk to the TACACS server to authenticate you, or if the 89 # TACACS server is not working, then it will use the enable 90 # passwd. Or, the router might not have TACACS turned on, 91 # then it will just send the passwd. 92 # if telnet fails with connection refused, try ssh 93 expect { 94 -re "(Connection refused|Secure connection \[^\n\r]+ refused|Connection closed by)" { 95 catch {close}; catch {wait}; 96 if !$progs { 97 send_user "\nError: Connection Refused ($prog)\n"; return 1 98 } 99 } 100 eof { send_user "\nError: Couldn't login\n"; wait; return 1 } 101 -nocase "unknown host\r" { 102 catch {close}; catch {wait}; 103 send_user "\nError: Unknown host\n"; wait; return 1 104 } 105 "Host is unreachable" { 106 catch {close}; catch {wait}; 107 send_user "\nError: Host Unreachable!\n"; wait; return 1 108 } 109 "No address associated with name" { 110 catch {close}; catch {wait}; 111 send_user "\nError: Unknown host\n"; wait; return 1 112 } 113 -re "(Host key not found |The authenticity of host .* be established)" { 114 expect { 115 -re "\\(yes\/no\[^\\)]*\\)\\?" { 116 send "yes\r"; 117 send_user "\nHost $router added to the list of known hosts.\n" 118 } 119 -re "\[^\r\n]*\[\r\n]+" { exp_continue; } 120 } 121 exp_continue 122 } 123 -re "HOST IDENTIFICATION HAS CHANGED" { 124 send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" 125 expect { 126 -re "\\(yes\/no\\)\\?" { send "no\r" } 127 -re " strict checking\.\[\r\n]+" { } 128 -re "\[^\r\n]*\[\r\n]+" { exp_continue; } 129 } 130 catch {close}; catch {wait}; 131 return 1 132 } 133 -re "Offending key for " { 134 send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" 135 expect { 136 -re "\\(yes\/no\\)\\?" { send "no\r" } 137 -re "\[^\r\n]*\[\r\n]+" { exp_continue; } 138 } 139 catch {close}; catch {wait}; 140 return 1 141 } 142 -re "(denied|Sorry)" { 143 send_user "\nError: Check your passwd for $router\n" 144 catch {close}; catch {wait}; return 1 145 } 146 "Login failed" { 147 send_user "\nError: Check your passwd for $router\n" 148 return 1 149 } 150 -re "% (Bad passwords|Authentication failed)" { 151 send_user "\nError: Check your passwd for $router\n" 152 return 1 153 } 154 # newer netscaler code (NS8.0: Build 47.8) the password prompt is 155 # "Password:" not "user@hosts's password:" 156 -re "(@\[^\r\n]+ )?$p_prompt" { 157 # ssh pwd prompt 158 sleep 1 159 send -- "$userpswd\r" 160 exp_continue 161 } 162 163 "$prompt" { break; } 164 "Login invalid" { 165 send_user "\nError: Invalid login\n"; 166 catch {close}; catch {wait}; return 1 167 } 168 } 169 } 170 171 set in_proc 0 172 return 0 173} 174 175 176# Run commands given on the command line. 177 178proc run_commands { prompt command } { 179 global do_interact in_proc 180 set in_proc 1 181 182 # escape any parens in the prompt, such as "(enable)" 183 regsub -all "\[)(]" $prompt {\\&} reprompt 184 # this is the only way i see to get rid of more prompts in o/p..grrrrr 185 log_user 0 186 187 # handle escaped ;s in commands, and ;; and ^; 188 regsub -all {([^\\]);} $command "\\1\u0002;" esccommand 189 regsub -all {([^\\]);;} $esccommand "\\1;\u0002;" command 190 regsub {^;} $command "\u0002;" esccommand 191 regsub -all {[\\];} $esccommand ";" command 192 regsub -all {\u0002;} $command "\u0002" esccommand 193 set sep "\u0002" 194 set commands [split $esccommand $sep] 195 set num_commands [llength $commands] 196 # the pager can not be turned off on the PIX, so we have to look 197 # for the "More" prompt. the extreme is equally obnoxious, with a 198 # global switch in the config. 199 for {set i 0} {$i < $num_commands} { incr i} { 200 send -- "[subst -nocommands [lindex $commands $i]]\r" 201 expect { 202 -re "\b+" { exp_continue } 203 -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" 204 } 205 -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" 206 exp_continue 207 } 208 -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" 209 exp_continue 210 } 211 -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*" { 212 send " " 213 # bloody ^[[2K after " " 214 expect { 215 -re "^\[^\r\n]*\r" {} 216 } 217 exp_continue 218 } 219 -re "^ --More--\[^\n\r]*" { 220 send " " 221 exp_continue 222 } 223 -re "^<-+ More -+>\[^\n\r]*" { 224 send_user -- "$expect_out(buffer)" 225 send " " 226 exp_continue 227 } 228 } 229 } 230 log_user 1 231 232 if { $do_interact == 1 } { 233 interact 234 return 0 235 } 236 237 send "quit\r" 238 expect { 239 "Do you wish to save your configuration changes" { 240 send "n\r" 241 exp_continue 242 } 243 "\n" { exp_continue } 244 timeout { catch {close}; catch {wait}; 245 return 0 246 } 247 eof { return 0 } 248 } 249 set in_proc 0 250} 251 252 253 254# 255# For each router... (this is main loop) 256# 257source_password_file $password_file 258set in_proc 0 259set exitval 0 260foreach router [lrange $argv $i end] { 261 set router [string tolower $router] 262 send_user "$router\n" 263 264 # device timeout 265 set timeout [find timeout $router] 266 if { [llength $timeout] == 0 } { 267 set timeout $timeoutdflt 268 } 269 270 # Figure out prompt. 271 set prompt ">" 272 273 # look for noenable option in .cloginrc 274 if { [find noenable $router] == "1" } { 275 set enable 0 276 } else { 277 set enable $avenable 278 } 279 280 # Figure out passwords 281 if { $do_passwd } { 282 set pswd [find password $router] 283 if { [llength $pswd] == 0 } { 284 send_user -- "\nError: no password for $router in $password_file.\n" 285 continue 286 } 287 if { $enable && $autoenable == 0 && [llength $pswd] < 2 } { 288 send_user -- "\nError: no enable password for $router in $password_file.\n" 289 continue 290 } 291 if { $do_passwd } { 292 set passwd [join [lindex $pswd 0] ""] 293 } else { 294 set passwd $userpasswd 295 } 296 if { $do_enapasswd } { 297 set enapasswd [join [lindex $pswd 1] ""] 298 } else { 299 set enapasswd $enapasswd 300 } 301 } else { 302 set passwd $userpasswd 303 set enapasswd $enapasswd 304 } 305 306 # Figure out username 307 if {[info exists username]} { 308 # command line username 309 set ruser $username 310 } else { 311 set ruser [join [find user $router] ""] 312 if { "$ruser" == "" } { set ruser $default_user } 313 } 314 315 # Figure out username's password (if different from the vty password) 316 if {[info exists userpasswd]} { 317 # command line username 318 set userpswd $userpasswd 319 } else { 320 set userpswd [join [find userpassword $router] ""] 321 if { "$userpswd" == "" } { set userpswd $passwd } 322 } 323 324 # Figure out enable username 325 if {[info exists enausername]} { 326 # command line enausername 327 set enauser $enausername 328 } else { 329 set enauser [join [find enauser $router] ""] 330 if { "$enauser" == "" } { set enauser $ruser } 331 } 332 333 # Figure out prompts 334 set u_prompt [find userprompt $router] 335 if { "$u_prompt" == "" } { 336 set u_prompt "(Username|Login|login|user name):" 337 } else { 338 set u_prompt [join [lindex $u_prompt 0] ""] 339 } 340 set p_prompt [find passprompt $router] 341 if { "$p_prompt" == "" } { 342 set p_prompt "(\[Pp]assword|passwd):" 343 } else { 344 set p_prompt [join [lindex $p_prompt 0] ""] 345 } 346 set e_prompt [find enableprompt $router] 347 if { "$e_prompt" == "" } { 348 set e_prompt "\[Pp]assword:" 349 } else { 350 set e_prompt [join [lindex $e_prompt 0] ""] 351 } 352 353 # Figure out cypher type 354 if {[info exists cypher]} { 355 # command line cypher type 356 set cyphertype $cypher 357 } else { 358 set cyphertype [find cyphertype $router] 359 } 360 361 # Figure out connection method 362 set cmethod [find method $router] 363 if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } 364 365 # Figure out the SSH executable name 366 set sshcmd [join [lindex [find sshcmd $router] 0] ""] 367 if { "$sshcmd" == "" } { set sshcmd {ssh} } 368 369 # if [-mM], skip do not login 370 if { $do_cloginrcdbg > 0 } { continue; } 371 372 # Login to the router 373 if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype]} { 374 incr exitval 375 continue 376 } 377 378 # we are logged in, now figure out the full prompt 379 send "\r" 380 expect { 381 -re "\[\r\n]+" { exp_continue; } 382 -re "^$prompt" { set junk $expect_out(0,string); 383 regsub -all "\[\]\[]" $junk {\\&} prompt; } 384 } 385 386 if { $do_command } { 387 if {[run_commands $prompt $command]} { 388 incr exitval 389 continue 390 } 391 } elseif { $do_script } { 392 # If the prompt is (enable), then we are on a switch and the 393 # command is "set length 0"; otherwise its "term length 0". 394 if [ regexp -- ".*> .*enable" "$prompt" ] { 395 send "set length 0\r" 396 send "set logging session disable\r" 397 } else { 398 send "term length 0\r" 399 } 400 expect -re $prompt {} 401 source $sfile 402 catch {close}; 403 } else { 404 label $router 405 log_user 1 406 interact 407 } 408 409 # End of for each router 410 catch {wait}; 411 sleep 0.3 412} 413exit $exitval 414