1#! @EXPECT_PATH@ --
2##
3## @PACKAGE@ @VERSION@
4@copyright@
5#
6# alogin - Alteon WebOS switch login
7#
8# afort@choqolat.org is responsible for this particular mess
9# (andrew fort)
10#
11
12# default timeout
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 prompt cmethod cyphertype } {
22    global spawn_id in_proc do_command do_script
23    global u_prompt p_prompt sshcmd telnetcmd
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 match "telnet*" $prog] {
32	    regexp {telnet(:([^[:space:]]+))*} $prog command suffix port
33	    if {"$port" == ""} {
34		set retval [ catch {eval spawn [split "$telnetcmd $router"]} reason ]
35	    } else {
36		set retval [ catch {eval spawn [split "$telnetcmd $router $port"]} reason ]
37	    }
38	    if { $retval } {
39		send_user "\nError: telnet failed: $reason\n"
40		return 1
41	    }
42	} elseif ![string compare $prog "ssh"] {
43	    regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port
44            set cmd $sshcmd
45            if {"$port" != ""} {
46                set cmd "$cmd -p $port"
47            }
48	    if {"$cyphertype" != ""} {
49		set cmd "$cmd -c $cyphertype"
50	    }
51	    set retval [ catch {eval spawn [split "$cmd -x -l $user $router" { }]} reason ]
52	    if { $retval } {
53		send_user "\nError: $cmd failed: $reason\n"
54		return 1
55	    }
56	} elseif ![string compare $prog "rsh"] {
57	    send_error "\nError: unsupported method: rsh\n"
58	    if { $progs == 0 } {
59		return 1
60	    }
61	    continue;
62	} else {
63            send_user "\nError: unknown connection method: $prog\n"
64            return 1
65	}
66        sleep 0.3
67
68    # This helps cleanup each expect clause.
69    expect_after {
70	timeout {
71	    global in_proc
72	    send_user "\nError: TIMEOUT reached\n"
73	    catch {close}; catch {wait};
74	    if {$in_proc} {
75		return 1
76	    } else {
77		continue
78	    }
79	} eof {
80	    global in_proc
81	    send_user "\nError: EOF received\n"
82	    catch {close}; catch {wait};
83	    if {$in_proc} {
84		return 1
85	    } else {
86		continue
87	    }
88	}
89    }
90
91    expect {
92	"Connection refused" {
93	  catch {close}; catch {wait};
94	  sleep 0.3
95	  catch {expect eof}
96	  send_user "\nError: Connection Refused\n";
97	  catch {wait};
98	  return 1
99	}
100	eof {
101	  send_user "\nError: Couldn't login\n";
102	  catch {wait};
103	  return 1
104	}
105	"Unknown host\r\n" {
106	  catch {expect eof}
107	  send_user "\nError: Unknown host\n";
108	  catch {wait};
109	  return 1
110	}
111	"Host is unreachable" {
112	  expect eof
113	  send_user "\nError: Host Unreachable!\n";
114	  catch {wait};
115	  return 1
116	}
117	"No address associated with name" {
118	  expect eof
119	  send_user "\nError: Unknown host\n";
120	  catch {wait};
121	  return 1
122	}
123	-re "(Host key not found |The authenticity of host .* be established)" {
124	    expect {
125		-re "\\(yes\/no\[^\\)]*\\)\\?" {
126					  send "yes\r";
127					  send_user "\nHost $router added to the list of known hosts.\n"
128					 }
129		-re "\[^\r\n]*\[\r\n]+"	{ exp_continue; }
130	    }
131	    exp_continue
132	}
133	-re "HOST IDENTIFICATION HAS CHANGED" {
134	    send_user "\nError: The host key for $router has changed.  Update the SSH known_hosts file accordingly.\n"
135	    expect {
136		-re "\\(yes\/no\\)\\?"	{ send "no\r" }
137		-re " strict checking\.\[\r\n]+" { }
138		-re "\[^\r\n]*\[\r\n]+"	{ exp_continue; }
139	    }
140	    catch {close}; catch {wait};
141	    return 1
142	}
143	-re "Offending key for " {
144	    send_user "\nError: host key mismatch for $router.  Update the SSH known_hosts file accordingly.\n"
145	    expect {
146		-re "\\(yes\/no\\)\\?"	{ send "no\r" }
147		-re "\[^\r\n]*\[\r\n]+"	{ exp_continue; }
148	    }
149	    catch {close}; catch {wait};
150	    return 1
151	}
152	-nocase -re "^warning: remote host denied authentication agent forwarding." {
153	    exp_continue;
154	}
155	-re "NOTICE:\[^\n\r]* - display now \[^\n\r]*:" {
156					  send "no\r"
157					  exp_continue
158					}
159	-re "$u_prompt"			{
160					  send -- "$user\r"
161					  set uprompt_seen 1
162					  exp_continue
163					}
164	-re "$p_prompt"			{
165					  sleep 1
166					  if {$uprompt_seen == 1} {
167						send -- "$userpswd\r"
168					  } else {
169						send -- "$passwd\r"
170					  }
171					  exp_continue
172					}
173	-re "^Confirm seeing above note" {
174					  send "y\r"
175					  exp_continue
176					}
177	-re "^Select Command Line Interface mode\[^:]*:" {
178					  send "ibmnos-cli\r"
179					  exp_continue
180					}
181	"Password incorrect"	{ send_user "\nError: Check your password for $router\n";
182				  catch {close}; catch {wait}; return 1 }
183	-re "$prompt"	{ break; }
184	-re "Warning: Remote host denied" {
185			  exp_continue
186			}
187	denied		{ send_user "\nError: Check your passwd for $router\n"
188			  catch {close}; catch {wait}; return 1
189			}
190	-re "\[^\r\n]*\[\r\n]+"		{ exp_continue; }
191    }
192  }
193    set in_proc 0
194    return 0
195}
196
197# Run commands given on the command line.
198proc run_commands { prompt command } {
199    global do_interact do_saveconfig in_proc cmethod
200    set in_proc 1
201
202    send "lines 0\r"
203    expect -re $prompt {}
204
205    regsub -all "\[)(]" $prompt {\\&} reprompt
206
207    # handle escaped ;s in commands, and ;; and ^;
208    regsub -all {([^\\]);} $command "\\1\u0002;" esccommand
209    regsub -all {([^\\]);;} $esccommand "\\1;\u0002;" command
210    regsub {^;} $command "\u0002;" esccommand
211    regsub -all {[\\];} $esccommand ";" command
212    regsub -all {\u0002;} $command "\u0002" esccommand
213    set sep "\u0002"
214    set commands [split $esccommand $sep]
215    set num_commands [llength $commands]
216    for {set i 0} {$i < $num_commands} { incr i} {
217	send -- "[subst -nocommands [lindex $commands $i]]\r"
218	expect {
219	    -re "^\[^\n\r]*$reprompt"		{}
220	    -re "^\[^\n\r ]*>>.*$reprompt"	{ exp_continue }
221	    -re "\[\n\r]+"			{ exp_continue }
222	    -re "Display private keys"		{
223						  if { "$cmethod" == "ssh" } {
224						    send "y\r"
225						  } else {
226						    send "n\r"
227						  }
228						  exp_continue
229						}
230	}
231    }
232
233    if { $do_interact == 1 } {
234	interact
235	return 0
236    }
237
238    send "exit\r"
239    expect {
240	-re "^WARNING: There are unsaved configuration changes." {
241						 if {$do_saveconfig} {
242						   catch {send "y\r"}
243						 } else {
244						   catch {send "n\r"}
245						 }
246						 exp_continue
247						}
248	-re "^Confirm Sync to Peer \[^:]*: "	{
249						 if {$do_saveconfig} {
250						   catch {send "y\r"}
251						 } else {
252						   catch {send "n\r"}
253						 }
254						 exp_continue
255						}
256	"\n"					{ exp_continue }
257	"\[^\n\r *]*Session terminated"		{ return 0 }
258	timeout					{ catch {close}; catch {wait};
259						  return 0
260						}
261	eof					{ return 0 }
262    }
263    set in_proc 0
264}
265
266#
267# For each router... (this is main loop)
268#
269source_password_file $password_file
270set in_proc 0
271set exitval 0
272foreach router [lrange $argv $i end] {
273    set router [string tolower $router]
274    send_user "$router\n"
275
276    # device timeout
277    set timeout [find timeout $router]
278    if { [llength $timeout] == 0 } {
279	set timeout $timeoutdflt
280    }
281
282    # Figure out prompt.
283    set prompt ">> \[^\r\n]*\[#|>] "
284    # alteon only "enables" based on the password used at login time
285    set autoenable 1
286    set enable 0
287
288    # Figure out passwords
289    if { $do_passwd } {
290	set pswd [find password $router]
291	if { [llength $pswd] == 0 } {
292	    send_user -- "\nError: no password for $router in $password_file.\n"
293	    continue
294	}
295	set passwd [join [lindex $pswd 0] ""]
296    }
297
298    # Figure out username
299    if {[info exists username]} {
300      # command line username
301      set ruser $username
302    } else {
303      set ruser [join [find user $router] ""]
304      if { "$ruser" == "" } { set ruser $default_user }
305    }
306
307    # Figure out username's password (if different from the vty password)
308    if {[info exists userpasswd]} {
309      # command line username
310      set userpswd $userpasswd
311    } else {
312      set userpswd [join [find userpassword $router] ""]
313      if { "$userpswd" == "" } { set userpswd $passwd }
314    }
315
316    # Figure out prompts
317    set u_prompt [find userprompt $router]
318    if { "$u_prompt" == "" } {
319	set u_prompt "(Username|login|  Login):"
320    } else {
321	set u_prompt [join [lindex $u_prompt 0] ""]
322    }
323    set p_prompt [find passprompt $router]
324    if { "$p_prompt" == "" } {
325	set p_prompt "\[Pp]assword:"
326    } else {
327	set p_prompt [join [lindex $p_prompt 0] ""]
328    }
329
330    # Figure out cypher type
331    if {[info exists cypher]} {
332      # command line cypher type
333      set cyphertype $cypher
334    } else {
335      set cyphertype [find cyphertype $router]
336    }
337
338    # Figure out connection method
339    set cmethod [find method $router]
340    if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
341
342    # Figure out the SSH executable name
343    set sshcmd [join [lindex [find sshcmd $router] 0] ""]
344    if { "$sshcmd" == "" } { set sshcmd {ssh} }
345
346    # Figure out the telnet executable name
347    set telnetcmd [join [lindex [find telnetcmd $router] 0] ""]
348    if { "$telnetcmd" == "" } { set telnetcmd "@TELNET_CMD@" }
349
350    # if [-mM], skip do not login
351    if { $do_cloginrcdbg > 0 } { continue; }
352
353    # Login to the router
354    if {[login $router $ruser $userpswd $passwd $prompt $cmethod $cyphertype]} {
355	incr exitval
356	continue
357    }
358
359    if { $do_command } {
360	if {[run_commands $prompt $command]} {
361	    incr exitval
362	    continue
363	}
364    } elseif { $do_script } {
365	send "lines 0\r"
366	expect -re $prompt	{}
367	source $sfile
368	catch {close};
369    } else {
370	label $router
371	log_user 1
372	interact
373    }
374
375    # End of for each router
376    catch {wait};
377    sleep 0.3
378}
379exit $exitval
380