#! @EXPECT_PATH@ -- ## ## @PACKAGE@ @VERSION@ @copyright@ # # mtlogin - MikroTik router login # # bootc@bootc.net wrote this (Chris Boot) # # Sometimes routers take awhile to answer (the default is 10 sec) set timeoutdflt 45 # Some CLIs having problems if we write too fast (Extreme, PIX, Cat) set send_human {.2 .1 .4 .2 1} @login_top@ # Log into the router. # returns: 0 on success, 1 on failure proc login { router user userpswd passwd prompt cmethod cyphertype identfile } { global spawn_id in_proc do_command do_script global u_prompt p_prompt sshcmd telnetcmd set in_proc 1 set uprompt_seen 0 # try each of the connection methods in $cmethod until one is successful set progs [llength $cmethod] foreach prog [lrange $cmethod 0 end] { incr progs -1 if [string match "telnet*" $prog] { regexp {telnet(:([^[:space:]]+))*} $prog command suffix port if {"$port" == ""} { set retval [ catch {eval spawn [split "$telnetcmd $router"]} reason ] } else { set retval [ catch {eval spawn [split "$telnetcmd $router $port"]} reason ] } if { $retval } { send_user "\nError: telnet failed: $reason\n" return 1 } } elseif [string match "ssh*" $prog] { # ssh to the router & try to login with or without an identfile. regexp {ssh(:([^[:space:]]+))*} $prog methcmd suffix port set cmd $sshcmd if {"$port" != ""} { set cmd "$cmd -p $port" } if {"$cyphertype" != ""} { set cmd "$cmd -c $cyphertype" } if {"$identfile" != ""} { set cmd "$cmd -i $identfile" } set retval [catch {eval spawn [split "$cmd -x -l $user+ct200w $router" { }]} reason] if { $retval } { send_user "\nError: $cmd failed: $reason\n" return 1 } } elseif ![string compare $prog "rsh"] { send_error "\nError: unsupported method: rsh\n" if { $progs == 0 } { return 1 } continue; } else { send_user "\nError: unknown connection method: $prog\n" return 1 } sleep 0.3 # This helps cleanup each expect clause. expect_after { timeout { global in_proc send_user "\nError: TIMEOUT reached\n" catch {close}; catch {wait}; if {$in_proc} { return 1 } else { continue } } eof { global in_proc send_user "\nError: EOF received\n" catch {close}; catch {wait}; if {$in_proc} { return 1 } else { continue } } } expect { "Connection refused" { catch {close}; catch {wait}; sleep 0.3 expect eof send_user "\nError: Connection Refused\n"; wait; return 1 } eof { send_user "\nError: Couldn't login\n"; wait; return 1 } "Unknown host\r\n" { expect eof send_user "\nError: Unknown host\n"; wait; return 1 } "Host is unreachable" { expect eof send_user "\nError: Host Unreachable!\n"; wait; return 1 } "No address associated with name" { expect eof send_user "\nError: Unknown host\n"; wait; return 1 } -re "(Host key not found |The authenticity of host .* be established)" { expect { -re "\\(yes\/no\[^\\)]*\\)\\?" { send "yes\r"; send_user "\nHost $router added to the list of known hosts.\n" } -re "\[^\r\n]*\[\r\n]+" { exp_continue; } } exp_continue } -re "HOST IDENTIFICATION HAS CHANGED" { send_user "\nError: The host key for $router has changed. Update the SSH known_hosts file accordingly.\n" expect { -re "\\(yes\/no\\)\\?" { send "no\r" } -re " strict checking\.\[\r\n]+" { } -re "\[^\r\n]*\[\r\n]+" { exp_continue; } } catch {close}; catch {wait}; return 1 } -re "Offending key for " { send_user "\nError: host key mismatch for $router. Update the SSH known_hosts file accordingly.\n" expect { -re "\\(yes\/no\\)\\?" { send "no\r" } -re "\[^\r\n]*\[\r\n]+" { exp_continue; } } catch {close}; catch {wait}; return 1 } -nocase -re "^warning: remote host denied authentication agent forwarding." { exp_continue; } -re "Enter passphrase.*: " { # sleep to allow time for stty -echo sleep .3 send -- "$passphrase\r" exp_continue } -re "$u_prompt" { send -- "$user+ct200w\r" set uprompt_seen 1 exp_continue } -re "$p_prompt" { sleep 1 if {$uprompt_seen == 1} { send -- "$userpswd\r" } else { send -- "$passwd\r" } exp_continue } -re "^Confirm seeing above note" { send "y\r" exp_continue } "Password incorrect" { send_user "\nError: Check your password for $router\n"; catch {close}; catch {wait}; return 1 } -re "$prompt" { break; } denied { send_user "\nError: Check your passwd for $router\n" catch {close}; catch {wait}; return 1 } "\r\n" { exp_continue; } } } set in_proc 0 return 0 } # Run commands given on the command line. proc run_commands { prompt command } { global do_interact in_proc set in_proc 1 # escape any parens in the prompt, such as "(enable)" regsub -all "\[)(]" $prompt {\\&} reprompt # handle escaped ;s in commands, and ;; and ^; regsub -all {([^\\]);} $command "\\1\u0002;" esccommand regsub -all {([^\\]);;} $esccommand "\\1;\u0002;" command regsub {^;} $command "\u0002;" esccommand regsub -all {[\\];} $esccommand ";" command regsub -all {\u0002;} $command "\u0002" esccommand set sep "\u0002" set commands [split $esccommand $sep] set num_commands [llength $commands] for {set i 0} {$i < $num_commands} { incr i} { send -- "[subst -nocommands [lindex $commands $i]]\r" expect { -re "^\[^\n\r]*$reprompt" {} -re "^\[^\n\r ]*>>.*$reprompt" { exp_continue } -re "\[\n\r]+" { exp_continue } } } if { $do_interact == 1 } { interact return 0 } send "quit\r" expect { -re "^WARNING: There are unsaved configuration changes." { send "y\r" exp_continue } "\n" { exp_continue } "\[^\n\r *]*Session terminated" { return 0 } timeout { catch {close}; catch {wait}; return 0 } eof { return 0 } } set in_proc 0 } # # For each router... (this is main loop) # source_password_file $password_file set in_proc 0 set exitval 0 # http://www.shrubbery.net/pipermail/rancid-discuss/2015-January/007984.html # if we have dont have a tty, we need some additional terminal settings if [catch {open /dev/tty w} ttyid] { # no tty, ie: cron set spawnopts "-nottycopy" set stty_init "cols 132" } else { catch {close ttyid} reason } foreach router [lrange $argv $i end] { set router [string tolower $router] send_user "$router\n" # Figure out prompt. set prompt "] > " # alteon only "enables" based on the password used at login time set autoenable 1 set enable 0 # device timeout set timeout [find timeout $router] if { [llength $timeout] == 0 } { set timeout $timeoutdflt } # Figure out passwords if { $do_passwd } { set pswd [find password $router] if { [llength $pswd] == 0 } { send_user -- "\nError: no password for $router in $password_file.\n" continue } set passwd [join [lindex $pswd 0] ""] } # Figure out username if {[info exists username]} { # command line username set ruser $username } else { set ruser [join [find user $router] ""] if { "$ruser" == "" } { set ruser $default_user } } # Figure out username's password (if different from the vty password) if {[info exists userpasswd]} { # command line username set userpswd $userpasswd } else { set userpswd [join [find userpassword $router] ""] if { "$userpswd" == "" } { set userpswd $passwd } } # Figure out prompts set u_prompt [find userprompt $router] if { "$u_prompt" == "" } { set u_prompt "Login:" } else { set u_prompt [join [lindex $u_prompt 0] ""] } set p_prompt [find passprompt $router] if { "$p_prompt" == "" } { set p_prompt "\[Pp]assword:" } else { set p_prompt [join [lindex $p_prompt 0] ""] } # Figure out identity file to use set identfile [join [lindex [find identity $router] 0] ""] # Figure out passphrase to use if {[info exists avpassphrase]} { set passphrase $avpassphrase } else { set passphrase [join [lindex [find passphrase $router] 0] ""] } if { ! [string length "$passphrase"]} { set passphrase $passwd } # Figure out cypher type if {[info exists cypher]} { # command line cypher type set cyphertype $cypher } else { set cyphertype [find cyphertype $router] } # Figure out connection method set cmethod [find method $router] if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} } # Figure out the SSH executable name set sshcmd [join [lindex [find sshcmd $router] 0] ""] if { "$sshcmd" == "" } { set sshcmd {ssh} } # Figure out the telnet executable name set telnetcmd [join [lindex [find telnetcmd $router] 0] ""] if { "$telnetcmd" == "" } { set telnetcmd "@TELNET_CMD@" } # if [-mM], skip do not login if { $do_cloginrcdbg > 0 } { continue; } # Login to the router if {[login $router $ruser $userpswd $passwd $prompt $cmethod $cyphertype $identfile]} { incr exitval continue } if { $do_command } { if {[run_commands $prompt $command]} { incr exitval continue } } elseif { $do_script } { source $sfile catch {close}; } else { label $router log_user 1 interact } # End of for each router catch {wait}; sleep 0.3 } exit $exitval