PageRenderTime 62ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/msf/core/data_store.rb

https://bitbucket.org/DinoRex99/metasploit-framework
Ruby | 399 lines | 230 code | 62 blank | 107 comment | 32 complexity | 3e4625b2e0dd88abebd3359e43abb9d4 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-3.0, GPL-2.0
  1. # -*- coding: binary -*-
  2. module Msf
  3. ###
  4. #
  5. # The data store is just a bitbucket that holds keyed values. It is used
  6. # by various classes to hold option values and other state information.
  7. #
  8. ###
  9. class DataStore < Hash
  10. #
  11. # Initializes the data store's internal state.
  12. #
  13. def initialize()
  14. @options = Hash.new
  15. @aliases = Hash.new
  16. @imported = Hash.new
  17. @imported_by = Hash.new
  18. end
  19. attr_accessor :options
  20. attr_accessor :aliases
  21. attr_accessor :imported
  22. attr_accessor :imported_by
  23. #
  24. # Clears the imported flag for the supplied key since it's being set
  25. # directly.
  26. #
  27. def []=(k, v)
  28. k = find_key_case(k)
  29. @imported[k] = false
  30. @imported_by[k] = nil
  31. opt = @options[k]
  32. unless opt.nil?
  33. if opt.validate_on_assignment?
  34. unless opt.valid?(v, check_empty: false)
  35. raise OptionValidateError.new(["Value '#{v}' is not valid for option '#{k}'"])
  36. end
  37. v = opt.normalize(v)
  38. end
  39. end
  40. super(k,v)
  41. end
  42. #
  43. # Case-insensitive wrapper around hash lookup
  44. #
  45. def [](k)
  46. super(find_key_case(k))
  47. end
  48. #
  49. # Case-insensitive wrapper around store
  50. #
  51. def store(k,v)
  52. super(find_key_case(k), v)
  53. end
  54. #
  55. # Case-insensitive wrapper around delete
  56. #
  57. def delete(k)
  58. super(find_key_case(k))
  59. end
  60. #
  61. # Updates a value in the datastore with the specified name, k, to the
  62. # specified value, v. This update does not alter the imported status of
  63. # the value.
  64. #
  65. def update_value(k, v)
  66. self.store(k, v)
  67. end
  68. #
  69. # This method is a helper method that imports the default value for
  70. # all of the supplied options
  71. #
  72. def import_options(options, imported_by = nil, overwrite = false)
  73. options.each_option do |name, opt|
  74. if self[name].nil? || overwrite
  75. import_option(name, opt.default, true, imported_by, opt)
  76. end
  77. end
  78. end
  79. #
  80. # Imports option values from a whitespace separated string in
  81. # VAR=VAL format.
  82. #
  83. def import_options_from_s(option_str, delim = nil)
  84. hash = {}
  85. # Figure out the delimeter, default to space.
  86. if (delim.nil?)
  87. delim = /\s/
  88. if (option_str.split('=').length <= 2 or option_str.index(',') != nil)
  89. delim = ','
  90. end
  91. end
  92. # Split on the delimeter
  93. option_str.split(delim).each { |opt|
  94. var, val = opt.split('=')
  95. next if (var =~ /^\s+$/)
  96. # Invalid parse? Raise an exception and let those bastards know.
  97. if (var == nil or val == nil)
  98. var = "unknown" if (!var)
  99. raise Rex::ArgumentParseError, "Invalid option specified: #{var}",
  100. caller
  101. end
  102. # Remove trailing whitespaces from the value
  103. val.gsub!(/\s+$/, '')
  104. # Store the value
  105. hash[var] = val
  106. }
  107. import_options_from_hash(hash)
  108. end
  109. #
  110. # Imports options from a hash and stores them in the datastore.
  111. #
  112. def import_options_from_hash(option_hash, imported = true, imported_by = nil)
  113. option_hash.each_pair { |key, val|
  114. import_option(key, val, imported, imported_by)
  115. }
  116. end
  117. def import_option(key, val, imported = true, imported_by = nil, option = nil)
  118. self.store(key, val)
  119. if option
  120. option.aliases.each do |a|
  121. @aliases[a.downcase] = key.downcase
  122. end
  123. end
  124. @options[key] = option
  125. @imported[key] = imported
  126. @imported_by[key] = imported_by
  127. end
  128. #
  129. # Serializes the options in the datastore to a string.
  130. #
  131. def to_s(delim = ' ')
  132. str = ''
  133. keys.sort.each { |key|
  134. str << "#{key}=#{self[key]}" + ((str.length) ? delim : '')
  135. }
  136. return str
  137. end
  138. def to_h
  139. datastore_hash = {}
  140. self.keys.each do |k|
  141. datastore_hash[k.to_s] = self[k].to_s
  142. end
  143. datastore_hash
  144. end
  145. # Hack on a hack for the external modules
  146. def to_nested_values
  147. datastore_hash = {}
  148. array_nester = ->(arr) do
  149. if arr.first.is_a? Array
  150. arr.map &array_nester
  151. else
  152. arr.map &:to_s
  153. end
  154. end
  155. self.keys.each do |k|
  156. # TODO arbitrary depth
  157. if self[k].is_a? Array
  158. datastore_hash[k.to_s] = array_nester.call(self[k])
  159. else
  160. datastore_hash[k.to_s] = self[k].to_s
  161. end
  162. end
  163. datastore_hash
  164. end
  165. #
  166. # Persists the contents of the data store to a file
  167. #
  168. def to_file(path, name = 'global')
  169. ini = Rex::Parser::Ini.new(path)
  170. ini.add_group(name)
  171. # Save all user-defined options to the file.
  172. user_defined.each_pair { |k, v|
  173. ini[name][k] = v
  174. }
  175. ini.to_file(path)
  176. end
  177. #
  178. # Imports datastore values from the specified file path using the supplied
  179. # name
  180. #
  181. def from_file(path, name = 'global')
  182. begin
  183. ini = Rex::Parser::Ini.from_file(path)
  184. rescue
  185. return
  186. end
  187. if (ini.group?(name))
  188. import_options_from_hash(ini[name], false)
  189. end
  190. end
  191. #
  192. # Return a deep copy of this datastore.
  193. #
  194. def copy
  195. ds = self.class.new
  196. self.keys.each do |k|
  197. ds.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k], @imported_by[k])
  198. end
  199. ds.aliases = self.aliases.dup
  200. ds
  201. end
  202. #
  203. # Override merge! so that we merge the aliases and imported hashes
  204. #
  205. def merge!(other)
  206. if other.is_a? DataStore
  207. self.aliases.merge!(other.aliases)
  208. self.imported.merge!(other.imported)
  209. self.imported_by.merge!(other.imported_by)
  210. end
  211. # call super last so that we return a reference to ourselves
  212. super
  213. end
  214. #
  215. # Override merge to ensure we merge the aliases and imported hashes
  216. #
  217. def merge(other)
  218. ds = self.copy
  219. ds.merge!(other)
  220. end
  221. #
  222. # Returns a hash of user-defined datastore values. The returned hash does
  223. # not include default option values.
  224. #
  225. def user_defined
  226. reject { |k, v|
  227. @imported[k] == true
  228. }
  229. end
  230. #
  231. # Remove all imported options from the data store.
  232. #
  233. def clear_non_user_defined
  234. @imported.delete_if { |k, v|
  235. if (v and @imported_by[k] != 'self')
  236. self.delete(k)
  237. @imported_by.delete(k)
  238. end
  239. v
  240. }
  241. end
  242. #
  243. # Completely clear all values in the hash
  244. #
  245. def clear
  246. self.keys.each {|k| self.delete(k) }
  247. self
  248. end
  249. #
  250. # Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
  251. # "can't add a new key into hash during iteration"
  252. #
  253. def each(&block)
  254. list = []
  255. self.keys.sort.each do |sidx|
  256. list << [sidx, self[sidx]]
  257. end
  258. list.each(&block)
  259. end
  260. protected
  261. #
  262. # Case-insensitive key lookup
  263. #
  264. def find_key_case(k)
  265. # Scan each alias looking for a key
  266. search_k = k.downcase
  267. if self.aliases.has_key?(search_k)
  268. search_k = self.aliases[search_k]
  269. end
  270. # Scan each key looking for a match
  271. self.each_key do |rk|
  272. if rk.downcase == search_k
  273. return rk
  274. end
  275. end
  276. # Fall through to the non-existent value
  277. return k
  278. end
  279. end
  280. ###
  281. #
  282. # DataStore wrapper for modules that will attempt to back values against the
  283. # framework's datastore if they aren't found in the module's datastore. This
  284. # is done to simulate global data store values.
  285. #
  286. ###
  287. class ModuleDataStore < DataStore
  288. def initialize(m)
  289. super()
  290. @_module = m
  291. end
  292. #
  293. # Fetch the key from the local hash first, or from the framework datastore
  294. # if we can't directly find it
  295. #
  296. def fetch(key)
  297. key = find_key_case(key)
  298. val = nil
  299. val = super if(@imported_by[key] != 'self')
  300. if (val.nil? and @_module and @_module.framework)
  301. val = @_module.framework.datastore[key]
  302. end
  303. val = super if val.nil?
  304. val
  305. end
  306. #
  307. # Same as fetch
  308. #
  309. def [](key)
  310. key = find_key_case(key)
  311. val = nil
  312. val = super if(@imported_by[key] != 'self')
  313. if (val.nil? and @_module and @_module.framework)
  314. val = @_module.framework.datastore[key]
  315. end
  316. val = super if val.nil?
  317. val
  318. end
  319. #
  320. # Was this entry actually set or just using its default
  321. #
  322. def default?(key)
  323. (@imported_by[key] == 'self')
  324. end
  325. #
  326. # Return a deep copy of this datastore.
  327. #
  328. def copy
  329. ds = self.class.new(@_module)
  330. self.keys.each do |k|
  331. ds.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k], @imported_by[k])
  332. end
  333. ds.aliases = self.aliases.dup
  334. ds
  335. end
  336. end
  337. end