fluent-plugin-windows-eventlog 0.4.0 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ea9a134414a5572bf7d3c9dca355ea53d47d6a8701b6a631f0426bafa0de5c9
4
- data.tar.gz: 26d9fa562585f26fdbef294aa6f64a13e7749ed11915390d1822c5367656ccb7
3
+ metadata.gz: b22aa563236f503aa9b606c6848b223995eab6174cf5ab244ef9cf535afcb8c9
4
+ data.tar.gz: 90dfddd1015ff28d730d11168fe60466e6a9c69b9c436601fb25eff867c935b0
5
5
  SHA512:
6
- metadata.gz: e292b037dc58e418aa8b74b1fa8b19db22124c927876e4fbf2e59b457042e08944e912e37104891fdd93f841b306ea8d09d2b1bbf939dad2015f18e26c021a11
7
- data.tar.gz: 6d82ed5588b14f92bca8bdf42a8c9a085306ed23717e9b0f0fc6cdc994b376a00195469c51dcb9ddeb5a6a786fc7c5b96e24279037bc20bfa96f42477407851d
6
+ metadata.gz: 57f27df3303f3424057f4fce75d7a12c804cc7bd5ecc2c8cf9579512dd9dc29c944ebea038541bbdac508028c9da669a246ac754c572fac19e3028ecabefab8c
7
+ data.tar.gz: 78d02ada2bbc70fc91df533fdcd7f47a4d680707c06f1a26eaa014a2c57435c90d2e47c3d82b3c43d81229ffabc3e2f7791d397bf168d11911b20a8d4a451250
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ # Release v0.4.5 - 2020/01/28
2
+ * in_windows_eventlog2: Handle empty key case in parsing description method.
3
+
4
+ # Release v0.4.4 - 2019/11/07
5
+ * in_windows_eventlog: Improve error handling and logging when failed to open Windows Event Log.
6
+
7
+ # Release v0.4.3 - 2019/10/31
8
+ * in_windows_eventlog2: Handle privileges record on #parse_desc
9
+ * in_windows_eventlog2: Raise error when handling invalid bookmark xml
10
+
11
+ # Release v0.4.2 - 2019/10/16
12
+ * in_windows_eventlog2: Handle invalid data error from `Winevt::EventLog::Query::Error`
13
+
14
+ # Release v0.4.1 - 2019/10/11
15
+ * in_windows_eventlog2: Add a missing ProcessID record
16
+
1
17
  # Release v0.4.0 - 2019/10/10
2
18
 
3
19
  * in_windows_eventlog2: Add new `render_as_xml` parameter to switch rendering as XML or Ruby Hash object
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "fluent-plugin-windows-eventlog"
7
- spec.version = "0.4.0"
7
+ spec.version = "0.4.5"
8
8
  spec.authors = ["okahashi117", "Hiroshi Hatake", "Masahiro Nakagawa"]
9
9
  spec.email = ["naruki_okahashi@jbat.co.jp", "cosmo0920.oucc@gmail.com", "repeatedly@gmail.com"]
10
10
  spec.summary = %q{Fluentd Input plugin to read windows event log.}
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "test-unit", "~> 3.2.0"
23
23
  spec.add_runtime_dependency "fluentd", [">= 0.14.12", "< 2"]
24
24
  spec.add_runtime_dependency "win32-eventlog"
25
- spec.add_runtime_dependency "winevt_c", ">= 0.6.0"
25
+ spec.add_runtime_dependency "winevt_c", ">= 0.6.1"
26
26
  spec.add_runtime_dependency "nokogiri", "~> 1.10"
27
27
  spec.add_runtime_dependency "fluent-plugin-parser-winevt_xml", ">= 0.1.2"
28
28
  end
@@ -151,7 +151,11 @@ module Fluent::Plugin
151
151
  end
152
152
 
153
153
  def on_notify(ch)
154
- el = Win32::EventLog.open(ch)
154
+ begin
155
+ el = Win32::EventLog.open(ch)
156
+ rescue => e
157
+ log.error "Failed to open Windows Event log.", error: e
158
+ end
155
159
 
156
160
  current_oldest_record_number = el.oldest_record_number
157
161
  current_total_records = el.total_records
@@ -186,7 +190,9 @@ module Fluent::Plugin
186
190
  receive_lines(ch, winlogs)
187
191
  @pos_storage.put(ch, [read_start, read_num + winlogs.size])
188
192
  ensure
189
- el.close
193
+ if el
194
+ el.close
195
+ end
190
196
  end
191
197
 
192
198
  GROUP_DELIMITER = "\r\n\r\n".freeze
@@ -21,6 +21,7 @@ module Fluent::Plugin
21
21
  "EventRecordID" => ["EventRecordID", :string],
22
22
  "ActivityID" => ["ActivityID", :string],
23
23
  "RelatedActivityID" => ["RelatedActivityID", :string],
24
+ "ProcessID" => ["ProcessID", :string],
24
25
  "ThreadID" => ["ThreadID", :string],
25
26
  "Channel" => ["Channel", :string],
26
27
  "Computer" => ["Computer", :string],
@@ -88,9 +89,17 @@ module Fluent::Plugin
88
89
  @chs.each do |ch|
89
90
  bookmarkXml = @bookmarks_storage.get(ch) || ""
90
91
  subscribe = Winevt::EventLog::Subscribe.new
91
- bookmark = Winevt::EventLog::Bookmark.new(bookmarkXml)
92
+ bookmark = unless bookmarkXml.empty?
93
+ Winevt::EventLog::Bookmark.new(bookmarkXml)
94
+ else
95
+ nil
96
+ end
92
97
  subscribe.tail = @tailing
93
- subscribe.subscribe(ch, "*", bookmark)
98
+ begin
99
+ subscribe.subscribe(ch, "*", bookmark)
100
+ rescue Winevt::EventLog::Query::Error => e
101
+ raise Fluent::ConfigError, "Invalid Bookmark XML is loaded. #{e}"
102
+ end
94
103
  subscribe.render_as_xml = @render_as_xml
95
104
  subscribe.rate_limit = @rate_limit
96
105
  timer_execute("in_windows_eventlog_#{escape_channel(ch)}".to_sym, @read_interval) do
@@ -109,35 +118,40 @@ module Fluent::Plugin
109
118
 
110
119
  def on_notify_xml(ch, subscribe)
111
120
  es = Fluent::MultiEventStream.new
112
- subscribe.each do |xml, message, string_inserts|
113
- @parser.parse(xml) do |time, record|
114
- # record.has_key?("EventData") for none parser checking.
115
- if @winevt_xml
116
- record["Description"] = message
117
- record["EventData"] = string_inserts
118
-
119
- h = {}
120
- @keynames.each do |k|
121
- type = KEY_MAP[k][1]
122
- value = record[KEY_MAP[k][0]]
123
- h[k]=case type
124
- when :string
125
- value.to_s
126
- when :array
127
- value.map {|v| v.to_s}
128
- else
129
- raise "Unknown value type: #{type}"
130
- end
121
+ begin
122
+ subscribe.each do |xml, message, string_inserts|
123
+ @parser.parse(xml) do |time, record|
124
+ # record.has_key?("EventData") for none parser checking.
125
+ if @winevt_xml
126
+ record["Description"] = message
127
+ record["EventData"] = string_inserts
128
+
129
+ h = {}
130
+ @keynames.each do |k|
131
+ type = KEY_MAP[k][1]
132
+ value = record[KEY_MAP[k][0]]
133
+ h[k]=case type
134
+ when :string
135
+ value.to_s
136
+ when :array
137
+ value.map {|v| v.to_s}
138
+ else
139
+ raise "Unknown value type: #{type}"
140
+ end
141
+ end
142
+ parse_desc(h) if @parse_description
143
+ es.add(Fluent::Engine.now, h)
144
+ else
145
+ record["Description"] = message
146
+ record["EventData"] = string_inserts
147
+ # for none parser
148
+ es.add(Fluent::Engine.now, record)
131
149
  end
132
- parse_desc(h) if @parse_description
133
- es.add(Fluent::Engine.now, h)
134
- else
135
- record["Description"] = message
136
- record["EventData"] = string_inserts
137
- # for none parser
138
- es.add(Fluent::Engine.now, record)
139
150
  end
140
151
  end
152
+ rescue Winevt::EventLog::Query::Error => e
153
+ log.warn "Invalid XML data", error: e
154
+ log.warn_backtrace
141
155
  end
142
156
  router.emit_stream(@tag, es)
143
157
  @bookmarks_storage.put(ch, subscribe.bookmark)
@@ -145,24 +159,29 @@ module Fluent::Plugin
145
159
 
146
160
  def on_notify_hash(ch, subscribe)
147
161
  es = Fluent::MultiEventStream.new
148
- subscribe.each do |record, message, string_inserts|
149
- record["Description"] = message
150
- record["EventData"] = string_inserts
151
- h = {}
152
- @keynames.each do |k|
153
- type = KEY_MAP[k][1]
154
- value = record[KEY_MAP[k][0]]
155
- h[k]=case type
156
- when :string
157
- value.to_s
158
- when :array
159
- value.map {|v| v.to_s}
160
- else
161
- raise "Unknown value type: #{type}"
162
- end
162
+ begin
163
+ subscribe.each do |record, message, string_inserts|
164
+ record["Description"] = message
165
+ record["EventData"] = string_inserts
166
+ h = {}
167
+ @keynames.each do |k|
168
+ type = KEY_MAP[k][1]
169
+ value = record[KEY_MAP[k][0]]
170
+ h[k]=case type
171
+ when :string
172
+ value.to_s
173
+ when :array
174
+ value.map {|v| v.to_s}
175
+ else
176
+ raise "Unknown value type: #{type}"
177
+ end
178
+ end
179
+ parse_desc(h) if @parse_description
180
+ es.add(Fluent::Engine.now, h)
163
181
  end
164
- parse_desc(h) if @parse_description
165
- es.add(Fluent::Engine.now, h)
182
+ rescue Winevt::EventLog::Query::Error => e
183
+ log.warn "Invalid Hash data", error: e
184
+ log.warn_backtrace
166
185
  end
167
186
  router.emit_stream(@tag, es)
168
187
  @bookmarks_storage.put(ch, subscribe.bookmark)
@@ -181,6 +200,7 @@ module Fluent::Plugin
181
200
 
182
201
  elems = desc.split(GROUP_DELIMITER)
183
202
  record['DescriptionTitle'] = elems.shift
203
+ previous_key = nil
184
204
  elems.each { |elem|
185
205
  parent_key = nil
186
206
  elem.split(RECORD_DELIMITER).each { |r|
@@ -189,19 +209,26 @@ module Fluent::Plugin
189
209
  else
190
210
  r.split(NONE_FIELD_DELIMITER)
191
211
  end
212
+ key = "" if key.nil?
192
213
  key.chop! # remove ':' from key
193
214
  if value.nil?
194
215
  parent_key = to_key(key)
195
216
  else
196
217
  # parsed value sometimes contain unexpected "\t". So remove it.
197
218
  value.strip!
198
- if parent_key.nil?
219
+ # merge empty key values into the previous non-empty key record.
220
+ if key.empty?
221
+ record[previous_key] = [record[previous_key], value].flatten.reject {|e| e.nil?}
222
+ elsif parent_key.nil?
199
223
  record[to_key(key)] = value
200
224
  else
201
225
  k = "#{parent_key}.#{to_key(key)}"
202
226
  record[k] = value
203
227
  end
204
228
  end
229
+ # XXX: This is for empty privileges record key.
230
+ # We should investigate whether an another case exists or not.
231
+ previous_key = to_key(key) unless key.empty?
205
232
  }
206
233
  }
207
234
  end
@@ -0,0 +1,27 @@
1
+ A new external device was recognized by the system.
2
+
3
+ Subject:
4
+ Security ID: SYSTEM
5
+ Account Name: IIZHU2016$
6
+ Account Domain: ITSS
7
+ Logon ID: 0x3E7
8
+
9
+ Device ID: SWD\PRINTENUM\{60FA1C6A-1AB2-440A-AEE1-62ABFB9A4650}
10
+
11
+ Device Name: Microsoft Print to PDF
12
+
13
+ Class ID: {1ed2bbf9-11f0-4084-b21f-ad83a8e6dcdc}
14
+
15
+ Class Name: PrintQueue
16
+
17
+ Vendor IDs:
18
+ PRINTENUM\{084f01fa-e634-4d77-83ee-074817c03581}
19
+ PRINTENUM\LocalPrintQueue
20
+ {084f01fa-e634-4d77-83ee-074817c03581}
21
+
22
+
23
+
24
+ Compatible IDs:
25
+ GenPrintQueue
26
+ SWD\GenericRaw
27
+ SWD\Generic
@@ -48,6 +48,63 @@ DESC
48
48
  assert_equal(expected, h)
49
49
  end
50
50
 
51
+ def test_parse_privileges_description
52
+ d = create_driver
53
+ desc = ["Special privileges assigned to new logon.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-X-Y-ZZ\r\n\t",
54
+ "AccountName:\t\tSYSTEM\r\n\tAccount Domain:\t\tNT AUTHORITY\r\n\tLogon ID:\t\t0x3E7\r\n\r\n",
55
+ "Privileges:\t\tSeAssignPrimaryTokenPrivilege\r\n\t\t\tSeTcbPrivilege\r\n\t\t\t",
56
+ "SeSecurityPrivilege\r\n\t\t\tSeTakeOwnershipPrivilege\r\n\t\t\tSeLoadDriverPrivilege\r\n\t\t\t",
57
+ "SeBackupPrivilege\r\n\t\t\tSeRestorePrivilege\r\n\t\t\tSeDebugPrivilege\r\n\t\t\t",
58
+ "SeAuditPrivilege\r\n\t\t\tSeSystemEnvironmentPrivilege\r\n\t\t\tSeImpersonatePrivilege\r\n\t\t\t",
59
+ "SeDelegateSessionUserImpersonatePrivilege"].join("")
60
+
61
+ h = {"Description" => desc}
62
+ expected = {"DescriptionTitle" => "Special privileges assigned to new logon.",
63
+ "subject.security_id" => "S-X-Y-ZZ",
64
+ "subject.accountname" => "SYSTEM",
65
+ "subject.account_domain" => "NT AUTHORITY",
66
+ "subject.logon_id" => "0x3E7",
67
+ "privileges" => ["SeAssignPrimaryTokenPrivilege",
68
+ "SeTcbPrivilege",
69
+ "SeSecurityPrivilege",
70
+ "SeTakeOwnershipPrivilege",
71
+ "SeLoadDriverPrivilege",
72
+ "SeBackupPrivilege",
73
+ "SeRestorePrivilege",
74
+ "SeDebugPrivilege",
75
+ "SeAuditPrivilege",
76
+ "SeSystemEnvironmentPrivilege",
77
+ "SeImpersonatePrivilege",
78
+ "SeDelegateSessionUserImpersonatePrivilege"]}
79
+ d.instance.parse_desc(h)
80
+ assert_equal(expected, h)
81
+ end
82
+
83
+ test "A new external device was recognized by the system." do
84
+ # using the event log example: eventopedia.cloudapp.net/EventDetails.aspx?id=17ef124e-eb89-4c01-9ba2-d761e06b2b68
85
+ d = create_driver
86
+ desc = nil
87
+ File.open('./test/data/eventid_6416', 'r') do |f|
88
+ desc = f.read.gsub(/\R/, "\r\n")
89
+ end
90
+ h = {"Description" => desc}
91
+ expected = {"DescriptionTitle" => "A new external device was recognized by the system.",
92
+ "class_id" => "{1ed2bbf9-11f0-4084-b21f-ad83a8e6dcdc}",
93
+ "class_name" => "PrintQueue",
94
+ "compatible_ids" => ["GenPrintQueue", "SWD\\GenericRaw", "SWD\\Generic"],
95
+ "device_id" => "SWD\\PRINTENUM\\{60FA1C6A-1AB2-440A-AEE1-62ABFB9A4650}",
96
+ "device_name" => "Microsoft Print to PDF",
97
+ "subject.account_domain" => "ITSS",
98
+ "subject.account_name" => "IIZHU2016$",
99
+ "subject.logon_id" => "0x3E7",
100
+ "subject.security_id" => "SYSTEM",
101
+ "vendor_ids" => ["PRINTENUM\\{084f01fa-e634-4d77-83ee-074817c03581}",
102
+ "PRINTENUM\\LocalPrintQueue",
103
+ "{084f01fa-e634-4d77-83ee-074817c03581}"]}
104
+ d.instance.parse_desc(h)
105
+ assert_equal(expected, h)
106
+ end
107
+
51
108
  def test_write
52
109
  d = create_driver
53
110
 
@@ -58,7 +115,7 @@ DESC
58
115
  end
59
116
 
60
117
  assert(d.events.length >= 1)
61
- event = d.events.last
118
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
62
119
  record = event.last
63
120
 
64
121
  assert_equal("Application", record["Channel"])
@@ -114,7 +171,7 @@ DESC
114
171
  end
115
172
 
116
173
  assert(d.events.length >= 1)
117
- event = d.events.last
174
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
118
175
  record = event.last
119
176
 
120
177
  assert_false(d.instance.render_as_xml)
@@ -155,7 +212,7 @@ DESC
155
212
  end
156
213
 
157
214
  assert(d.events.length >= 1)
158
- event = d.events.last
215
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
159
216
  record = event.last
160
217
 
161
218
  prev_id = record["EventRecordID"].to_i
@@ -180,6 +237,21 @@ DESC
180
237
 
181
238
  assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
182
239
  end
240
+
241
+ def test_start_with_invalid_bookmark
242
+ invalid_storage_contents = <<-EOS
243
+ <BookmarkList>\r\n <Bookmark Channel='Application' RecordId='20063' IsCurrent='true'/>\r\n
244
+ EOS
245
+ d = create_driver(CONFIG2)
246
+ storage = d.instance.instance_variable_get(:@bookmarks_storage)
247
+ storage.put('application', invalid_storage_contents)
248
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
249
+
250
+ d2 = create_driver(CONFIG2)
251
+ assert_raise(Fluent::ConfigError) do
252
+ d2.instance.start
253
+ end
254
+ end
183
255
  end
184
256
 
185
257
  def test_write_with_none_parser
@@ -38,7 +38,7 @@ class WindowsEventLogInputTest < Test::Unit::TestCase
38
38
  end
39
39
 
40
40
  assert(d.events.length >= 1)
41
- event = d.events.last
41
+ event = d.events.select {|e| e.last["event_id"] == "65500" }.last
42
42
  record = event.last
43
43
  assert_equal("application", record["channel"])
44
44
  assert_equal("65500", record["event_id"])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-windows-eventlog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - okahashi117
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-10-10 00:00:00.000000000 Z
13
+ date: 2020-01-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -94,14 +94,14 @@ dependencies:
94
94
  requirements:
95
95
  - - ">="
96
96
  - !ruby/object:Gem::Version
97
- version: 0.6.0
97
+ version: 0.6.1
98
98
  type: :runtime
99
99
  prerelease: false
100
100
  version_requirements: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="
103
103
  - !ruby/object:Gem::Version
104
- version: 0.6.0
104
+ version: 0.6.1
105
105
  - !ruby/object:Gem::Dependency
106
106
  name: nokogiri
107
107
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +149,7 @@ files:
149
149
  - fluent-plugin-winevtlog.gemspec
150
150
  - lib/fluent/plugin/in_windows_eventlog.rb
151
151
  - lib/fluent/plugin/in_windows_eventlog2.rb
152
+ - test/data/eventid_6416
152
153
  - test/generate-windows-event.rb
153
154
  - test/helper.rb
154
155
  - test/plugin/test_in_windows_eventlog2.rb
@@ -173,11 +174,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
174
  version: '0'
174
175
  requirements: []
175
176
  rubyforge_project:
176
- rubygems_version: 2.7.3
177
+ rubygems_version: 2.7.6.2
177
178
  signing_key:
178
179
  specification_version: 4
179
180
  summary: Fluentd Input plugin to read windows event log.
180
181
  test_files:
182
+ - test/data/eventid_6416
181
183
  - test/generate-windows-event.rb
182
184
  - test/helper.rb
183
185
  - test/plugin/test_in_windows_eventlog2.rb