Class: Msf::DataStore
- Inherits:
-
Hash
- Object
- Hash
- Msf::DataStore
- Defined in:
- lib/msf/core/data_store.rb
Overview
The data store is just a bitbucket that holds keyed values. It is used by various classes to hold option values and other state information.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#aliases ⇒ Object
Returns the value of attribute aliases.
-
#imported ⇒ Object
Returns the value of attribute imported.
-
#imported_by ⇒ Object
Returns the value of attribute imported_by.
-
#options ⇒ Object
Returns the value of attribute options.
Class Method Summary collapse
-
.new ⇒ Object
Temporary forking logic for conditionally using the ModuleDatastoreWithFallbacks implementation.
Instance Method Summary collapse
-
#[](k) ⇒ Object
Case-insensitive wrapper around hash lookup.
-
#[]=(k, v) ⇒ Object
Clears the imported flag for the supplied key since it’s being set directly.
-
#clear ⇒ Object
Completely clear all values in the hash.
-
#clear_non_user_defined ⇒ Object
Remove all imported options from the data store.
-
#copy ⇒ Object
Return a deep copy of this datastore.
-
#delete(k) ⇒ Object
Case-insensitive wrapper around delete.
-
#each(&block) ⇒ Object
Overrides the builtin ‘each’ operator to avoid the following exception on Ruby 1.9.2+ “can’t add a new key into hash during iteration”.
-
#find_key_case(k) ⇒ Object
Case-insensitive key lookup.
-
#from_file(path, name = 'global') ⇒ Object
Imports datastore values from the specified file path using the supplied name.
-
#import_option(key, val, imported = true, imported_by = nil, option = nil) ⇒ Object
TODO: Doesn’t normalize data in the same vein as: github.com/rapid7/metasploit-framework/pull/6644.
-
#import_options(options, imported_by = nil, overwrite = false) ⇒ Object
This method is a helper method that imports the default value for all of the supplied options.
-
#import_options_from_hash(option_hash, imported = true, imported_by = nil) ⇒ Object
Imports options from a hash and stores them in the datastore.
-
#import_options_from_s(option_str, delim = nil) ⇒ Object
Imports option values from a whitespace separated string in VAR=VAL format.
-
#initialize ⇒ DataStore
constructor
Initializes the data store’s internal state.
-
#merge(other) ⇒ Object
Override merge to ensure we merge the aliases and imported hashes.
-
#merge!(other) ⇒ Object
Override merge! so that we merge the aliases and imported hashes.
-
#store(k, v) ⇒ Object
Case-insensitive wrapper around store.
-
#to_external_message_h ⇒ Object
Hack on a hack for the external modules.
-
#to_file(path, name = 'global') ⇒ Object
Persists the contents of the data store to a file.
-
#to_h ⇒ Object
Override Hash’s to_h method so we can include the original case of each key (failing to do this breaks a number of places in framework and pro that use serialized datastores).
-
#to_s(delim = ' ') ⇒ Object
Serializes the options in the datastore to a string.
-
#update_value(k, v) ⇒ Object
Updates a value in the datastore with the specified name, k, to the specified value, v.
-
#user_defined ⇒ Object
Returns a hash of user-defined datastore values.
Constructor Details
#initialize ⇒ DataStore
Initializes the data store’s internal state.
29 30 31 32 33 34 |
# File 'lib/msf/core/data_store.rb', line 29 def initialize() @options = Hash.new @aliases = Hash.new @imported = Hash.new @imported_by = Hash.new end |
Instance Attribute Details
#aliases ⇒ Object
Returns the value of attribute aliases.
37 38 39 |
# File 'lib/msf/core/data_store.rb', line 37 def aliases @aliases end |
#imported ⇒ Object
Returns the value of attribute imported.
38 39 40 |
# File 'lib/msf/core/data_store.rb', line 38 def imported @imported end |
#imported_by ⇒ Object
Returns the value of attribute imported_by.
39 40 41 |
# File 'lib/msf/core/data_store.rb', line 39 def imported_by @imported_by end |
#options ⇒ Object
Returns the value of attribute options.
36 37 38 |
# File 'lib/msf/core/data_store.rb', line 36 def @options end |
Class Method Details
.new ⇒ Object
Temporary forking logic for conditionally using the ModuleDatastoreWithFallbacks implementation.
This method replaces the default ‘ModuleDataStore.new` with the ability to instantiate the `ModuleDataStoreWithFallbacks` class instead, if the feature is enabled
16 17 18 19 20 21 22 23 24 |
# File 'lib/msf/core/data_store.rb', line 16 def self.new if Msf::FeatureManager.instance.enabled?(Msf::FeatureManager::DATASTORE_FALLBACKS) return Msf::DataStoreWithFallbacks.new end instance = allocate instance.send(:initialize) instance end |
Instance Method Details
#[](k) ⇒ Object
Case-insensitive wrapper around hash lookup
66 67 68 |
# File 'lib/msf/core/data_store.rb', line 66 def [](k) super(find_key_case(k)) end |
#[]=(k, v) ⇒ Object
Clears the imported flag for the supplied key since it’s being set directly.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/msf/core/data_store.rb', line 45 def []=(k, v) k = find_key_case(k) @imported[k] = false @imported_by[k] = nil opt = @options[k] unless opt.nil? if opt.validate_on_assignment? unless opt.valid?(v, check_empty: false) raise Msf::OptionValidateError.new(["Value '#{v}' is not valid for option '#{k}'"]) end v = opt.normalize(v) end end super(k,v) end |
#clear ⇒ Object
Completely clear all values in the hash
311 312 313 314 |
# File 'lib/msf/core/data_store.rb', line 311 def clear self.keys.each {|k| self.delete(k) } self end |
#clear_non_user_defined ⇒ Object
Remove all imported options from the data store.
297 298 299 300 301 302 303 304 305 306 |
# File 'lib/msf/core/data_store.rb', line 297 def clear_non_user_defined @imported.delete_if { |k, v| if (v and @imported_by[k] != 'self') self.delete(k) @imported_by.delete(k) end v } end |
#copy ⇒ Object
Return a deep copy of this datastore.
254 255 256 257 258 259 260 261 |
# File 'lib/msf/core/data_store.rb', line 254 def copy ds = self.class.new self.keys.each do |k| ds.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k], @imported_by[k]) end ds.aliases = self.aliases.dup ds end |
#delete(k) ⇒ Object
Case-insensitive wrapper around delete
80 81 82 83 |
# File 'lib/msf/core/data_store.rb', line 80 def delete(k) @aliases.delete_if { |_, v| v.casecmp(k) == 0 } super(find_key_case(k)) end |
#each(&block) ⇒ Object
Overrides the builtin ‘each’ operator to avoid the following exception on Ruby 1.9.2+
"can't add a new key into hash during iteration"
320 321 322 323 324 325 326 |
# File 'lib/msf/core/data_store.rb', line 320 def each(&block) list = [] self.keys.sort.each do |sidx| list << [sidx, self[sidx]] end list.each(&block) end |
#find_key_case(k) ⇒ Object
Case-insensitive key lookup
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/msf/core/data_store.rb', line 331 def find_key_case(k) # Scan each alias looking for a key search_k = k.downcase if self.aliases.has_key?(search_k) search_k = self.aliases[search_k] end # Scan each key looking for a match self.each_key do |rk| if rk.casecmp(search_k) == 0 return rk end end # Fall through to the non-existent value return k end |
#from_file(path, name = 'global') ⇒ Object
Imports datastore values from the specified file path using the supplied name
239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/msf/core/data_store.rb', line 239 def from_file(path, name = 'global') begin ini = Rex::Parser::Ini.from_file(path) rescue return end if (ini.group?(name)) (ini[name], false) end end |
#import_option(key, val, imported = true, imported_by = nil, option = nil) ⇒ Object
TODO: Doesn’t normalize data in the same vein as: github.com/rapid7/metasploit-framework/pull/6644
159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/msf/core/data_store.rb', line 159 def import_option(key, val, imported = true, imported_by = nil, option = nil) self.store(key, val) if option option.aliases.each do |a| @aliases[a.downcase] = key.downcase end end @options[key] = option @imported[key] = imported @imported_by[key] = imported_by end |
#import_options(options, imported_by = nil, overwrite = false) ⇒ Object
This method is a helper method that imports the default value for all of the supplied options
99 100 101 102 103 104 105 |
# File 'lib/msf/core/data_store.rb', line 99 def (, imported_by = nil, overwrite = false) .each_option do |name, opt| if self[name].nil? || overwrite import_option(name, opt.default, true, imported_by, opt) end end end |
#import_options_from_hash(option_hash, imported = true, imported_by = nil) ⇒ Object
Imports options from a hash and stores them in the datastore.
151 152 153 154 155 |
# File 'lib/msf/core/data_store.rb', line 151 def (option_hash, imported = true, imported_by = nil) option_hash.each_pair { |key, val| import_option(key, val, imported, imported_by) } end |
#import_options_from_s(option_str, delim = nil) ⇒ Object
Imports option values from a whitespace separated string in VAR=VAL format.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/msf/core/data_store.rb', line 111 def (option_str, delim = nil) hash = {} # Figure out the delimiter, default to space. if (delim.nil?) delim = /\s/ if (option_str.split('=').length <= 2 or option_str.index(',') != nil) delim = ',' end end # Split on the delimiter option_str.split(delim).each { |opt| var, val = opt.split('=', 2) next if (var =~ /^\s+$/) # Invalid parse? Raise an exception and let those bastards know. if (var == nil or val == nil) var = "unknown" if (!var) raise Rex::ArgumentParseError, "Invalid option specified: #{var}", caller end # Remove trailing whitespaces from the value val.gsub!(/\s+$/, '') # Store the value hash[var] = val } (hash) end |
#merge(other) ⇒ Object
Override merge to ensure we merge the aliases and imported hashes
279 280 281 282 |
# File 'lib/msf/core/data_store.rb', line 279 def merge(other) ds = self.copy ds.merge!(other) end |
#merge!(other) ⇒ Object
Override merge! so that we merge the aliases and imported hashes
266 267 268 269 270 271 272 273 274 |
# File 'lib/msf/core/data_store.rb', line 266 def merge!(other) if other.is_a? DataStore self.aliases.merge!(other.aliases) self.imported.merge!(other.imported) self.imported_by.merge!(other.imported_by) end # call super last so that we return a reference to ourselves super end |
#store(k, v) ⇒ Object
Case-insensitive wrapper around store
73 74 75 |
# File 'lib/msf/core/data_store.rb', line 73 def store(k,v) super(find_key_case(k), v) end |
#to_external_message_h ⇒ Object
Hack on a hack for the external modules
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/msf/core/data_store.rb', line 197 def datastore_hash = {} array_nester = ->(arr) do if arr.first.is_a? Array arr.map &array_nester else arr.map { |item| item.to_s.dup.force_encoding('UTF-8') } end end self.keys.each do |k| # TODO arbitrary depth if self[k].is_a? Array datastore_hash[k.to_s.dup.force_encoding('UTF-8')] = array_nester.call(self[k]) else datastore_hash[k.to_s.dup.force_encoding('UTF-8')] = self[k].to_s.dup.force_encoding('UTF-8') end end datastore_hash end |
#to_file(path, name = 'global') ⇒ Object
Persists the contents of the data store to a file
222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/msf/core/data_store.rb', line 222 def to_file(path, name = 'global') ini = Rex::Parser::Ini.new(path) ini.add_group(name) # Save all user-defined options to the file. user_defined.each_pair { |k, v| ini[name][k] = v } ini.to_file(path) end |
#to_h ⇒ Object
Override Hash’s to_h method so we can include the original case of each key (failing to do this breaks a number of places in framework and pro that use serialized datastores)
188 189 190 191 192 193 194 |
# File 'lib/msf/core/data_store.rb', line 188 def to_h datastore_hash = {} self.keys.each do |k| datastore_hash[k.to_s] = self[k].to_s end datastore_hash end |
#to_s(delim = ' ') ⇒ Object
Serializes the options in the datastore to a string.
175 176 177 178 179 180 181 182 183 |
# File 'lib/msf/core/data_store.rb', line 175 def to_s(delim = ' ') str = '' keys.sort.each { |key| str << "#{key}=#{self[key]}" + ((str.length) ? delim : '') } return str end |
#update_value(k, v) ⇒ Object
Updates a value in the datastore with the specified name, k, to the specified value, v. This update does not alter the imported status of the value.
91 92 93 |
# File 'lib/msf/core/data_store.rb', line 91 def update_value(k, v) self.store(k, v) end |
#user_defined ⇒ Object
Returns a hash of user-defined datastore values. The returned hash does not include default option values.
288 289 290 291 292 |
# File 'lib/msf/core/data_store.rb', line 288 def user_defined reject { |k, v| @imported[k] == true } end |