1#! @EXPECT_PATH@ --
2##
3## @PACKAGE@ @VERSION@
4@copyright@
5#
6# clogin - Cisco login
7#
8# Most options are intuitive for logging into a Cisco router.
9# The default is to enable (thus -noenable).  Some folks have
10# setup tacacs to have a user login at priv-lvl = 15 (enabled)
11# so the -autoenable flag was added for this case (don't go through
12# the process of enabling and the prompt will be the "#" prompt.
13# The default username password is the same as the vty password.
14#
15
16# Sometimes routers take awhile to answer (the default is 10 sec)
17set timeoutdflt 45
18# Some CLIs having problems if we write too fast (Extreme, PIX, Cat)
19set send_human {.2 .1 .4 .2 1}
20
21@login_top@
22
23# Log into the router.
24# returns: 0 on success, 1 on failure, -1 if rsh was used successfully
25proc login { router user userpswd passwd enapasswd cmethod cyphertype identfile } {
26    global command spawn_id in_proc do_command do_script platform passphrase
27    global prompt prompt_match u_prompt p_prompt e_prompt sshcmd telnetcmd
28    set in_proc 1
29    set uprompt_seen 0
30
31    # try each of the connection methods in $cmethod until one is successful
32    set progs [llength $cmethod]
33    foreach prog [lrange $cmethod 0 end] {
34	incr progs -1
35	if [string match "telnet*" $prog] {
36	    regexp {telnet(:([^[:space:]]+))*} $prog methcmd suffix port
37	    if {"$port" == ""} {
38		set retval [catch {eval spawn [split "$telnetcmd $router"]} reason]
39	    } else {
40		set retval [catch {eval spawn [split "$telnetcmd $router $port"]} reason]
41	    }
42	    if { $retval } {
43		send_user "\nError: telnet failed: $reason\n"
44		return 1
45	    }
46	} elseif [string match "ssh*" $prog] {
47	    # ssh to the router & try to login with or without an identfile.
48	    regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
49	    set cmd $sshcmd
50	    if {"$port" != ""} {
51		set cmd "$cmd -p $port"
52	    }
53	    if {"$cyphertype" != ""} {
54		set cmd "$cmd -c $cyphertype"
55	    }
56	    if {"$identfile" != ""} {
57		set cmd "$cmd -i $identfile"
58	    }
59	    set retval [catch {eval spawn [split "$cmd -x -l $user $router" { }]} reason]
60	    if { $retval } {
61		send_user "\nError: $cmd failed: $reason\n"
62		return 1
63	    }
64	} elseif ![string compare $prog "rsh"] {
65	    if { ! $do_command } {
66		if { [llength $cmethod] == 1 } {
67		    send_user "\nError: rsh is an invalid method for -x and "
68		    send_user "interactive logins\n"
69		}
70		if { $progs == 0 } {
71		    return 1
72		}
73		continue;
74	    }
75
76	    # handle escaped ;s in commands, and ;; and ^;
77	    regsub -all {([^\\]);} $command "\\1\u0002;" esccommand
78	    regsub -all {([^\\]);;} $esccommand "\\1;\u0002;" command
79	    regsub {^;} $command "\u0002;" esccommand
80	    regsub -all {[\\];} $esccommand ";" command
81	    regsub -all {\u0002;} $command "\u0002" esccommand
82	    set sep "\u0002;"
83	    set commands [split $esccommand $sep]
84	    set num_commands [llength $commands]
85	    set rshfail 0
86	    for {set i 0} {$i < $num_commands && !$rshfail} { incr i} {
87		log_user 0
88		set retval [catch {spawn rsh $user@$router [lindex $commands $i] } reason]
89		if { $retval } {
90		    send_user "\nError: rsh failed: $reason\n"
91		    log_user 1; return 1
92		}
93		send_user "$router# [lindex $commands $i]\n"
94
95		# rcmd does not get a pager and no prompts, so we just have to
96		# look for failures & lines.
97		expect {
98		  "Connection refused"	{ catch {close}; catch {wait};
99					  send_user "\nError: Connection\
100						    Refused ($prog): $router\n"
101					  set rshfail 1
102					}
103		  -re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
104					  catch {close}; catch {wait};
105					  send_user "\nError: Connection\
106						    closed ($prog): $router\n"
107					  set rshfail 1
108					}
109		  "Host is unreachable"	{ catch {close}; catch {wait};
110					  send_user "\nError: Host Unreachable:\
111						    $router\n"
112					  set rshfail 1
113					}
114		  "No address associated with" {
115					  catch {close}; catch {wait};
116					  send_user "\nError: Unknown host\
117						    $router\n"
118					  set rshfail 1
119					}
120		  -re "\b+"		{ exp_continue }
121		  -re "\[\n\r]+"	{ send_user -- "$expect_out(buffer)"
122					  exp_continue
123					}
124		  timeout		{ catch {close}; catch {wait};
125					  send_user "\nError: TIMEOUT reached\n"
126					  set rshfail 1
127					}
128		  eof			{ catch {close}; catch {wait}; }
129		}
130		log_user 1
131	    }
132	    if { $rshfail } {
133		if { !$progs } {
134		    return 1
135		} else {
136		    continue
137		}
138	    }
139	    # fake the end of the session for rancid.
140	    send_user "$router# exit\n"
141	    # return rsh "success"
142	    return -1
143	} else {
144	    send_user "\nError: unknown connection method: $prog\n"
145	    return 1
146	}
147	sleep 0.3
148
149	# This helps cleanup each expect clause.
150	expect_after {
151	    timeout {
152		global in_proc
153		send_user "\nError: TIMEOUT reached\n"
154		catch {close}; catch {wait};
155		if {$in_proc} {
156		    return 1
157		} else {
158		    continue
159		}
160	    } eof {
161		global in_proc
162		send_user "\nError: EOF received\n"
163		catch {close}; catch {wait};
164		if {$in_proc} {
165		    return 1
166		} else {
167		    continue
168		}
169	    }
170	}
171
172    # Here we get a little tricky.  There are several possibilities:
173    # the router can ask for a username and passwd and then
174    # talk to the TACACS server to authenticate you, or if the
175    # TACACS server is not working, then it will use the enable
176    # passwd.  Or, the router might not have TACACS turned on,
177    # then it will just send the passwd.
178    # if telnet fails with connection refused, try ssh
179    expect {
180	-re "^<-+ More -+>\[^\n\r]*" {
181	    # ASA will use the pager for long banners
182	    send " ";
183	    exp_continue
184	}
185	-re "(Connection refused|Secure connection \[^\n\r]+ refused)" {
186	    catch {close}; catch {wait};
187	    if !$progs {
188		send_user "\nError: Connection Refused ($prog): $router\n"
189		return 1
190	    }
191	}
192	-re "(Connection closed by|Connection to \[^\n\r]+ closed)" {
193	    catch {close}; catch {wait};
194	    if !$progs {
195		send_user "\nError: Connection closed ($prog): $router\n"
196		return 1
197	    }
198	}
199	eof { send_user "\nError: Couldn't login: $router\n"; wait; return 1 }
200	-nocase "unknown host\r" {
201	    send_user "\nError: Unknown host $router\n";
202	    catch {close}; catch {wait};
203	    return 1
204	}
205	"Host is unreachable" {
206	    send_user "\nError: Host Unreachable: $router\n";
207	    catch {close}; catch {wait};
208	    return 1
209	}
210	"No address associated with name" {
211	    send_user "\nError: Unknown host $router\n";
212	    catch {close}; catch {wait};
213	    return 1
214	}
215	-re "(Host key not found |The authenticity of host .* be established)" {
216	    expect {
217		-re "\\(yes\/no\[^\\)]*\\)\\?" {
218					  send "yes\r";
219					  send_user "\nHost $router added to the list of known hosts.\n"
220					 }
221		-re "\[^\r\n]*\[\r\n]+"	{ exp_continue; }
222	    }
223	    exp_continue
224	}
225	-re "HOST IDENTIFICATION HAS CHANGED" {
226	    send_user "\nError: The host key for $router has changed.  Update the SSH known_hosts file accordingly.\n"
227	    expect {
228		-re "\\(yes\/no\\)\\?"	{ send "no\r" }
229		-re " strict checking\.\[\r\n]+" { }
230		-re "\[^\r\n]*\[\r\n]+"	{ exp_continue; }
231	    }
232	    catch {close}; catch {wait};
233	    return 1
234	}
235	-re "Offending key for " {
236	    send_user "\nError: host key mismatch for $router.  Update the SSH known_hosts file accordingly.\n"
237	    expect {
238		-re "\\(yes\/no\\)\\?"	{ send "no\r" }
239		-re "\[^\r\n]*\[\r\n]+"	{ exp_continue; }
240	    }
241	    catch {close}; catch {wait};
242	    return 1
243	}
244	-nocase -re "^warning: remote host denied authentication agent forwarding." {
245	    exp_continue;
246	}
247	-re "(denied|Sorry)"	{
248				  send_user "\nError: Check your passwd for $router\n"
249				  catch {close}; catch {wait}; return 1
250				}
251	-nocase -re "last login:"	{
252				  exp_continue
253				}
254	-nocase -re "failed login:"	{
255				  exp_continue
256				}
257	"Login failed"		{
258				  send_user "\nError: Check your passwd for $router\n"
259				  catch {close}; catch {wait}; return 1
260				}
261	-re "% (Bad passwords|Authentication failed)"	{
262				  send_user "\nError: Check your passwd for $router\n"
263				  catch {close}; catch {wait}; return 1
264				}
265	"Press any key to continue" {
266				  # send_user "Pressing the ANY key\n"
267				  send "\r"
268				  exp_continue
269				}
270	-re "Enter Selection: " {
271				  # Catalyst 1900s have some lame menu.  Enter
272				  # K to reach a command-line.
273				  send "K\r"
274				  exp_continue
275				}
276	-re "Press the <tab> key \[^\r\n]+\[\r\n]+"	{
277				  exp_continue
278				}
279	-re "@\[^\r\n]+ $p_prompt"	{
280				  # ssh pwd prompt
281				  sleep 1
282				  send -- "$userpswd\r"
283				  exp_continue
284				}
285	-re "Enter passphrase.*: " {
286				  # sleep briefly to allow time for stty -echo
287				  sleep .3
288				  send -- "$passphrase\r"
289				  exp_continue
290				}
291	-re "$u_prompt"		{
292				  send -- "$user\r"
293				  set uprompt_seen 1
294				  exp_continue
295				}
296	-re "$p_prompt"		{
297				  sleep 1
298				  if {$uprompt_seen == 1} {
299					send -- "$userpswd\r"
300				  } else {
301					send -- "$passwd\r"
302				  }
303				  exp_continue
304				}
305	-re "$prompt"		{
306				  set prompt_match $expect_out(0,string);
307				  break;
308				}
309	"Login invalid"		{
310				  send_user "\nError: Invalid login: $router\n";
311				  catch {close}; catch {wait}; return 1
312				}
313	-re "\[^\r\n]*\[\r\n]+"	{ exp_continue; }
314     }
315    }
316
317    set in_proc 0
318    return 0
319}
320
321# Enable
322proc do_enable { enauser enapasswd } {
323    global in_proc
324    global prompt u_prompt e_prompt enacmd
325    set in_proc 1
326
327    send "$enacmd\r"
328    expect {
329	-re "$u_prompt"	{ send -- "$enauser\r"; exp_continue}
330	-re "$e_prompt"	{ send -- "$enapasswd\r"; exp_continue}
331	"#"		{ set prompt "#" }
332	"(enable)"	{ set prompt "> \\(enable\\) " }
333	"% Invalid input" {
334			  send_user "\nError: Unrecognized command, check your enable command\n";
335			  return 1
336			}
337	-re "(denied|Sorry|Incorrect)"	{
338			  # % Access denied - from local auth and poss. others
339			  send_user "\nError: Check your Enable passwd\n";
340			  return 1
341			}
342	"% Error in authentication" {
343			  send_user "\nError: Check your Enable passwd\n"
344			  return 1
345			}
346	"% Bad passwords" {
347			  send_user "\nError: Check your Enable passwd\n"
348			  return 1
349			}
350    }
351    # We set the prompt variable (above) so script files don't need
352    # to know what it is.
353    set in_proc 0
354    return 0
355}
356
357# Run commands given on the command line.
358proc run_commands { prompt command } {
359    global do_interact do_saveconfig in_proc platform
360    set in_proc 1
361
362    if { [string compare "extreme" "$platform"] } {
363	# match cisco config mode prompts too, such as router(config-if)#
364	# and truncatedr(config-if)#.
365	# catalyst does not change in this fashion, but does have its
366	# abnormal format, router> (enable).
367	# first, drop the "> (enable) " from the catos prompt.
368	regsub -lineanchor -- {> *\\\(enable\\\) *} $prompt {} reprompt
369	regsub -lineanchor -- {^(.{1,11}).*([#>])$} $reprompt {\1} reprompt
370	regsub -all -- {[\\]$} $reprompt {} reprompt
371	append reprompt {([^#>\r\n]+)?[#>](\\([^)\\r\\n]+\\))?}
372    } else {
373	set reprompt $prompt
374    }
375
376    # this is the only way i see to get rid of more prompts in o/p..grrrrr
377    log_user 0
378
379    # handle escaped ;s in commands, and ;; and ^;
380    regsub -all {([^\\]);} $command "\\1\u0002;" esccommand
381    regsub -all {([^\\]);;} $esccommand "\\1;\u0002;" command
382    regsub {^;} $command "\u0002;" esccommand
383    regsub -all {[\\];} $esccommand ";" command
384    regsub -all {\u0002;} $command "\u0002" esccommand
385    set sep "\u0002"
386    set commands [split $esccommand $sep]
387    set num_commands [llength $commands]
388    # the pager can not be turned off on the PIX, so we have to look
389    # for the "More" prompt.  the extreme is equally obnoxious in pre-12.3 XOS,
390    # with a global switch in the config.
391    for {set i 0} {$i < $num_commands} { incr i} {
392	send -- "[subst -nocommands [lindex $commands $i]]\r"
393	expect {
394	    -re "^\b+"				{ exp_continue }
395	    -re "^\[^\n\r *]*$reprompt"		{ send_user -- "$expect_out(buffer)"
396						}
397	    -re "^\[^\n\r]*$reprompt."		{ send_user -- "$expect_out(buffer)"
398						  exp_continue
399						}
400	    -re "^--More--\[\r\n]+"		{ # specific match c1900 pager
401						  send " "
402						  exp_continue
403						}
404	    -re "\[^\r\n]*\[\n\r]+"		{ send_user -- "$expect_out(buffer)"
405						  exp_continue
406						}
407	    # respond to prompt from "file prompt noisy" config
408	    -nocase -re "^display filename \\\[\[^]]*]\\?" 	{
409						  send "\r"
410						  exp_continue
411						}
412	    -re "\[^\r\n]*Press <SPACE> to cont\[^\r\n]*"	{
413						  send " "
414						  # bloody ^[[2K after " "
415						  expect {
416							-re "^\[^\r\n]*\r" {}
417							}
418						  exp_continue
419						}
420	    -re "^ *--More--\[^\n\r]*"		{
421						  send " "
422						  exp_continue }
423	    -re "^<-+ More -+>\[^\n\r]*"	{
424						  send_user -- "$expect_out(buffer)"
425						  send " "
426						  exp_continue }
427	}
428    }
429    log_user 1
430
431    if { $do_interact == 1 } {
432	interact
433	return 0
434    }
435
436    if { [string compare "extreme" "$platform"] } {
437	send -h "exit\r"
438    } else {
439	send -h "quit\r"
440    }
441    expect {
442	-re "^\[^\n\r *]*$reprompt"		{
443						  # the Cisco CE and Jnx ERX
444						  # return to non-enabled mode
445						  # on exit in enabled mode.
446						  send -h "exit\r"
447						  exp_continue;
448						}
449	-re "^\[^\n\r *]*Use .quit. to end"	{
450						  # the F5 >=11 uses quit
451						  send -h "quit\r"
452						  exp_continue;
453						}
454	"The system has unsaved changes"	{ # Force10 SFTOS
455						  if {$do_saveconfig} {
456						    catch {send "y\r"}
457						  } else {
458						    catch {send "n\r"}
459						  }
460						  exp_continue
461						}
462	"Would you like to save them now"	{ # Force10
463						  if {$do_saveconfig} {
464						    catch {send "y\r"}
465						  } else {
466						    catch {send "n\r"}
467						  }
468						  exp_continue
469						}
470	-re "(Profile|Configuration) changes have occurred.*"	{
471						  # Cisco CSS
472						  if {$do_saveconfig} {
473						    catch {send "y\r"}
474						  } else {
475						    catch {send "n\r"}
476						  }
477						  exp_continue
478						}
479	"Do you wish to save your configuration changes" {
480						  if {$do_saveconfig} {
481						    catch {send "y\r"}
482						  } else {
483						    catch {send "n\r"}
484						  }
485						  exp_continue
486						}
487	-re "\[\n\r]+"				{ exp_continue }
488	timeout					{ catch {close}; catch {wait};
489						  return 1
490						}
491	eof					{ return 0 }
492    }
493    set in_proc 0
494}
495
496#
497# For each router... (this is main loop)
498#
499source_password_file $password_file
500set in_proc 0
501set exitval 0
502set prompt_match ""
503# if we have dont have a tty, we need some additional terminal settings
504if [catch {open /dev/tty w} ttyid] {
505    # no tty, ie: cron
506    set spawnopts "-nottycopy"
507    set stty_init "cols 132"
508} else {
509    catch {close ttyid} reason
510}
511foreach router [lrange $argv $i end] {
512    set router [string tolower $router]
513    # attempt at platform switching.
514    set platform ""
515    send_user -- "$router\n"
516
517    # device timeout
518    set timeout [find timeout $router]
519    if { [llength $timeout] == 0 } {
520	set timeout $timeoutdflt
521    }
522
523    # Default prompt.
524    set prompt [join [find prompt $router] ""]
525    if { [llength $prompt] == 0 } {
526	set prompt "(>|#| \\(enable\\))"
527    }
528
529    # look for autoenable option in .cloginrc & cmd-line
530    set ae [find autoenable $router]
531    if { "$ae" == "1" || $avautoenable } {
532	set autoenable 1
533    } else {
534	set autoenable 0
535    }
536    # look for enable options in .cloginrc & cmd-line
537    if { $avenable == 0 } {
538	set enable 0
539    } else {
540	set ne [find noenable $router]
541	if { "$ne" == "1" || "$autoenable" == "1" } {
542	    set enable 0
543	} else {
544	    set enable 1
545	}
546    }
547
548    # Figure out passwords
549    if { $do_passwd || $do_enapasswd } {
550	set pswd [find password $router]
551	if { [llength $pswd] == 0 } {
552	    send_user -- "\nError: no password for $router in $password_file.\n"
553	    continue
554	}
555	if { $enable && $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } {
556	    send_user -- "\nError: no enable password for $router in $password_file.\n"
557	    continue
558	}
559	if { $do_passwd } {
560	    set passwd [join [lindex $pswd 0] ""]
561	} else {
562	    set passwd $userpasswd
563	}
564	if { $do_enapasswd } {
565	    set enapasswd [join [lindex $pswd 1] ""]
566	} else {
567	    set enapasswd $enapasswd
568	}
569    } else {
570	set passwd $userpasswd
571	set enapasswd $enapasswd
572    }
573
574    # Figure out username
575    if {[info exists username]} {
576      # command line username
577      set ruser $username
578    } else {
579      set ruser [join [find user $router] ""]
580      if { "$ruser" == "" } { set ruser $default_user }
581    }
582
583    # Figure out username's password (if different from the vty password)
584    if {[info exists userpasswd]} {
585      # command line username
586      set userpswd $userpasswd
587    } else {
588      set userpswd [join [find userpassword $router] ""]
589      if { "$userpswd" == "" } { set userpswd $passwd }
590    }
591
592    # Figure out enable username
593    if {[info exists enausername]} {
594      # command line enausername
595      set enauser $enausername
596    } else {
597      set enauser [join [find enauser $router] ""]
598      if { "$enauser" == "" } { set enauser $ruser }
599    }
600
601    # Figure out enable command
602    set enacmd [join [find enablecmd $router] ""]
603    if { "$enacmd" == "" } { set enacmd "enable" }
604
605    # Figure out prompts
606    set u_prompt [find userprompt $router]
607    if { "$u_prompt" == "" } {
608	set u_prompt "(\[Uu]sername|\[Ll]ogin|\[Uu]ser \[Nn]ame|User):"
609    } else {
610	set u_prompt [join [lindex $u_prompt 0] ""]
611    }
612    set p_prompt [find passprompt $router]
613    if { "$p_prompt" == "" } {
614	set p_prompt "(\[Pp]assword|passwd|Enter password for \[^ :]+):"
615    } else {
616	set p_prompt [join [lindex $p_prompt 0] ""]
617    }
618    set e_prompt [find enableprompt $router]
619    if { "$e_prompt" == "" } {
620	set e_prompt "\[Pp]assword:"
621    } else {
622	set e_prompt [join [lindex $e_prompt 0] ""]
623    }
624
625    # Figure out identity file to use
626    set identfile [join [lindex [find identity $router] 0] ""]
627
628    # Figure out passphrase to use
629    if {[info exists avpassphrase]} {
630	set passphrase $avpassphrase
631    } else {
632	set passphrase [join [lindex [find passphrase $router] 0] ""]
633    }
634    if { ! [string length "$passphrase"]} {
635	set passphrase $passwd
636    }
637
638    # Figure out cypher type
639    if {[info exists cypher]} {
640        # command line cypher type
641        set cyphertype $cypher
642    } else {
643        set cyphertype [find cyphertype $router]
644    }
645
646    # Figure out connection method
647    set cmethod [find method $router]
648    if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
649
650    # Figure out the SSH executable name
651    set sshcmd [join [lindex [find sshcmd $router] 0] ""]
652    if { "$sshcmd" == "" } { set sshcmd {ssh} }
653
654    # Figure out the telnet executable name
655    set telnetcmd [join [lindex [find telnetcmd $router] 0] ""]
656    if { "$telnetcmd" == "" } { set telnetcmd "@TELNET_CMD@" }
657
658    # if [-mM], skip do not login
659    if { $do_cloginrcdbg > 0 } { continue; }
660
661    # Login to the router
662    if {[login $router $ruser $userpswd $passwd $enapasswd $cmethod $cyphertype $identfile]} {
663	incr exitval
664	# if login failed or rsh was unsuccessful, move on to the next device
665	continue
666    }
667    # Figure out the prompt.
668    if { [regexp -- "(#| \\(enable\\))" $prompt_match junk] == 1 } {
669	set enable 0
670    }
671    if { $enable } {
672	if {[do_enable $enauser $enapasswd]} {
673	    if { $do_command || $do_script } {
674		incr exitval
675		catch {close}; catch {wait};
676		continue
677	    }
678	}
679    }
680    # we are logged in, now figure out the full prompt
681    send "\r"
682    regsub -all {^(\^*)(.*)} $prompt {\2} reprompt
683    expect {
684	-re "\[\r\n]+"		{ exp_continue; }
685	-re "^(.+\[:.])1 ($reprompt)" { # stoopid extreme cmd-line numbers and
686				  # prompt based on state of config changes,
687				  # which may have an * at the beginning.
688				  set junk $expect_out(1,string)
689				  regsub -all "^\\\* " $expect_out(1,string) {} junk
690				  regsub -all "\[\]\[\(\)]" $junk {\\&} junk;
691				  set prompt ".? ?$junk\[0-9]+ $expect_out(2,string)";
692				  set platform "extreme"
693				}
694	-re "^.+$reprompt"	{ set junk $expect_out(0,string);
695				  regsub -all "\[\]\[\(\)\*+]" $junk {\\&} prompt;
696				}
697    }
698    if { $do_command || $do_script } {
699	if { [string compare "extreme" "$platform"] } {
700	    # If the prompt is (enable), then we are on a cataylyst switch and
701	    # the command is "set length 0"; otherwise its "terminal length 0".
702	    if [regexp -- ".*> .*enable" "$prompt"] {
703		send "set length 0\r"
704		expect -re $prompt  	{}
705		send "set width 132\r"
706		expect -re $prompt	{}
707		send "set logging session disable\r"
708	    } else {
709		send "terminal length 0\r"
710		expect -re $prompt  	{}
711		send "terminal width 132\r"
712	    }
713	    expect -re $prompt		{}
714	} else {
715	    send "disable clipaging\r"
716	    expect -re $prompt		{}
717	}
718    }
719    if { $do_command } {
720	if {[run_commands $prompt $command]} {
721	    incr exitval
722	    continue
723	}
724    } elseif { $do_script } {
725	source $sfile
726	catch {close};
727    } else {
728	label $router
729	log_user 1
730	interact
731    }
732
733    # End of for each router
734    catch {wait};
735    sleep 0.3
736}
737exit $exitval
738