]>
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})); | |
280 | push (@args, SOAP::Data->name('IanaOemNumber' => 4542)); | |
281 | do_soap($rcs, "RemoteControl", @args); | |
282 | } else { | |
283 | printf "canceled\n"; | |
284 | } | |
285 | } | |
286 | ||
287 | sub ipv4_addr($$) { | |
288 | my $name = shift; | |
289 | my $ipv4 = shift; | |
290 | ||
291 | $ipv4 =~ m/(\d+).(\d+).(\d+).(\d+)/ or die "parse ipv4 address: $ipv4"; | |
292 | my $num = $1 * 256 * 256 * 256 + | |
293 | $2 * 256 * 246 + | |
294 | $3 * 256 + | |
295 | $4; | |
296 | printf STDERR "ipv4 %-24s: %-16s -> %d\n", $name, $ipv4, $num | |
297 | if $amt_debug; | |
298 | return SOAP::Data->name($name => $num); | |
299 | } | |
300 | ||
301 | sub configure_network { | |
302 | my $if = shift; | |
303 | my $link = shift; | |
304 | my $ip = shift; | |
305 | my $mask = shift; | |
306 | my $gw = shift; | |
307 | my $dns1 = shift; | |
308 | my $dns2 = shift; | |
309 | ||
310 | my $mode; | |
311 | my @ifdesc; | |
312 | my @ipv4; | |
313 | ||
314 | my $method; | |
315 | my @args; | |
316 | ||
317 | # build argument structs ... | |
318 | die "no interface" if !defined($if); | |
319 | die "no linkpolicy" if !defined($link); | |
320 | if (defined($ip)) { | |
321 | $mode = "SEPARATE_MAC_ADDRESS"; | |
322 | die "no ip mask" if !defined($mask); | |
323 | die "no default gw" if !defined($gw); | |
324 | $dns1 = $gw if !defined($dns1); | |
325 | $dns2 = "0.0.0.0" if !defined($dns2); | |
326 | push (@ipv4, ipv4_addr("LocalAddress", $ip)); | |
327 | push (@ipv4, ipv4_addr("SubnetMask", $mask)); | |
328 | push (@ipv4, ipv4_addr("DefaultGatewayAddress", $gw)); | |
329 | push (@ipv4, ipv4_addr("PrimaryDnsAddress", $dns1)); | |
330 | push (@ipv4, ipv4_addr("SecondaryDnsAddress", $dns2)); | |
331 | } else { | |
332 | $mode = "SHARED_MAC_ADDRESS"; | |
333 | # no ip info -- use DHCP | |
334 | } | |
335 | ||
336 | push (@ifdesc, SOAP::Data->name("InterfaceMode" => $mode)); | |
337 | push (@ifdesc, SOAP::Data->name("LinkPolicy" => $link)); | |
338 | push (@ifdesc, SOAP::Data->name("IPv4Parameters" => | |
339 | \SOAP::Data->value(@ipv4))) | |
340 | if @ipv4; | |
341 | ||
342 | push (@args, SOAP::Data->name("InterfaceHandle" => $if)); | |
343 | push (@args, SOAP::Data->name("InterfaceDescriptor" => | |
344 | \SOAP::Data->value(@ifdesc))); | |
345 | ||
346 | # perform call | |
347 | do_soap($nas, "SetInterfaceSettings", @args); | |
348 | } | |
349 | ||
350 | ||
351 | ############################################################################# | |
352 | # main | |
353 | ||
354 | if (!defined($amt_host)) { | |
355 | usage(); | |
356 | exit 1; | |
357 | } | |
358 | ||
359 | soap_init; | |
360 | ||
361 | if ($amt_command eq "info") { | |
362 | print_general_info; | |
363 | print_remote_info; | |
364 | } elsif ($amt_command eq "netinfo") { | |
365 | check_amt_version(2,5); | |
366 | print_network_info; | |
367 | } elsif ($amt_command eq "netconf") { | |
368 | check_amt_version(2,5); | |
369 | configure_network(@ARGV); | |
370 | } elsif ($amt_command =~ m/^(reset|powerup|powerdown|powercycle)$/) { | |
371 | remote_control($amt_command); | |
372 | } else { | |
373 | print "unknown command: $amt_command\n"; | |
374 | } | |
375 |