1#!/usr/local/bin/expect -f 2############################################################################### 3# Written by Chris Dunlap <cdunlap@llnl.gov>. 4# Copyright (C) 2007-2018 Lawrence Livermore National Security, LLC. 5# Copyright (C) 2001-2007 The Regents of the University of California. 6# UCRL-CODE-2002-009. 7# 8# This file is part of ConMan: The Console Manager. 9# For details, see <https://dun.github.io/conman/>. 10############################################################################### 11# This script connects to a console on a given blade in an IBM BladeCenter 12# via Serial Over LAN (SOL) using the telnet protocol. 13# 14# This script can be specified in "conman.conf" in the following manner: 15# 16# console name="zot" dev="/path/to/ibm-bc.exp HOST BLADE USER PSWD" 17# 18# HOST is the hostname of the blade server. 19# BLADE is the blade number associated with the console. 20# USER is the username being authenticated. 21# PSWD is the corresponding password. 22# 23# Since this command-line will persist in the process listing for the duration 24# of the connection, passing sensitive information like PSWD in this manner is 25# not recommended. Instead, consider using either a command-line argument 26# default or the password database (see below). 27############################################################################### 28 29## 30# Set "exp_internal" to 1 to print diagnostics describing internal operations. 31# This is helpful in diagnosing pattern-match failures. 32## 33 exp_internal 0 34 35## 36# Set "log_user" to 1 to show the underlying dialogue establishing a connection 37# to the console. 38## 39 log_user 0 40 41## 42# The "timeout" specifies the number of seconds before the connection attempt 43# times-out and terminates the connection. 44## 45 set timeout 10 46 47## 48# If "bcmm_timeout" is set greater than or equal to 0, the telnet inactivity 49# timeout of the BladeCenter management module will be set to this value. 50# This setting specifies the number of seconds of inactivity before the 51# interface session times-out; setting it to 0 disables the timeout. 52## 53 set bcmm_timeout 0 54 55## 56# If "idle_timeout" is set greater than 0, a "space-backspace" sequence will 57# be sent every ${idle_timeout} seconds after no output activity has been 58# detected in order to keep the connection alive. 59# This setting should ideally be the same value as "bcmm_timeout". 60## 61 set idle_timeout 0 62 63## 64# If "session_override" is enabled, an existing connection to this console 65# session will be terminated and the new connection will be established. 66# Subsequent attempts to steal this console session will be thwarted. 67# Otherwise, an existing connection to this console session will cause the new 68# connection to fail with "console session already in use". If the console 69# session is not in use and the connection succeeds, the console session may 70# subsequently be stolen thereby causing this connection to terminate with 71# "console session stolen". 72# Beware of dueling banjos if a given console session is overridden by more 73# than one process, as these processes will continuously steal the console 74# session from each other. 75## 76 set session_override 1 77 78## 79# The "password_db" specifies the location of the password database. 80# This avoids exposing sensitive information on the command-line without 81# needing to modify this script. 82# Whitespace and lines beginning with '#' are ignored. The file format is: 83# <host-regex> : <user> : <pswd> 84## 85 set password_db "/etc/conman.pswd" 86 87## 88# Command-line argument defaults can be specified here. This avoids exposing 89# sensitive information on the command-line. 90## 91# set user "USERID" 92# set pswd "PASSW0RD" 93 94############################################################################### 95 96set env(PATH) "/usr/bin:/bin" 97 98proc get_password {host user index} { 99 global password_db 100 set db_pswd {} 101 if {! [info exists password_db]} { 102 return 103 } 104 if {[catch {open $password_db} input]} { 105 return 106 } 107 while {[gets $input line] != -1} { 108 if {[regexp {^[ \t]*#} $line]} { 109 continue 110 } 111 set record [split $line ":"] 112 set db_host [string trim [lindex $record 0]] 113 if {[catch {regexp "^$db_host$" $host} got_host_match]} { 114 continue 115 } 116 if {! $got_host_match && [string length $db_host]} { 117 continue 118 } 119 set db_user [string trim [lindex $record 1]] 120 if {[string compare $db_user $user]} { 121 continue 122 } 123 set db_pswd [string trim [lindex $record $index]] 124 break 125 } 126 close $input 127 return $db_pswd 128} 129 130if {! $argc} { 131 set prog [lindex [split $argv0 "/"] end] 132 send_user "Usage: $prog <host> <blade> <user> <pswd>\r\n" 133 exit 1 134} 135if {$argc > 0} { 136 set host [lindex $argv 0] 137} 138if {$argc > 1} { 139 set blade [lindex $argv 1] 140} 141if {$argc > 2} { 142 set user [lindex $argv 2] 143} 144if {$argc > 3} { 145 set pswd [lindex $argv 3] 146} 147set bcmm_bay 1 148set cmd_sent 0 149set connected 0 150if {! [info exists host]} { 151 send_user "Error: Unspecified hostname.\r\n" 152 exit 1 153} 154if {! [info exists blade]} { 155 send_user "Error: Unspecified blade number.\r\n" 156 exit 1 157} 158if {! [info exists user]} { 159 send_user "Error: Unspecified username.\r\n" 160 exit 1 161} 162if {! [info exists pswd]} { 163 set pswd [get_password $host $user 2] 164 if {! [string length $pswd]} { 165 send_user "Error: Unspecified password.\r\n" 166 exit 1 167 } 168} 169if {! [info exists bcmm_timeout] || ($bcmm_timeout < 0)} { 170 set bcmm_timeout -1 171} 172if {! [info exists idle_timeout] || ($idle_timeout <= 0)} { 173 set idle_timeout -1 174} 175set cmd "console -T system:blade\[$blade]" 176if {[info exists session_override] && ($session_override > 0)} { 177 append cmd " -o" 178} 179if {[catch "spawn telnet $host" spawn_result]} { 180 send_user "Error: $spawn_result.\r\n" 181 exit 1 182} 183expect { 184 -gl "\u001b\\\[2J" { 185 if {$connected == 0} { 186 exp_continue -continue_timer 187 } 188 } 189 -gl "Invalid login" { 190 send_user "Error: Permission denied.\r\n" 191 exit 1 192 } 193 -gl "Command not recognized" { 194 send_user "Error: Command not recognized.\r\n" 195 exit 1 196 } 197 -gl "Invalid target path" { 198 send_user "Error: Invalid blade name.\r\n" 199 exit 1 200 } 201 -gl "The target bay is out of range" { 202 send_user "Error: Invalid blade number.\r\n" 203 exit 1 204 } 205 -gl "SOL session is already active" { 206 send_user "Error: Console session already in use.\r\n" 207 exit 1 208 } 209 eof { 210 send_user "Error: Connection closed by remote host.\r\n" 211 exit 1 212 } 213 timeout { 214 if {$connected == 0} { 215 send_user "Error: Timed-out.\r\n" 216 exit 1 217 } 218 } 219 -nocase -gl "username: \$" { 220 if {$connected == 0} { 221 send "$user\r" 222 } 223 exp_continue -continue_timer 224 } 225 -nocase -gl "password: \$" { 226 if {$connected == 0} { 227 send "$pswd\r" 228 } 229 exp_continue -continue_timer 230 } 231 -nocase -gl "OK\r\n" { 232 if {$cmd_sent != 0} { 233 incr bcmm_bay 234 set cmd_sent 0 235 } 236 exp_continue -continue_timer 237 } 238 -nocase -gl "The target bay is empty.\r\n" { 239 if {$bcmm_bay == 0} { 240 send_user "Error: No blade in specified slot.\r\n" 241 exit 1 242 } elseif {$cmd_sent != 0} { 243 set bcmm_bay 0 244 set bcmm_timeout -1 245 set cmd_sent 0 246 } 247 exp_continue -continue_timer 248 } 249 -nocase -gl "Command cannot be issued to this target." { 250 if {$cmd_sent != 0} { 251 set bcmm_timeout -1 252 set cmd_sent 0 253 } 254 exp_continue -continue_timer 255 } 256 -nocase -gl "User does not have the authority to issue this command.\r\n" { 257 if {$cmd_sent != 0} { 258 set bcmm_timeout -1 259 set cmd_sent 0 260 } 261 exp_continue -continue_timer 262 } 263 -nocase -gl "system> \$" { 264 if {($bcmm_timeout >= 0) && ($cmd_sent == 0)} { 265 send "telnetcfg -T system:mm\[$bcmm_bay] -t $bcmm_timeout\r" 266 incr cmd_sent 267 } elseif {($connected == 0) && ($cmd_sent == 0)} { 268 send "$cmd\r" 269 incr connected 270 } else { 271 send_user "Error: Unrecognized response.\r\n" 272 exit 1 273 } 274 exp_continue -continue_timer 275 } 276 -re "\[^\r]*\r+\n" { 277 exp_continue -continue_timer 278 } 279} 280send_user "Connection established via telnet (pid $spawn_result).\r\n" 281 282set timeout 2 283interact { 284 # Replace "&B" with serial-break. 285 "&B" { 286 send "\035send brk\r\n" 287 expect "telnet> send brk" 288 } 289 # Match subsequent patterns against spawned process, not user's keystrokes. 290 -o 291 # Send "space-backspace" sequence after ${idle_timeout} seconds of inactivity 292 # in order to keep the connection alive. 293 timeout $idle_timeout { 294 send " \177" 295 } 296 # Disable "ESC (" sequence for stopping the console session and returning to 297 # the BladeCenter management module prompt. If "session_override" is set, 298 # this will also prevent the console session from being stolen. 299 -re "\r\nsystem> \$" { 300 send "$cmd\r" 301 expect { 302 -gl "\r\nSOL session is already active\r\nsystem> \$" { 303 send_user "\r\nConsole session stolen.\r\n" 304 exit 1 305 } 306 -gl "\u001b\\\[2J" 307 } 308 } 309} 310