boris 1.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.md +9 -0
- data/README.md +94 -0
- data/boris.gemspec +28 -0
- data/doc/Array.html +437 -0
- data/doc/Boris.html +230 -0
- data/doc/Boris/ConnectionAlreadyActive.html +123 -0
- data/doc/Boris/ConnectionFailed.html +127 -0
- data/doc/Boris/Connector.html +794 -0
- data/doc/Boris/InvalidCredentials.html +131 -0
- data/doc/Boris/InvalidOption.html +123 -0
- data/doc/Boris/InvalidTargetName.html +123 -0
- data/doc/Boris/Lumberjack.html +466 -0
- data/doc/Boris/MissingCredentials.html +123 -0
- data/doc/Boris/NoActiveConnection.html +123 -0
- data/doc/Boris/NoProfileDetected.html +123 -0
- data/doc/Boris/Options.html +783 -0
- data/doc/Boris/Profiles.html +117 -0
- data/doc/Boris/Profiles/Linux.html +1151 -0
- data/doc/Boris/Profiles/RedHat.html +875 -0
- data/doc/Boris/Profiles/Solaris.html +1230 -0
- data/doc/Boris/Profiles/Structure.html +2050 -0
- data/doc/Boris/Profiles/UNIX.html +893 -0
- data/doc/Boris/Profiles/Windows.html +1846 -0
- data/doc/Boris/Profiles/Windows/Windows2003.html +304 -0
- data/doc/Boris/Profiles/Windows/Windows2008.html +379 -0
- data/doc/Boris/Profiles/Windows/Windows2012.html +304 -0
- data/doc/Boris/SNMPConnector.html +512 -0
- data/doc/Boris/SSHConnector.html +633 -0
- data/doc/Boris/Target.html +2002 -0
- data/doc/Boris/WMIConnector.html +1134 -0
- data/doc/BorisLogger.html +217 -0
- data/doc/Hash.html +195 -0
- data/doc/String.html +1246 -0
- data/doc/_index.html +420 -0
- data/doc/class_list.html +53 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +328 -0
- data/doc/file.README.html +183 -0
- data/doc/file_list.html +55 -0
- data/doc/frames.html +28 -0
- data/doc/index.html +183 -0
- data/doc/js/app.js +214 -0
- data/doc/js/full_list.js +173 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +1468 -0
- data/doc/top-level-namespace.html +126 -0
- data/lib/boris.rb +30 -0
- data/lib/boris/connectors.rb +47 -0
- data/lib/boris/connectors/snmp.rb +56 -0
- data/lib/boris/connectors/ssh.rb +110 -0
- data/lib/boris/connectors/wmi.rb +186 -0
- data/lib/boris/errors.rb +17 -0
- data/lib/boris/helpers/array.rb +63 -0
- data/lib/boris/helpers/constants.rb +20 -0
- data/lib/boris/helpers/hash.rb +8 -0
- data/lib/boris/helpers/scrubber.rb +51 -0
- data/lib/boris/helpers/string.rb +130 -0
- data/lib/boris/lumberjack.rb +47 -0
- data/lib/boris/options.rb +86 -0
- data/lib/boris/profiles/linux/redhat.rb +77 -0
- data/lib/boris/profiles/linux_core.rb +216 -0
- data/lib/boris/profiles/unix/solaris.rb +307 -0
- data/lib/boris/profiles/unix_core.rb +85 -0
- data/lib/boris/profiles/windows/windows2003.rb +15 -0
- data/lib/boris/profiles/windows/windows2008.rb +23 -0
- data/lib/boris/profiles/windows/windows2012.rb +15 -0
- data/lib/boris/profiles/windows_core.rb +530 -0
- data/lib/boris/structure.rb +167 -0
- data/lib/boris/target.rb +340 -0
- data/test/connector_tests/test_snmp.rb +35 -0
- data/test/connector_tests/test_ssh.rb +51 -0
- data/test/connector_tests/test_wmi.rb +129 -0
- data/test/helper_tests/test_array.rb +25 -0
- data/test/helper_tests/test_hash.rb +10 -0
- data/test/helper_tests/test_string.rb +136 -0
- data/test/profile_tests/test_core_skeleton +107 -0
- data/test/profile_tests/test_linux_core.rb +331 -0
- data/test/profile_tests/test_redhat.rb +134 -0
- data/test/profile_tests/test_solaris.rb +523 -0
- data/test/profile_tests/test_unix_core.rb +117 -0
- data/test/profile_tests/test_windows.rb +536 -0
- data/test/setup_tests.rb +14 -0
- data/test/test_all.rb +8 -0
- data/test/test_options.rb +44 -0
- data/test/test_structure.rb +136 -0
- data/test/test_target.rb +146 -0
- 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
|