manageiq-smartstate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +4 -0
- data/.rspec_ci +4 -0
- data/.travis.yml +15 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +202 -0
- data/README.md +45 -0
- data/Rakefile +23 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/MiqContainerGroup/MiqContainerGroup.rb +31 -0
- data/lib/MiqVm/MiqLocalVm.rb +50 -0
- data/lib/MiqVm/MiqRhevmVm.rb +179 -0
- data/lib/MiqVm/MiqVm.rb +355 -0
- data/lib/MiqVm/miq_azure_vm.rb +96 -0
- data/lib/MiqVm/miq_scvmm_vm.rb +38 -0
- data/lib/MiqVm/test/camcorder_fleece_test.rb +60 -0
- data/lib/MiqVm/test/localVm.rb +45 -0
- data/lib/MiqVm/test/partitionAlignmentCheck.rb +76 -0
- data/lib/MiqVm/test/remoteVm.rb +65 -0
- data/lib/MiqVm/test/rhevmNfsTest.rb +62 -0
- data/lib/MiqVm/test/rhevmNfsTest2.rb +66 -0
- data/lib/MiqVm/test/rhevmTest.rb +70 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackCommon.rb +107 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackImage.rb +67 -0
- data/lib/OpenStackExtract/MiqOpenStackVm/MiqOpenStackInstance.rb +182 -0
- data/lib/Scvmm/miq_hyperv_disk.rb +273 -0
- data/lib/Scvmm/miq_scvmm_parse_powershell.rb +75 -0
- data/lib/Scvmm/miq_scvmm_vm_ssa_info.rb +135 -0
- data/lib/Scvmm/test/miq_hyperv_disk_test.rb +33 -0
- data/lib/Scvmm/test/miq_scvmm_vm_ssa_info_test.rb +41 -0
- data/lib/VmLocalDiskAccess/test/localCfg.rb +97 -0
- data/lib/VolumeManager/LVM/logical_volume.rb +75 -0
- data/lib/VolumeManager/LVM/lv_segment.rb +43 -0
- data/lib/VolumeManager/LVM/lvm2disk.rb +158 -0
- data/lib/VolumeManager/LVM/parser.rb +138 -0
- data/lib/VolumeManager/LVM/physical_volume.rb +19 -0
- data/lib/VolumeManager/LVM/scanner.rb +156 -0
- data/lib/VolumeManager/LVM/thin/btree.rb +83 -0
- data/lib/VolumeManager/LVM/thin/constants.rb +86 -0
- data/lib/VolumeManager/LVM/thin/data_map.rb +44 -0
- data/lib/VolumeManager/LVM/thin/mapping_tree.rb +19 -0
- data/lib/VolumeManager/LVM/thin/space_maps.rb +58 -0
- data/lib/VolumeManager/LVM/thin/superblock.rb +136 -0
- data/lib/VolumeManager/LVM/thin.rb +6 -0
- data/lib/VolumeManager/LVM/volume_group.rb +97 -0
- data/lib/VolumeManager/LVM.rb +8 -0
- data/lib/VolumeManager/MiqLdm.rb +546 -0
- data/lib/VolumeManager/MiqLvm.rb +17 -0
- data/lib/VolumeManager/MiqNativeVolumeManager.rb +150 -0
- data/lib/VolumeManager/MiqVolumeManager.rb +277 -0
- data/lib/VolumeManager/VolMgrPlatformSupport.rb +18 -0
- data/lib/VolumeManager/VolMgrPlatformSupportLinux.rb +77 -0
- data/lib/VolumeManager/VolMgrPlatformSupportWin.rb +17 -0
- data/lib/VolumeManager/test/blockDevTest.rb +40 -0
- data/lib/VolumeManager/test/ldm.rb +97 -0
- data/lib/blackbox/VmBlackBox.rb +103 -0
- data/lib/blackbox/xmlStorage.rb +180 -0
- data/lib/db/MiqBdb/MiqBdb.rb +309 -0
- data/lib/db/MiqBdb/MiqBdbBtree.rb +219 -0
- data/lib/db/MiqBdb/MiqBdbHash.rb +199 -0
- data/lib/db/MiqBdb/MiqBdbPage.rb +159 -0
- data/lib/db/MiqBdb/MiqBdbUtil.rb +18 -0
- data/lib/db/MiqSqlite/MiqSqlite3.rb +330 -0
- data/lib/db/MiqSqlite/MiqSqlite3Cell.rb +167 -0
- data/lib/db/MiqSqlite/MiqSqlite3Page.rb +151 -0
- data/lib/db/MiqSqlite/MiqSqlite3Table.rb +124 -0
- data/lib/db/MiqSqlite/MiqSqlite3Util.rb +32 -0
- data/lib/disk/DiskProbe.rb +68 -0
- data/lib/disk/MiqDisk.rb +317 -0
- data/lib/disk/camcorder_test.rb +90 -0
- data/lib/disk/dos_mbr.img +0 -0
- data/lib/disk/modules/AzureBlobDisk.rb +101 -0
- data/lib/disk/modules/LocalDevMod.rb +47 -0
- data/lib/disk/modules/LocalDevProbe.rb +6 -0
- data/lib/disk/modules/MSCommon.rb +352 -0
- data/lib/disk/modules/MSVSDiffDisk.rb +91 -0
- data/lib/disk/modules/MSVSDiskProbe.rb +61 -0
- data/lib/disk/modules/MSVSDynamicDisk.rb +42 -0
- data/lib/disk/modules/MSVSFixedDisk.rb +45 -0
- data/lib/disk/modules/MiqLargeFile.rb +63 -0
- data/lib/disk/modules/MiqLargeFileWin32.rb +107 -0
- data/lib/disk/modules/QcowDisk.rb +692 -0
- data/lib/disk/modules/QcowDiskProbe.rb +34 -0
- data/lib/disk/modules/RawBlockIO.rb +116 -0
- data/lib/disk/modules/RawDisk.rb +45 -0
- data/lib/disk/modules/RawDiskProbe.rb +7 -0
- data/lib/disk/modules/RhevmDescriptor.rb +167 -0
- data/lib/disk/modules/RhevmDiskProbe.rb +52 -0
- data/lib/disk/modules/VMWareCowdDisk.rb +207 -0
- data/lib/disk/modules/VMWareDescriptor.rb +214 -0
- data/lib/disk/modules/VMWareDiskProbe.rb +74 -0
- data/lib/disk/modules/VMWareSparseDisk.rb +189 -0
- data/lib/disk/modules/VhdxDisk.rb +625 -0
- data/lib/disk/modules/VhdxDiskProbe.rb +46 -0
- data/lib/disk/modules/VixDiskMod.rb +54 -0
- data/lib/disk/modules/VixDiskProbe.rb +6 -0
- data/lib/disk/modules/miq_disk_cache.rb +135 -0
- data/lib/disk/modules/miq_dummy_disk.rb +41 -0
- data/lib/disk/modules/vhdx_bat_entry.rb +10 -0
- data/lib/disk/test.rb +66 -0
- data/lib/fs/MetakitFS/MetakitFS.rb +530 -0
- data/lib/fs/MetakitFS/test/Makefile +14 -0
- data/lib/fs/MetakitFS/test/MkCollectFiles.rb +165 -0
- data/lib/fs/MetakitFS/test/MkSelectFiles.rb +30 -0
- data/lib/fs/MetakitFS/test/collect_files.yaml +70 -0
- data/lib/fs/MetakitFS/test/init.rb +3 -0
- data/lib/fs/MetakitFS/test/mk2vmdk.rb +64 -0
- data/lib/fs/MetakitFS/test/mk4test.c +92 -0
- data/lib/fs/MetakitFS/test/mkFsTest.rb +113 -0
- data/lib/fs/MetakitFS/test/proto.rb +97 -0
- data/lib/fs/MiqFS/FsProbe.rb +39 -0
- data/lib/fs/MiqFS/MiqFS.rb +515 -0
- data/lib/fs/MiqFS/modules/AUFSProbe.rb +26 -0
- data/lib/fs/MiqFS/modules/Ext3.rb +305 -0
- data/lib/fs/MiqFS/modules/Ext3Probe.rb +25 -0
- data/lib/fs/MiqFS/modules/Ext4.rb +304 -0
- data/lib/fs/MiqFS/modules/Ext4Probe.rb +25 -0
- data/lib/fs/MiqFS/modules/Fat32.rb +318 -0
- data/lib/fs/MiqFS/modules/Fat32Probe.rb +30 -0
- data/lib/fs/MiqFS/modules/HFSProbe.rb +18 -0
- data/lib/fs/MiqFS/modules/Iso9660.rb +293 -0
- data/lib/fs/MiqFS/modules/Iso9660Probe.rb +18 -0
- data/lib/fs/MiqFS/modules/LocalFS.rb +105 -0
- data/lib/fs/MiqFS/modules/NTFS.rb +287 -0
- data/lib/fs/MiqFS/modules/NTFSProbe.rb +21 -0
- data/lib/fs/MiqFS/modules/NativeFS.rb +155 -0
- data/lib/fs/MiqFS/modules/ReFSProbe.rb +17 -0
- data/lib/fs/MiqFS/modules/RealFS.rb +79 -0
- data/lib/fs/MiqFS/modules/RealFSProbe.rb +6 -0
- data/lib/fs/MiqFS/modules/Reiser4Probe.rb +18 -0
- data/lib/fs/MiqFS/modules/ReiserFS.rb +315 -0
- data/lib/fs/MiqFS/modules/ReiserFSProbe.rb +42 -0
- data/lib/fs/MiqFS/modules/UnionFSProbe.rb +18 -0
- data/lib/fs/MiqFS/modules/WebDAV.rb +127 -0
- data/lib/fs/MiqFS/modules/WebDAVFile.rb +68 -0
- data/lib/fs/MiqFS/modules/XFS.rb +300 -0
- data/lib/fs/MiqFS/modules/XFSProbe.rb +26 -0
- data/lib/fs/MiqFS/modules/ZFSProbe.rb +18 -0
- data/lib/fs/MiqFS/test.rb +59 -0
- data/lib/fs/MiqFsUtil.rb +383 -0
- data/lib/fs/MiqMountManager.rb +209 -0
- data/lib/fs/MiqNativeMountManager.rb +101 -0
- data/lib/fs/MountManagerProbe.rb +29 -0
- data/lib/fs/ReiserFS/block.rb +209 -0
- data/lib/fs/ReiserFS/directory.rb +136 -0
- data/lib/fs/ReiserFS/directory_entry.rb +140 -0
- data/lib/fs/ReiserFS/file_data.rb +111 -0
- data/lib/fs/ReiserFS/superblock.rb +140 -0
- data/lib/fs/ReiserFS/utils.rb +95 -0
- data/lib/fs/VimDatastoreFS/VimDatastoreFS.rb +192 -0
- data/lib/fs/ext3/alloc_bitmap.rb +38 -0
- data/lib/fs/ext3/block_pointers_path.rb +130 -0
- data/lib/fs/ext3/directory.rb +51 -0
- data/lib/fs/ext3/directory_entry.rb +67 -0
- data/lib/fs/ext3/ex_attrib_header.rb +14 -0
- data/lib/fs/ext3/ex_attrib_name.rb +23 -0
- data/lib/fs/ext3/file_data.rb +130 -0
- data/lib/fs/ext3/group_descriptor_entry.rb +65 -0
- data/lib/fs/ext3/group_descriptor_table.rb +54 -0
- data/lib/fs/ext3/hash_tree_entry.rb +18 -0
- data/lib/fs/ext3/hash_tree_header.rb +15 -0
- data/lib/fs/ext3/inode.rb +228 -0
- data/lib/fs/ext3/posix_acl_entry.rb +29 -0
- data/lib/fs/ext3/posix_acl_header.rb +11 -0
- data/lib/fs/ext3/superblock.rb +406 -0
- data/lib/fs/ext3/test/tc_Ext3BlockPointersPath.rb +74 -0
- data/lib/fs/ext4/alloc_bitmap.rb +38 -0
- data/lib/fs/ext4/directory.rb +87 -0
- data/lib/fs/ext4/directory_entry.rb +77 -0
- data/lib/fs/ext4/ex_attrib_header.rb +14 -0
- data/lib/fs/ext4/ex_attrib_name.rb +23 -0
- data/lib/fs/ext4/extent.rb +35 -0
- data/lib/fs/ext4/extent_header.rb +40 -0
- data/lib/fs/ext4/extent_index.rb +33 -0
- data/lib/fs/ext4/group_descriptor_entry.rb +69 -0
- data/lib/fs/ext4/group_descriptor_table.rb +54 -0
- data/lib/fs/ext4/hash_tree_entry.rb +58 -0
- data/lib/fs/ext4/hash_tree_header.rb +35 -0
- data/lib/fs/ext4/inode.rb +465 -0
- data/lib/fs/ext4/posix_acl_entry.rb +29 -0
- data/lib/fs/ext4/posix_acl_header.rb +11 -0
- data/lib/fs/ext4/superblock.rb +412 -0
- data/lib/fs/fat32/boot_sect.rb +379 -0
- data/lib/fs/fat32/directory.rb +222 -0
- data/lib/fs/fat32/directory_entry.rb +540 -0
- data/lib/fs/fat32/file_data.rb +128 -0
- data/lib/fs/iso9660/boot_sector.rb +170 -0
- data/lib/fs/iso9660/directory.rb +90 -0
- data/lib/fs/iso9660/directory_entry.rb +147 -0
- data/lib/fs/iso9660/file_data.rb +78 -0
- data/lib/fs/iso9660/rock_ridge.rb +329 -0
- data/lib/fs/iso9660/util.rb +57 -0
- data/lib/fs/modules/LinuxMount.rb +300 -0
- data/lib/fs/modules/LinuxMountProbe.rb +29 -0
- data/lib/fs/modules/WinMount.rb +97 -0
- data/lib/fs/modules/WinMountProbe.rb +24 -0
- data/lib/fs/ntfs/attrib_attribute_list.rb +131 -0
- data/lib/fs/ntfs/attrib_bitmap.rb +26 -0
- data/lib/fs/ntfs/attrib_data.rb +74 -0
- data/lib/fs/ntfs/attrib_file_name.rb +110 -0
- data/lib/fs/ntfs/attrib_header.rb +194 -0
- data/lib/fs/ntfs/attrib_index_allocation.rb +19 -0
- data/lib/fs/ntfs/attrib_index_root.rb +247 -0
- data/lib/fs/ntfs/attrib_object_id.rb +40 -0
- data/lib/fs/ntfs/attrib_standard_information.rb +107 -0
- data/lib/fs/ntfs/attrib_type.rb +49 -0
- data/lib/fs/ntfs/attrib_volume_information.rb +53 -0
- data/lib/fs/ntfs/attrib_volume_name.rb +31 -0
- data/lib/fs/ntfs/boot_sect.rb +253 -0
- data/lib/fs/ntfs/data_run.rb +358 -0
- data/lib/fs/ntfs/directory_index_node.rb +114 -0
- data/lib/fs/ntfs/index_node_header.rb +69 -0
- data/lib/fs/ntfs/index_record_header.rb +85 -0
- data/lib/fs/ntfs/mft_entry.rb +288 -0
- data/lib/fs/ntfs/utils.rb +43 -0
- data/lib/fs/test/camcorder_fs_test.rb +108 -0
- data/lib/fs/test/collect_files_direct.yaml +22 -0
- data/lib/fs/test/collect_files_in.yaml +24 -0
- data/lib/fs/test/collect_files_in_nc.yaml +22 -0
- data/lib/fs/test/collect_files_out.yaml +6 -0
- data/lib/fs/test/collect_files_rm.yaml +6 -0
- data/lib/fs/test/copyTest.rb +126 -0
- data/lib/fs/test/fsTest.rb +87 -0
- data/lib/fs/test/updateTest.rb +184 -0
- data/lib/fs/xfs/allocation_group.rb +160 -0
- data/lib/fs/xfs/bmap_btree_block.rb +125 -0
- data/lib/fs/xfs/bmap_btree_record.rb +80 -0
- data/lib/fs/xfs/bmap_btree_root_node.rb +72 -0
- data/lib/fs/xfs/directory.rb +133 -0
- data/lib/fs/xfs/directory2_data_header.rb +27 -0
- data/lib/fs/xfs/directory3_data_header.rb +34 -0
- data/lib/fs/xfs/directory_block_tail.rb +22 -0
- data/lib/fs/xfs/directory_data_header.rb +46 -0
- data/lib/fs/xfs/directory_entry.rb +106 -0
- data/lib/fs/xfs/inode.rb +532 -0
- data/lib/fs/xfs/inode_map.rb +100 -0
- data/lib/fs/xfs/short_form_directory_entry.rb +91 -0
- data/lib/fs/xfs/short_form_header.rb +44 -0
- data/lib/fs/xfs/superblock.rb +556 -0
- data/lib/lib/tasks/azure.rake +52 -0
- data/lib/manageiq/smartstate/version.rb +5 -0
- data/lib/manageiq/smartstate.rb +7 -0
- data/lib/manageiq-smartstate.rb +1 -0
- data/lib/metadata/MIQExtract/MIQExtract.rb +297 -0
- data/lib/metadata/MIQExtract/test/extractTest.rb +41 -0
- data/lib/metadata/MIQExtract/test/full_extract_test.rb +68 -0
- data/lib/metadata/ScanProfile/HostScanItem.rb +4 -0
- data/lib/metadata/ScanProfile/HostScanProfile.rb +4 -0
- data/lib/metadata/ScanProfile/HostScanProfiles.rb +41 -0
- data/lib/metadata/ScanProfile/ScanItemBase.rb +63 -0
- data/lib/metadata/ScanProfile/ScanProfileBase.rb +51 -0
- data/lib/metadata/ScanProfile/ScanProfilesBase.rb +60 -0
- data/lib/metadata/ScanProfile/VmScanItem.rb +4 -0
- data/lib/metadata/ScanProfile/VmScanProfile.rb +4 -0
- data/lib/metadata/ScanProfile/VmScanProfiles.rb +38 -0
- data/lib/metadata/ScanProfile/modules/HostScanItemFile.rb +51 -0
- data/lib/metadata/ScanProfile/modules/HostScanItemNteventlog.rb +84 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemFile.rb +39 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemNteventlog.rb +34 -0
- data/lib/metadata/ScanProfile/modules/VmScanItemRegistry.rb +64 -0
- data/lib/metadata/VMMount/VMMount.rb +81 -0
- data/lib/metadata/VMMount/VMPlatformMount.rb +18 -0
- data/lib/metadata/VMMount/VMPlatformMountLinux.rb +75 -0
- data/lib/metadata/VMMount/VMPlatformMountWin.rb +13 -0
- data/lib/metadata/VmConfig/GetNativeCfg.rb +45 -0
- data/lib/metadata/VmConfig/VmConfig.rb +947 -0
- data/lib/metadata/VmConfig/cfgConfig.rb +45 -0
- data/lib/metadata/VmConfig/ovfConfig.rb +99 -0
- data/lib/metadata/VmConfig/test/GetVMwareCfgTest.rb +40 -0
- data/lib/metadata/VmConfig/vmcConfig.rb +116 -0
- data/lib/metadata/VmConfig/vmtxConfig.rb +4 -0
- data/lib/metadata/VmConfig/vmxConfig.rb +162 -0
- data/lib/metadata/VmConfig/xmlConfig.rb +79 -0
- data/lib/metadata/VmConfig/xmlMsHyperVConfig.rb +41 -0
- data/lib/metadata/linux/InitProcHash.rb +632 -0
- data/lib/metadata/linux/LinuxInitProcs.rb +142 -0
- data/lib/metadata/linux/LinuxOSInfo.rb +237 -0
- data/lib/metadata/linux/LinuxPackages.rb +209 -0
- data/lib/metadata/linux/LinuxSystemd.rb +130 -0
- data/lib/metadata/linux/LinuxUsers.rb +289 -0
- data/lib/metadata/linux/LinuxUtils.rb +197 -0
- data/lib/metadata/linux/MiqConaryPackages.rb +41 -0
- data/lib/metadata/linux/MiqRpmPackages.rb +160 -0
- data/lib/metadata/linux/test/Name +0 -0
- data/lib/metadata/linux/test/Packages +0 -0
- data/lib/metadata/linux/test/rpoTest.rb +5 -0
- data/lib/metadata/linux/test/tc_LinuxUtils.rb +4157 -0
- data/lib/metadata/util/event_log_filter.rb +61 -0
- data/lib/metadata/util/md5deep.rb +280 -0
- data/lib/metadata/util/win32/Win32Accounts.rb +764 -0
- data/lib/metadata/util/win32/Win32EventLog.rb +743 -0
- data/lib/metadata/util/win32/Win32Services.rb +86 -0
- data/lib/metadata/util/win32/Win32Software.rb +326 -0
- data/lib/metadata/util/win32/Win32System.rb +333 -0
- data/lib/metadata/util/win32/boot_info_win.rb +59 -0
- data/lib/metadata/util/win32/fleece_hives.rb +220 -0
- data/lib/metadata/util/win32/ms-registry.rb +650 -0
- data/lib/metadata/util/win32/peheader.rb +868 -0
- data/lib/metadata/util/win32/remote-registry.rb +142 -0
- data/lib/metadata/util/win32/system_path_win.rb +103 -0
- data/lib/metadata/util/win32/versioninfo.rb +17 -0
- data/manageiq-smartstate.gemspec +35 -0
- 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
|