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 using the IPMI Serial-Over-LAN protocol. 12# IPMItool is available from <http://ipmitool.sourceforge.net/>. 13# 14# This script can be specified in "conman.conf" in the following manner: 15# 16# console name="zot" dev="/path/to/ipmitool.exp HOST USER PSWD [KEYG]" 17# 18# HOST is the hostname of the remote server. 19# USER is the username being authenticated. 20# PSWD is the corresponding password. 21# KEYG is the optional key-generation key "Kg" for IPMIv2 authentication. 22# 23# Since this command-line will persist in the process listing for the duration 24# of the connection, passing sensitive information like PSWD or KEYG in this 25# manner is not recommended. Instead, consider using either a command-line 26# argument default or the password database (see below). 27# 28# WARNING: 29# As of version 1.8.9, ipmitool does not support prompting for the "Kg" key. 30# Consequently, this key will be exposed on the ipmitool command-line. 31############################################################################### 32 33## 34# Set "exp_internal" to 1 to print diagnostics describing internal operations. 35# This is helpful in diagnosing pattern-match failures. 36## 37 exp_internal 0 38 39## 40# Set "log_user" to 1 to show the underlying dialogue establishing a connection 41# to the console. 42## 43 log_user 0 44 45## 46# The "timeout" specifies the number of seconds before the connection attempt 47# times-out and terminates the connection. 48## 49 set timeout 5 50 51## 52# The "password_db" specifies the location of the password database. 53# This avoids exposing sensitive information on the command-line without 54# needing to modify this script. 55# Whitespace and lines beginning with '#' are ignored. The file format is: 56# <host-regex> : <user> : <pswd> [ : <keyg> ] 57## 58 set password_db "/etc/conman.pswd" 59 60## 61# Command-line argument defaults can be specified here. This avoids exposing 62# sensitive information on the command-line. 63## 64# set user "foo" 65# set pswd "bar" 66# set keyg "qux" 67 68############################################################################### 69 70set env(PATH) "/usr/bin:/bin" 71 72proc get_password {host user index} { 73 global password_db 74 set db_pswd {} 75 if {! [info exists password_db]} { 76 return 77 } 78 if {[catch {open $password_db} input]} { 79 return 80 } 81 while {[gets $input line] != -1} { 82 if {[regexp {^[ \t]*#} $line]} { 83 continue 84 } 85 set record [split $line ":"] 86 set db_host [string trim [lindex $record 0]] 87 if {[catch {regexp "^$db_host$" $host} got_host_match]} { 88 continue 89 } 90 if {! $got_host_match && [string length $db_host]} { 91 continue 92 } 93 set db_user [string trim [lindex $record 1]] 94 if {[string compare $db_user $user]} { 95 continue 96 } 97 set db_pswd [string trim [lindex $record $index]] 98 break 99 } 100 close $input 101 return $db_pswd 102} 103 104if {! $argc} { 105 set prog [lindex [split $argv0 "/"] end] 106 send_user "Usage: $prog <host> <user> <pswd> \[<keyg>]\r\n" 107 exit 1 108} 109if {$argc > 0} { 110 set host [lindex $argv 0] 111} 112if {$argc > 1} { 113 set user [lindex $argv 1] 114} 115if {$argc > 2} { 116 set pswd [lindex $argv 2] 117} 118if {$argc > 3} { 119 set keyg [lindex $argv 3] 120} 121set authenticated 0 122if {! [info exists host]} { 123 send_user "Error: Unspecified hostname.\r\n" 124 exit 1 125} 126if {! [info exists user]} { 127 send_user "Error: Unspecified username.\r\n" 128 exit 1 129} 130if {! [info exists pswd]} { 131 set pswd [get_password $host $user 2] 132 if {! [string length $pswd]} { 133 send_user "Error: Unspecified password.\r\n" 134 exit 1 135 } 136 if {! [info exists keyg]} { 137 set keyg [get_password $host $user 3] 138 if {! [string length $keyg]} { 139 unset keyg 140 } 141 } 142} 143set cmd "ipmitool -e \& -I lanplus -H $host -U $user -a" 144if {[info exists keyg]} { 145 append cmd " -k $keyg" 146} 147if {[catch "spawn $cmd sol deactivate" spawn_result]} { 148 send_user "Error: $spawn_result.\r\n" 149 exit 1 150} 151expect { 152 -nocase -gl "Password:" { 153 if {$authenticated == 0} { 154 send "$pswd\r" 155 incr authenticated 156 } 157 exp_continue -continue_timer 158 } 159 eof { 160 ; 161 } 162 timeout { 163 send_user "Error: Timed-out.\r\n" 164 exit 1 165 } 166} 167wait 168 169if {[catch "spawn $cmd sol activate" spawn_result]} { 170 send_user "Error: $spawn_result.\r\n" 171 exit 1 172} 173set authenticated 0 174expect { 175 -nocase -re "\\\[SOL Session operational" { 176 ; 177 } 178 -nocase -re "^Error: (\[^\r]*)\r+\n" { 179 send_user "Error: $expect_out(1,string)\r\n" 180 exit 1 181 } 182 -nocase -gl "SOL payload already active on another session" { 183 send_user "Error: Console session already in use.\r\n" 184 exit 1 185 } 186 eof { 187 send_user "Error: Connection closed by remote host.\r\n" 188 exit 1 189 } 190 timeout { 191 send_user "Error: Timed-out.\r\n" 192 exit 1 193 } 194 -nocase -gl "Password:" { 195 if {$authenticated == 0} { 196 send "$pswd\r" 197 incr authenticated 198 } 199 exp_continue -continue_timer 200 } 201 -re "\[^\r]*\r+\n" { 202 exp_continue -continue_timer 203 } 204} 205send_user "Connection established via ipmitool (pid $spawn_result).\r\n" 206 207interact 208