boris 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5f54a0bce9420195098ba5d362bc8ba592de3b2e
4
+ data.tar.gz: 6e798f3e9814cd293b3f9a3ea5bceb606be21ffa
5
+ SHA512:
6
+ metadata.gz: 4bbc75ecf7d833216e5dc6d8a1501ff243f489c50905a3c3f45493f49da1c1f27d20dcf9bfb122e2304aaf4d10eb72ab13f1438413dfbb38d6966a07a922758b
7
+ data.tar.gz: d06c12bf5cfa6b2be0d17ecfae0957d78305f05b01bed97759edb208ba39f37a8b3fe1f8eba72bb2d2f01e4b000513e1ce65c7b3504491a005d05ad52ad93803
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 1.0.2
2
+ * Fix for devices asking for password when connecting via SSH
3
+ * Fixed return value for Target#connect
4
+ * Added #failure_message to connectors
5
+ * Added registry subkey and value caching for WMI connections
6
+ * Added constants for connection failures, changed logging messages for connectors
7
+ * Changed all eval calls to Object.send
8
+ * Various bug fixes
9
+
1
10
  # 1.0.1
2
11
  * Renamed Profiles to Profilers
3
12
  * Moved networking helper methods to newly created Network module
data/README.md CHANGED
@@ -19,36 +19,35 @@ Out of the box, Boris has server support for Red Hat, Solaris,and Windows (with
19
19
  ## Installation
20
20
  gem install boris
21
21
 
22
+ Or if using Bundler, add to your Gemfile
23
+
24
+ gem 'boris'
25
+
22
26
  ## Example
23
27
  Let's pull some information from a RedHat Enterprise Linux server on our network:
24
28
 
25
29
  ```ruby
26
30
  require 'boris'
27
31
 
28
- # Boris has different levels of logging. We can optionally set our logging level, which will apply
29
- # to all Targets created during this session. If not set, the log level defaults to :fatal.
30
32
  Boris.log_level = :debug
31
33
 
32
34
  hostname = 'redhatserver01.mydomain.com'
33
35
 
34
- # let's use a helper to suggest how we should connect to it (which is useful if we're not sure what
35
- # kind of device this is)
36
+ # let's use a helper to suggest how we should connect to it (if we're not sure what kind of device this is)
36
37
  puts Boris::Network.suggested_connection_method(hostname)
37
38
 
38
- # you can also add the logic to make the decision yourself by checking if certain TCP ports are responsive
39
+ # you can also add the logic to make the decision yourself
39
40
  puts Boris::Network.tcp_port_responding?(hostname, 22)
40
41
 
41
- # create our target
42
42
  target = Boris::Target.new(hostname)
43
43
 
44
- # add credentials to try against this target
45
44
  target.options.add_credential(:user=>'myusername', :password=>'mypassword', :connection_types=>[:ssh])
46
45
 
47
- # if this is a host using SSH, we can also pass in Net::SSH options (such as a private key for authentication).
48
- # SSH options passed to Boris will automatically be pushed to Net:SSH.
46
+ # if this is a host using SSH, we can also pass in Net::SSH options (such as a private key for
47
+ # authentication). SSH options passed to Boris will automatically be passed to Net:SSH. Likewise for
48
+ # Net::SNMP--options passed to :snmp_options will be passed to the Net::SNMP library.
49
49
  target.options[:ssh_options] = {:keys=>['/path/to/my/private/key']}
50
50
 
51
- # attempt to connect to this target using the credentials we supplied above
52
51
  target.connect
53
52
 
54
53
  if target.connected?
@@ -60,9 +59,7 @@ if target.connected?
60
59
 
61
60
  # we can call individual methods to grab specific information we may be interested in
62
61
  target.get(:hardware)
63
-
64
- # or maybe get some network interface info
65
- puts target.get(:network_interfaces)
62
+ target.get(:network_interfaces)
66
63
 
67
64
  # retrieved items can be referenced two ways:
68
65
  puts target[:network_interfaces].inspect
@@ -73,10 +70,12 @@ if target.connected?
73
70
  target.retrieve_all
74
71
 
75
72
  # if there is more information we want to collect but is not collected by default, we can specify
76
- # our own commands to run against the target via two methods: #get_values returns an Array (each
77
- # line is an element of the array), or #get_value, which returns a String (the first line returned
78
- # from the command)
73
+ # our own commands to run against the target via two methods:
74
+
75
+ # #get_values returns an Array (each line is an element of the array)
79
76
  puts target.connector.values_at('cat /etc/redhat-release')
77
+
78
+ # #get_value, which returns a String (the first line returned from the command)
80
79
  puts target.connector.value_at('uname -a')
81
80
 
82
81
  # NOTE: if this were a Windows server, you would send WMI queries instead of shell commands, ie:
@@ -84,14 +83,81 @@ if target.connected?
84
83
  # target.connector.values_at('SELECT * FROM Win32_ComputerSystem')
85
84
  #
86
85
 
87
- # finally, we can package up all of the data into json format for portability (the true argument
88
- # tells the #to_json method to output the json with tabbed formatting)
89
86
  puts target.to_json(:pretty_print)
90
87
 
91
88
  target.disconnect
92
89
  end
93
90
  ```
94
91
 
92
+ ## Sample Output
93
+ ```ruby
94
+ target.get(:hardware)
95
+ target.get(:operating_system)
96
+
97
+ target.scrub_data!
98
+
99
+ puts target[:hardware]
100
+ #=>{
101
+ # :cpu_architecture=>64,
102
+ # :cpu_core_count=>2,
103
+ # :cpu_model=>'AMD Opteron Processor 6174',
104
+ # :cpu_physical_count=>1,
105
+ # :cpu_speed_mhz=>2200,
106
+ # :cpu_vendor=>'AMD, Inc.',
107
+ # :firmware_version=>'6.0',
108
+ # :model=>'VMware Virtual Platform',
109
+ # :memory_installed_mb=>1024,
110
+ # :serial=>'VMware-1234',
111
+ # :vendor=>'VMware, Inc.'
112
+ # }
113
+
114
+ puts target[:operating_system]
115
+ #=>{
116
+ # :date_installed=>#<DateTime: 2013-02-04T19:08:49-05:00 ((2456329j,529s,891979000n),-18000s,2299161j)>,
117
+ # :features=>[],
118
+ # :kernel=>'5.2.3790',
119
+ # :license_key=>'BBBBB-BBBBB-BBBBB-BBBBB-BBBBB',
120
+ # :name=>'Microsoft Windows',
121
+ # :roles=>['TerminalServer', 'TimeServer'],
122
+ # :service_pack=>'Service Pack 2',
123
+ # :version=>'Server 2003 R2 Standard'
124
+ # }
125
+ ```
126
+
127
+ ## Data
128
+ Through a number of queries and algorithms, Boris efficiently polls devices on the network for information including, but not limited to, network configuration, hardware capabilities, installed software and services, applied hotfixes/patches, and more.
129
+
130
+ **Available methods for use on most platforms include:**
131
+
132
+ * **file systems** - file system, mount point, capacity and utilization
133
+ * **hardware** - make/model, cpu information, firmware/bios version, serial number
134
+ * **hosted shares** - folders shared by the target
135
+ * **installed applications** - installed applications and the dates of their installation
136
+ * **installed patches** - installed patches/hotfixes and the dates of their installation
137
+ * **installed services/daemons** - background services and their startup modes
138
+ * **local users and groups** - local groups and the users within each
139
+ * **network ID** - hostname and domain
140
+ * **network interfaces** - ethernet and fibre channel interfaces, including IPs, MAC addresses, connection status
141
+ * **operating system** - name, version, kernel, date installed
142
+
143
+ See [Boris::Profilers::Structure](http://www.rubydoc.info/github/alkalinecoffee/boris/Boris/Profilers/Structure) for more details on the data structure.
144
+
145
+ Because the commands that might work correctly on one type of platform most likely won't work on another, Boris handles this by the use of...
146
+
147
+ ## Profilers
148
+ Profilers contain the instructions that allow us to run commands against our target and then parse and make sense of the data. Boris comes with the capability to communicate with targets over SNMP, SSH, or WMI. Each profiler is written to use one of these methods of communication (internally called 'connectors'), which serve as a vehicle for running commands against a server. Boris comes with a few profilers built-in for some popular platforms, but can be easily extended to include other devices.
149
+
150
+ **Available profilers:**
151
+
152
+ * **[Linux Core](http://rubydoc.info/github/alkalinecoffee/boris/master/Boris/Profilers/Linux)**
153
+ * [Red Hat Linux](http://rubydoc.info/github/alkalinecoffee/boris/master/Boris/Profilers/RedHat)
154
+ * **[UNIX Core](http://rubydoc.info/github/alkalinecoffee/boris/master/Boris/Profilers/UNIX)**
155
+ * [Oracle Solaris](http://rubydoc.info/github/alkalinecoffee/boris/master/Boris/Profilers/Solaris)
156
+ * **[Windows Core](http://rubydoc.info/github/alkalinecoffee/boris/master/Boris/Profilers/Windows)**
157
+ * [Windows 2003 Server](http://rubydoc.info/github/alkalinecoffee/boris/master/Boris/Profilers/Windows2003)
158
+ * [Windows 2008 Server](http://rubydoc.info/github/alkalinecoffee/boris/master/Boris/Profilers/Windows2008)
159
+ * [Windows 2012 Server](http://rubydoc.info/github/alkalinecoffee/boris/master/Boris/Profilers/Windows2012)
160
+
95
161
  ## Extending Boris
96
162
  You can also run your own commands to grab information off of systems. For example, on a Linux device, to run your own script that is already on the target and retrieve its output:
97
163
 
@@ -104,7 +170,7 @@ multiple_lines_of_data = target.connector.values_at('/path/to/some/script')
104
170
  single_line_of_data = target.connector.value_at('/path/to/some/script')
105
171
  ```
106
172
 
107
- Running commands in this fashion utilizes the #exec function from Net::SSH.
173
+ Running commands in this fashion utilizes the #exec method from the Net::SSH library.
108
174
 
109
175
  For a Windows host, which uses WMI vice SSH, you can send WMI queries or registry keys to the connector to get information:
110
176
 
@@ -112,53 +178,22 @@ For a Windows host, which uses WMI vice SSH, you can send WMI queries or registr
112
178
  # this will pull rows from a class in the standard root\CIMV2 namespace, returning an array of hashes
113
179
  multiple_rows_of_data = target.connector.values_at('SELECT * FROM Win32_NetworkAdapter')
114
180
 
115
- # this will pull rows from a class in the lower-level root\WMI namespace (note the second argument we're passing to #values_at):
181
+ # this will pull rows from a class in the lower-level root\WMI namespace (note the second argument we're
182
+ # passing to #values_at):
116
183
  multiple_rows_of_data = target.connector.values_at('SELECT * FROM MSNdis_EnumerateAdapter', :root_wmi)
117
184
 
118
- # you can also poll for registry keys under HKEY_LOCAL_MACHINE by providing a base key path, which returns an array of keys:
185
+ # you can also poll for registry keys under HKEY_LOCAL_MACHINE by providing a base key path, which returns
186
+ # an array of keys:
119
187
  registry_keys = target.connector.registry_subkeys_at('SOFTWARE\Microsoft\Windows')
120
188
 
121
- # and then grab values found at some key via #registry_values_at, which returns value/data elements in a Hash:
189
+ # and then grab values found at some key via #registry_values_at, which returns value/data elements in a
190
+ # Hash:
122
191
  registry_values = target.connector.registry_values_at('SOFTWARE\Microsoft\Windows\CurrentVersion')
123
192
  ```
124
193
 
125
194
  **Coming soon--a write-up for SNMP devices**
126
195
 
127
- Boris also comes with the ability to add your own complete modules for using the framework by writing your own data collection algorithms. This will also be written up in the near future.
128
-
129
- ## Data
130
- Through a number of queries and algorithms, Boris efficiently polls devices on the network for information including, but not limited to, network configuration, hardware capabilities, installed software and services, applied hotfixes/patches, and more.
131
-
132
- **Available methods for use on most platforms include:**
133
-
134
- * **file systems** - file system, mount point, capacity and utilization
135
- * **hardware** - make/model, cpu information, firmware/bios version, serial number
136
- * **hosted shares** - folders shared by the target
137
- * **installed applications** - installed applications and the dates of their installation
138
- * **installed patches** - installed patches/hotfixes and the dates of their installation
139
- * **installed services/daemons** - background services and their startup modes
140
- * **local users and groups** - local groups and the member users within each
141
- * **network ID** - hostname and domain
142
- * **network interfaces** - ethernet and fibre channel interfaces, including IPs, MAC addresses, connection status
143
- * **operating system** - name, version, kernel, date installed
144
-
145
- See {http://www.rubydoc.info/github/alkalinecoffee/boris/Boris/Profilers/Structure Boris::Profilers::Structure} for more details on the data structure.
146
-
147
- Because the commands that might work correctly on one type of platform most likely won't work on another, Boris handles this by the use of...
148
-
149
- ## Profilers
150
- Profilers contain the instructions that allow us to run commands against our target and then parse and make sense of the data. Boris comes with the capability to communicate with targets over SNMP, SSH, or WMI. Each profiler is written to use one of these methods of communication (internally called 'connectors'), which serve as a vehicle for running commands against a server. Boris comes with a few profilers built-in for some popular platforms, but can be easily extended to include other devices.
151
-
152
- **Available profilers:**
153
-
154
- * **Linux Core**
155
- * Red Hat Linux
156
- * **UNIX Core**
157
- * Oracle Solaris
158
- * **Windows Core**
159
- * Windows 2003 Server
160
- * Windows 2008 Server
161
- * Windows 2012 Server
196
+ Boris also comes with the ability to add your own complete modules for using the framework by writing your own data collection algorithms. I will also write-up a howto in the near future.
162
197
 
163
198
  ## User Account Requirements
164
199
  While Boris does its best to gather data from devices without any special privileges, sometimes it just can't be helped. One example of this is the RedHat profiler, which requires `sudo` access for the `dmidecode` command, as there isn't a well known, reliable way to grab this info without `dmidecode`. If Boris attempts to run a command that requires special access and is denied, it will throw a message to the logger and move on.
data/lib/boris.rb CHANGED
@@ -13,5 +13,6 @@ require 'socket'
13
13
  require 'thread'
14
14
  require 'win32ole' if PLATFORM == :win32
15
15
 
16
+ require 'boris/helpers'
16
17
  require 'boris/lumberjack'
17
18
  require 'boris/target'
@@ -12,6 +12,8 @@ module Boris
12
12
  attr_reader :host
13
13
  attr_reader :options
14
14
  attr_reader :reconnectable
15
+ attr_reader :failure_message
16
+ attr_reader :user
15
17
 
16
18
  def initialize(host, cred={})
17
19
  @logger = Boris.logger
@@ -11,7 +11,7 @@ module Boris
11
11
  # @param [Hash] cred credential we wish to use
12
12
  # @param [Hash] options an optional list of options. See {Boris::Options} for a list of all
13
13
  # possible options. The relevant option set here would be :snmp_options.
14
- def initialize(host, cred, options={})
14
+ def initialize(host, cred, options=Options.new)
15
15
  super(host, cred)
16
16
  @snmp_options = options[:snmp_options].merge(:host=>@host, :version=>:SNMPv1, :community=>@user)
17
17
 
@@ -11,10 +11,15 @@ module Boris
11
11
  # @param [Hash] cred credential we wish to use
12
12
  # @param [Hash] options an optional list of options. See {Boris::Options} for a list of all
13
13
  # possible options. The relevant option set here would be :ssh_options.
14
- def initialize(host, cred, options={})
14
+ def initialize(host, cred, options=Options.new)
15
15
  @ssh_options = options[:ssh_options]
16
- @ssh_options[:password] = @password if @password
17
-
16
+
17
+ @ssh_options[:auth_methods] = ['publickey']
18
+ if @password
19
+ @ssh_options[:auth_methods] << 'password'
20
+ @ssh_options[:password] = @password
21
+ end
22
+
18
23
  if @ssh_options
19
24
  invalid_ssh_options = @ssh_options.keys - Net::SSH::VALID_OPTIONS
20
25
  raise ArgumentError, "invalid ssh option(s): #{invalid_ssh_options.join(', ')}" if invalid_ssh_options.any?
@@ -41,12 +46,20 @@ module Boris
41
46
  @connected = @reconnectable = true
42
47
  rescue Net::SSH::AuthenticationFailed
43
48
  warn "connection failed (connection made but credentials not accepted with user #{@user})"
49
+ @failure_message = CONN_FAILURE_AUTH_FAILED
44
50
  @reconnectable = true
45
51
  rescue Net::SSH::HostKeyMismatch
46
- warn 'connection failed (host key mismatch)'
52
+ warn CONN_FAILURE_HOST_KEY_MISMATCH
53
+ @failure_message = CONN_FAILURE_HOST_KEY_MISMATCH
54
+ @reconnectable = false
55
+ rescue SocketError, Errno::ETIMEDOUT
56
+ warn CONN_FAILURE_NO_HOST
57
+ @failure_message = CONN_FAILURE_NO_HOST
47
58
  @reconnectable = false
48
59
  rescue => error
49
- warn "connection failed (#{error.message})"
60
+ message = "connection failed (#{error.message})"
61
+ warn message
62
+ @failure_message = message
50
63
  @reconnectable = true
51
64
  end
52
65
 
@@ -102,7 +115,7 @@ module Boris
102
115
  elsif data =~ /sorry, try again/i
103
116
  ch.close
104
117
  return_data = []
105
- info "channel closed (we have a password to supply but system its not accepted)"
118
+ info 'channel closed (we have a password to supply but it is not accepted)'
106
119
  elsif data =~ /permission denied/i
107
120
  warn "permission denied for this request (#{data.gsub(/\n|\s+/, ', ')})"
108
121
  else
@@ -112,6 +125,11 @@ module Boris
112
125
 
113
126
  # called when something is written to stderr
114
127
  chan.on_extended_data do |ch, type, data|
128
+ if data =~ /password has expired/i
129
+ @failure_message = CONN_FAILURE_PASSWORD_EXPIRED
130
+ ch.close
131
+ disconnect
132
+ end
115
133
  error_messages.concat(data.split(/\n/))
116
134
  end
117
135
 
@@ -3,6 +3,7 @@ require 'boris/connectors'
3
3
  module Boris
4
4
  class WMIConnector < Connector
5
5
  attr_accessor :wmi, :root_wmi, :registry
6
+ attr_reader :registry_cache
6
7
 
7
8
  HKEY_LOCAL_MACHINE = 0x80000002
8
9
  KEY_QUERY_VALUE = 1
@@ -16,6 +17,8 @@ module Boris
16
17
  # @param [Hash] cred credential we wish to use
17
18
  def initialize(host, cred)
18
19
  super(host, cred)
20
+
21
+ @registry_cache = []
19
22
  end
20
23
 
21
24
  # Disconnect from the host.
@@ -56,17 +59,31 @@ module Boris
56
59
  @connected = false
57
60
  if error.message =~ /access is denied/i
58
61
  warn "connection failed (connection made but credentials not accepted with user #{@user})"
62
+ @failure_message = CONN_FAILURE_AUTH_FAILED
59
63
  @reconnectable = true
64
+ elsif error.message =~ /call was canceled by the message filter/i
65
+ warn CONN_FAILURE_RPC_FILTERED
66
+ @failure_message = CONN_FAILURE_RPC_FILTERED
67
+ @reconnectable = false
60
68
  elsif error.message =~ /rpc server is unavailable/i
61
- warn 'connection failed (rpc server not available)'
69
+ warn CONN_FAILURE_RPC_UNAVAILABLE
70
+ @failure_message = CONN_FAILURE_RPC_UNAVAILABLE
62
71
  @reconnectable = false
72
+ elsif error.message =~ /user credentials cannot be used for local connections/i
73
+ # clear the credentials then try to connect again
74
+ warn CONN_FAILURE_LOCAL_CREDENTIALS
75
+ @user = nil
76
+ @password = nil
77
+ establish_connection
63
78
  else
64
- warn "connection failed (#{error.message.gsub(/\n\s*/, '. ')})"
79
+ message = "connection failed (#{error.message.gsub(/\n\s*/, '. ')})"
80
+ warn message
81
+ @failure_message = message
65
82
  @reconnectable = true
66
83
  end
67
84
  end
68
85
 
69
- if @reconnectable == true
86
+ if @connected == false && @reconnectable == true
70
87
  info 'connection available for retry'
71
88
  elsif @reconnectable == false
72
89
  info 'connection does not seem to be available (so we will not retry)'
@@ -95,7 +112,20 @@ module Boris
95
112
  access_params.sSubKeyName = key_path
96
113
  access_params.uRequired = permission_to_check
97
114
 
98
- @registry.ExecMethod_('CheckAccess', access_params).bGranted
115
+ has_access = false
116
+
117
+ begin
118
+ @registry.ExecMethod_('CheckAccess', access_params).bGranted
119
+ has_access = true
120
+ rescue => error
121
+ if error.message =~ /access is denied/i
122
+ info "access denied on checking access on #{key_path}"
123
+ else
124
+ info "error while checking access on #{key_path}"
125
+ end
126
+ end
127
+
128
+ has_access
99
129
  end
100
130
 
101
131
 
@@ -110,18 +140,26 @@ module Boris
110
140
  def registry_subkeys_at(key_path)
111
141
  subkeys = []
112
142
 
113
- debug "reading registry subkeys at path #{key_path}"
143
+ debug "reading registry subkeys at #{key_path}"
144
+
145
+ found_key = @registry_cache.select{|item| item[:key_path] == key_path}.first
114
146
 
115
- if has_access_for(key_path, KEY_ENUMERATE_SUB_KEYS)
147
+ if found_key && found_key[:subkeys]
148
+ debug "subkeys found in cache at #{key_path}"
149
+ subkeys = found_key[:subkeys]
150
+ elsif has_access_for(key_path, KEY_ENUMERATE_SUB_KEYS)
116
151
  in_params = @registry.Methods_('EnumKey').inParameters.SpawnInstance_
117
152
  in_params.hDefKey = HKEY_LOCAL_MACHINE
118
153
  in_params.sSubKeyName = key_path
119
154
 
120
- @registry.ExecMethod_('EnumKey', in_params).sNames.each do |key|
121
- subkeys << key_path + '\\' + key
122
- end
155
+ keys_names = @registry.ExecMethod_('EnumKey', in_params).sNames
156
+ keys_names ? keys_names.each {|key| subkeys << key_path + '\\' + key} : subkeys = []
157
+
158
+ @registry_cache << {:key_path=>key_path, :subkeys=>subkeys}
123
159
  else
124
- info "no access for enumerating keys at (#{key_path})"
160
+ info "no access for enumerating keys at #{key_path}"
161
+
162
+ @registry_cache << {:key_path=>key_path, :subkeys=>subkeys}
125
163
  end
126
164
 
127
165
  subkeys
@@ -140,7 +178,12 @@ module Boris
140
178
 
141
179
  debug "reading registry values at path #{key_path}"
142
180
 
143
- if has_access_for(key_path, KEY_QUERY_VALUE)
181
+ found_key = @registry_cache.select{|item| item[:key_path] == key_path}.first
182
+
183
+ if found_key && found_key[:values]
184
+ debug "values found in cache (#{key_path})"
185
+ values = found_key[:values]
186
+ elsif has_access_for(key_path, KEY_QUERY_VALUE)
144
187
  in_params = @registry.Methods_('EnumValues').inParameters.SpawnInstance_
145
188
  in_params.hDefKey = HKEY_LOCAL_MACHINE
146
189
  in_params.sSubKeyName = key_path
@@ -152,27 +195,31 @@ module Boris
152
195
  subkey_values ||= []
153
196
 
154
197
  subkey_values.each do |value|
155
- if value.length > 0
156
- str_params.sValueName = value
157
-
158
- begin
159
- x = @registry.ExecMethod_('GetStringValue', str_params).sValue
160
- x = @registry.ExecMethod_('GetBinaryValue', str_params).uValue unless x
161
- x = @registry.ExecMethod_('GetDWORDValue', str_params).uValue unless x
162
- x = @registry.ExecMethod_('GetExpandedStringValue', str_params).sValue unless x
163
- x = @registry.ExecMethod_('GetMultiStringValue', str_params).sValue unless x
164
- x = @registry.ExecMethod_('GetQWORDValue', str_params).uValue unless x
165
-
166
- values[value.downcase.to_sym] = x
167
- rescue
168
- if $!.message =~ /invalid method/i
169
- warn "unreadable registry value (#{key_path}\\#{value})"
170
- end
198
+ break if value.length == 0
199
+
200
+ str_params.sValueName = value
201
+
202
+ begin
203
+ x = @registry.ExecMethod_('GetStringValue', str_params).sValue
204
+ x = @registry.ExecMethod_('GetBinaryValue', str_params).uValue unless x
205
+ x = @registry.ExecMethod_('GetDWORDValue', str_params).uValue unless x
206
+ x = @registry.ExecMethod_('GetExpandedStringValue', str_params).sValue unless x
207
+ x = @registry.ExecMethod_('GetMultiStringValue', str_params).sValue unless x
208
+ x = @registry.ExecMethod_('GetQWORDValue', str_params).uValue unless x
209
+
210
+ values[value.downcase.to_sym] = x
211
+ rescue
212
+ if $!.message =~ /invalid method/i
213
+ warn "unreadable registry value (#{key_path}\\#{value})"
171
214
  end
172
215
  end
173
216
  end
217
+
218
+ @registry_cache << {:key_path=>key_path, :values=>values}
174
219
  else
175
220
  info "no access for enumerating values at (#{key_path})"
221
+
222
+ @registry_cache << {:key_path=>key_path, :values=>values}
176
223
  end
177
224
 
178
225
  values