manageiq-smartstate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (305) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +4 -0
  4. data/.rspec_ci +4 -0
  5. data/.travis.yml +15 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE.txt +202 -0
  8. data/README.md +45 -0
  9. data/Rakefile +23 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/lib/MiqContainerGroup/MiqContainerGroup.rb +31 -0
  13. data/lib/MiqVm/MiqLocalVm.rb +50 -0
  14. data/lib/MiqVm/MiqRhevmVm.rb +179 -0
  15. data/lib/MiqVm/MiqVm.rb +355 -0
  16. data/lib/MiqVm/miq_azure_vm.rb +96 -0
  17. data/lib/MiqVm/miq_scvmm_vm.rb +38 -0
  18. data/lib/MiqVm/test/camcorder_fleece_test.rb +60 -0
  19. data/lib/MiqVm/test/localVm.rb +45 -0
  20. data/lib/MiqVm/test/partitionAlignmentCheck.rb +76 -0
  21. data/lib/MiqVm/test/remoteVm.rb +65 -0
  22. data/lib/MiqVm/test/rhevmNfsTest.rb +62 -0
  23. data/lib/MiqVm/test/rhevmNfsTest2.rb +66 -0
  24. data/lib/MiqVm/test/rhevmTest.rb +70 -0
  25. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackCommon.rb +107 -0
  26. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackImage.rb +67 -0
  27. data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackInstance.rb +182 -0
  28. data/lib/Scvmm/miq_hyperv_disk.rb +273 -0
  29. data/lib/Scvmm/miq_scvmm_parse_powershell.rb +75 -0
  30. data/lib/Scvmm/miq_scvmm_vm_ssa_info.rb +135 -0
  31. data/lib/Scvmm/test/miq_hyperv_disk_test.rb +33 -0
  32. data/lib/Scvmm/test/miq_scvmm_vm_ssa_info_test.rb +41 -0
  33. data/lib/VmLocalDiskAccess/test/localCfg.rb +97 -0
  34. data/lib/VolumeManager/LVM/logical_volume.rb +75 -0
  35. data/lib/VolumeManager/LVM/lv_segment.rb +43 -0
  36. data/lib/VolumeManager/LVM/lvm2disk.rb +158 -0
  37. data/lib/VolumeManager/LVM/parser.rb +138 -0
  38. data/lib/VolumeManager/LVM/physical_volume.rb +19 -0
  39. data/lib/VolumeManager/LVM/scanner.rb +156 -0
  40. data/lib/VolumeManager/LVM/thin/btree.rb +83 -0
  41. data/lib/VolumeManager/LVM/thin/constants.rb +86 -0
  42. data/lib/VolumeManager/LVM/thin/data_map.rb +44 -0
  43. data/lib/VolumeManager/LVM/thin/mapping_tree.rb +19 -0
  44. data/lib/VolumeManager/LVM/thin/space_maps.rb +58 -0
  45. data/lib/VolumeManager/LVM/thin/superblock.rb +136 -0
  46. data/lib/VolumeManager/LVM/thin.rb +6 -0
  47. data/lib/VolumeManager/LVM/volume_group.rb +97 -0
  48. data/lib/VolumeManager/LVM.rb +8 -0
  49. data/lib/VolumeManager/MiqLdm.rb +546 -0
  50. data/lib/VolumeManager/MiqLvm.rb +17 -0
  51. data/lib/VolumeManager/MiqNativeVolumeManager.rb +150 -0
  52. data/lib/VolumeManager/MiqVolumeManager.rb +277 -0
  53. data/lib/VolumeManager/VolMgrPlatformSupport.rb +18 -0
  54. data/lib/VolumeManager/VolMgrPlatformSupportLinux.rb +77 -0
  55. data/lib/VolumeManager/VolMgrPlatformSupportWin.rb +17 -0
  56. data/lib/VolumeManager/test/blockDevTest.rb +40 -0
  57. data/lib/VolumeManager/test/ldm.rb +97 -0
  58. data/lib/blackbox/VmBlackBox.rb +103 -0
  59. data/lib/blackbox/xmlStorage.rb +180 -0
  60. data/lib/db/MiqBdb/MiqBdb.rb +309 -0
  61. data/lib/db/MiqBdb/MiqBdbBtree.rb +219 -0
  62. data/lib/db/MiqBdb/MiqBdbHash.rb +199 -0
  63. data/lib/db/MiqBdb/MiqBdbPage.rb +159 -0
  64. data/lib/db/MiqBdb/MiqBdbUtil.rb +18 -0
  65. data/lib/db/MiqSqlite/MiqSqlite3.rb +330 -0
  66. data/lib/db/MiqSqlite/MiqSqlite3Cell.rb +167 -0
  67. data/lib/db/MiqSqlite/MiqSqlite3Page.rb +151 -0
  68. data/lib/db/MiqSqlite/MiqSqlite3Table.rb +124 -0
  69. data/lib/db/MiqSqlite/MiqSqlite3Util.rb +32 -0
  70. data/lib/disk/DiskProbe.rb +68 -0
  71. data/lib/disk/MiqDisk.rb +317 -0
  72. data/lib/disk/camcorder_test.rb +90 -0
  73. data/lib/disk/dos_mbr.img +0 -0
  74. data/lib/disk/modules/AzureBlobDisk.rb +101 -0
  75. data/lib/disk/modules/LocalDevMod.rb +47 -0
  76. data/lib/disk/modules/LocalDevProbe.rb +6 -0
  77. data/lib/disk/modules/MSCommon.rb +352 -0
  78. data/lib/disk/modules/MSVSDiffDisk.rb +91 -0
  79. data/lib/disk/modules/MSVSDiskProbe.rb +61 -0
  80. data/lib/disk/modules/MSVSDynamicDisk.rb +42 -0
  81. data/lib/disk/modules/MSVSFixedDisk.rb +45 -0
  82. data/lib/disk/modules/MiqLargeFile.rb +63 -0
  83. data/lib/disk/modules/MiqLargeFileWin32.rb +107 -0
  84. data/lib/disk/modules/QcowDisk.rb +692 -0
  85. data/lib/disk/modules/QcowDiskProbe.rb +34 -0
  86. data/lib/disk/modules/RawBlockIO.rb +116 -0
  87. data/lib/disk/modules/RawDisk.rb +45 -0
  88. data/lib/disk/modules/RawDiskProbe.rb +7 -0
  89. data/lib/disk/modules/RhevmDescriptor.rb +167 -0
  90. data/lib/disk/modules/RhevmDiskProbe.rb +52 -0
  91. data/lib/disk/modules/VMWareCowdDisk.rb +207 -0
  92. data/lib/disk/modules/VMWareDescriptor.rb +214 -0
  93. data/lib/disk/modules/VMWareDiskProbe.rb +74 -0
  94. data/lib/disk/modules/VMWareSparseDisk.rb +189 -0
  95. data/lib/disk/modules/VhdxDisk.rb +625 -0
  96. data/lib/disk/modules/VhdxDiskProbe.rb +46 -0
  97. data/lib/disk/modules/VixDiskMod.rb +54 -0
  98. data/lib/disk/modules/VixDiskProbe.rb +6 -0
  99. data/lib/disk/modules/miq_disk_cache.rb +135 -0
  100. data/lib/disk/modules/miq_dummy_disk.rb +41 -0
  101. data/lib/disk/modules/vhdx_bat_entry.rb +10 -0
  102. data/lib/disk/test.rb +66 -0
  103. data/lib/fs/MetakitFS/MetakitFS.rb +530 -0
  104. data/lib/fs/MetakitFS/test/Makefile +14 -0
  105. data/lib/fs/MetakitFS/test/MkCollectFiles.rb +165 -0
  106. data/lib/fs/MetakitFS/test/MkSelectFiles.rb +30 -0
  107. data/lib/fs/MetakitFS/test/collect_files.yaml +70 -0
  108. data/lib/fs/MetakitFS/test/init.rb +3 -0
  109. data/lib/fs/MetakitFS/test/mk2vmdk.rb +64 -0
  110. data/lib/fs/MetakitFS/test/mk4test.c +92 -0
  111. data/lib/fs/MetakitFS/test/mkFsTest.rb +113 -0
  112. data/lib/fs/MetakitFS/test/proto.rb +97 -0
  113. data/lib/fs/MiqFS/FsProbe.rb +39 -0
  114. data/lib/fs/MiqFS/MiqFS.rb +515 -0
  115. data/lib/fs/MiqFS/modules/AUFSProbe.rb +26 -0
  116. data/lib/fs/MiqFS/modules/Ext3.rb +305 -0
  117. data/lib/fs/MiqFS/modules/Ext3Probe.rb +25 -0
  118. data/lib/fs/MiqFS/modules/Ext4.rb +304 -0
  119. data/lib/fs/MiqFS/modules/Ext4Probe.rb +25 -0
  120. data/lib/fs/MiqFS/modules/Fat32.rb +318 -0
  121. data/lib/fs/MiqFS/modules/Fat32Probe.rb +30 -0
  122. data/lib/fs/MiqFS/modules/HFSProbe.rb +18 -0
  123. data/lib/fs/MiqFS/modules/Iso9660.rb +293 -0
  124. data/lib/fs/MiqFS/modules/Iso9660Probe.rb +18 -0
  125. data/lib/fs/MiqFS/modules/LocalFS.rb +105 -0
  126. data/lib/fs/MiqFS/modules/NTFS.rb +287 -0
  127. data/lib/fs/MiqFS/modules/NTFSProbe.rb +21 -0
  128. data/lib/fs/MiqFS/modules/NativeFS.rb +155 -0
  129. data/lib/fs/MiqFS/modules/ReFSProbe.rb +17 -0
  130. data/lib/fs/MiqFS/modules/RealFS.rb +79 -0
  131. data/lib/fs/MiqFS/modules/RealFSProbe.rb +6 -0
  132. data/lib/fs/MiqFS/modules/Reiser4Probe.rb +18 -0
  133. data/lib/fs/MiqFS/modules/ReiserFS.rb +315 -0
  134. data/lib/fs/MiqFS/modules/ReiserFSProbe.rb +42 -0
  135. data/lib/fs/MiqFS/modules/UnionFSProbe.rb +18 -0
  136. data/lib/fs/MiqFS/modules/WebDAV.rb +127 -0
  137. data/lib/fs/MiqFS/modules/WebDAVFile.rb +68 -0
  138. data/lib/fs/MiqFS/modules/XFS.rb +300 -0
  139. data/lib/fs/MiqFS/modules/XFSProbe.rb +26 -0
  140. data/lib/fs/MiqFS/modules/ZFSProbe.rb +18 -0
  141. data/lib/fs/MiqFS/test.rb +59 -0
  142. data/lib/fs/MiqFsUtil.rb +383 -0
  143. data/lib/fs/MiqMountManager.rb +209 -0
  144. data/lib/fs/MiqNativeMountManager.rb +101 -0
  145. data/lib/fs/MountManagerProbe.rb +29 -0
  146. data/lib/fs/ReiserFS/block.rb +209 -0
  147. data/lib/fs/ReiserFS/directory.rb +136 -0
  148. data/lib/fs/ReiserFS/directory_entry.rb +140 -0
  149. data/lib/fs/ReiserFS/file_data.rb +111 -0
  150. data/lib/fs/ReiserFS/superblock.rb +140 -0
  151. data/lib/fs/ReiserFS/utils.rb +95 -0
  152. data/lib/fs/VimDatastoreFS/VimDatastoreFS.rb +192 -0
  153. data/lib/fs/ext3/alloc_bitmap.rb +38 -0
  154. data/lib/fs/ext3/block_pointers_path.rb +130 -0
  155. data/lib/fs/ext3/directory.rb +51 -0
  156. data/lib/fs/ext3/directory_entry.rb +67 -0
  157. data/lib/fs/ext3/ex_attrib_header.rb +14 -0
  158. data/lib/fs/ext3/ex_attrib_name.rb +23 -0
  159. data/lib/fs/ext3/file_data.rb +130 -0
  160. data/lib/fs/ext3/group_descriptor_entry.rb +65 -0
  161. data/lib/fs/ext3/group_descriptor_table.rb +54 -0
  162. data/lib/fs/ext3/hash_tree_entry.rb +18 -0
  163. data/lib/fs/ext3/hash_tree_header.rb +15 -0
  164. data/lib/fs/ext3/inode.rb +228 -0
  165. data/lib/fs/ext3/posix_acl_entry.rb +29 -0
  166. data/lib/fs/ext3/posix_acl_header.rb +11 -0
  167. data/lib/fs/ext3/superblock.rb +406 -0
  168. data/lib/fs/ext3/test/tc_Ext3BlockPointersPath.rb +74 -0
  169. data/lib/fs/ext4/alloc_bitmap.rb +38 -0
  170. data/lib/fs/ext4/directory.rb +87 -0
  171. data/lib/fs/ext4/directory_entry.rb +77 -0
  172. data/lib/fs/ext4/ex_attrib_header.rb +14 -0
  173. data/lib/fs/ext4/ex_attrib_name.rb +23 -0
  174. data/lib/fs/ext4/extent.rb +35 -0
  175. data/lib/fs/ext4/extent_header.rb +40 -0
  176. data/lib/fs/ext4/extent_index.rb +33 -0
  177. data/lib/fs/ext4/group_descriptor_entry.rb +69 -0
  178. data/lib/fs/ext4/group_descriptor_table.rb +54 -0
  179. data/lib/fs/ext4/hash_tree_entry.rb +58 -0
  180. data/lib/fs/ext4/hash_tree_header.rb +35 -0
  181. data/lib/fs/ext4/inode.rb +465 -0
  182. data/lib/fs/ext4/posix_acl_entry.rb +29 -0
  183. data/lib/fs/ext4/posix_acl_header.rb +11 -0
  184. data/lib/fs/ext4/superblock.rb +412 -0
  185. data/lib/fs/fat32/boot_sect.rb +379 -0
  186. data/lib/fs/fat32/directory.rb +222 -0
  187. data/lib/fs/fat32/directory_entry.rb +540 -0
  188. data/lib/fs/fat32/file_data.rb +128 -0
  189. data/lib/fs/iso9660/boot_sector.rb +170 -0
  190. data/lib/fs/iso9660/directory.rb +90 -0
  191. data/lib/fs/iso9660/directory_entry.rb +147 -0
  192. data/lib/fs/iso9660/file_data.rb +78 -0
  193. data/lib/fs/iso9660/rock_ridge.rb +329 -0
  194. data/lib/fs/iso9660/util.rb +57 -0
  195. data/lib/fs/modules/LinuxMount.rb +300 -0
  196. data/lib/fs/modules/LinuxMountProbe.rb +29 -0
  197. data/lib/fs/modules/WinMount.rb +97 -0
  198. data/lib/fs/modules/WinMountProbe.rb +24 -0
  199. data/lib/fs/ntfs/attrib_attribute_list.rb +131 -0
  200. data/lib/fs/ntfs/attrib_bitmap.rb +26 -0
  201. data/lib/fs/ntfs/attrib_data.rb +74 -0
  202. data/lib/fs/ntfs/attrib_file_name.rb +110 -0
  203. data/lib/fs/ntfs/attrib_header.rb +194 -0
  204. data/lib/fs/ntfs/attrib_index_allocation.rb +19 -0
  205. data/lib/fs/ntfs/attrib_index_root.rb +247 -0
  206. data/lib/fs/ntfs/attrib_object_id.rb +40 -0
  207. data/lib/fs/ntfs/attrib_standard_information.rb +107 -0
  208. data/lib/fs/ntfs/attrib_type.rb +49 -0
  209. data/lib/fs/ntfs/attrib_volume_information.rb +53 -0
  210. data/lib/fs/ntfs/attrib_volume_name.rb +31 -0
  211. data/lib/fs/ntfs/boot_sect.rb +253 -0
  212. data/lib/fs/ntfs/data_run.rb +358 -0
  213. data/lib/fs/ntfs/directory_index_node.rb +114 -0
  214. data/lib/fs/ntfs/index_node_header.rb +69 -0
  215. data/lib/fs/ntfs/index_record_header.rb +85 -0
  216. data/lib/fs/ntfs/mft_entry.rb +288 -0
  217. data/lib/fs/ntfs/utils.rb +43 -0
  218. data/lib/fs/test/camcorder_fs_test.rb +108 -0
  219. data/lib/fs/test/collect_files_direct.yaml +22 -0
  220. data/lib/fs/test/collect_files_in.yaml +24 -0
  221. data/lib/fs/test/collect_files_in_nc.yaml +22 -0
  222. data/lib/fs/test/collect_files_out.yaml +6 -0
  223. data/lib/fs/test/collect_files_rm.yaml +6 -0
  224. data/lib/fs/test/copyTest.rb +126 -0
  225. data/lib/fs/test/fsTest.rb +87 -0
  226. data/lib/fs/test/updateTest.rb +184 -0
  227. data/lib/fs/xfs/allocation_group.rb +160 -0
  228. data/lib/fs/xfs/bmap_btree_block.rb +125 -0
  229. data/lib/fs/xfs/bmap_btree_record.rb +80 -0
  230. data/lib/fs/xfs/bmap_btree_root_node.rb +72 -0
  231. data/lib/fs/xfs/directory.rb +133 -0
  232. data/lib/fs/xfs/directory2_data_header.rb +27 -0
  233. data/lib/fs/xfs/directory3_data_header.rb +34 -0
  234. data/lib/fs/xfs/directory_block_tail.rb +22 -0
  235. data/lib/fs/xfs/directory_data_header.rb +46 -0
  236. data/lib/fs/xfs/directory_entry.rb +106 -0
  237. data/lib/fs/xfs/inode.rb +532 -0
  238. data/lib/fs/xfs/inode_map.rb +100 -0
  239. data/lib/fs/xfs/short_form_directory_entry.rb +91 -0
  240. data/lib/fs/xfs/short_form_header.rb +44 -0
  241. data/lib/fs/xfs/superblock.rb +556 -0
  242. data/lib/lib/tasks/azure.rake +52 -0
  243. data/lib/manageiq/smartstate/version.rb +5 -0
  244. data/lib/manageiq/smartstate.rb +7 -0
  245. data/lib/manageiq-smartstate.rb +1 -0
  246. data/lib/metadata/MIQExtract/MIQExtract.rb +297 -0
  247. data/lib/metadata/MIQExtract/test/extractTest.rb +41 -0
  248. data/lib/metadata/MIQExtract/test/full_extract_test.rb +68 -0
  249. data/lib/metadata/ScanProfile/HostScanItem.rb +4 -0
  250. data/lib/metadata/ScanProfile/HostScanProfile.rb +4 -0
  251. data/lib/metadata/ScanProfile/HostScanProfiles.rb +41 -0
  252. data/lib/metadata/ScanProfile/ScanItemBase.rb +63 -0
  253. data/lib/metadata/ScanProfile/ScanProfileBase.rb +51 -0
  254. data/lib/metadata/ScanProfile/ScanProfilesBase.rb +60 -0
  255. data/lib/metadata/ScanProfile/VmScanItem.rb +4 -0
  256. data/lib/metadata/ScanProfile/VmScanProfile.rb +4 -0
  257. data/lib/metadata/ScanProfile/VmScanProfiles.rb +38 -0
  258. data/lib/metadata/ScanProfile/modules/HostScanItemFile.rb +51 -0
  259. data/lib/metadata/ScanProfile/modules/HostScanItemNteventlog.rb +84 -0
  260. data/lib/metadata/ScanProfile/modules/VmScanItemFile.rb +39 -0
  261. data/lib/metadata/ScanProfile/modules/VmScanItemNteventlog.rb +34 -0
  262. data/lib/metadata/ScanProfile/modules/VmScanItemRegistry.rb +64 -0
  263. data/lib/metadata/VMMount/VMMount.rb +81 -0
  264. data/lib/metadata/VMMount/VMPlatformMount.rb +18 -0
  265. data/lib/metadata/VMMount/VMPlatformMountLinux.rb +75 -0
  266. data/lib/metadata/VMMount/VMPlatformMountWin.rb +13 -0
  267. data/lib/metadata/VmConfig/GetNativeCfg.rb +45 -0
  268. data/lib/metadata/VmConfig/VmConfig.rb +947 -0
  269. data/lib/metadata/VmConfig/cfgConfig.rb +45 -0
  270. data/lib/metadata/VmConfig/ovfConfig.rb +99 -0
  271. data/lib/metadata/VmConfig/test/GetVMwareCfgTest.rb +40 -0
  272. data/lib/metadata/VmConfig/vmcConfig.rb +116 -0
  273. data/lib/metadata/VmConfig/vmtxConfig.rb +4 -0
  274. data/lib/metadata/VmConfig/vmxConfig.rb +162 -0
  275. data/lib/metadata/VmConfig/xmlConfig.rb +79 -0
  276. data/lib/metadata/VmConfig/xmlMsHyperVConfig.rb +41 -0
  277. data/lib/metadata/linux/InitProcHash.rb +632 -0
  278. data/lib/metadata/linux/LinuxInitProcs.rb +142 -0
  279. data/lib/metadata/linux/LinuxOSInfo.rb +237 -0
  280. data/lib/metadata/linux/LinuxPackages.rb +209 -0
  281. data/lib/metadata/linux/LinuxSystemd.rb +130 -0
  282. data/lib/metadata/linux/LinuxUsers.rb +289 -0
  283. data/lib/metadata/linux/LinuxUtils.rb +197 -0
  284. data/lib/metadata/linux/MiqConaryPackages.rb +41 -0
  285. data/lib/metadata/linux/MiqRpmPackages.rb +160 -0
  286. data/lib/metadata/linux/test/Name +0 -0
  287. data/lib/metadata/linux/test/Packages +0 -0
  288. data/lib/metadata/linux/test/rpoTest.rb +5 -0
  289. data/lib/metadata/linux/test/tc_LinuxUtils.rb +4157 -0
  290. data/lib/metadata/util/event_log_filter.rb +61 -0
  291. data/lib/metadata/util/md5deep.rb +280 -0
  292. data/lib/metadata/util/win32/Win32Accounts.rb +764 -0
  293. data/lib/metadata/util/win32/Win32EventLog.rb +743 -0
  294. data/lib/metadata/util/win32/Win32Services.rb +86 -0
  295. data/lib/metadata/util/win32/Win32Software.rb +326 -0
  296. data/lib/metadata/util/win32/Win32System.rb +333 -0
  297. data/lib/metadata/util/win32/boot_info_win.rb +59 -0
  298. data/lib/metadata/util/win32/fleece_hives.rb +220 -0
  299. data/lib/metadata/util/win32/ms-registry.rb +650 -0
  300. data/lib/metadata/util/win32/peheader.rb +868 -0
  301. data/lib/metadata/util/win32/remote-registry.rb +142 -0
  302. data/lib/metadata/util/win32/system_path_win.rb +103 -0
  303. data/lib/metadata/util/win32/versioninfo.rb +17 -0
  304. data/manageiq-smartstate.gemspec +35 -0
  305. metadata +486 -0
@@ -0,0 +1,743 @@
1
+ # encoding: US-ASCII
2
+
3
+ # TODO:
4
+ # Provide collection of custom log names?
5
+
6
+ # Specifically use the Platform mod used in MiqDisk.
7
+ require 'sys-uname'
8
+
9
+ # For message table resources.
10
+ require 'metadata/util/win32/peheader'
11
+
12
+ # For registry export on MiqFS.
13
+ require 'metadata/util/win32/remote-registry'
14
+
15
+ # Dev needs this.
16
+ require 'Win32API' if Sys::Platform::OS == :windows
17
+ require 'metadata/util/win32/system_path_win'
18
+
19
+ require 'digest/md5'
20
+
21
+ # Common utilities.
22
+ require 'binary_struct'
23
+ require 'util/miq-unicode'
24
+ require 'util/miq-xml'
25
+ require 'util/miq-exception'
26
+
27
+ require 'metadata/util/event_log_filter'
28
+
29
+ class Win32EventLog
30
+ # Standard file log names
31
+ SYSTEM_LOGS = %w(Application System Security)
32
+ BUFFER_READ_SIZE = 10485760 # 10 MB buffer
33
+
34
+ # Data definitions. (http://msdn.microsoft.com/en-gb/library/bb309024.aspx)
35
+ ELF_LOGFILE_HEADER = BinaryStruct.new([
36
+ 'L', :header_size, # The size of the header structure. The size is always 0x30.
37
+ 'a4', :signature, # The signature is always 0x654c664c, which is ASCII for eLfL.
38
+ 'L', :majorVersion, # The major version number of the event log. The major version number is always set to 1.
39
+ 'L', :minorVersion, # The minor version number of the event log. The minor version number is always set to 1.
40
+ 'L', :start_offset, # The offset to the oldest record in the event log.
41
+ 'L', :end_offset, # The offset to the ELF_EOF_RECORD in the event log.
42
+ 'L', :current_record_number, # The number of the next record that will be added to the event log.
43
+ 'L', :oldest_record_number, # The number of the oldest record in the event log. For an empty file, the oldest record number is set to 0.
44
+ 'L', :max_size, # The maximum size, in bytes, of the event log. The maximum size is defined when the event log is created.
45
+ # The event-logging service does not typically update this value, it relies on the registry configuration.
46
+ # The reader of the event log can use normal file APIs to determine the size of the file.
47
+ 'L', :flags, # See ELF_ below.
48
+ 'L', :retention, # The retention value of the file when it is created.
49
+ # The event-logging service does not typically update this value, it relies on the registry configuration.
50
+ # For more information about registry configuration values, see Eventlog Key.
51
+ 'L', :end_header_size # The ending size of the header structure. The size is always 0x30.
52
+ ])
53
+
54
+ # Event Log header flags.
55
+ ELF_DIRTY = 0x00000001 # If set, don't rely on other values in the header.
56
+ ELF_WRAPPED = 0x00000002 # Indicates the log is wrapped.
57
+ ELF_LOGFULL = 0x00000004 # Set if log full (extended implications in EventLogFormat.txt).
58
+ ELF_LOGFILE_ARCHIVE_SET = 0x00000008 # Indicates that the archive attribute has been set for the file.
59
+ # Normal file APIs can also be used to determine the value of this flag.
60
+
61
+ # Data definitions. (http://msdn.microsoft.com/en-gb/library/bb309022(VS.85).aspx )
62
+ EVENTLOGEOF = BinaryStruct.new([
63
+ 'L', :record_size_beginning, # The beginning size of the ELF_EOF_RECORD. The beginning size is always 0x28.
64
+ 'a16', :magic, # Always \001\001\001\001\002\002\002\002\003\003\003\003\004\004\004\004
65
+ 'L', :begin_record, # The offset to the oldest record. If the event log is empty, this is set to the start of this structure.
66
+ 'L', :end_record, # The offset to the start of this structure.
67
+ 'L', :current_record_number, # The record number of the next event that will be written to the event log.
68
+ 'L', :oldest_record_number, # The record number of the oldest record in the event log. The record number will be 0 if the event log is empty.
69
+ 'L', :record_size_end # The ending size of the ELF_EOF_RECORD. The ending size is always 0x28.
70
+ ])
71
+
72
+ # Data definitions. (http://msdn.microsoft.com/en-gb/library/aa363646(VS.85).aspx)
73
+ EVENTRECORD = BinaryStruct.new([
74
+ 'L', :record_length, # The size of this event record, in bytes. Note that this value is stored at both ends
75
+ # of the entry to ease moving forward or backward through the log. The length includes
76
+ # any pad bytes inserted at the end of the record for DWORD alignment.
77
+ 'a4', :magic, # A DWORD value that is always set to ELF_LOG_SIGNATURE (the value is 0x654c664c), which is ASCII for eLfL.
78
+ 'L', :record_num, # The number of the record.
79
+ 'L', :generated, # The time at which this entry was submitted. This time is measured in the number of seconds elapsed since 00:00:00 January 1, 1970, Universal Coordinated Time.
80
+ 'L', :written, # The time at which this entry was received by the service to be written to the log. This time is measured in the number of seconds elapsed since 00:00:00 January 1, 1970, Universal Coordinated Time.
81
+ 'L', :event_id, # The event identifier. The value is specific to the event source for the event, and is used with source name to locate a description string in the message file for the event source
82
+ 'S', :level, # See EVENTLOG_ below.
83
+ 'S', :num_strings, # The number of strings present in the log (at the position indicated by StringOffset). These strings are merged into the message before it is displayed to the user.
84
+ 'S', :category, # The category for this event. The meaning of this value depends on the event source.
85
+ 'S', :reserved_flags, # Reserved.
86
+ 'L', :closing_rec_num, # Reserved.
87
+ 'L', :string_offset, # Offset from beginning of record to UTF-16 strings.
88
+ 'L', :user_sid_length, # The size of the UserSid member, in bytes. This value can be zero if no security identifier was provided.
89
+ 'L', :user_sid_offset, # Offset from beginning of record.
90
+ 'L', :data_length, # Length of parameter data (0 if none).
91
+ 'L', :data_offset, # The offset of the event-specific information within this event log record, in bytes.
92
+ # This information could be something specific (a disk driver might log the number of retries, for example),
93
+ # followed by binary information specific to the event being logged and to the source that generated the entry.
94
+ ])
95
+
96
+ EVENTRECORDLENGTH = BinaryStruct.new([
97
+ 'L', :record_length, # The size of this event record, in bytes. Note that this value is stored at both ends
98
+ ])
99
+
100
+ # Event types.
101
+ EVENT_TYPES = {
102
+ 0x0000 => :info, # EVENTLOG_SUCCESS
103
+ 0x0001 => :error, # EVENTLOG_ERROR_TYPE
104
+ 0x0002 => :warn, # EVENTLOG_WARNING_TYPE
105
+ 0x0004 => :info, # EVENTLOG_INFORMATION_TYPE
106
+ 0x0008 => :info, # VENTLOG_AUDIT_SUCCESS
107
+ 0x0010 => :error, # EVENTLOG_AUDIT_FAILURE
108
+ }
109
+
110
+ # Magic numbers used by log record types.
111
+ MAGIC_HDR = "LfLe"
112
+ MAGIC_CSR = "\x11\x11\x11\x11\x22\x22\x22\x22\x33\x33\x33\x33\x44\x44\x44\x44"
113
+
114
+ # Registry constants.
115
+ HKLM = 0x80000002
116
+ KEY_READ = 0x00020019
117
+ REG_MULTI_SZ = 7
118
+
119
+ # Key name buffer size.
120
+ SIZE_BUF = 256
121
+
122
+ # Misc Windows constants.
123
+ INVALID_HANDLE_VALUE = -1
124
+ ERROR_SUCCESS = 0
125
+ ERROR_NO_MORE_ITEMS = 259
126
+
127
+ # Lookup object for translating the common %? sequences in the messages
128
+ FORMAT_TR = Hash.new { |_h, k| k }.merge(
129
+ '% ' => " ",
130
+ '%b' => " ",
131
+ '%.' => ".",
132
+ '%!' => "!",
133
+ '%n' => "\r\n",
134
+ '%r' => "\r",
135
+ '%t' => "\t",
136
+ '%0' => "",
137
+ '!s!' => ""
138
+ )
139
+
140
+ # Keys that will be in the final node record
141
+ NODE_REC_KEYS = [:generated, :event_id, :level, :category, :computer_name, :source, :message]
142
+
143
+ attr_reader :xmlDoc, :customFileName
144
+ attr_reader :readTimes
145
+
146
+ def initialize(vmMiqFs = nil)
147
+ # vmMiqFs is an MiqFS instance for the file system
148
+ # of the guest vm if guest logs or nil if host logs.
149
+
150
+ # If an MiqFS instance was not passed, then the OS has to be (or emulate) Win32.
151
+ # If an MiqFS instance *was* passed, then if the guest OS is not Windows then getSystemRoot will throw.
152
+ raise "#{self.class}::initialize: Platform is not Windows and file system is not MiqFS: cannot continue" if Sys::Platform::OS != :windows and !vmMiqFs.class.to_s.include?('Miq')
153
+
154
+ # Get a file system instance if we don't already have one.
155
+ @fs = vmMiqFs
156
+ @fs = File if @fs.nil?
157
+
158
+ # Init times.
159
+ @readTimes = {}
160
+
161
+ @msgtbl_cache = {}
162
+
163
+ # Get root, system message tables & init messagetable cache.
164
+ if @fs == File
165
+ @systemRoot = 'c:/windows/system32'
166
+ @kernel32_fn = 'c:/windows/system32/kernel32.dll'
167
+ else
168
+ @systemRoot = Win32::SystemPath.systemRoot(@fs)
169
+ @kernel32_fn = "#{Win32::SystemPath.system32Path(@fs, @systemRoot)}/kernel32.dll"
170
+ end
171
+ end
172
+
173
+ def readAllLogs(options)
174
+ options = options.collect { |l| {:name => l, :filter => nil} } if options[0].kind_of?(String)
175
+
176
+ options.each do |o|
177
+ start = Time.now
178
+ readLog(o[:name], o[:filter])
179
+ @readTimes[o[:name]] = Time.now - start
180
+ end
181
+ @xmlDoc
182
+ end
183
+
184
+ def readLog(log, filter = nil)
185
+ filter ||= {}
186
+ EventLogFilter.prepare_filter!(filter)
187
+
188
+ # Get message source files. (This also caches the event log registry entries.)
189
+ sources = getEventSourceMessageFiles(log)
190
+ @f = @buf = nil
191
+
192
+ # Get event log file and validate it is a format we support
193
+ event_file = mkLogPath(log)
194
+ unless File.extname(event_file).downcase == ".evt"
195
+ raise MiqException::NtEventLogFormat, "#{self.class}: Unsupported Win32 Eventlog format [#{File.extname(event_file)}] for event log [#{log}]. File:[#{event_file}]"
196
+ end
197
+
198
+ # Start an XML document
199
+ recordsNode = mkXmlDoc(log, event_file)
200
+
201
+ getFileObj(event_file) do |f, filename|
202
+ st = Time.now
203
+ $log.info "#{self.class}: Opening file for [#{log}]" if $log
204
+ @f = f
205
+ @offset = BUFFER_READ_SIZE * -1
206
+
207
+ hdr = ELF_LOGFILE_HEADER.decode(read_buffer(0, ELF_LOGFILE_HEADER.size))
208
+ hdr[:wrapped] = !(hdr[:flags] & ELF_WRAPPED).zero?
209
+ @file_size = @fs == File ? File.size(filename) : @fs.fileSize(filename)
210
+
211
+ $log.info "#{self.class}: Opened file for [#{log}] in [#{Time.now - st}] seconds. Data Size:[#{@file_size}] Wrapped:[#{hdr[:wrapped]}]" if $log
212
+
213
+ parse_time = Time.now
214
+ recs_found = 0
215
+ recs_processed = 0
216
+ @dup_check = {}
217
+
218
+ each_record(hdr, log) do |rec|
219
+ recs_processed += 1
220
+
221
+ # Get log record components & filter on them
222
+ rec[:generated] = Time.at(rec[:generated]).utc.iso8601
223
+ break if EventLogFilter.filter_by_generated?(rec[:generated], filter)
224
+
225
+ rec[:level] = EVENT_TYPES[rec[:level]]
226
+ next if EventLogFilter.filter_by_level?(rec[:level], filter)
227
+
228
+ getSourceName(rec)
229
+ next if EventLogFilter.filter_by_source?(rec[:source], filter)
230
+
231
+ getStrings(rec)
232
+ getMessage(log, rec, sources)
233
+ next if EventLogFilter.filter_by_message?(rec[:message], filter)
234
+
235
+ # Get the rest of the record components
236
+ getComputerName(rec)
237
+ # There are not presently being used, so there is no need to collect them
238
+ # rec[:written] = Time.at(rec[:written]).utc.iso8601
239
+ # getSID(buf, pos, rec)
240
+ # getData(buf, pos, rec)
241
+
242
+ # Add the node to the XML
243
+ recs_found += 1 if addNodeRec(recordsNode, rec)
244
+
245
+ # Quit if we've found enough records
246
+ break if EventLogFilter.filter_by_rec_count?(recs_found, filter)
247
+ end
248
+
249
+ # Clean up
250
+ @dup_check = nil
251
+
252
+ # Store based on log.
253
+ recordsNode.add_attribute(:num_records, recs_found)
254
+
255
+ $log.info "#{self.class}: Parsed [#{recs_processed}] [#{log}] records in [#{Time.now - parse_time}] seconds. Collected [#{recs_found}] records. Total time [#{Time.now - st}] seconds." if $log
256
+ end
257
+ @f = nil
258
+ end
259
+
260
+ private
261
+
262
+ def mkLogPath(log)
263
+ unless @reg_source_xml.nil?
264
+ appKey = XmlFind.findElement("CurrentControlSet/Services/Eventlog/#{log}/File", @reg_source_xml)
265
+ logPath = appKey.text
266
+ else
267
+ logPath = Win32::SystemPath.registryPath(@fs, @systemRoot) + "/"
268
+ logPath = case log
269
+ when 'Application' then logPath + "appevent.evt"
270
+ when 'Security' then logPath + "secevent.evt"
271
+ when 'System' then logPath + "sysevent.evt"
272
+ else
273
+ raise "#{self.class}::mkLogPath: '#{log}' is not a path to an event log file." unless log.class.to_s == "String"
274
+ raise "#{self.class}::mkLogPath: File not found: '#{log}'" unless isFile?(log)
275
+ @customFileName = log
276
+ end
277
+ end
278
+ logPath
279
+ end
280
+
281
+ # These functions hide the differences for equivalent calls in the file instance.
282
+ def isFile?(fn)
283
+ meth = @fs.respond_to?(:fileExists?) ? :fileExists? : :exists?
284
+ @fs.send(meth, fn)
285
+ end
286
+
287
+ def getFileObj(fn)
288
+ # Determine what file open method to use
289
+ meth = @fs.respond_to?(:fileOpen) ? :fileOpen : :open
290
+ fn = fn.tr('\\', '/')
291
+ f = @fs.send(meth, fn, "rb")
292
+
293
+ # If we are passed a block, run it and close the file handle
294
+ return f unless block_given?
295
+ begin
296
+ yield(f, fn)
297
+ ensure
298
+ f.close rescue nil
299
+ end
300
+ end
301
+
302
+ def mkXmlDoc(log, event_file)
303
+ @xmlDoc ||= XmlHash.createDoc("<event_log/>")
304
+ @xmlDoc.root.add_element(:log, {:name => log, :path => event_file})
305
+ end
306
+
307
+ # This function finds the first event record in the buffer.
308
+ def getFirstRecordOffset(hdr)
309
+ # Find the cursor record and get first rec from there.
310
+ # hdr[:end_offset] should point to the offset of the EOF record. If the dirty flag
311
+ # is set this is likely to have moved, but should be in front of it, so start the search there.
312
+ pos = findCursorRecord(hdr[:end_offset])
313
+ pos = findCursorRecord(0) if pos.nil?
314
+ raise "Win32 Eventlog cursor record not found." if pos.nil?
315
+
316
+ EVENTLOGEOF.decode(read_buffer(pos - 4, EVENTLOGEOF.size))
317
+ end
318
+
319
+ # The last 4 bytes of a record hold the record length for that record.
320
+ # Grab it and set the new position to the top of that record.
321
+ def getNextRecordOffset(curr_pos, hdr)
322
+ # Called the first time
323
+ if curr_pos.nil?
324
+ @csr = getFirstRecordOffset(hdr)
325
+ curr_pos = @csr[:end_record]
326
+ end
327
+
328
+ # Check for wrapped messages
329
+ if curr_pos == ELF_LOGFILE_HEADER.size
330
+ curr_pos = findEndBuffer
331
+ end
332
+
333
+ offset = curr_pos - 4
334
+ prev_rec_length = read_buffer(offset, 4, -1)
335
+ rec_len = EVENTRECORDLENGTH.decode(prev_rec_length)[:record_length]
336
+ new_pos = (curr_pos - rec_len)
337
+
338
+ # Check for wrapped messages
339
+ if new_pos < ELF_LOGFILE_HEADER.size
340
+ copy_from_end = ELF_LOGFILE_HEADER.size - new_pos
341
+ new_pos = @file_size - copy_from_end
342
+ end
343
+ new_pos
344
+ end
345
+
346
+ # If the record header cannot fit at the end of the file when the log file wraps
347
+ # the end of the file is padded with 0x27 markers after the record length. So
348
+ # walk backwards until a non-0x27 marker is found.
349
+ def findEndBuffer
350
+ offset = @file_size - 4
351
+ while EVENTRECORDLENGTH.decode(read_buffer(offset, 4, -1))[:record_length] == 0x27
352
+ offset -= 4
353
+ end
354
+ offset + 4
355
+ end
356
+
357
+ def findCursorRecord(search_offset)
358
+ pos = nil
359
+ while pos.nil?
360
+ pos = read_buffer(search_offset, BUFFER_READ_SIZE).index(MAGIC_CSR)
361
+ search_offset += BUFFER_READ_SIZE if pos.nil?
362
+ break if search_offset >= @file_size
363
+ end
364
+ pos += search_offset unless pos.nil?
365
+ pos
366
+ end
367
+
368
+ def each_record(hdr, log)
369
+ # Check for an empty event log file
370
+ return if hdr[:oldest_record_number].zero?
371
+
372
+ last_pos = pos = getNextRecordOffset(nil, hdr)
373
+
374
+ loop do
375
+ # Get this record.
376
+ rec = EVENTRECORD.decode(read_buffer(pos, EVENTRECORD.size, -1))
377
+
378
+ # If record wraps around to the start of the buffer
379
+ if pos + rec[:record_length] > @file_size
380
+
381
+ # If we get to the end of the file make sure the event log is marked as wrapped
382
+ # before trying to process data from the begin of the file.
383
+ break if (hdr[:flags] & ELF_WRAPPED).zero?
384
+
385
+ # If the record header fits then in the remaining bytes the header
386
+ # and data is written upto the end of the file. The remaining data
387
+ # is writting at the top of the file after the file header.
388
+ remaining_bytes = @file_size - pos
389
+ wrapped_byte_count = rec[:record_length] - remaining_bytes
390
+ wrapped_bytes = read_buffer(ELF_LOGFILE_HEADER.size, wrapped_byte_count)
391
+ read_buffer(pos, rec[:record_length], -1)
392
+ @buf << wrapped_bytes
393
+ end
394
+
395
+ # Verify record synchronization.
396
+ if rec[:magic] != MAGIC_HDR
397
+ csr = EVENTLOGEOF.decode(read_buffer(pos, EVENTLOGEOF.size))
398
+ break if csr[:magic] == MAGIC_CSR
399
+ # Check if the Cursor record appears anywhere in the buffer data for this mis-aligned record.
400
+ break unless read_buffer(pos, last_pos - pos).index(MAGIC_CSR).nil?
401
+ # When the log is wrapped if we find a mis-aligned record it is on the cursor record missing, likely due
402
+ # to the log actively being updated when we read it.
403
+ break if hdr[:wrapped] == true
404
+
405
+ if $log
406
+ $log.error "MIQ(#{self.class}-readLog) Log synchronization for {#{log}} is broken - rec:[#{rec.inspect}] csr:[#{csr.inspect}] header:[#{hdr.inspect}] pos:[#{pos}] buf length:[#{@buf.length}]"
407
+ $log.error "MIQ(#{self.class}-readLog) 4K buf < pos:"
408
+ read_buffer((pos < 4096 ? 0 : pos - 4096), 4096).hex_dump(:obj => $log, :meth => :error, :newline => false)
409
+ $log.error "MIQ(#{self.class}-readLog) 4K buf >= pos:"
410
+ read_buffer(pos, 4096).hex_dump(:obj => $log, :meth => :error, :newline => false)
411
+ end
412
+ raise "MIQ(#{self.class}-readLog) Log synchronization is broken."
413
+ end
414
+
415
+ rec[:data] = read_buffer(pos, rec[:record_length], -1)
416
+ yield(rec)
417
+
418
+ break if rec[:record_num] == @csr[:oldest_record_number]
419
+
420
+ last_pos = pos
421
+ pos = getNextRecordOffset(pos, hdr)
422
+ end
423
+ end
424
+
425
+ def read_buffer(offset, length, direction = 1)
426
+ # puts "[#{@offset}] -- [#{@offset+BUFFER_READ_SIZE}], O:[#{offset}] L:[#{length}]"
427
+ if (offset < @offset) || (offset + length > @offset + BUFFER_READ_SIZE)
428
+ read_offset = offset
429
+ if direction < 0
430
+ # When adjusting the read offset backwards account for the length of the data
431
+ # being read plus an extra 4K which should cover the data portion of a record
432
+ # since we have to read the record header ahead of the data.
433
+ read_offset = offset - BUFFER_READ_SIZE + length + 4096
434
+ read_offset = 0 if read_offset < 0
435
+ end
436
+ # puts "***Loading from offset [#{read_offset}]"
437
+ @f.seek(read_offset)
438
+ @buf = @f.read(BUFFER_READ_SIZE)
439
+ @offset = read_offset
440
+ end
441
+
442
+ @buf[offset - @offset, length]
443
+ end
444
+
445
+ def getSourceName(rec)
446
+ str = rec[:data][EVENTRECORD.size..-1]
447
+ if str
448
+ str = weirdFixString(str)
449
+ str.UnicodeToUtf8!
450
+ rec[:source] = str
451
+ end
452
+ end
453
+
454
+ def getComputerName(rec)
455
+ str = rec[:data][(EVENTRECORD.size + rec[:source].length * 2 + 2)..-1]
456
+ if str
457
+ str = weirdFixString(str)
458
+ str.UnicodeToUtf8!
459
+ rec[:computer_name] = str
460
+ end
461
+ end
462
+
463
+ def getSID(buf, pos, rec)
464
+ if rec[:user_sid_length] > 0
465
+ rec[:user_sid] = decodeSid(buf[pos + rec[:user_sid_offset], rec[:user_sid_length]])
466
+ end
467
+ end
468
+
469
+ def decodeSid(data)
470
+ sid = "S-"
471
+ # BYTE Revision
472
+ sid << data[0].to_s << "-"
473
+ # BYTE SubAuthorityCount
474
+ subCount = data[1]
475
+ # WORD Authority[3]
476
+ 0.upto(2) {|i|
477
+ auth = data[2 + i * 2, 2].unpack('n')[0]
478
+ sid << auth.to_s << "-" if auth != 0
479
+ }
480
+ # DWORD SubAuthority[*]
481
+ 0.upto(subCount - 1) {|i|
482
+ subAuth = data[8 + i * 4, 4].unpack('L')[0]
483
+ sid << subAuth.to_s << "-"
484
+ }
485
+ sid.chop!
486
+ sid
487
+ end
488
+
489
+ def getStrings(rec)
490
+ rec[:strings] = []
491
+ return if rec[:num_strings] <= 0
492
+
493
+ offset = rec[:string_offset]
494
+ (rec[:num_strings] - 1).times do
495
+ str = rec[:data][offset..-1]
496
+ if str
497
+ str = weirdFixString(str)
498
+ # Compensate for nil strings.
499
+ if str == "\000"
500
+ rec[:strings] << ""
501
+ offset += 2
502
+ else
503
+ offset += str.length + 2
504
+ rec[:strings] << str.UnicodeToUtf8!
505
+ end
506
+ end
507
+ end
508
+ end
509
+
510
+ def getData(buf, pos, rec)
511
+ if rec[:data_length] > 0
512
+ rec[:data] = buf[pos + rec[:data_offset], rec[:data_length]]
513
+ end
514
+ end
515
+
516
+ # The standard conversion doesn't terminate a string at \000\000 so use this.
517
+ def weirdFixString(str)
518
+ idx = str.index("\000\000")
519
+ idx.nil? ? str : str[0..idx]
520
+ end
521
+
522
+ def addNodeRec(node, rec)
523
+ node_rec = {}
524
+
525
+ # Put the needed fields in the node_rec, and collect them for md5 hashing to
526
+ # verify that this record is unique
527
+ md5 = NODE_REC_KEYS.collect { |k| node_rec[k] = rec[k] }.join(' ')
528
+ md5 = Digest::MD5.hexdigest(md5)
529
+ return false if @dup_check.key?(md5)
530
+ @dup_check[md5] = nil
531
+
532
+ node_rec[:uid] = md5
533
+
534
+ node.add_element(:record, node_rec)
535
+ true
536
+ end
537
+
538
+ # Given a record, turn it's event id into a log message.
539
+ def getMessage(log, rec, sources)
540
+ src = rec[:source].downcase
541
+ unless sources[:message].key?(src)
542
+ # TODO: Use the Windows message from els.dll
543
+ rec[:message] = "#{self.class}::getMessage: The source '#{rec[:source]}' is not listed under HKLM\\System\\CurrentControlSet\\Services\\EventLog\\#{log}"
544
+ return
545
+ end
546
+
547
+ msgfiles = sources[:message][src].split(";")
548
+ paramfiles = sources[:param][src].split(";") if sources[:param].key?(src)
549
+
550
+ msg = errMsg = nil
551
+ id = rec[:event_id]
552
+
553
+ msgfiles.each do |fn|
554
+ msgtbls = getMessageTables(fn)
555
+ unless msgtbls.kind_of?(Hash)
556
+ errMsg ||= ""
557
+ errMsg << "#{msgtbls}\n"
558
+ next
559
+ end
560
+
561
+ str = getString(id, msgtbls)
562
+ next if str.nil?
563
+ fmtSub(str)
564
+
565
+ msg = str.dup
566
+ strSub(msg, rec, msgtbls, paramfiles)
567
+ break
568
+ end
569
+
570
+ msg = errMsg.nil? ? "#{self.class}::getMessage: Couldn't find message id in any listed source" : errMsg if msg.nil?
571
+
572
+ rec[:message] = msg.chomp!
573
+ end
574
+
575
+ def getParamMessage(id, paramfiles)
576
+ return "" if paramfiles.nil?
577
+
578
+ paramfiles.each do |fn|
579
+ msgtbls = getMessageTables(fn)
580
+ return "" unless msgtbls.kind_of?(Hash)
581
+
582
+ str = getString(id, msgtbls)
583
+ return str.dup unless str.nil?
584
+ end
585
+
586
+ ""
587
+ end
588
+
589
+ # Search for id in messagetables.
590
+ def getString(id, msgtbls)
591
+ return msgtbls unless msgtbls.kind_of?(Hash)
592
+ msgtbls[id]
593
+ end
594
+
595
+ def getMessageTables(fn)
596
+ # Check cache for this file's messagetables.
597
+ return @msgtbl_cache[fn] if @msgtbl_cache.key?(fn)
598
+
599
+ # Get file & read messagetable resources.
600
+ peh = nil
601
+ begin
602
+ getFileObj(fn) do |f, _fn2|
603
+ begin
604
+ peh = PEheader.new(f)
605
+ # Stick this table in the cache.
606
+ @msgtbl_cache[fn] = peh.messagetables
607
+ rescue
608
+ @msgtbl_cache[fn] = "#{self.class}::getMessageTables: Invalid message table in file: #{fn}"
609
+ end
610
+ end
611
+ rescue
612
+ @msgtbl_cache[fn] = "#{self.class}::getMessageTables: File not found: #{fn}"
613
+ end
614
+
615
+ @msgtbl_cache[fn]
616
+ end
617
+
618
+ def fmtSub(msg)
619
+ msg.gsub!(/%[b\.!nrt0]|!s!/) { |s| FORMAT_TR[s] }
620
+ end
621
+
622
+ # String substitution for Win32 FormatMessage (%1, %2 & so on).
623
+ def strSub(msg, rec, msgtbls, paramfiles)
624
+ # Replace occurances of %%n[n...] with the value from the parameter message file
625
+ # Replace occurances of %n[n...] with (in this order):
626
+ # 1. A string from the record's Strings array.
627
+ # 2. A string from a messagetable whose id is n[n...]
628
+ # 3. A string from the system messagetable whose id is n[n...]
629
+ msg.gsub!(/(%%?)([1-9][0-9]*)/) do
630
+ percents, id = $1, $2.to_i
631
+
632
+ if percents.length == 1
633
+ param = rec[:strings][id - 1] if id <= rec[:strings].size
634
+ param = getString(id, msgtbls) if param.nil?
635
+ param = getString(id, getMessageTables(@kernel32_fn)) if param.nil?
636
+ else
637
+ param = getParamMessage(id, paramfiles)
638
+ end
639
+ param = "NO PARAM: #{id}" if param.nil?
640
+
641
+ param
642
+ end
643
+ end
644
+
645
+ # Given a log name, get event sources & message files in a hash.
646
+ def getEventSourceMessageFiles(log)
647
+ return getSourcesFromMiqFS(log) if Object.const_defined?(:MiqFS) && @fs.kind_of?(MiqFS)
648
+ getSourcesFromWin32(log)
649
+ end
650
+
651
+ def getSourcesFromMiqFS(log)
652
+ # Initialize the message source hash object
653
+ sources = {:message => {}, :param => {}, :category => {}}
654
+
655
+ # Load registry section where we find the NT event log message source files.
656
+ if @reg_source_xml.nil?
657
+ reg = RemoteRegistry.new(@fs, true)
658
+ @reg_source_xml = reg.loadHive("system", [{:key => 'CurrentControlSet/Services/Eventlog', :value => ['CategoryMessageFile', 'EventMessageFile', 'ParameterMessageFile', 'File']}])
659
+ end
660
+
661
+ appKey = XmlFind.findElement("CurrentControlSet/Services/Eventlog/#{log}", @reg_source_xml)
662
+ appKey.each_element(:key) do |src|
663
+ keyName = src.attributes[:keyname].downcase
664
+
665
+ [['EventMessageFile', :message],
666
+ ['ParameterMessageFile', :param],
667
+ ['CategoryMessageFile', :category]].each do |msg_file, type|
668
+ src.each_element_with_attribute(:name, msg_file) do |e|
669
+ fn = e.text.to_s
670
+ fn.gsub!(/%SystemRoot%/i, @systemRoot)
671
+ sources[type][keyName] = fn
672
+ end
673
+ end
674
+ end
675
+ sources
676
+ end
677
+
678
+ def getSourcesFromWin32(log)
679
+ require 'win32/registry'
680
+ sources = {:message => {}, :param => {}, :category => {}}
681
+ types = {'EventMessageFile' => sources[:message], 'ParameterMessageFile' => sources[:param], 'CategoryMessageFile' => sources[:category]}
682
+ src = "system\\currentcontrolset\\services\\eventlog\\#{log}"
683
+
684
+ Win32::Registry::HKEY_LOCAL_MACHINE.open(src) do |reg|
685
+ reg.each_key do |subKey, _wtime|
686
+ subpath = "#{src}\\#{subKey}"
687
+ subKey.downcase!
688
+ Win32::Registry::HKEY_LOCAL_MACHINE.open(subpath) do |reg|
689
+ reg.each_value do |name, _type, data|
690
+ case name
691
+ when 'EventMessageFile', 'ParameterMessageFile', 'CategoryMessageFile' then
692
+ fn = data.to_s
693
+ fn.gsub!(/%SystemRoot%/i, @systemRoot)
694
+ types[name][subKey] = fn
695
+ end
696
+ end
697
+ end
698
+ end
699
+ end
700
+ sources
701
+ end
702
+
703
+ def getEvtMsgFile(hKey)
704
+ buf = ""
705
+ len = [0].pack('L')
706
+ type = [0].pack('L')
707
+ res = @@RegQueryValueEx.call(hKey, "EventMessageFile", 0, type, buf, len)
708
+ # Beware: this MAY come up at some point.
709
+ raise "#{self.class}::getEvtMsgFile: Got REG_MULTI_SZ" if type.unpack('L')[0] == REG_MULTI_SZ
710
+
711
+ len = len.unpack('L')[0]
712
+ buf = " " * len
713
+ len = [len].pack('L')
714
+
715
+ res = @@RegQueryValueEx.call(hKey, "EventMessageFile", 0, type, buf, len)
716
+ if res != ERROR_SUCCESS
717
+ buf = ""
718
+ len = [0].pack('L')
719
+ end
720
+ return buf, len
721
+ end
722
+
723
+ def fixFileList(buf, len)
724
+ buf = buf[0...(len.unpack('L')[0] - 1)]
725
+ buf = buf.split("\\").join("/")
726
+ buf.gsub!(/%SystemRoot%/i, @systemRoot)
727
+ buf
728
+ end
729
+ end
730
+
731
+ # If invoked from command line.
732
+ if __FILE__ == $0
733
+ puts "Reading logs..."
734
+ start = Time.now
735
+ log = Win32EventLog.new
736
+
737
+ filter = {:level => :warn}
738
+ log.readLog("Application", filter)
739
+ log.readLog("Security", filter)
740
+ log.readLog("System", filter)
741
+
742
+ puts "Read logs completed in #{Time.now - start} seconds"
743
+ end