PageRenderTime 63ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/msf/core/data_store.rb

https://bitbucket.org/cfield/metasploit-framework
Ruby | 312 lines | 164 code | 53 blank | 95 comment | 28 complexity | 1b81c3a2df306556b89cd510a515d80a MD5 | raw file
  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. @imported = Hash.new
  15. @imported_by = Hash.new
  16. end
  17. #
  18. # Clears the imported flag for the supplied key since it's being set
  19. # directly.
  20. #
  21. def []=(k, v)
  22. k = find_key_case(k)
  23. @imported[k] = false
  24. @imported_by[k] = nil
  25. super(k,v)
  26. end
  27. #
  28. # Case-insensitive wrapper around hash lookup
  29. #
  30. def [](k)
  31. super(find_key_case(k))
  32. end
  33. #
  34. # Case-insensitive wrapper around store
  35. #
  36. def store(k,v)
  37. super(find_key_case(k), v)
  38. end
  39. #
  40. # Updates a value in the datastore with the specified name, k, to the
  41. # specified value, v. This update does not alter the imported status of
  42. # the value.
  43. #
  44. def update_value(k, v)
  45. self.store(k, v)
  46. end
  47. #
  48. # This method is a helper method that imports the default value for
  49. # all of the supplied options
  50. #
  51. def import_options(options, imported_by = nil, overwrite = false)
  52. options.each_option { |name, opt|
  53. # If there's already a value defined for this option, then skip it
  54. # and don't import it.
  55. next if self.has_key?(name) and overwrite == false
  56. # If the option has a default value, import it, but only if the
  57. # datastore doesn't already have a value set for it.
  58. if ((opt.default != nil) and (overwrite or self[name] == nil))
  59. import_option(name, opt.default.to_s, true, imported_by)
  60. end
  61. }
  62. end
  63. #
  64. # Imports option values from a whitespace separated string in
  65. # VAR=VAL format.
  66. #
  67. def import_options_from_s(option_str, delim = nil)
  68. hash = {}
  69. # Figure out the deliminter, default to space.
  70. if (delim.nil?)
  71. delim = /\s/
  72. if (option_str.split('=').length <= 2 or option_str.index(',') != nil)
  73. delim = ','
  74. end
  75. end
  76. # Split on the deliminter
  77. option_str.split(delim).each { |opt|
  78. var, val = opt.split('=')
  79. next if (var =~ /^\s+$/)
  80. # Invalid parse? Raise an exception and let those bastards know.
  81. if (var == nil or val == nil)
  82. var = "unknown" if (!var)
  83. raise Rex::ArgumentParseError, "Invalid option specified: #{var}",
  84. caller
  85. end
  86. # Remove trailing whitespaces from the value
  87. val.gsub!(/\s+$/, '')
  88. # Store the value
  89. hash[var] = val
  90. }
  91. import_options_from_hash(hash)
  92. end
  93. #
  94. # Imports options from a hash and stores them in the datastore.
  95. #
  96. def import_options_from_hash(option_hash, imported = true, imported_by = nil)
  97. option_hash.each_pair { |key, val|
  98. import_option(key, val.to_s, imported, imported_by)
  99. }
  100. end
  101. def import_option(key, val, imported=true, imported_by=nil)
  102. self.store(key, val)
  103. @imported[key] = imported
  104. @imported_by[key] = imported_by
  105. end
  106. #
  107. # Serializes the options in the datastore to a string.
  108. #
  109. def to_s(delim = ' ')
  110. str = ''
  111. keys.sort.each { |key|
  112. str << "#{key}=#{self[key]}" + ((str.length) ? delim : '')
  113. }
  114. return str
  115. end
  116. def to_h
  117. datastore_hash = {}
  118. self.keys.each do |k|
  119. datastore_hash[k.to_s] = self[k].to_s
  120. end
  121. datastore_hash
  122. end
  123. #
  124. # Persists the contents of the data store to a file
  125. #
  126. def to_file(path, name = 'global')
  127. ini = Rex::Parser::Ini.new(path)
  128. ini.add_group(name)
  129. # Save all user-defined options to the file.
  130. user_defined.each_pair { |k, v|
  131. ini[name][k] = v
  132. }
  133. ini.to_file(path)
  134. end
  135. #
  136. # Imports datastore values from the specified file path using the supplied
  137. # name
  138. #
  139. def from_file(path, name = 'global')
  140. begin
  141. ini = Rex::Parser::Ini.from_file(path)
  142. rescue
  143. return
  144. end
  145. if (ini.group?(name))
  146. import_options_from_hash(ini[name], false)
  147. end
  148. end
  149. #
  150. # Returns a hash of user-defined datastore values. The returned hash does
  151. # not include default option values.
  152. #
  153. def user_defined
  154. reject { |k, v|
  155. @imported[k] == true
  156. }
  157. end
  158. #
  159. # Remove all imported options from the data store.
  160. #
  161. def clear_non_user_defined
  162. @imported.delete_if { |k, v|
  163. if (v and @imported_by[k] != 'self')
  164. self.delete(k)
  165. @imported_by.delete(k)
  166. end
  167. v
  168. }
  169. end
  170. #
  171. # Completely clear all values in the hash
  172. #
  173. def clear
  174. self.keys.each {|k| self.delete(k) }
  175. self
  176. end
  177. #
  178. # Overrides the builtin 'each' operator to avoid the following exception on Ruby 1.9.2+
  179. # "can't add a new key into hash during iteration"
  180. #
  181. def each(&block)
  182. list = []
  183. self.keys.sort.each do |sidx|
  184. list << [sidx, self[sidx]]
  185. end
  186. list.each(&block)
  187. end
  188. protected
  189. #
  190. # Case-insensitive key lookup
  191. #
  192. def find_key_case(k)
  193. # Scan each key looking for a match
  194. self.each_key do |rk|
  195. if (rk.downcase == k.downcase)
  196. return rk
  197. end
  198. end
  199. # Fall through to the non-existent value
  200. return k
  201. end
  202. end
  203. ###
  204. #
  205. # DataStore wrapper for modules that will attempt to back values against the
  206. # framework's datastore if they aren't found in the module's datastore. This
  207. # is done to simulate global data store values.
  208. #
  209. ###
  210. class ModuleDataStore < DataStore
  211. def initialize(m)
  212. super()
  213. @_module = m
  214. end
  215. #
  216. # Fetch the key from the local hash first, or from the framework datastore
  217. # if we can't directly find it
  218. #
  219. def fetch(key)
  220. key = find_key_case(key)
  221. val = nil
  222. val = super if(@imported_by[key] != 'self')
  223. if (val.nil? and @_module and @_module.framework)
  224. val = @_module.framework.datastore[key]
  225. end
  226. val = super if val.nil?
  227. val
  228. end
  229. #
  230. # Same as fetch
  231. #
  232. def [](key)
  233. key = find_key_case(key)
  234. val = nil
  235. val = super if(@imported_by[key] != 'self')
  236. if (val.nil? and @_module and @_module.framework)
  237. val = @_module.framework.datastore[key]
  238. end
  239. val = super if val.nil?
  240. val
  241. end
  242. #
  243. # Was this entry actually set or just using its default
  244. #
  245. def default?(key)
  246. (@imported_by[key] == 'self')
  247. end
  248. #
  249. # Return a deep copy of this datastore.
  250. #
  251. def copy
  252. clone = self.class.new(@_module)
  253. self.keys.each do |k|
  254. clone.import_option(k, self[k].kind_of?(String) ? self[k].dup : self[k], @imported[k], @imported_by[k])
  255. end
  256. clone
  257. end
  258. end
  259. end