]>
Commit | Line | Data |
---|---|---|
402f63cd MG |
1 | #!/usr/bin/perl |
2 | use strict; | |
3 | use warnings; | |
4 | use SOAP::Lite; | |
5 | #use SOAP::Lite +trace => 'all'; | |
6 | ||
7 | my $amt_host = shift; | |
8 | my $amt_port = "16992"; | |
9 | $main::amt_user = "admin"; | |
10 | $main::amt_pass = $ENV{'AMT_PASSWORD'}; | |
11 | my $amt_debug = 0; | |
12 | $amt_debug = $ENV{'AMT_DEBUG'} if defined($ENV{'AMT_DEBUG'}); | |
13 | ||
14 | my $amt_command = shift; | |
15 | $amt_command = "info" if !defined($amt_command); | |
16 | ||
17 | my $amt_version; | |
18 | ||
19 | ############################################################################# | |
20 | # data | |
21 | ||
22 | my @ps = ("S0", "S1", "S2", "S3", "S4", "S5 (soft-off)", "S4/S5", "Off"); | |
23 | my %rcc = ( | |
24 | "reset" => "16", | |
25 | "powerup" => "17", | |
26 | "powerdown" => "18", | |
27 | "powercycle" => "19", | |
28 | ); | |
29 | ||
30 | # incomplete list | |
31 | my %pt_status = ( | |
32 | 0x0 => "success", | |
33 | 0x1 => "internal error", | |
34 | 0x3 => "invalid pt_mode", | |
35 | 0xc => "invalid name", | |
36 | 0xf => "invalid byte_count", | |
37 | 0x10 => "not permitted", | |
38 | 0x17 => "max limit_reached", | |
39 | 0x18 => "invalid auth_type", | |
40 | 0x1a => "invalid dhcp_mode", | |
41 | 0x1b => "invalid ip_address", | |
42 | 0x1c => "invalid domain_name", | |
43 | 0x20 => "invalid provisioning_state", | |
44 | 0x22 => "invalid time", | |
45 | 0x23 => "invalid index", | |
46 | 0x24 => "invalid parameter", | |
47 | 0x25 => "invalid netmask", | |
48 | 0x26 => "flash write_limit_exceeded", | |
49 | 0x800 => "network if_error_base", | |
50 | 0x801 => "unsupported oem_number", | |
51 | 0x802 => "unsupported boot_option", | |
52 | 0x803 => "invalid command", | |
53 | 0x804 => "invalid special_command", | |
54 | 0x805 => "invalid handle", | |
55 | 0x806 => "invalid password", | |
56 | 0x807 => "invalid realm", | |
57 | 0x808 => "storage acl_entry_in_use", | |
58 | 0x809 => "data missing", | |
59 | 0x80a => "duplicate", | |
60 | 0x80b => "eventlog frozen", | |
61 | 0x80c => "pki missing_keys", | |
62 | 0x80d => "pki generating_keys", | |
63 | 0x80e => "invalid key", | |
64 | 0x80f => "invalid cert", | |
65 | 0x810 => "cert key_not_match", | |
66 | 0x811 => "max kerb_domain_reached", | |
67 | 0x812 => "unsupported", | |
68 | 0x813 => "invalid priority", | |
69 | 0x814 => "not found", | |
70 | 0x815 => "invalid credentials", | |
71 | 0x816 => "invalid passphrase", | |
72 | 0x818 => "no association", | |
73 | ); | |
74 | ||
75 | ||
76 | ############################################################################# | |
77 | # soap setup | |
78 | ||
79 | my ($nas, $sas, $rcs); | |
80 | ||
81 | sub SOAP::Transport::HTTP::Client::get_basic_credentials { | |
82 | return $main::amt_user => $main::amt_pass; | |
83 | } | |
84 | ||
85 | sub soap_init() { | |
86 | my $proxybase = "http://$amt_host:$amt_port"; | |
87 | my $schemabase = "http://schemas.intel.com/platform/client"; | |
88 | ||
89 | $nas = SOAP::Lite->new( | |
90 | proxy => "$proxybase/NetworkAdministrationService", | |
91 | default_ns => "$schemabase/NetworkAdministration/2004/01"); | |
92 | $sas = SOAP::Lite->new( | |
93 | proxy => "$proxybase/SecurityAdministrationService", | |
94 | default_ns => "$schemabase/SecurityAdministration/2004/01"); | |
95 | $rcs = SOAP::Lite->new( | |
96 | proxy => "$proxybase/RemoteControlService", | |
97 | default_ns => "$schemabase/RemoteControl/2004/01"); | |
98 | ||
99 | $nas->autotype(0); | |
100 | $sas->autotype(0); | |
101 | $rcs->autotype(0); | |
102 | ||
103 | $amt_version = $sas->GetCoreVersion()->paramsout; | |
104 | } | |
105 | ||
106 | ||
107 | ############################################################################# | |
108 | # functions | |
109 | ||
110 | sub usage() { | |
111 | print STDERR <<EOF; | |
112 | ||
113 | This utility can talk to Intel AMT managed machines. | |
114 | ||
115 | usage: amttool <hostname> [ <command> ] | |
116 | commands: | |
117 | info - print some machine info (default). | |
118 | reset - reset machine. | |
119 | powerup - turn on machine. | |
120 | powerdown - turn off machine. | |
121 | powercycle - powercycle machine. | |
122 | ||
123 | AMT 2.5+ only: | |
124 | netinfo - print network config. | |
125 | netconf <args> - configure network (check manpage). | |
126 | ||
127 | Password is passed via AMT_PASSWORD environment variable. | |
128 | ||
129 | EOF | |
130 | } | |
131 | ||
132 | sub print_result($) { | |
133 | my $ret = shift; | |
134 | my $rc = $ret->result; | |
135 | my $msg; | |
136 | ||
137 | if (!defined($rc)) { | |
138 | $msg = "soap failure"; | |
139 | } elsif (!defined($pt_status{$rc})) { | |
140 | $msg = sprintf("unknown pt_status code: 0x%x", $rc); | |
141 | } else { | |
142 | $msg = "pt_status: " . $pt_status{$rc}; | |
143 | } | |
144 | printf "result: %s\n", $msg; | |
145 | } | |
146 | ||
147 | sub print_paramsout($) { | |
148 | my $ret = shift; | |
149 | my @paramsout = $ret->paramsout; | |
150 | print "params: " . join(", ", @paramsout) . "\n"; | |
151 | } | |
152 | ||
153 | sub print_hash { | |
154 | my $hash = shift; | |
155 | my $in = shift; | |
156 | my $wi = shift; | |
157 | ||
158 | foreach my $item (sort keys %{$hash}) { | |
159 | if (ref($hash->{$item}) eq "HASH") { | |
160 | # printf "%*s%s\n", $in, "", $item; | |
161 | next; | |
162 | } | |
163 | printf "%*s%-*s%s\n", $in, "", $wi, $item, $hash->{$item}; | |
164 | } | |
165 | } | |
166 | ||
167 | sub print_hash_ipv4 { | |
168 | my $hash = shift; | |
169 | my $in = shift; | |
170 | my $wi = shift; | |
171 | ||
172 | foreach my $item (sort keys %{$hash}) { | |
173 | my $addr = sprintf("%d.%d.%d.%d", | |
174 | $hash->{$item} / 256 / 256 / 256, | |
175 | $hash->{$item} / 256 / 256 % 256, | |
176 | $hash->{$item} / 256 % 256, | |
177 | $hash->{$item} % 256); | |
178 | printf "%*s%-*s%s\n", $in, "", $wi, $item, $addr; | |
179 | } | |
180 | } | |
181 | ||
182 | sub do_soap { | |
183 | my $soap = shift; | |
184 | my $name = shift; | |
185 | my @args = @_; | |
186 | my $method; | |
187 | ||
188 | $method = SOAP::Data->name($name) | |
189 | ->attr( { xmlns => $soap->ns } ); | |
190 | ||
191 | if ($amt_debug) { | |
192 | print "-- \n"; | |
193 | open XML, "| xmllint --format -"; | |
194 | print XML $soap->serializer->envelope(method => $method, @_); | |
195 | close XML; | |
196 | print "-- \n"; | |
197 | } | |
198 | ||
199 | my $ret = $soap->call($method, @args); | |
200 | print_result($ret); | |
201 | return $ret; | |
202 | } | |
203 | ||
204 | sub check_amt_version { | |
205 | my $major = shift; | |
206 | my $minor = shift; | |
207 | ||
208 | $amt_version =~ m/^(\d+).(\d+)/; | |
209 | return if $1 > $major; | |
210 | return if $1 == $major && $2 >= $minor; | |
211 | die "version mismatch (need >= $major.$minor, have $amt_version)"; | |
212 | } | |
213 | ||
214 | sub print_general_info() { | |
215 | printf "### AMT info on machine '%s' ###\n", $amt_host; | |
216 | ||
217 | printf "AMT version: %s\n", $amt_version; | |
218 | ||
219 | my $hostname = $nas->GetHostName()->paramsout; | |
220 | my $domainname = $nas->GetDomainName()->paramsout; | |
221 | printf "Hostname: %s.%s\n", $hostname, $domainname; | |
222 | ||
223 | my $powerstate = $rcs->GetSystemPowerState()->paramsout; | |
224 | printf "Powerstate: %s\n", $ps [ $powerstate & 0x0f ]; | |
225 | } | |
226 | ||
227 | sub print_remote_info() { | |
228 | my @rccaps = $rcs->GetRemoteControlCapabilities()->paramsout; | |
229 | printf "Remote Control Capabilities:\n"; | |
230 | printf " IanaOemNumber %x\n", $rccaps[0]; | |
231 | printf " OemDefinedCapabilities %s%s%s%s%s\n", | |
232 | $rccaps[1] & 0x01 ? "IDER " : "", | |
233 | $rccaps[1] & 0x02 ? "SOL " : "", | |
234 | $rccaps[1] & 0x04 ? "BiosReflash " : "", | |
235 | $rccaps[1] & 0x08 ? "BiosSetup " : "", | |
236 | $rccaps[1] & 0x10 ? "BiosPause " : ""; | |
237 | ||
238 | printf " SpecialCommandsSupported %s%s%s%s%s\n", | |
239 | $rccaps[2] & 0x0100 ? "PXE-boot " : "", | |
240 | $rccaps[2] & 0x0200 ? "HD-boot " : "", | |
241 | $rccaps[2] & 0x0400 ? "HD-boot-safemode " : "", | |
242 | $rccaps[2] & 0x0800 ? "diag-boot " : "", | |
243 | $rccaps[2] & 0x1000 ? "cd-boot " : ""; | |
244 | ||
245 | printf " SystemCapabilitiesSupported %s%s%s%s\n", | |
246 | $rccaps[3] & 0x01 ? "powercycle " : "", | |
247 | $rccaps[3] & 0x02 ? "powerdown " : "", | |
248 | $rccaps[3] & 0x03 ? "powerup " : "", | |
249 | $rccaps[3] & 0x04 ? "reset " : ""; | |
250 | ||
251 | printf " SystemFirmwareCapabilities %x\n", $rccaps[4]; | |
252 | } | |
253 | ||
254 | sub print_network_info() { | |
255 | my $ret; | |
256 | ||
257 | $ret = $nas->EnumerateInterfaces(); | |
258 | my @if = $ret->paramsout; | |
259 | foreach my $if (@if) { | |
260 | printf "Network Interface %s:\n", $if; | |
261 | my $arg = SOAP::Data->name('InterfaceHandle' => $if); | |
262 | $ret = $nas->GetInterfaceSettings($arg); | |
263 | my $desc = $ret->paramsout; | |
264 | print_hash($ret->paramsout, 4, 32); | |
265 | print_hash_ipv4($ret->paramsout->{'IPv4Parameters'}, 8, 28); | |
266 | } | |
267 | } | |
268 | ||
269 | sub remote_control($) { | |
270 | my $command = shift; | |
271 | my @args; | |
272 | ||
273 | my $hostname = $nas->GetHostName()->paramsout; | |
274 | my $domainname = $nas->GetDomainName()->paramsout; | |
275 | printf "host %s.%s, %s [y/N] ? ", $hostname, $domainname, $command; | |
276 | my $reply = <>; | |
277 | if ($reply =~ m/^(y|yes)$/i) { | |
278 | printf "execute: %s\n", $command; | |
279 | push (@args, SOAP::Data->name('Command' => $rcc{$command})); | |
b562f16a MG |
280 | push (@args, SOAP::Data->name('IanaOemNumber' => 343)); |
281 | if ($command ne 'powerdown') { | |
b562f16a MG |
282 | push (@args, SOAP::Data->name('SpecialCommand' => 0xC1 )); |
283 | push (@args, SOAP::Data->name('SpecialCommandParameter' => 0)); | |
b43d857c | 284 | push (@args, SOAP::Data->name('OEMparameters' => 1 )); |
b562f16a | 285 | } |
402f63cd MG |
286 | do_soap($rcs, "RemoteControl", @args); |
287 | } else { | |
288 | printf "canceled\n"; | |
289 | } | |
290 | } | |
291 | ||
292 | sub ipv4_addr($$) { | |
293 | my $name = shift; | |
294 | my $ipv4 = shift; | |
295 | ||
296 | $ipv4 =~ m/(\d+).(\d+).(\d+).(\d+)/ or die "parse ipv4 address: $ipv4"; | |
297 | my $num = $1 * 256 * 256 * 256 + | |
298 | $2 * 256 * 246 + | |
299 | $3 * 256 + | |
300 | $4; | |
301 | printf STDERR "ipv4 %-24s: %-16s -> %d\n", $name, $ipv4, $num | |
302 | if $amt_debug; | |
303 | return SOAP::Data->name($name => $num); | |
304 | } | |
305 | ||
306 | sub configure_network { | |
307 | my $if = shift; | |
308 | my $link = shift; | |
309 | my $ip = shift; | |
310 | my $mask = shift; | |
311 | my $gw = shift; | |
312 | my $dns1 = shift; | |
313 | my $dns2 = shift; | |
314 | ||
315 | my $mode; | |
316 | my @ifdesc; | |
317 | my @ipv4; | |
318 | ||
319 | my $method; | |
320 | my @args; | |
321 | ||
322 | # build argument structs ... | |
323 | die "no interface" if !defined($if); | |
324 | die "no linkpolicy" if !defined($link); | |
325 | if (defined($ip)) { | |
326 | $mode = "SEPARATE_MAC_ADDRESS"; | |
327 | die "no ip mask" if !defined($mask); | |
328 | die "no default gw" if !defined($gw); | |
329 | $dns1 = $gw if !defined($dns1); | |
330 | $dns2 = "0.0.0.0" if !defined($dns2); | |
331 | push (@ipv4, ipv4_addr("LocalAddress", $ip)); | |
332 | push (@ipv4, ipv4_addr("SubnetMask", $mask)); | |
333 | push (@ipv4, ipv4_addr("DefaultGatewayAddress", $gw)); | |
334 | push (@ipv4, ipv4_addr("PrimaryDnsAddress", $dns1)); | |
335 | push (@ipv4, ipv4_addr("SecondaryDnsAddress", $dns2)); | |
336 | } else { | |
337 | $mode = "SHARED_MAC_ADDRESS"; | |
338 | # no ip info -- use DHCP | |
339 | } | |
340 | ||
341 | push (@ifdesc, SOAP::Data->name("InterfaceMode" => $mode)); | |
342 | push (@ifdesc, SOAP::Data->name("LinkPolicy" => $link)); | |
343 | push (@ifdesc, SOAP::Data->name("IPv4Parameters" => | |
344 | \SOAP::Data->value(@ipv4))) | |
345 | if @ipv4; | |
346 | ||
347 | push (@args, SOAP::Data->name("InterfaceHandle" => $if)); | |
348 | push (@args, SOAP::Data->name("InterfaceDescriptor" => | |
349 | \SOAP::Data->value(@ifdesc))); | |
350 | ||
351 | # perform call | |
352 | do_soap($nas, "SetInterfaceSettings", @args); | |
353 | } | |
354 | ||
355 | ||
356 | ############################################################################# | |
357 | # main | |
358 | ||
359 | if (!defined($amt_host)) { | |
360 | usage(); | |
361 | exit 1; | |
362 | } | |
363 | ||
364 | soap_init; | |
365 | ||
366 | if ($amt_command eq "info") { | |
367 | print_general_info; | |
368 | print_remote_info; | |
369 | } elsif ($amt_command eq "netinfo") { | |
370 | check_amt_version(2,5); | |
371 | print_network_info; | |
372 | } elsif ($amt_command eq "netconf") { | |
373 | check_amt_version(2,5); | |
374 | configure_network(@ARGV); | |
375 | } elsif ($amt_command =~ m/^(reset|powerup|powerdown|powercycle)$/) { | |
376 | remote_control($amt_command); | |
377 | } else { | |
378 | print "unknown command: $amt_command\n"; | |
379 | } | |
380 |