ruby-amt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/AUTHORS +1 -0
  2. data/COPYING +15 -0
  3. data/ChangeLog +392 -0
  4. data/GPL +674 -0
  5. data/Rakefile +292 -0
  6. data/VERSION +1 -0
  7. data/doc/default.css +211 -0
  8. data/doc/default.template +78 -0
  9. data/doc/documentation.page +40 -0
  10. data/doc/img/bg.jpg +0 -0
  11. data/doc/img/image.jpg +0 -0
  12. data/doc/img/line.jpg +0 -0
  13. data/doc/img/shadow.jpg +0 -0
  14. data/doc/index.page +61 -0
  15. data/doc/installation.page +115 -0
  16. data/doc/news.page +25 -0
  17. data/doc/news/release_0_1_0.page +16 -0
  18. data/doc/virtual +2 -0
  19. data/lib/amt/pt_status.rb +59 -0
  20. data/lib/amt/service.rb +16 -0
  21. data/lib/amt/service/basic.rb +159 -0
  22. data/lib/amt/service/hardware_asset.rb +83 -0
  23. data/lib/amt/service/hardware_asset/amt_information_table.rb +49 -0
  24. data/lib/amt/service/hardware_asset/asset.rb +118 -0
  25. data/lib/amt/service/hardware_asset/baseboard.rb +31 -0
  26. data/lib/amt/service/hardware_asset/bios.rb +65 -0
  27. data/lib/amt/service/hardware_asset/computer_system.rb +30 -0
  28. data/lib/amt/service/hardware_asset/fru.rb +37 -0
  29. data/lib/amt/service/hardware_asset/media_device.rb +63 -0
  30. data/lib/amt/service/hardware_asset/memory_module.rb +91 -0
  31. data/lib/amt/service/hardware_asset/portable_battery.rb +80 -0
  32. data/lib/amt/service/hardware_asset/processor.rb +123 -0
  33. data/lib/amt/service/hardware_asset/vpro_verification_table.rb +120 -0
  34. data/lib/amt/service/network_administration.rb +181 -0
  35. data/lib/amt/service/network_administration/structures.rb +29 -0
  36. data/lib/amt/service/remote_control.rb +73 -0
  37. data/lib/amt/service/remote_control/structures.rb +120 -0
  38. data/lib/amt/service/security_administration.rb +430 -0
  39. data/lib/amt/service/security_administration/structures.rb +117 -0
  40. data/lib/amt/system.rb +134 -0
  41. data/lib/amt/utility.rb +33 -0
  42. data/lib/amt/utility/bit_struct.rb +164 -0
  43. data/lib/amt/utility/enum.rb +119 -0
  44. data/lib/amt/version.rb +8 -0
  45. data/setup.rb +1585 -0
  46. metadata +125 -0
@@ -0,0 +1,117 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'amt/service/security_administration'
4
+ require 'amt/utility'
5
+
6
+ module AMT
7
+ module Service
8
+ class SecurityAdministration
9
+
10
+ # Enumeration containing names of AMT interfaces that can be enabled/disabled. Used for
11
+ # SecurityAdministration#set_enabled_interfaces and
12
+ # SecurityAdministration#get_enabled_interfaces.
13
+ class EnabledInterface < AMT::Utility::Enum
14
+ multi_add %w[WebUI SerialOverLAN IdeRedirection]
15
+ end
16
+
17
+ # The AMT SOAP interface enumeration. Used for SecurityAdministration#set_tls_options
18
+ # and SecurityAdministration#get_tls_options.
19
+ class Interface < AMT::Utility::Enum
20
+ multi_add %w[NetworkInterface LocalHostInterface]
21
+ end
22
+
23
+ # The TLS Authentication method enumeration. Used for SecurityAdministration#set_tls_options
24
+ # and SecurityAdministration#get_tls_options.
25
+ class TlsAuthentication < AMT::Utility::Enum
26
+ multi_add %w[NoAuth ServerAuth MutualAuth]
27
+ end
28
+
29
+ # Struct class containing version information as returned by
30
+ # SecurityAdministration#get_core_version.
31
+ CoreVersion = Struct.new(:major, :minor, :micro)
32
+
33
+ # Mapping of provisioning mode name to value. Used for SecurityAdministration#unprovision and
34
+ # SecurityAdministration#get_provisioning_mode.
35
+ class ProvisioningMode < AMT::Utility::Enum
36
+ multi_add(0 => :current, 1 => :enterprise, 2 => :small_business, 3 => :remote_connectivity)
37
+ end
38
+
39
+ # Struct class containing information about an user ACL. The +user+ field may either contain a
40
+ # binary String identifying a Kerberos SID or a User class instance, the +access_permission+
41
+ # field contains an instance of AccessPermission and +realms+ contains a list of UserAclRealm
42
+ # instances. Used for SecurityAdministration#add_user_acl_entry_ex and
43
+ # SecurityAdministration#update_user_acl_entry_ex.
44
+ UserAclEntryEx = Struct.new(:user, :access_permission, :realms)
45
+
46
+ # Class containing information about a user. Either a plain text password or an already hashed
47
+ # password must be provided. If a plain text password is provided, the hashed password is
48
+ # automatically calculated.
49
+ class User
50
+
51
+ # The username to be used. May only contain 7-bit ASCII characters, in the range of 33- 126,
52
+ # excluding ‘:’, ‘,’, ‘<’, ‘>’, ‘&’, and ‘”’ characters. Length is limited to 16 characters.
53
+ attr_reader :username
54
+
55
+ # The password for the user. This or #hashed_password must be set.
56
+ attr_reader :password
57
+
58
+ # The hashed password for the user. This or #password must be set.
59
+ attr_reader :hashed_password
60
+
61
+
62
+ # Create a new User object with the given +username+ and, optionally, +password+.
63
+ def initialize(username, password = nil)
64
+ self.username = username
65
+ self.password = password
66
+ end
67
+
68
+ # Contains the characters that are allowed in the username.
69
+ ALLOWED_USERNAME_CHARS = (33..126).to_a - ":,<>&\"".unpack('c*')
70
+
71
+ # Set the username to +value+. If the username is not valid, an ArgumentError is raised.
72
+ def username=(value)
73
+ value.each_byte do |b|
74
+ ALLOWED_USERNAME_CHARS.include?(b) || raise(ArgumentError, "invalid character in username")
75
+ end
76
+ raise(ArgumentError, 'username length is limited to 16 characters') if value.length > 16
77
+ raise(ArgumentError, 'username must not be empty') if value.length == 0
78
+ @username = value
79
+ end
80
+
81
+ # Set the #password to +value+ and clear the #hashed_password.
82
+ def password=(value)
83
+ @hashed_password, @password = nil, value
84
+ end
85
+
86
+ # Set the #hashed_password to +value+ and clear the #password.
87
+ def hashed_password=(value)
88
+ @password, @hashed_password = nil, value
89
+ end
90
+
91
+ end
92
+
93
+ # Access permissions enumeration. Used in the UserAclEntryEx structure.
94
+ class AccessPermission < AMT::Utility::Enum
95
+ multi_add %w[LocalAccessPermission NetworkAccessPermission AnyAccessPermission]
96
+ end
97
+
98
+ # The user ACL realms enumeration. Used in the UserAclEntryEx structure.
99
+ class UserAclRealm < AMT::Utility::Enum
100
+ multi_add(0 => :invalid, 1 => :rcs, 2 => :redirection, 3 => :pt_administration,
101
+ 4 => :hardware_asset, 5 => :remote_control, 6 => :storage,
102
+ 7 => :event_manager, 8 => :storage_admin, 9 => :agent_presence_local,
103
+ 10 => :agent_presence_remote, 11 => :circuit_breaker, 12 => :network_time,
104
+ 13 => :general_info, 14 => :firmware_update, 15 => :eit, 16 => :local_un,
105
+ 17 => :endpoint_access_control, 18 => :endpoint_access_control_admin,
106
+ 19 => :event_log_reader, 20 => :security_audit_log, 21 => :user_access_control,
107
+ 22 => :reserved, 23 => :anti_theft)
108
+ end
109
+
110
+ # Struct class containing the fields for a global power policy (used by
111
+ # SecurityAdministration#set_global_power_policy and
112
+ # SecurityAdministration#get_global_power_policy).
113
+ GlobalPowerPolicy = Struct.new(:idle_wake_timeout)
114
+
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,134 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ##
4
+ # This is the API documentation for ruby-amt!
5
+ #
6
+ # Have a look at the \AMT module which provides a good starting point!
7
+
8
+
9
+ #
10
+ # The ruby-amt library provides access to the SOAP services provided by Intel AMT devices. Before
11
+ # you decide whether to use the library or not, you should know the following:
12
+ #
13
+ # * The library has been designed to be used with Intel AMT 5.0 devices. This is the reason why no
14
+ # deprecated methods have been implemented.
15
+ #
16
+ # * Furthermore, the library has been designed to be used with Intel AMT devices in SMB mode. So
17
+ # SOAP methods which are only useful for devices in Enterprise Mode have not been implemented. One
18
+ # reason is that I don't have access to devices in Enterprise Mode and therefore cannot test these
19
+ # methods.
20
+ #
21
+ # = Short Overview
22
+ #
23
+ # The library provides a "low-level" implementation of the client side of the SOAP services (as
24
+ # classes in AMT::Service) as well as a class (AMT::System) for high-level access. The adjective
25
+ # "low-level" is not really correct since the implementation of the client side of the SOAP services
26
+ # is not done by generating code from WSDL files (which normally results in a direct mapping of the
27
+ # SOAP methods and data structures) but by hand-crafting the code and providing simple but adequate
28
+ # data structures.
29
+ #
30
+ # So, although the SOAP service classes directly represent SOAP services and their methods, their
31
+ # usage in an application is actually quite simple. However, there are some AMT work flows which
32
+ # require calling more than one method or getting available states before actually setting
33
+ # something. This can easily be overlooked by people not acquainted with Intel AMT. Therefore there
34
+ # exists a class for high-level access to the AMT functionality of a system which takes this burden
35
+ # of you.
36
+ #
37
+ # = Library Organization
38
+ #
39
+ # This module houses all modules/classes that are in the ruby-amt library. There are three main
40
+ # modules/classes:
41
+ #
42
+ # [AMT::Service]
43
+ # This module contains all SOAP service classes. There is a one-to-one mapping from
44
+ # the Intel AMT SOAP services to classes in this module. Note that not all SOAP services are
45
+ # implemented because some are not really useful for a management application.
46
+ #
47
+ # [AMT::Utility]
48
+ # This module houses utility classes that are used by other classes (mostly the service classes).
49
+ #
50
+ # [AMT::System]
51
+ # This is the class that can be used for high-level access to the functionality of an AMT system.
52
+ #
53
+ # = Library Usage
54
+ #
55
+ # == Direct use of SOAP Service Classes
56
+ #
57
+ # All service classes are derived from AMT::Service::Basic and have the same initialization
58
+ # parameters. You need to provide at least the hostname of the AMT device, a username and a
59
+ # password.
60
+ #
61
+ # You don't need to load an individual service class, just use
62
+ #
63
+ # require 'amt/service'
64
+ #
65
+ # since this will automatically load any service class and any data structures that are needed on
66
+ # demand.
67
+ #
68
+ # For example, the AMT::Service::RemoteControl service can be created like this:
69
+ #
70
+ # rcs = AMT::Service::RemoteControl.new('amt.example.com', 'admin', 'P@ssw0rD')
71
+ #
72
+ # After that you can just call the method you would like to invoke on the AMT system. But before
73
+ # that you should read the method description sothat you know what parameters to pass. Since the
74
+ # SOAP service classes are not created from WSDL files, they provide a nicer, more Ruby like
75
+ # interface to the SOAP methods. However, this also means that the method signature sometimes
76
+ # differs a little bit from the method signature as defined in the "Network Interface Guide" (which
77
+ # can be found in the Intel AMT SDK).
78
+ #
79
+ # Take the AMT::Service::RemoteControl#get_system_power_state as example:
80
+ #
81
+ # sps = rcs.get_system_power_state
82
+ #
83
+ # Since this method takes no parameters, there is no difference in this respect. The method would
84
+ # nominally return a bit structure as an unsigned 32 bit integer. However, this has been changed
85
+ # sothat it returns an instance of AMT::Service::RemoteControl::SystemPowerState which provides easy
86
+ # access to the fields of the bit structure. For example:
87
+ #
88
+ # sps.power_state # => :s0
89
+ # sps.watchdog_expired? # => false
90
+ # sps.power_source # => :ac
91
+ #
92
+ # Such a conversion of input or output arguments is true for all implemented methods. The special
93
+ # data structures needed by a service are defined in the namespace of the service. For example, all
94
+ # data structures needed as input or returned as output for the RemoteControl service are defined
95
+ # unter AMT::Service::RemoteControl.
96
+ #
97
+ # So how does one provide input parameters? We take the AMT::Service::RemoteControl#remote_control
98
+ # method as example. You can learn from the method description that it has one mandatory and several
99
+ # optional arguments. Additionally, it is stated which type the arguments have. In its simplest
100
+ # form, one needs to provide just a value for the +command+ parameter which should be an instance of
101
+ # AMT::Service::RemoteControl::RemoteControlCommand. Checking out the class we see that it is a
102
+ # subclass of AMT::Utility::Enum. This allows us to use any of the following ways to power up an AMT
103
+ # system which is currently powered down:
104
+ #
105
+ # rcs.remote_control(AMT::Service::RemoteControl::RemoteControlCommand.for(:0x11))
106
+ # rcs.remote_control(AMT::Service::RemoteControl::RemoteControlCommand.for(:power_up))
107
+ # rcs.remote_control(0x11)
108
+ # rcs.remote_control(:power_up)
109
+ #
110
+ # As you can see, one doesn't actually need to create an instance of the RemoteControlCommand class,
111
+ # one just needs to provide either a valid enumeration value or enumeration name! <b>This is true
112
+ # everywhere a subclass of AMT::Utility::Enum is expected.</b>
113
+ #
114
+ # A simliar short-cut is available when an instance of a subclass of AMT::Utility::BitStruct is
115
+ # expected - see AMT::Utility::BitStruct.new !
116
+ #
117
+ # Here is a final example with some optional parameters:
118
+ #
119
+ # rcs.remote_control(:power_up, 343, :boot_options => [:lock_keyboard], :special_command => :pxe_boot)
120
+ #
121
+ #
122
+ # == High-level Interface
123
+ #
124
+ # The high-level interface is not implemented currently.
125
+ #
126
+ module AMT
127
+
128
+ # High-level access to AMT functionality.
129
+ #
130
+ # NOT IMPLEMENTED
131
+ class System
132
+ end
133
+
134
+ end
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module AMT
4
+
5
+ # This module houses utility classes that are used by the other AMT classes.
6
+ module Utility
7
+
8
+ autoload :BitStruct, 'amt/utility/bit_struct'
9
+ autoload :Enum, 'amt/utility/enum'
10
+
11
+
12
+ # Create a UUID string from binary data which can either have a length of 16 characters (then it
13
+ # is considered to be a binary UUID) or a length of 32 characters (an already unpacked binary
14
+ # UUID).
15
+ def self.binary_to_uuid(data)
16
+ data = data.unpack('H32').first if data.length == 16
17
+ a = data.scan(/../)
18
+ a[0,4].reverse.join('') + "-" + a[4,2].reverse.join('') + "-" + a[6,2].reverse.join('') +
19
+ "-" + a[8,2].join('') + "-" + a[10,6].join('')
20
+ end
21
+
22
+ # Convert a UUID string to binary data.
23
+ def self.uuid_to_binary(uuid)
24
+ [uuid[0,8].scan(/../).reverse.join('') +
25
+ uuid[9,4].scan(/../).reverse.join('') +
26
+ uuid[14,4].scan(/../).reverse.join('') +
27
+ uuid[19,4].scan(/../).join('') +
28
+ uuid[24,12].scan(/../).join('')].pack('H32')
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,164 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module AMT
4
+
5
+ module Utility
6
+
7
+ # A very simple base class which can be used to extract information from a number based on its
8
+ # bits, or to set it.
9
+ #
10
+ # It isn't useful to create objects directly from this class but one should create a subclass
11
+ # and use the provided class methods to define how to interpret the bits of a number.
12
+ class BitStruct
13
+
14
+ # Interpret the bit with the +index+ (starting from zero) as boolean flag named +name+ (should
15
+ # be a Symbol). If the bit at the index is +1+, the flag is interpreted as +true+. The
16
+ # optional parameter +desc+ can be used to provide a textual representation of the +true+
17
+ # state.
18
+ #
19
+ # This method also adds accessor methods for the property. For example, if the property is
20
+ # called +amt_enabled+, the created getter method is called <tt>#amt_enabled?</tt> and the
21
+ # setter method is called <tt>#amt_enabled!</tt>. Note the trailing question/exclamation
22
+ # marks.
23
+ #
24
+ # Example usage:
25
+ #
26
+ # boolean 5, :amt_enabled, 'AMT is enabled'
27
+ def self.boolean(index, name, desc = name.to_s)
28
+ index = (0x1 << index)
29
+ (@boolean ||= []) << [name, desc]
30
+ define_method("#{name}?") do
31
+ @value & index == index
32
+ end
33
+ define_method("#{name}!") do
34
+ @value |= index
35
+ end
36
+ end
37
+
38
+
39
+ # Same as BitStruct.boolean but +mask+ defines a bit mask and the value is only +true+ if all
40
+ # bits specified by the bit mask (ie. all bits that are +1+ in the bit mask) are set.
41
+ #
42
+ # Example usage:
43
+ #
44
+ # mboolean 0b101, :amt_enabled, 'AMT is enabled'
45
+ def self.mboolean(mask, name, desc = name.to_s)
46
+ (@boolean ||= []) << [name, desc]
47
+ define_method("#{name}?") do
48
+ @value & mask == mask
49
+ end
50
+ define_method("#{name}!") do
51
+ @value |= mask
52
+ end
53
+ end
54
+
55
+
56
+ # Interpret the bits in the +bit_range+ (starting from zero) as unsigned integer named +name+
57
+ # (should be a Symbol). The optional parameter +desc+ can be used to provide a textual
58
+ # representation of the meaning of the value.
59
+ #
60
+ # This method also adds accessor methods for the property. For example, if the property is
61
+ # called +version+, the created getter method is called <tt>#version</tt> and the setter
62
+ # method is called <tt>#version=</tt>.
63
+ #
64
+ # Example usage:
65
+ #
66
+ # unsigned 2..5, :version, 'The integer version of the AMT device'
67
+ def self.unsigned(bit_range, name, desc = name.to_s)
68
+ mask = (2**(bit_range.end - bit_range.begin + 1) - 1) << bit_range.begin
69
+ (@unsigned ||= []) << [name, desc]
70
+ define_method(name) do
71
+ (@value & mask) >> bit_range.begin
72
+ end
73
+ define_method("#{name}=") do |number|
74
+ @value |= (number << bit_range.begin) & mask
75
+ end
76
+ end
77
+
78
+ # Interpret the bits in the +bit_range+ (starting from zero) as unsigned integer value of an
79
+ # enumeration called +name+ (should be a Symbol).
80
+ #
81
+ # The parameter +values+ specifies the mapping from number to meaning (normally a String). The
82
+ # optional parameter +desc+ can be used to provide a textual representation of the meaning of
83
+ # the enumeration.
84
+ #
85
+ # This method also adds accessor methods for the property. For example, if the property is
86
+ # called +version+, the created getter method is called <tt>#version</tt> and the setter
87
+ # method is called <tt>#version=</tt>.
88
+ #
89
+ # Example usage:
90
+ #
91
+ # enum 0..1, :device_type, {0 => 'Foo', 1 => 'Bar', 2 => 'Baz', 3 => Quux'}
92
+ def self.enum(bit_range, name, values, desc = name.to_s)
93
+ mask = (2**(bit_range.end - bit_range.begin + 1) - 1) << bit_range.begin
94
+ (@enum ||= []) << [name, values, desc]
95
+ define_method(name) do
96
+ values[(@value & mask) >> bit_range.begin]
97
+ end
98
+ define_method("#{name}=") do |number|
99
+ @value |= (number << bit_range.begin) & mask
100
+ end
101
+ end
102
+
103
+ # Return a hash of all defined fields for this class. The hash keys are <tt>:boolean</tt> for
104
+ # the boolean properties, <tt>:unsigned</tt> for the unsigned integer properties and
105
+ # <tt>:enum</tt> for the enumeration properties. The hash values are arrays with information
106
+ # (depending on the type of the field) about the fields.
107
+ def self.fields
108
+ {:boolean => @boolean || [], :unsigned => @unsigned || [], :enum => @enum || []}
109
+ end
110
+
111
+ # The integer value which should be interpreted bit-wise.
112
+ attr_reader :value
113
+
114
+ # Create a new object. If +value+ is an integer, it is used directly and interpreted bit-wise.
115
+ # If +value+ is an array, it is processed in the following way:
116
+ #
117
+ # * symbols are interpreted as boolean fields
118
+ # * two-item arrays where the first item is a symbol and the second an integer are interpreted
119
+ # as unsigned or enum fields (depending in which category the symbol falls).
120
+ def initialize(value = 0)
121
+ if value.kind_of?(Integer)
122
+ @value = value
123
+ elsif value.kind_of?(Array)
124
+ @value = 0
125
+ value.each do |sym, val|
126
+ if val.nil?
127
+ send("#{sym}!")
128
+ else
129
+ send("#{sym}=", val)
130
+ end
131
+ end
132
+ else
133
+ raise ArgumentError, 'invalid argument type specified'
134
+ end
135
+ end
136
+
137
+ def inspect #:nodoc:
138
+ bools = self.class.fields[:boolean].select {|n,d| send("#{n}?")}.collect {|n, d| n.to_s}
139
+ unsigns = self.class.fields[:unsigned].collect {|n, d| "#{n}=#{send(n)}"}
140
+ enum = self.class.fields[:enum].collect {|n, d| "#{n}=#{send(n)}"}
141
+ "#<#{self.class.name} #{(bools + unsigns + enum).join(', ')}>"
142
+ end
143
+
144
+ # Return an array with textual representations for output purposes of the the fields specified
145
+ # by +used_fields+.
146
+ def list(used_fields = [:boolean, :unsigned, :enum])
147
+ result = []
148
+ if used_fields.include?(:boolean)
149
+ result += self.class.fields[:boolean].select {|n,d| send("#{n}?")}.collect {|n,d| d}
150
+ end
151
+ if used_fields.include?(:unsigned)
152
+ result += self.class.fields[:unsigned].collect {|n, d| "#{d}=#{send(n)}"}
153
+ end
154
+ if used_fields.include?(:enum)
155
+ result += self.class.fields[:enum].collect {|n, d| "#{d}=#{send(n)}"}
156
+ end
157
+ result
158
+ end
159
+
160
+ end
161
+
162
+ end
163
+
164
+ end