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