mirror of
https://github.com/ovh/the-bastion.git
synced 2024-11-14 12:17:32 +08:00
130 lines
4.7 KiB
Text
Executable file
130 lines
4.7 KiB
Text
Executable file
#!/usr/bin/env expect
|
|
# vim: set filetype=expect ts=4 sw=4 sts=4 et:
|
|
|
|
# To debug this script, you may want to uncomment the two following lines:
|
|
#exp_internal 1
|
|
#strace 2
|
|
|
|
set ::env(TERM) ""
|
|
|
|
# we need 6 arguments
|
|
if { [llength $argv] < 8 } {
|
|
puts {BASTION SAYS: autologin usage error, expected 6 args: <ssh|telnet> <login> <ip> <port> <file_with_password> <password_id> <timeout> <fallback_delay> [passthrough arguments to ssh or telnet]}
|
|
exit 1
|
|
}
|
|
|
|
# name our arguments
|
|
set arg_prog [lindex $argv 0]
|
|
set arg_login [lindex $argv 1]
|
|
set arg_ip [lindex $argv 2]
|
|
set arg_port [lindex $argv 3]
|
|
set arg_file [lindex $argv 4]
|
|
set arg_password_id [lindex $argv 5]
|
|
set arg_timeout [lindex $argv 6]
|
|
set arg_fallback_delay [lindex $argv 7]
|
|
set arg_remaining [lrange $argv 8 end]
|
|
|
|
# start the program
|
|
if { $arg_prog == "ssh" } {
|
|
lappend spawn_args -l $arg_login -p $arg_port $arg_ip
|
|
} elseif { $arg_prog == "telnet" } {
|
|
lappend spawn_args $arg_ip $arg_port
|
|
} else {
|
|
puts "BASTION SAYS: autologin usage error, program must be either 'ssh' or 'telnet'"
|
|
exit 1
|
|
}
|
|
|
|
if { [llength $arg_remaining] > 0 } {
|
|
set spawn_args [concat $spawn_args $arg_remaining]
|
|
}
|
|
|
|
# set the interactive timeout for expect{} blocks
|
|
set timeout $arg_timeout
|
|
|
|
# if success, doesn't return (calls interact then exit 0)
|
|
# if auth failed, return 100 (caller might retry with another password)
|
|
# if other non-critical error, return 101
|
|
# if critical error, exits
|
|
proc attempt_to_login args {
|
|
set tryid [lindex $args 0]
|
|
set prog [lindex $args 1]
|
|
set login [lindex $args 2]
|
|
set file [lindex $args 3]
|
|
set arg_fallback_delay [lindex $args 4]
|
|
set spawn_args [lindex $args 5]
|
|
|
|
if { [file exists $file] == 0 } {
|
|
if { $tryid == 0 } { puts "BASTION SAYS: file $file does not exist" }
|
|
return 101
|
|
}
|
|
if { [file readable $file] == 0 } {
|
|
if { $tryid == 0 } { puts "BASTION SAYS: file $file is not readable with our current rights" }
|
|
return 101
|
|
}
|
|
|
|
if { $tryid > 0 } {
|
|
puts "BASTION SAYS: trying with fallback password $tryid after sleeping for $arg_fallback_delay seconds..."
|
|
sleep $arg_fallback_delay
|
|
}
|
|
|
|
# reading password (256 chars max)
|
|
set pass_fh [open $file r]
|
|
set pass [read $pass_fh 256]
|
|
close $pass_fh
|
|
|
|
spawn -noecho $prog {*}$spawn_args
|
|
|
|
if { $prog == "telnet" } {
|
|
# send login (only for telnet)
|
|
expect {
|
|
-re "login:|Username:" { send -- "$login\n" }
|
|
eof { puts "BASTION SAYS: connection failed"; exit 2 }
|
|
timeout { puts "BASTION SAYS: timed out while waiting for login prompt"; exit 2 }
|
|
}
|
|
}
|
|
|
|
# send password
|
|
expect {
|
|
-re {[Pp]assword:|Password for [a-zA-Z0-9@._-]+:} { send -- "$pass" }
|
|
eof { puts "BASTION SAYS: connection aborted"; exit 3 }
|
|
timeout { puts "BASTION SAYS: timed out while waiting for password prompt"; exit 3 }
|
|
}
|
|
|
|
# do we have a login success with interactive prompt?
|
|
expect {
|
|
# prompts
|
|
"#" { interact; exit 0 }
|
|
">" { interact; exit 0 }
|
|
# 'enable' prompt on a network device
|
|
"(enable)" { interact; exit 0 }
|
|
# a successful login on a bastion (mainly for tests)
|
|
-exact "the-bastion-" { interact; exit 0 }
|
|
# login failure messages
|
|
-re {[Pp]assword:|Password for [a-zA-Z0-9@_-]+:|Authentication failed|Permission denied|UNIX authentication refused} {
|
|
if { $tryid == 0 } { puts "BASTION SAYS: authentication failed!" }
|
|
close
|
|
wait
|
|
return 100
|
|
}
|
|
eof { puts "BASTION SAYS: connection aborted"; exit 4 }
|
|
timeout { puts "BASTION SAYS: timed out while waiting for interactive prompt on success login"; exit 4 }
|
|
}
|
|
# unreachable:
|
|
exit 5
|
|
}
|
|
|
|
# if no specific pasword was requested, try to login with the main password file, then try the fallbacks
|
|
set tryid 0
|
|
if { $arg_password_id == -1 } {
|
|
set last_attempt [attempt_to_login $tryid $arg_prog $arg_login $arg_file $arg_fallback_delay $spawn_args]
|
|
while { $last_attempt == 100 && $tryid < 10 } {
|
|
# auth failed, might want to try with the fallback
|
|
incr tryid
|
|
set last_attempt [attempt_to_login $tryid $arg_prog $arg_login "$arg_file.$tryid" $arg_fallback_delay $spawn_args]
|
|
}
|
|
} elseif { $arg_password_id == 0 } {
|
|
set last_attempt [attempt_to_login $tryid $arg_prog $arg_login $arg_file $arg_fallback_delay $spawn_args]
|
|
} else {
|
|
set last_attempt [attempt_to_login $tryid $arg_prog $arg_login "$arg_file.$arg_password_id" $arg_fallback_delay $spawn_args]
|
|
}
|
|
exit $last_attempt
|