-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexecution.go
More file actions
188 lines (177 loc) · 5.56 KB
/
execution.go
File metadata and controls
188 lines (177 loc) · 5.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package laptop_booter
import (
"bytes"
"fmt"
"log"
"golang.org/x/crypto/ssh"
)
type Configuration struct {
Username string
Password string
BastionUsername string
BastionHost string
BastionPort int
AmtHost string
AmtPort int
DropbearUsername string
DropbearHost string
DropbearPort int
RealSSHUsername string
RealSSHHost string
RealSSHPort int
DiskUnlockPassword string
Command string
LocalRealSSHPort int
LocalAmtPort int
LocalDropbearPort int
AgentConfiguration *ssh.ClientConfig
}
const (
// CmdStatus will print the power state and check if main SSH port is there
CmdStatus = "status"
// CmdUp will do AMT "powerup" the machine and then decrypt the disk
CmdActivate = "activate"
// CmdShutdown will execute "shutdown -h now" on the remote system
CmdShutdown = "shutdown"
)
func Execute(c *Configuration) (output string, err error) {
if c.AgentConfiguration == nil {
sshAgentCloser, sshConfig, err := SSHConfigFromAgent(c.BastionUsername)
if err != nil {
return "", fmt.Errorf("failed to create ssh configuration: %w", err)
}
defer sshAgentCloser()
c.AgentConfiguration = sshConfig
}
bastion := &Endpoint{
Host: c.BastionHost,
Port: c.BastionPort,
}
amtTunnel := &SSHTunnel{
Config: c.AgentConfiguration,
Local: &Endpoint{
Host: "localhost",
Port: c.LocalAmtPort,
},
Mediator: bastion,
Remote: &Endpoint{
Host: c.AmtHost,
Port: c.AmtPort,
},
}
amtTunnel.Activate()
dropbearTunnel := &SSHTunnel{
Config: c.AgentConfiguration,
Local: &Endpoint{
Host: "localhost",
Port: c.LocalDropbearPort,
},
Mediator: bastion,
Remote: &Endpoint{
Host: c.DropbearHost,
Port: c.DropbearPort,
},
}
dropbearTunnel.Activate()
realSSHTunnel := &SSHTunnel{
Config: c.AgentConfiguration,
Local: &Endpoint{
Host: "localhost",
Port: c.LocalRealSSHPort,
},
Mediator: bastion,
Remote: &Endpoint{
Host: c.RealSSHHost,
Port: c.RealSSHPort,
},
}
realSSHTunnel.Activate()
switch c.Command {
case CmdStatus:
log.Println("Command chosen: show status")
status := getAmtStatus(c.Username, c.Password, c.LocalAmtPort)
if status.StateHTTP != 200 {
return "", fmt.Errorf("Wrong response code from server: %w", status.StateHTTP)
}
return legacyPowerstateTextMap[status.StateAMT], nil
case CmdActivate:
log.Println("Command chosen: activate")
status := getAmtStatus(c.Username, c.Password, c.LocalAmtPort)
if status.StateHTTP != 200 {
return "", fmt.Errorf("Wrong response code from server when fetching status: %v", status.StateHTTP)
}
if status.StateAMT == amtStateOn {
log.Println("System is already on, ignoring poweron instruction")
} else {
log.Println("Activating AMT poweron function")
setPowerStateOn(c.Username, c.Password, c.LocalAmtPort)
}
if singleCheckSSHConnectivityViaLocalPort(c.LocalRealSSHPort, c.RealSSHUsername, c.AgentConfiguration) {
log.Println("System's real SSH is already on, ignoring disk decryption voodoo")
} else {
log.Println("System's real SSH is not available, reaching out to dropbear to unlock")
dropbearConn, err := awaitSSHConnectivityViaLocalPort(c.LocalDropbearPort, "root", c.AgentConfiguration)
if err != nil {
return "", fmt.Errorf("Dropbear connection could not be established!: %w", err)
}
defer dropbearConn.Close()
log.Printf("Dropbear connection established!")
session, err := dropbearConn.NewSession()
if err != nil {
return "", fmt.Errorf("Failed to create new ssh session: %w", err)
}
err = unlockDisk(c.DiskUnlockPassword, session)
if err != nil {
return "", fmt.Errorf("Failed to unlock the disk: %w", err)
}
_, err = awaitSSHConnectivityViaLocalPort(c.LocalRealSSHPort, c.RealSSHUsername, c.AgentConfiguration)
if err != nil {
return "", fmt.Errorf("Failed to establish error to real SSH: %w", err)
}
log.Printf("Real SSH active")
}
return "Success", nil
case CmdShutdown:
log.Println("Command chosen: shutdown")
status := getAmtStatus(c.Username, c.Password, c.LocalAmtPort)
if status.StateHTTP != 200 {
return "", fmt.Errorf("Wrong response code from server when fetching status: %v", status.StateHTTP)
}
if status.StateAMT == amtStateSoftOff {
log.Println("System is already turned off")
} else if singleCheckSSHConnectivityViaLocalPort(c.LocalRealSSHPort, c.RealSSHUsername, c.AgentConfiguration) {
log.Println("System's real SSH is already on, proceeding with SSH-driven turn off")
realSSHConn, err := awaitSSHConnectivityViaLocalPort(c.LocalRealSSHPort, c.RealSSHUsername, c.AgentConfiguration)
if err != nil {
return "", fmt.Errorf("Failed to establish error to real SSH: %w", err)
}
defer realSSHConn.Close()
session, err := realSSHConn.NewSession()
if err != nil {
return "", fmt.Errorf("Failed to create new ssh session: %w", err)
}
err = session.Start("sudo shutdown -h now")
if err != nil {
return "", fmt.Errorf("Shutdown call failed: %w", err)
}
} else {
log.Println("Activating AMT poweroff function")
setPowerStateOff(c.Username, c.Password, c.LocalAmtPort)
}
return "Success", nil
default:
return "", fmt.Errorf("Unknown command '%s'", c.Command)
}
}
func unlockDisk(diskUnlockPassword string, session *ssh.Session) error {
var b bytes.Buffer
b.WriteString(diskUnlockPassword)
session.Stdin = &b
log.Printf("Sending disk unlock password!")
output, err := session.CombinedOutput("cryptroot-unlock")
if err != nil {
return fmt.Errorf("Unlock call failed: %w", err)
}
log.Println(string(output))
return nil
}