boris 1.0.0.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. data/LICENSE.md +9 -0
  2. data/README.md +94 -0
  3. data/boris.gemspec +28 -0
  4. data/doc/Array.html +437 -0
  5. data/doc/Boris.html +230 -0
  6. data/doc/Boris/ConnectionAlreadyActive.html +123 -0
  7. data/doc/Boris/ConnectionFailed.html +127 -0
  8. data/doc/Boris/Connector.html +794 -0
  9. data/doc/Boris/InvalidCredentials.html +131 -0
  10. data/doc/Boris/InvalidOption.html +123 -0
  11. data/doc/Boris/InvalidTargetName.html +123 -0
  12. data/doc/Boris/Lumberjack.html +466 -0
  13. data/doc/Boris/MissingCredentials.html +123 -0
  14. data/doc/Boris/NoActiveConnection.html +123 -0
  15. data/doc/Boris/NoProfileDetected.html +123 -0
  16. data/doc/Boris/Options.html +783 -0
  17. data/doc/Boris/Profiles.html +117 -0
  18. data/doc/Boris/Profiles/Linux.html +1151 -0
  19. data/doc/Boris/Profiles/RedHat.html +875 -0
  20. data/doc/Boris/Profiles/Solaris.html +1230 -0
  21. data/doc/Boris/Profiles/Structure.html +2050 -0
  22. data/doc/Boris/Profiles/UNIX.html +893 -0
  23. data/doc/Boris/Profiles/Windows.html +1846 -0
  24. data/doc/Boris/Profiles/Windows/Windows2003.html +304 -0
  25. data/doc/Boris/Profiles/Windows/Windows2008.html +379 -0
  26. data/doc/Boris/Profiles/Windows/Windows2012.html +304 -0
  27. data/doc/Boris/SNMPConnector.html +512 -0
  28. data/doc/Boris/SSHConnector.html +633 -0
  29. data/doc/Boris/Target.html +2002 -0
  30. data/doc/Boris/WMIConnector.html +1134 -0
  31. data/doc/BorisLogger.html +217 -0
  32. data/doc/Hash.html +195 -0
  33. data/doc/String.html +1246 -0
  34. data/doc/_index.html +420 -0
  35. data/doc/class_list.html +53 -0
  36. data/doc/css/common.css +1 -0
  37. data/doc/css/full_list.css +57 -0
  38. data/doc/css/style.css +328 -0
  39. data/doc/file.README.html +183 -0
  40. data/doc/file_list.html +55 -0
  41. data/doc/frames.html +28 -0
  42. data/doc/index.html +183 -0
  43. data/doc/js/app.js +214 -0
  44. data/doc/js/full_list.js +173 -0
  45. data/doc/js/jquery.js +4 -0
  46. data/doc/method_list.html +1468 -0
  47. data/doc/top-level-namespace.html +126 -0
  48. data/lib/boris.rb +30 -0
  49. data/lib/boris/connectors.rb +47 -0
  50. data/lib/boris/connectors/snmp.rb +56 -0
  51. data/lib/boris/connectors/ssh.rb +110 -0
  52. data/lib/boris/connectors/wmi.rb +186 -0
  53. data/lib/boris/errors.rb +17 -0
  54. data/lib/boris/helpers/array.rb +63 -0
  55. data/lib/boris/helpers/constants.rb +20 -0
  56. data/lib/boris/helpers/hash.rb +8 -0
  57. data/lib/boris/helpers/scrubber.rb +51 -0
  58. data/lib/boris/helpers/string.rb +130 -0
  59. data/lib/boris/lumberjack.rb +47 -0
  60. data/lib/boris/options.rb +86 -0
  61. data/lib/boris/profiles/linux/redhat.rb +77 -0
  62. data/lib/boris/profiles/linux_core.rb +216 -0
  63. data/lib/boris/profiles/unix/solaris.rb +307 -0
  64. data/lib/boris/profiles/unix_core.rb +85 -0
  65. data/lib/boris/profiles/windows/windows2003.rb +15 -0
  66. data/lib/boris/profiles/windows/windows2008.rb +23 -0
  67. data/lib/boris/profiles/windows/windows2012.rb +15 -0
  68. data/lib/boris/profiles/windows_core.rb +530 -0
  69. data/lib/boris/structure.rb +167 -0
  70. data/lib/boris/target.rb +340 -0
  71. data/test/connector_tests/test_snmp.rb +35 -0
  72. data/test/connector_tests/test_ssh.rb +51 -0
  73. data/test/connector_tests/test_wmi.rb +129 -0
  74. data/test/helper_tests/test_array.rb +25 -0
  75. data/test/helper_tests/test_hash.rb +10 -0
  76. data/test/helper_tests/test_string.rb +136 -0
  77. data/test/profile_tests/test_core_skeleton +107 -0
  78. data/test/profile_tests/test_linux_core.rb +331 -0
  79. data/test/profile_tests/test_redhat.rb +134 -0
  80. data/test/profile_tests/test_solaris.rb +523 -0
  81. data/test/profile_tests/test_unix_core.rb +117 -0
  82. data/test/profile_tests/test_windows.rb +536 -0
  83. data/test/setup_tests.rb +14 -0
  84. data/test/test_all.rb +8 -0
  85. data/test/test_options.rb +44 -0
  86. data/test/test_structure.rb +136 -0
  87. data/test/test_target.rb +146 -0
  88. metadata +241 -0
@@ -0,0 +1,85 @@
1
+ require 'boris/structure'
2
+
3
+ module Boris; module Profiles
4
+ module UNIX
5
+ include Structure
6
+
7
+ def self.connection_type
8
+ Boris::SSHConnector
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ return true if connector.value_at('uname -a') !~ /linux/i
13
+ end
14
+
15
+ def get_file_systems
16
+ super
17
+
18
+ file_system_command = %q{df -kl 2>/dev/null | grep ^/ | nawk '{print $1 "|" $2 / 1024 "|" $3 / 1024 "|" $6}'}
19
+ @connector.values_at(file_system_command).each do |file_system|
20
+ h = file_system_template
21
+ file_system = file_system.split('|')
22
+
23
+ h[:capacity_mb] = file_system[1].to_i
24
+ h[:file_system] = file_system[0]
25
+ h[:mount_point] = file_system[3]
26
+ h[:used_space_mb] = file_system[2].to_i
27
+
28
+ @file_systems << h
29
+ end
30
+ end
31
+
32
+ def get_hardware; super; end
33
+ def get_hosted_shares; super; end
34
+ def get_installed_applications; super; end
35
+ def get_installed_patches; super; end
36
+ def get_installed_services; super; end
37
+
38
+ def get_local_user_groups
39
+ super
40
+
41
+ user_data = @connector.values_at('cat /etc/passwd | grep -v "^#"')
42
+ group_data = @connector.values_at('cat /etc/group | grep -v "^#"')
43
+
44
+ users = []
45
+ groups = []
46
+
47
+ user_data.each do |x|
48
+ h = {}
49
+ x = x.split(':')
50
+ h[:status] = nil
51
+ h[:primary_group_id] = x[3]
52
+ h[:username] = x[0]
53
+ users << h
54
+ end
55
+
56
+ group_data.each do |group|
57
+ group = group.split(':')
58
+ h = {:members=>[], :name=>group[0]}
59
+
60
+ h[:members] = users.select{|user| (user[:primary_group_id] == group[2])}.collect{|user| user[:username]}
61
+
62
+ @local_user_groups << h
63
+ end
64
+ end
65
+
66
+ def get_network_id
67
+ super
68
+
69
+ hostname = @connector.value_at('hostname')
70
+ domain = @connector.value_at('domainname')
71
+ domain = nil if domain =~ /\(none\)/i
72
+
73
+ if hostname =~ /\./
74
+ hostname = hostname.split('.').shift
75
+ domain = hostname.join('.') if hostname =~ /\./
76
+ end
77
+
78
+ @network_id[:hostname] = hostname
79
+ @network_id[:domain] = domain
80
+ end
81
+
82
+ def get_network_interfaces; super; end
83
+ def get_operating_system; super; end
84
+ end
85
+ end; end
@@ -0,0 +1,15 @@
1
+ require 'boris/profiles/windows_core'
2
+
3
+ module Boris; module Profiles; module Windows
4
+ module Windows2003
5
+ include Windows
6
+
7
+ def self.connection_type
8
+ Windows.connection_type
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ return true if connector.value_at('SELECT Name FROM Win32_OperatingSystem')[:name] =~ /2003/
13
+ end
14
+ end
15
+ end; end; end
@@ -0,0 +1,23 @@
1
+ require 'boris/profiles/windows_core'
2
+
3
+ module Boris; module Profiles; module Windows
4
+ module Windows2008
5
+ include Windows
6
+
7
+ def self.connection_type
8
+ Windows.connection_type
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ return true if connector.value_at('SELECT Name FROM Win32_OperatingSystem')[:name] =~ /2008/
13
+ end
14
+
15
+ def get_operating_system
16
+ super
17
+
18
+ # grab the 'features' from win2008 servers, as it's only available on this version
19
+ # and already deprecated as of win2012
20
+ @operating_system[:features] = @connector.values_at('SELECT Name FROM Win32_ServerFeature').map {|f| f[:name]}
21
+ end
22
+ end
23
+ end; end; end
@@ -0,0 +1,15 @@
1
+ require 'boris/profiles/windows_core'
2
+
3
+ module Boris; module Profiles; module Windows
4
+ module Windows2012
5
+ include Windows
6
+
7
+ def self.connection_type
8
+ Windows.connection_type
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ return true if connector.value_at('SELECT Name FROM Win32_OperatingSystem')[:name] =~ /2012/
13
+ end
14
+ end
15
+ end; end; end
@@ -0,0 +1,530 @@
1
+ require 'boris/structure'
2
+
3
+ module Boris; module Profiles
4
+ module Windows
5
+ include Structure
6
+
7
+ APP32_KEYPATH = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'
8
+ APP64_KEYPATH = 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
9
+
10
+ NIC_CFG_KEYPATH = 'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}'
11
+ TCPIP_CFG_KEYPATH = 'SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces'
12
+
13
+ ORACLE_KEYPATH = 'SOFTWARE\ORACLE'
14
+ IIS_KEYPATH = 'SOFTWARE\Microsoft\INetStp'
15
+
16
+ DUPLEX_REG_VALS = [
17
+ :autonegadvertised,
18
+ :duplexmode,
19
+ :forcedspeedduplex,
20
+ :media_type,
21
+ :mediaselect,
22
+ :req_medium,
23
+ :requestedmediatype,
24
+ :speedduplex
25
+ ]
26
+
27
+ def self.connection_type
28
+ Boris::WMIConnector
29
+ end
30
+
31
+ def self.matches_target?(connector)
32
+ return true if connector.value_at('SELECT Name FROM Win32_OperatingSystem')[:name] =~ /windows/i
33
+ end
34
+
35
+ def get_file_systems
36
+ super
37
+
38
+ logical_disks = @connector.values_at('SELECT Antecedent, Dependent FROM Win32_LogicalDiskToPartition')
39
+ disk_partitions = @connector.values_at('SELECT Antecedent, Dependent FROM Win32_DiskDriveToDiskPartition')
40
+ physical_drives = @connector.values_at('SELECT DeviceID, Model FROM Win32_DiskDrive')
41
+ disk_space = @connector.values_at('SELECT FreeSpace, Name, Size FROM Win32_LogicalDisk WHERE DriveType=3')
42
+
43
+ disk_space.each do |ds|
44
+ h = file_system_template
45
+ h[:mount_point] = ds[:name]
46
+ h[:capacity_mb] = ds[:size].to_i / 1024
47
+ h[:used_space_mb] = h[:capacity_mb] - (ds[:freespace].to_i / 1024)
48
+
49
+ ld = logical_disks.select{|ld| ld[:dependent].include?(h[:mount_point])}[0]
50
+ h[:file_system] = ld[:antecedent].split(/\"/)[1]
51
+
52
+ dp = disk_partitions.select{|dp| dp[:dependent].include?(h[:file_system])}[0]
53
+ drive_id = dp[:antecedent].split('\\').last.delete('\"')
54
+
55
+ physical_drive = physical_drives.select{|pd| pd[:deviceid].include?(drive_id)}[0]
56
+ h[:san_storage] = true if physical_drive[:model] =~ /open-v/i
57
+
58
+ @file_systems << h unless h[:file_system].nil?
59
+ end
60
+ end
61
+
62
+ def get_hardware
63
+ super
64
+
65
+ serial_data = @connector.value_at('SELECT SerialNumber, SMBIOSBIOSVersion FROM Win32_BIOS')
66
+ @hardware[:serial] = serial_data[:serialnumber]
67
+ @hardware[:firmware_version] = serial_data[:smbiosbiosversion]
68
+
69
+ system_data = @connector.value_at('SELECT Manufacturer, Model, TotalPhysicalMemory FROM Win32_ComputerSystem')
70
+ @hardware[:vendor] = system_data[:manufacturer]
71
+ @hardware[:model] = system_data[:model]
72
+ @hardware[:memory_installed_mb] = system_data[:totalphysicalmemory].to_i / 1024 / 1024
73
+
74
+ cpu_data = @connector.values_at('SELECT * FROM Win32_Processor')
75
+
76
+ @hardware[:cpu_physical_count] = cpu_data.size
77
+
78
+ cpu = cpu_data.first
79
+
80
+ @hardware[:cpu_architecture] = cpu[:datawidth]
81
+ @hardware[:cpu_core_count] = cpu[:numberofcores]
82
+
83
+ @hardware[:cpu_model] = cpu[:name]
84
+ @hardware[:cpu_speed_mhz] = cpu[:maxclockspeed]
85
+ @hardware[:cpu_vendor] = cpu[:manufacturer]
86
+ end
87
+
88
+ def get_hosted_shares
89
+ super
90
+
91
+ share_data = @connector.values_at('SELECT Name, Path FROM Win32_Share WHERE Type = 0')
92
+ share_data.each do |share|
93
+ h = hosted_share_template
94
+ h[:name] = share[:name]
95
+ h[:path] = share[:path]
96
+ @hosted_shares << h
97
+ end
98
+ end
99
+
100
+ def get_installed_applications
101
+ super
102
+
103
+ @patches_from_registry = []
104
+
105
+ [APP32_KEYPATH, APP64_KEYPATH].each do |app_path|
106
+ @connector.registry_subkeys_at(app_path).each do |app_key|
107
+ h = installed_application_template
108
+
109
+ app_values = @connector.registry_values_at(app_key)
110
+
111
+ h[:date_installed] = DateTime.parse(app_values[:installdate]) if app_values[:installdate].kind_of?(String)
112
+
113
+ if app_values.has_key?(:displayname) && !(app_values[:displayname] =~ /^kb|\(kb\d+/i)
114
+ h[:install_location] = app_values[:installlocation] if app_values[:installlocation].nil?
115
+ h[:license_key] = get_product_key(app_values[:displayname], app_key)
116
+ h[:name] = concat_app_edition(app_values[:displayname])
117
+ h[:vendor] = app_values[:publisher]
118
+ h[:version] = app_values[:displayversion]
119
+
120
+ @installed_applications << h
121
+ elsif app_values[:displayname] =~ /^kb|\(kb\d+/i
122
+ # likely a ms patch, so we'll save this data to parse later in #get_installed_patches
123
+ @patches_from_registry << {:key_path=>app_key, :values=>app_values}
124
+ end
125
+ end
126
+ end
127
+
128
+ # look for some other popular applications not found in the usual spots
129
+
130
+ # Oracle (RDMS, AppServer (AS), Client)
131
+ oracle_keys = @connector.registry_subkeys_at(ORACLE_KEYPATH)
132
+ oracle_keys.each do |app_key|
133
+ if app_key =~ /^key_ora(db|home)/i
134
+ app_values = registry_values_at(app_key)
135
+ if app_values.has_key?(:oracle_group_name)
136
+ h = installed_application_template
137
+ h[:install_location] = app_values[:oracle_home]
138
+ h[:name] = app_values[:oracle_group_name].split('_')[0] + " #{app_values[:oracle_bundle_name]}"
139
+ h[:vendor] = VENDOR_ORACLE
140
+
141
+ @installed_applications << h
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ def get_installed_patches
148
+ super
149
+
150
+ # get patches via wmi
151
+ patch_data = @connector.values_at('SELECT Description, HotFixID, InstalledBy, InstalledOn, ServicePackInEffect
152
+ FROM Win32_QuickFixEngineering')
153
+
154
+ patch_data.each do |patch|
155
+ if !(patch[:hotfixid] =~ /\{/)
156
+
157
+ h = installed_patch_template
158
+
159
+ h[:patch_code] = patch[:hotfixid] == 'File 1' ? patch[:servicepackineffect] : patch[:hotfixid]
160
+
161
+ h[:installed_by] = patch[:installedby] unless patch[:installedby].empty?
162
+ h[:installed_by] = get_username(patch[:installedby]) if patch[:installedby][0, 4] == 'S-1-'
163
+
164
+ h[:date_installed] = DateTime.strptime(patch[:installedon], '%m/%d/%Y') unless patch[:installedon].empty?
165
+
166
+ @installed_patches << h
167
+ end
168
+ end
169
+
170
+ # get patches from the registry (under the application keys) if necessary
171
+ if @patches_from_registry.nil?
172
+ @patches_from_registry = []
173
+
174
+ [APP32_KEYPATH, APP64_KEYPATH].each do |app_path|
175
+ @connector.registry_subkeys_at(app_path).each do |app_key|
176
+ app_values = @connector.registry_values_at(app_key)
177
+ if app_values[:displayname] =~ /^kb|\(kb\d+/i
178
+ @patches_from_registry << {:key_path=>app_key, :values=>app_values}
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ @patches_from_registry.each do |patch_hash|
185
+ h = installed_patch_template
186
+
187
+ key_path = patch_hash[:key_path].after_slash
188
+ patch = patch_hash[:values]
189
+
190
+ h[:date_installed] = DateTime.strptime(patch[:installdate], '%Y%m%d') if patch[:installdate].kind_of?(String)
191
+
192
+ if key_path =~ /^kb/i
193
+ h[:patch_code] = key_path
194
+ elsif key_path.after_period =~ /^kb/i
195
+ h[:patch_code] = key_path.after_period
196
+ elsif patch[:displayname] =~ /\(kb\d+/i
197
+ h[:patch_code] = patch[:displayname].between_parenthesis
198
+ end
199
+
200
+ @installed_patches << h if @installed_patches.select{|p| p[:patch_code] == h[:patch_code]}.empty?
201
+ end
202
+ end
203
+
204
+ def get_installed_services
205
+ super
206
+
207
+ service_data = @connector.values_at('SELECT Name, PathName, StartMode FROM Win32_Service')
208
+ service_data.each do |service|
209
+ h = installed_service_template
210
+ h[:name] = service[:name]
211
+ h[:install_location] = service[:pathname]
212
+ h[:start_mode] = service[:startmode]
213
+ @installed_services << h
214
+ end
215
+ end
216
+
217
+ def get_local_user_groups
218
+ super
219
+
220
+ # first, retrieve the network id if necessary (will be used in later wmi queries)
221
+ get_network_id if !@network_id || !@network_id[:hostname]
222
+
223
+ # next, let's check if this system is a domain controller, otherwise, our query results
224
+ # may return all user accounts associated with the domain
225
+ if @operating_system.nil?
226
+ system_roles = @connector.value_at('SELECT Roles FROM Win32_ComputerSystem')[:roles]
227
+ else
228
+ system_roles = @operating_system[:roles]
229
+ end
230
+
231
+ if system_roles.select{|role| role =~ /domaincontroller/i}.empty?
232
+ # not a domain controller, so move on with retrieving users
233
+ groups = []
234
+
235
+ group_data = @connector.values_at("SELECT Name FROM Win32_Group WHERE Domain = '#{@network_id[:hostname]}'")
236
+ group_data.each {|group| @local_user_groups << {:name=>group[:name], :members=>[]}}
237
+
238
+ @local_user_groups.each do |group|
239
+
240
+ members = @connector.values_at("SELECT * FROM Win32_GroupUser WHERE GroupComponent = \"Win32_Group.Domain='#{@network_id[:hostname]}',Name='#{group[:name]}'\"")
241
+
242
+ members.each do |member|
243
+ hostname, username = member[:partcomponent].within_quotes
244
+ group[:members] << "#{hostname}\\#{username}"
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ def get_network_id
251
+ super
252
+
253
+ network_data = @connector.value_at('SELECT Domain, Name FROM Win32_ComputerSystem')
254
+ @network_id[:domain] = network_data[:domain]
255
+ @network_id[:hostname] = network_data[:name]
256
+ end
257
+
258
+ def get_network_interfaces
259
+ super
260
+
261
+ # retrieve ethernet interfaces
262
+ ethernet_interfaces = @connector.values_at('SELECT Index, MACAddress, Manufacturer, NetConnectionID, NetConnectionStatus, ProductName FROM Win32_NetworkAdapter WHERE NetConnectionID IS NOT NULL')
263
+
264
+ ethernet_interfaces.each do |interface_profile|
265
+ h = network_interface_template
266
+
267
+ index = interface_profile[:index]
268
+ padded_index = '%04d' % index
269
+ h[:is_uplink] = false
270
+ h[:mac_address] = interface_profile[:macaddress]
271
+ h[:model] = interface_profile[:productname]
272
+ h[:name] = interface_profile[:netconnectionid]
273
+ h[:status] = case interface_profile[:netconnectionstatus]
274
+ when 1, 2; 'up'
275
+ else; 'down'
276
+ end
277
+ h[:type] = 'ethernet'
278
+ h[:vendor] = interface_profile[:manufacturer]
279
+
280
+ # retrieve config for this interface
281
+ interface_config = @connector.value_at("SELECT DNSServerSearchOrder, IPAddress, IPSubnet, SettingID FROM Win32_NetworkAdapterConfiguration WHERE Index = #{index}")
282
+ guid = interface_config[:settingid]
283
+ h[:dns_servers] = interface_config[:dnsserversearchorder]
284
+
285
+ subnet = interface_config[:ipsubnet]
286
+ interface_config[:ipaddress].each do |ip_address|
287
+ h[:ip_addresses] << {:ip_address=>ip_address, :subnet=>subnet}
288
+ end
289
+
290
+ cfg_keypath = NIC_CFG_KEYPATH + "\\#{padded_index}"
291
+
292
+ # retrieve auto negotiate/duplex setting. tricky to get because this is very driver-specific.
293
+ # basically we have some known duplex values in DUPLEX_REG_VALS, then we search in the registry
294
+ # for each value and see if it exists. if it exists, then we dig deeper into the subkeys
295
+ # of this NIC's driver registry key and get the translated value from the list of options
296
+ # (found in the \Enum subkey)
297
+ interface_driver_config = @connector.registry_values_at(cfg_keypath)
298
+ h[:auto_negotiate] = false
299
+ duplex_reg_value = interface_driver_config.select {|key, val| DUPLEX_REG_VALS.include?(key)}
300
+
301
+ if duplex_reg_value.empty?
302
+ h[:auto_negotiate] = true
303
+ h[:duplex] = 'auto'
304
+ else
305
+ duplex_value = @connector.registry_values_at(cfg_keypath + "\\Ndi\\params\\#{duplex_reg_value.keys[0]}\\Enum")
306
+ duplex_value = duplex_value.select{|key, val| key.to_s == duplex_reg_value.values[0].to_s}.values[0]
307
+
308
+ if duplex_value =~ /auto|default/i
309
+ h[:auto_negotiate] = true
310
+ h[:duplex] = 'auto'
311
+ elsif duplex_value =~ /1000|full/i
312
+ h[:duplex] = 'full'
313
+ elsif duplex_value =~ /half/i
314
+ h[:duplex] = 'half'
315
+ end
316
+ end
317
+
318
+ # get model/vendor ids
319
+ hardware_ids = interface_driver_config[:matchingdeviceid].scan(/[ven|dev]_(\d{4})/i)
320
+
321
+ h[:vendor_id] = '0x' + hardware_ids[0].join unless hardware_ids[0].nil?
322
+ h[:model_id] = '0x' + hardware_ids[1].join unless hardware_ids[1].nil?
323
+
324
+ # retrieve mtu
325
+ mtu_data = @connector.registry_values_at(TCPIP_CFG_KEYPATH + "\\#{guid}")
326
+ h[:mtu] = mtu_data[:mtu] if mtu_data.has_key?(:mtu)
327
+
328
+ # translate the adapter guid to it's internal device name (usually prefixed with \\DEVICE)
329
+ device_guid = @connector.registry_values_at(cfg_keypath + '\\Linkage')[:export][0].gsub(/\\/, '\\\\\\')
330
+
331
+ adapter_name_data = @connector.value_at("SELECT InstanceName FROM MSNdis_EnumerateAdapter WHERE DeviceName = '#{device_guid}'", :root_wmi)
332
+ internal_adapter_name = adapter_name_data[:instancename]
333
+
334
+ # now with the internal adapter name, we can grab the connection speed.
335
+ speed_data = @connector.value_at("SELECT NdisLinkSpeed FROM MSNdis_LinkSpeed WHERE InstanceName = '#{internal_adapter_name}'", :root_wmi)
336
+ h[:current_speed_mbps] = speed_data[:ndislinkspeed] / 10000
337
+
338
+ @network_interfaces << h
339
+ end
340
+
341
+ # retrieve fibre channel interfaces. for windows 2003, this only works if the hbaapi is
342
+ # available, which can be installed by the fibre controller software provided by the
343
+ # vendor, or is installed as a separate package (fcinfo from microsoft). newer versions
344
+ # should have it built-in by default.
345
+ fibre_interface_profiles = @connector.values_at('SELECT Attributes, InstanceName FROM MSFC_FibrePortHBAAttributes', :root_wmi)
346
+
347
+ fibre_interfaces = @connector.values_at('SELECT InstanceName, Manufacturer, ModelDescription FROM MSFC_FCAdapterHBAAttributes', :root_wmi)
348
+
349
+ fibre_interfaces.each do |fibre_interface|
350
+ h = network_interface_template
351
+
352
+ index = fibre_interface_profiles.index{|profile| profile[:instancename] == fibre_interface[:instancename]}
353
+ profile = fibre_interface_profiles[index]
354
+
355
+ h[:fabric_name] = profile[:fabricname].to_wwn
356
+
357
+ if h[:fabric_name] == '0000000000000000'
358
+ h[:fabric_name] = nil
359
+ h[:status] = 'down'
360
+ else
361
+ h[:current_speed_mbps] = case profile[:portspeed]
362
+ when 1; 1000
363
+ when 2; 2000
364
+ when 4; 10000
365
+ when 8; 4000
366
+ when 16; 8000
367
+ when 32; 16000
368
+ end
369
+ h[:status] = 'up'
370
+ end
371
+
372
+ hardware_ids = fibre_interface[:instancename].scan(/[ven|dev]_(\d{4})/i)
373
+
374
+ h[:vendor_id] = '0x' + hardware_ids[0].join
375
+ h[:model_id] = '0x' + hardware_ids[1].join
376
+
377
+ h[:is_uplink] = false
378
+ h[:model] = fibre_interface[:modeldescription]
379
+ h[:name] = "fc#{index}"
380
+ h[:node_wwn] = profile[:nodewwn].to_wwn
381
+ h[:port_wwn] = profile[:portwwn].to_wwn
382
+ h[:type] = 'fibre'
383
+ h[:vendor] = fibre_interface[:manufacturer]
384
+
385
+ @network_interfaces << h
386
+ end
387
+ end
388
+
389
+ def get_operating_system
390
+ super
391
+
392
+ os_data = @connector.value_at('SELECT Caption, CSDVersion, InstallDate, OtherTypeDescription, Version FROM Win32_OperatingSystem')
393
+ @operating_system[:date_installed] = DateTime.parse(os_data[:installdate])
394
+ @operating_system[:kernel] = os_data[:version]
395
+ @operating_system[:license_key] = get_product_key('microsoft windows')
396
+ @operating_system[:name] = 'Microsoft Windows'
397
+ @operating_system[:service_pack] = os_data[:csdversion]
398
+
399
+ role_data = @connector.value_at('SELECT Roles FROM Win32_ComputerSystem')
400
+ @operating_system[:roles] = role_data[:roles]
401
+
402
+ os_data[:caption].gsub!(/microsoftr*|windows|(?<=server)r|\(r\)|edition|,/i, '').strip!
403
+ edition = os_data[:othertypedescription]
404
+ os_data[:caption].sub!(/20[0-9]*/) {|y| "#{y} #{edition}"} if edition
405
+
406
+ @operating_system[:version] = os_data[:caption]
407
+ end
408
+
409
+ def get_product_key(app_name, guid=nil)
410
+
411
+ product_key = nil
412
+
413
+ if app_name =~ /microsoft/i
414
+
415
+ app_name.remove_arch
416
+
417
+ case
418
+ when app_name =~ /microsoft exchange/i
419
+
420
+ debug 'attempting to retrieve ms exchange product key'
421
+
422
+ key_path = 'SOFTWARE\Microsoft\Exchange\Setup'
423
+ product_key = @connector.registry_values_at(key_path)[:digitalproductid]
424
+ product_key = product_key.to_ms_product_key unless product_key.nil?
425
+
426
+ when app_name =~ /office/i
427
+
428
+ debug 'attempting to retrieve ms office product key'
429
+
430
+ version_code = case
431
+ when app_name =~ /2003/; 11
432
+ when app_name =~ /2007|server 12/; 12
433
+ when app_name =~ /2010/; 14
434
+ when app_name =~ /2013/; 15
435
+ end
436
+
437
+ key_path = "SOFTWARE\\Microsoft\\Office\\#{version_code}.0\\Registration\\#{guid}"
438
+ product_key = @connector.registry_values_at(key_path)[:digitalproductid]
439
+ product_key = product_key.to_ms_product_key unless product_key.nil?
440
+
441
+ when app_name =~ /sql server/i
442
+
443
+ debug 'attempting to retrieve ms sqlserver product key'
444
+
445
+ app_edition = nil
446
+
447
+ key_path = 'SOFTWARE\Microsoft\Microsoft SQL Server'
448
+
449
+ @connector.registry_subkeys_at(key_path).each do |key|
450
+
451
+ if key =~ /mssql(\.|10|11)/i
452
+
453
+ version_code = case
454
+ when key =~ /_50/i; nil # express edition (use nil to avoid detection of product key)
455
+ when key =~ /mssql\./i; 90 # 2005
456
+ when key =~ /mssql10/i; 100 # 2008
457
+ when key =~ /mssql11/i; 110 # 2012
458
+ end
459
+
460
+ if version_code
461
+ key_path = "#{key_path}\\#{version_code}\\ProductID"
462
+ product_key = @connector.registry_values_at(key_path)[:digitalproductid]
463
+ product_key = product_key.to_ms_product_key unless product_key.nil?
464
+ end
465
+ end
466
+ end
467
+
468
+ when app_name =~ /visual studio/i
469
+
470
+ debug 'attempting to retrieve ms visual studio product key'
471
+
472
+ version_code = case
473
+ when app_name =~ /2005/; 8
474
+ when app_name =~ /2008/; 9
475
+ when app_name =~ /2010/; 10
476
+ when app_name =~ /2012/; 11
477
+ end
478
+
479
+ key_path = "SOFTWARE\\Microsoft\\VisualStudio\\#{version_code}.0\\Registration"
480
+ product_key = @connector.registry_values_at(key_path)[:pidkey]
481
+ product_key = product_key.scan(/.{5}/).join('-') unless product_key.nil?
482
+
483
+ when app_name =~ /^microsoft windows$/i
484
+
485
+ debug 'attempting to retrieve ms windows product key'
486
+
487
+ key_path = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
488
+ product_key = @connector.registry_values_at(key_path)[:digitalproductid]
489
+ product_key = product_key.to_ms_product_key unless product_key.nil?
490
+ end
491
+
492
+ if product_key
493
+ debug 'product key retrieved'
494
+ return product_key
495
+ else
496
+ debug 'product key could not be retrieved'
497
+ end
498
+
499
+ end
500
+ end
501
+
502
+ def get_username(guid)
503
+ username = guid
504
+
505
+ user = @connector.value_at("SELECT Caption, SID FROM Win32_UserAccount WHERE SID = '#{guid}'")
506
+ username = user[:caption] if user[:sid] == guid
507
+
508
+ return username
509
+ end
510
+
511
+ private
512
+
513
+ def concat_app_edition(app_name)
514
+
515
+ case
516
+ when app_name =~ /sql server/i
517
+ # grab the edition (standard, enterprise, etc)
518
+ app_edition = connector.registry_values_at('SOFTWARE\Microsoft\Microsoft SQL Server\Setup')[:edition]
519
+
520
+ app_name = if app_name =~ /\(64\-bit\)/i
521
+ app_name.sub('(64-bit)', "#{app_edition} (64-bit)")
522
+ else
523
+ app_name + " #{app_edition}"
524
+ end unless !app_edition
525
+ end
526
+
527
+ return app_name
528
+ end
529
+ end
530
+ end; end