1#! @EXPECT_PATH@ -- 2## 3## @PACKAGE@ @VERSION@ 4@copyright@ 5# 6# xilogin - Xirrus & Hauwei RVP login 7# 8# Most options are intuitive for logging into a Xirrus array. 9# The default is to not enable. 10# 11 12# XXX need to import login_top. 13 14# Usage line 15set usage "Usage: $argv0 \[-diSV\] \[-autoenable\] \[-noenable\] \ 16\[-c command\] \[-Evar=x\] \[-e enable-password\] \[-f cloginrc-file\] \ 17\[-p user-password\] \[-r passphrase\] \[-s script-file\] \[-t timeout\] \ 18\[-u username\] \[-v vty-password\] \[-w enable-username\] \[-x command-file\] \ 19\[-y ssh_cypher_type\] router \[router...\]\n" 20 21# env(CLOGIN) may contain: 22# x == do not set xterm banner or name 23 24# Password file 25set password_file $env(HOME)/.cloginrc 26# Default is to login to the router 27set do_command 0 28set do_interact 0 29set do_script 0 30# The default is to automatically enable 31set avenable 1 32# The default is that you login non-enabled (tacacs can have you login already 33# enabled) 34set avautoenable 0 35# The default is to look in the password file to find the passwords. This 36# tracks if we receive them on the command line. 37set do_passwd 1 38set do_enapasswd 1 39# Save config, if prompted 40set do_saveconfig 0 41# cloginrc debugging knob 42set do_cloginrcdbg 0 43# Sometimes routers take awhile to answer (the default is 10 sec) 44set timeoutdflt 45 45# intialize cloginrc parsing stacks 46set int_file {} 47set int_lineno {} 48# Some CLIs having problems if we write too fast (Extreme, PIX, Cat) 49set send_human {.2 .1 .4 .2 1} 50 51# Find the user in the ENV, or use the unix userid. 52if {[info exists env(CISCO_USER)]} { 53 set default_user $env(CISCO_USER) 54} elseif {[info exists env(USER)]} { 55 set default_user $env(USER) 56} elseif {[info exists env(LOGNAME)]} { 57 set default_user $env(LOGNAME) 58} else { 59 # This uses "id" which I think is portable. At least it has existed 60 # (without options) on all machines/OSes I've been on recently - 61 # unlike whoami or id -nu. 62 if [catch {exec id} reason] { 63 send_error "\nError: could not exec id: $reason\n" 64 exit 1 65 } 66 regexp {\(([^)]*)} "$reason" junk default_user 67} 68if {[info exists env(CLOGINRC)]} { 69 set password_file $env(CLOGINRC) 70} 71 72# Process the command line 73for {set i 0} {$i < $argc} {incr i} { 74 set arg [lindex $argv $i] 75 76 switch -glob -- $arg { 77 # Expect debug mode 78 -d* { 79 exp_internal 1 80 # Username 81 } -u* { 82 if {! [regexp .\[uU\](.+) $arg ignore user]} { 83 incr i 84 set username [lindex $argv $i] 85 } 86 # cloginrc debugging knobs 87 } -m* { 88 set do_cloginrcdbg 1 89 } -M* { 90 set do_cloginrcdbg 2 91 # interactive 92 } -i* { 93 set do_interact 1 94 # VTY Password 95 } -p* { 96 if {! [regexp .\[pP\](.+) $arg ignore userpasswd]} { 97 incr i 98 set userpasswd [lindex $argv $i] 99 } 100 set do_passwd 0 101 # cloginrc debugging knobs 102 } -m* { 103 set do_cloginrcdbg 1 104 } -M* { 105 set do_cloginrcdbg 2 106 # ssh passphrase 107 } -r* { 108 if {! [regexp .\[rR\](.+) $arg ignore passphrase]} { 109 incr i 110 set vapassphrase [lindex $argv $i] 111 } 112 # VTY Password 113 } -v* { 114 if {! [regexp .\[vV\](.+) $arg ignore passwd]} { 115 incr i 116 set passwd [lindex $argv $i] 117 } 118 set do_passwd 0 119 # Version string 120 } -V* { 121 send_user "@PACKAGE@ @VERSION@\n"; 122 exit 0 123 # Enable Username 124 } -w* { 125 if {! [regexp .\[wW\](.+) $arg ignore enauser]} { 126 incr i 127 set enausername [lindex $argv $i] 128 } 129 # Environment variable to pass to -s scripts 130 } -E* { 131 if {[regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} { 132 set E$varname $varvalue 133 } else { 134 send_user "\nError: invalid format for -E in $arg\n" 135 exit 1 136 } 137 # Enable Password 138 } -e* { 139 if {! [regexp .\[e\](.+) $arg ignore enapasswd]} { 140 incr i 141 set enapasswd [lindex $argv $i] 142 } 143 set do_enapasswd 0 144 # Command to run. 145 } -c* { 146 if {! [regexp .\[cC\](.+) $arg ignore command]} { 147 incr i 148 set command [lindex $argv $i] 149 } 150 set do_command 1 151 # Expect script to run. 152 } -s* { 153 if {! [regexp .\[sS\](.+) $arg ignore sfile]} { 154 incr i 155 set sfile [lindex $argv $i] 156 } 157 if { ! [file readable $sfile] } { 158 send_user "\nError: Can't read $sfile\n" 159 exit 1 160 } 161 set do_script 1 162 # save config on exit 163 } -S* { 164 set do_saveconfig 1 165 # 'ssh -c' cypher type 166 } -y* { 167 if {! [regexp .\[eE\](.+) $arg ignore cypher]} { 168 incr i 169 set cypher [lindex $argv $i] 170 } 171 # alternate cloginrc file 172 } -f* { 173 if {! [regexp .\[fF\](.+) $arg ignore password_file]} { 174 incr i 175 set password_file [lindex $argv $i] 176 } 177 # Timeout 178 } -t* { 179 if {! [regexp .\[tT\](.+) $arg ignore timeout]} { 180 incr i 181 set timeoutdflt [lindex $argv $i] 182 } 183 # Command file 184 } -x* { 185 if {! [regexp .\[xX\](.+) $arg ignore cmd_file]} { 186 incr i 187 set cmd_file [lindex $argv $i] 188 } 189 if [catch {set cmd_fd [open $cmd_file r]} reason] { 190 send_user "\nError: $reason\n" 191 exit 1 192 } 193 set cmd_text [read $cmd_fd] 194 close $cmd_fd 195 set command [join [split $cmd_text \n] \;] 196 set do_command 1 197 # Do we enable? 198 } -noenable { 199 set avenable 0 200 # Does tacacs automatically enable us? 201 } -autoenable { 202 set avautoenable 1 203 set avenable 0 204 } -* { 205 send_user "\nError: Unknown argument! $arg\n" 206 send_user $usage 207 exit 1 208 } default { 209 break 210 } 211 } 212} 213# Process routers...no routers listed is an error. 214if { $i == $argc } { 215 send_user "\nError: $usage" 216} 217 218# Only be quiet if we are running a script (it can log its output 219# on its own) 220if { $do_script } { 221 log_user 0 222} else { 223 log_user 1 224} 225 226# 227# Done configuration/variable setting. Now run with it... 228# 229 230# Sets Xterm title if interactive...if its an xterm and the user cares 231proc label {host} { 232 global env 233 # if CLOGIN has an 'x' in it, don't set the xterm name/banner 234 if [info exists env(CLOGIN)] { 235 if {[string first "x" $env(CLOGIN)] != -1} { return } 236 } 237 # take host from ENV(TERM) 238 if [info exists env(TERM)] { 239 if [regexp \^(xterm|vs) $env(TERM) ignore] { 240 send_user "\033]1;[lindex [split $host "."] 0]\a" 241 send_user "\033]2;$host\a" 242 } 243 } 244} 245 246# This is a helper function to make the password file easier to 247# maintain. Using this the password file has the form: 248# add password sl* pete cow 249# add password at* steve 250# add password * hanky-pie 251proc add {var args} { 252 global int_file int_lineno int_$var 253 set file [lindex $int_file 0] 254 set lineno [lindex $int_lineno 0] 255 lappend int_$var "$var:$file:$lineno: $args" 256} 257proc include {args} { 258 global env 259 regsub -all "(^{|}$)" $args {} args 260 if {[regexp "^/" $args ignore] == 0} { 261 set args $env(HOME)/$args 262 } 263 source_password_file $args 264} 265 266proc find {var router} { 267 global do_cloginrcdbg 268 upvar int_$var list 269 if {[info exists list]} { 270 foreach line $list { 271 if {[string match -nocase [lindex $line 1] $router]} { 272 if {$do_cloginrcdbg > 0} { 273 send_error -- [join [list [lindex $line 0] [lrange $line 1 end] "\r\n"]] 274 } 275 if {$do_cloginrcdbg == 2} { 276 # save return value 277 if {! [info exists result]} { 278 set result [lrange $line 2 end] 279 } 280 } else { 281 return [lrange $line 2 end] 282 } 283 } 284 } 285 } 286 287 if {$do_cloginrcdbg == 2} { 288 if {[info exists result]} { 289 return $result 290 } 291 } 292 return {} 293} 294 295# Loads the password file. Note that as this file is tcl, and that 296# it is sourced, the user better know what to put in there, as it 297# could install more than just password info... I will assume however, 298# that a "bad guy" could just as easy put such code in the clogin 299# script, so I will leave .cloginrc as just an extention of that script 300proc source_password_file {file} { 301 global env int_file int_lineno 302 if {! [file exists $file]} { 303 send_user "\nError: password file ($file) does not exist\n" 304 exit 1 305 } 306 file stat $file fileinfo 307 if {[expr ($fileinfo(mode) & 007)] != 0000} { 308 send_user "\nError: $file must not be world readable/writable\n" 309 exit 1 310 } 311 if [catch {set fd [open $file "r"]} reason] { 312 send_user "\nError: $reason\n" 313 exit 1 314 } 315 set int_file [linsert $int_file 0 $file] 316 set int_lineno [linsert $int_lineno 0 0] 317 while {[gets $fd line] >= 0} { 318 set tmp [lindex $int_lineno 0]; incr tmp 319 lset int_lineno 0 $tmp 320 eval $line 321 } 322 set int_file [lrange $int_file 1 end] 323 set int_lineno [lrange $int_lineno 1 end] 324 close $fd 325} 326 327# Log into the router. 328# returns: 0 on success, 1 on failure, -1 if rsh was used successfully 329proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } { 330 global command spawn_id in_proc do_command do_script passphrase 331 global platform prompt u_prompt p_prompt sshcmd telnetcmd 332 set in_proc 1 333 set uprompt_seen 0 334 335 # try each of the connection methods in $cmethod until one is successful 336 set progs [llength $cmethod] 337 foreach prog [lrange $cmethod 0 end] { 338 incr progs -1 339 if [string match "telnet*" $prog] { 340 regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port 341 if {"$port" == ""} { 342 set retval [catch {eval spawn [split "$telnetcmd $router"]} reason] 343 } else { 344 set retval [catch {eval spawn [split "$telnetcmd $router $port"]} reason] 345 } 346 if { $retval } { 347 send_user "\nError: telnet failed: $reason\n" 348 return 1 349 } 350 } elseif [string match "ssh*" $prog] { 351 # ssh to the router & try to login with or without an identfile. 352 regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port 353 set cmd $sshcmd 354 if {"$port" != ""} { 355 set cmd "$cmd -p $port" 356 } 357 if {"$cyphertype" != ""} { 358 set cmd "$cmd -c $cyphertype" 359 } 360 if {"$identfile" != ""} { 361 set cmd "$cmd -i $identfile" 362 } 363 set retval [catch {eval spawn [split "$cmd -x -l $user $router" { }]} reason] 364 if { $retval } { 365 send_user "\nError: $cmd failed: $reason\n" 366 return 1 367 } 368 } elseif ![string compare $prog "rsh"] { 369 if { ! $do_command } { 370 if { [llength $cmethod] == 1 } { 371 send_user "\nError: rsh is an invalid method for -x and " 372 send_user "interactive logins\n" 373 } 374 if { $progs == 0 } { 375 return 1 376 } 377 continue; 378 } 379 380 # handle escaped ;s in commands, and ;; and ^; 381 regsub -all {([^\\]);} $command "\\1\u0002;" esccommand 382 regsub -all {([^\\]);;} $esccommand "\\1;\u0002;" command 383 regsub {^;} $command "\u0002;" esccommand 384 regsub -all {[\\];} $esccommand ";" command 385 regsub -all {\u0002;} $command "\u0002" esccommand 386 set sep "\u0002" 387 set commands [split $esccommand $sep] 388 set num_commands [llength $commands] 389 set rshfail 0 390 for {set i 0} {$i < $num_commands && !$rshfail} { incr i} { 391 log_user 0 392 set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason] 393 if { $retval } { 394 send_user "\nError: rsh failed: $reason\n" 395 log_user 1; return 1 396 } 397 send_user "$router# [lindex $commands $i]\n" 398 399 # rcmd does not get a pager and no prompts, so we just have to 400 # look for failures & lines. 401 expect { 402 "Connection refused" { catch {close}; catch {wait}; 403 send_user "\nError: Connection\ 404 Refused ($prog): $router\n" 405 set rshfail 1 406 } 407 -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { 408 catch {close}; catch {wait}; 409 send_user "\nError: Connection\ 410 closed ($prog): $router\n" 411 set rshfail 1 412 } 413 "Host is unreachable" { catch {close}; catch {wait}; 414 send_user "\nError: Host Unreachable:\ 415 $router\n" 416 set rshfail 1 417 } 418 "No address associated with" { 419 catch {close}; catch {wait}; 420 send_user "\nError: Unknown host\ 421 $router\n" 422 set rshfail 1 423 } 424 -re "\b+" { exp_continue } 425 -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" 426 exp_continue 427 } 428 timeout { catch {close}; catch {wait}; 429 send_user "\nError: TIMEOUT reached\n" 430 set rshfail 1 431 } 432 eof { catch {close}; catch {wait}; } 433 } 434 log_user 1 435 } 436 if { $rshfail } { 437 if { !$progs } { 438 return 1 439 } else { 440 continue 441 } 442 } 443 # fake the end of the session for rancid. 444 send_user "$router# exit\n" 445 # return rsh "success" 446 return -1 447 } else { 448 send_user "\nError: unknown connection method: $prog\n" 449 return 1 450 } 451 sleep 0.3 452 453 # This helps cleanup each expect clause. 454 expect_after { 455 timeout { 456 global in_proc 457 send_user "\nError: TIMEOUT reached\n" 458 catch {close}; catch {wait}; 459 if {$in_proc} { 460 return 1 461 } else { 462 continue 463 } 464 } eof { 465 global in_proc 466 send_user "\nError: EOF received\n" 467 catch {close}; catch {wait}; 468 if {$in_proc} { 469 return 1 470 } else { 471 continue 472 } 473 } 474 } 475 476 # Here we get a little tricky. There are several possibilities: 477 # the router can ask for a username and passwd and then 478 # talk to the TACACS server to authenticate you, or if the 479 # TACACS server is not working, then it will use the enable 480 # passwd. Or, the router might not have TACACS turned on, 481 # then it will just send the passwd. 482 # if telnet fails with connection refused, try ssh 483 expect { 484 -re "(Connection refused|Secure connection \[^\n\r]+ refused)" { 485 catch {close}; catch {wait}; 486 if !$progs { 487 send_user "\nError: Connection Refused ($prog): $router\n" 488 return 1 489 } 490 } 491 -re "(Connection closed by|Connection to \[^\n\r]+ closed)" { 492 catch {close}; catch {wait}; 493 if !$progs { 494 send_user "\nError: Connection closed ($prog): $router\n" 495 return 1 496 } 497 } 498 eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 } 499 -nocase "unknown host\r" { 500 send_user "\nError: Unknown host $router\n"; 501 catch {close}; catch {wait}; 502 return 1 503 } 504 "Host is unreachable" { 505 send_user "\nError: Host Unreachable: $router\n"; 506 catch {close}; catch {wait}; 507 return 1 508 } 509 "No address associated with name" { 510 send_user "\nError: Unknown host $router\n"; 511 catch {close}; catch {wait}; 512 return 1 513 } 514 -re "(Host key not found |The authenticity of host .* be established)" { 515 expect { 516 -re "\\(yes\/no\[^\\)]*\\)\\?" { 517 send "yes\r"; 518 send_user "\nHost $router added to the list of known hosts.\n" 519 } 520 -re "\[^\r\n]*\[\r\n]+" { exp_continue; } 521 } 522 exp_continue 523 } 524 -re "HOST IDENTIFICATION HAS CHANGED" { 525 send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" 526 expect { 527 -re "\\(yes\/no\\)\\?" { send "no\r" } 528 -re " strict checking\.\[\r\n]+" { } 529 -re "\[^\r\n]*\[\r\n]+" { exp_continue; } 530 } 531 catch {close}; catch {wait}; 532 return 1 533 } 534 -re "Offending key for " { 535 send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" 536 expect { 537 -re "\\(yes\/no\\)\\?" { send "no\r" } 538 -re "\[^\r\n]*\[\r\n]+" { exp_continue; } 539 } 540 catch {close}; catch {wait}; 541 return 1 542 } 543 -nocase -re "^warning: remote host denied authentication agent forwarding." { 544 exp_continue; 545 } 546 -nocase -re "^warning:" { exp_continue } 547 -re "(denied|Sorry)" { 548 send_user "\nError: Check your passwd for $router\n" 549 catch {close}; catch {wait}; return 1 550 } 551 "Login failed" { 552 send_user "\nError: Check your passwd for $router\n" 553 catch {close}; catch {wait}; return 1 554 } 555 -re "% (Bad passwords|Authentication failed)" { 556 send_user "\nError: Check your passwd for $router\n" 557 catch {close}; catch {wait}; return 1 558 } 559 "Press any key to continue" { 560 # send_user "Pressing the ANY key\n" 561 send "\r" 562 exp_continue 563 } 564 -re "Enter Selection: " { 565 # Catalyst 1900s have some lame menu. Enter 566 # K to reach a command-line. 567 send "K\r" 568 exp_continue 569 } 570 -nocase -re "(Welcome to ARCOS CLI|Linux arcos \[^\r\n]*)\[\r\n]+" { 571 set platform "arcos" 572 exp_continue 573 } 574 -re "Last login:\[^\r\n]*\[\r\n]+" { 575 exp_continue 576 } 577 -re "@\[^\r\n]+ $p_prompt" { 578 # ssh pwd prompt 579 sleep 1 580 send -- "$userpswd\r" 581 exp_continue 582 } 583 -re "Enter passphrase.*: " { 584 # sleep briefly to allow time for stty -echo 585 sleep .3 586 send -- "$passphrase\r" 587 exp_continue 588 } 589 -re "$u_prompt" { 590 send -- "$user\r" 591 set uprompt_seen 1 592 exp_continue 593 } 594 -re "$p_prompt" { 595 sleep 1 596 if {$uprompt_seen == 1} { 597 send -- "$userpswd\r" 598 } else { 599 send -- "$passwd\r" 600 } 601 exp_continue 602 } 603 -re "$prompt" { break; } 604 "Login invalid" { 605 send_user "\nError: Invalid login: $router\n"; 606 catch {close}; catch {wait}; return 1 607 } 608 -re "\[^\r\n]*\[\r\n]+" { exp_continue; } 609 } 610 } 611 612 set in_proc 0 613 return 0 614} 615 616# New subroutine to provide "login" command capabilities, using the enable user and enable password 617# Login 618proc do_login { enauser enapasswd } { 619 global prompt in_proc 620 global u_prompt 621 set in_proc 1 622 623 send "login\r" 624 expect { 625 -re "$u_prompt" { send "$enauser\r"; exp_continue} 626 "#" { set prompt "#" } 627 "(login)" { set prompt "> (login) " } 628 -re "(denied|Sorry|Incorrect)" { 629 # % Access denied - from local auth and poss. others 630 send_user "\nError: Check your Login passwd\n"; 631 return 1 632 } 633 "% Error in authentication" { 634 send_user "\nError: Check your Login passwd\n" 635 return 1 636 } 637 "% Bad passwords" { 638 send_user "\nError: Check your Login passwd\n" 639 return 1 640 } 641 } 642 # We set the prompt variable (above) so script files don't need 643 # to know what it is. 644 set in_proc 0 645 return 0 646} 647 648# Run commands given on the command line. 649proc run_commands { prompt command } { 650 global do_interact do_saveconfig in_proc 651 set in_proc 1 652 653 # Disable paging 654 send "\r" 655 # escape any parens in the prompt, such as "(enable)" 656 regsub -all {[)(]} $prompt {\\&} reprompt 657 expect { 658 -re $reprompt {} 659 -re "\[\n\r]+" { exp_continue } 660 } 661 662 # this is the only way i see to get rid of more prompts in o/p..grrrrr 663 log_user 0 664 665 # handle escaped ;s in commands, and ;; and ^; 666 regsub -all {([^\\]);} $command "\\1\u0002;" esccommand 667 regsub -all {([^\\]);;} $esccommand "\\1;\u0002;" command 668 regsub {^;} $command "\u0002;" esccommand 669 regsub -all {[\\];} $esccommand ";" command 670 regsub -all {\u0002;} $command "\u0002" esccommand 671 set sep "\u0002" 672 set commands [split $esccommand $sep] 673 set num_commands [llength $commands] 674 # the pager can not be turned off on the PIX, so we have to look 675 # for the "More" prompt. the extreme is equally obnoxious, with a 676 # global switch in the config. 677 for {set i 0} {$i < $num_commands} { incr i} { 678 send -- "[subst -nocommands [lindex $commands $i]]\r" 679 expect { 680 -re "\b+" { exp_continue } 681 -re "^\[^\n\r *]*$reprompt" { send_user -- "$expect_out(buffer)" 682 } 683 -re "^\[^\n\r]*$reprompt." { send_user -- "$expect_out(buffer)" 684 exp_continue 685 } 686 -re "^--MORE--\[\r\n]+" { # match Xirrus pager 687 send " " 688 exp_continue 689 } 690 -re "\[\n\r]+" { send_user -- "$expect_out(buffer)" 691 exp_continue 692 } 693 } 694 } 695 log_user 1 696 697 if { $do_interact == 1 } { 698 interact 699 return 0 700 } 701 702 send -h "quit\r" 703 expect { 704 "Do you want to save changes to flash" { # Xirrus 705 if {$do_saveconfig} { 706 catch {send "y\r"} 707 } else { 708 catch {send "n\r"} 709 } 710 exp_continue 711 } 712 -re "\[\n\r]+" { exp_continue } 713 timeout { catch {close}; catch {wait}; 714 return 0 715 } 716 eof { return 0 } 717 } 718 set in_proc 0 719} 720 721# 722# For each router... (this is main loop) 723# 724source_password_file $password_file 725set in_proc 0 726set exitval 0 727set platform "unknown" 728foreach router [lrange $argv $i end] { 729 set router [string tolower $router] 730 send_user -- "$router\n" 731 732 # device timeout 733 set timeout [find timeout $router] 734 if { [llength $timeout] == 0 } { 735 set timeout $timeoutdflt 736 } 737 738 # Default prompt. 739 set prompt "(>|#)" 740 741 # Figure out passwords 742 if { $do_passwd || $do_enapasswd } { 743 set pswd [find password $router] 744 if { [llength $pswd] == 0 } { 745 send_user -- "\nError: no password for $router in $password_file.\n" 746 continue 747 } 748 if { $do_passwd } { 749 set passwd [join [lindex $pswd 0] ""] 750 } else { 751 set passwd $userpasswd 752 } 753 if { $do_enapasswd } { 754 set enapasswd [join [lindex $pswd 1] ""] 755 } else { 756 set enapasswd $enapasswd 757 } 758 } else { 759 set passwd $userpasswd 760 set enapasswd $enapasswd 761 } 762 763 # Figure out username 764 if {[info exists username]} { 765 # command line username 766 set ruser $username 767 } else { 768 set ruser [join [find user $router] ""] 769 if { "$ruser" == "" } { set ruser $default_user } 770 } 771 772 # Figure out username's password (if different from the vty password) 773 if {[info exists userpasswd]} { 774 # command line username 775 set userpswd $userpasswd 776 } else { 777 set userpswd [join [find userpassword $router] ""] 778 if { "$userpswd" == "" } { set userpswd $passwd } 779 } 780 781 # Figure out prompts 782 set u_prompt [find userprompt $router] 783 if { "$u_prompt" == "" } { 784 set u_prompt "(Username|Login|login|user name|User):" 785 } else { 786 set u_prompt [join [lindex $u_prompt 0] ""] 787 } 788 set p_prompt [find passprompt $router] 789 if { "$p_prompt" == "" } { 790 set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):" 791 } else { 792 set p_prompt [join [lindex $p_prompt 0] ""] 793 } 794 795 # Figure out identity file to use 796 set identfile [join [lindex [find identity $router] 0] ""] 797 798 # Figure out passphrase to use 799 if {[info exists avpassphrase]} { 800 set passphrase $avpassphrase 801 } else { 802 set passphrase [join [lindex [find passphrase $router] 0] ""] 803 } 804 if { ! [string length "$passphrase"]} { 805 set passphrase $passwd 806 } 807 808 # Figure out cypher type 809 if {[info exists cypher]} { 810 # command line cypher type 811 set cyphertype $cypher 812 } else { 813 set cyphertype [find cyphertype $router] 814 } 815 816 # Figure out connection method 817 set cmethod [find method $router] 818 if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } 819 820 # Figure out the SSH executable name 821 set sshcmd [join [lindex [find sshcmd $router] 0] ""] 822 if { "$sshcmd" == "" } { set sshcmd {ssh} } 823 824 # Figure out the telnet executable name 825 set telnetcmd [join [lindex [find telnetcmd $router] 0] ""] 826 if { "$telnetcmd" == "" } { set telnetcmd "@TELNET_CMD@" } 827 828 # if [-mM], skip do not login 829 if { $do_cloginrcdbg > 0 } { continue; } 830 831 # Login to the router 832 if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} { 833 incr exitval 834 # if login failed or rsh was unsuccessful, move on to the next device 835 continue 836 } 837 838 # we are logged in, now figure out the full prompt 839 send "\r" 840 expect { 841 -re "\[\r\n]+" { exp_continue; } 842 -re "^.+$prompt" { set junk $expect_out(0,string); 843 regsub -all "\[\]\[\(\)]" $junk {\\&} prompt; 844 } 845 } 846 if { $do_command || $do_script } { 847 if { "$platform" == "arcos" } { 848 # Arrcus paging 849 send "screen-length 0\r" 850 expect -re $prompt {} 851 send "screen-width 132\r" 852 expect -re $prompt {} 853 } else { 854 # Hauwei paging 855 send "screen-length 0 temporary\r" 856 expect -re $prompt {} 857 # Disable paging 858 send "more off\r" 859 expect -re $prompt {} 860 # Disable command auto-completion on Xirus 861 send "auto-complete off \r" 862 expect { 863 -re $prompt {} 864 -re "\[\n\r]+" { exp_continue } 865 } 866 } 867 } 868 if { $do_command } { 869 if {[run_commands $prompt $command]} { 870 incr exitval 871 continue 872 } 873 } elseif { $do_script } { 874 source $sfile 875 catch {close}; 876 } else { 877 label $router 878 log_user 1 879 interact 880 } 881 882 # End of for each router 883 catch {wait}; 884 sleep 0.3 885} 886exit $exitval 887