fluent-plugin-windows-eventlog 0.4.1 → 0.4.6

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: 59131dc675a5af717f4f3d693af1f902d76aa7b557e82c14431cd310f28cf999
4
- data.tar.gz: f130a09fbb2c8a35a287869447e1486b3d21d371bc1acf4744ebd1a471e76edf
3
+ metadata.gz: f4516e76fe8713d76f90513a1312ad213eee4e779acecaef91244b799de7aa99
4
+ data.tar.gz: 84db0703a52631a1e982b3d90f382803e00f22909c749d12aca5c2bbc2ebe8ac
5
5
  SHA512:
6
- metadata.gz: 6b9e107c6dd037cc4c2ef391cacf6636884a210a3c7058770972c0968603c8600267babaeee7cebb3dc75259c13d3aa0697e3a1980c06cba3d0daf26912b063e
7
- data.tar.gz: 8e41835e28cf0ad5ba6a73d50c985518c001988a721a5fdee2dd4820d48e656835b4e26d19eeefdd0c3db62ee701f29d957efcff7d87f0ade7449f720c8f6849
6
+ metadata.gz: 3cfb0b205425eba34652d5c2dc4f22666ff9eb711b4d1a3f381d082ec7f0e162e03aa9f4cde83073d5b16b1c0ea8f7b432d36e7c2a129f55d32524261201d316
7
+ data.tar.gz: 9bc301c76c403093286c22d8be097e3f67a18322d73a434b73655856c5edb82e77ab036d9756d6e697729a2667e3662b16617cef3e585969c417943e61d7a1de
@@ -1,3 +1,19 @@
1
+ # Release v0.4.6 - 2020/02/15
2
+ * Fix winevt_c dependency to prevent fetching winevt_c v0.7.0 or later.
3
+
4
+ # Release v0.4.5 - 2020/01/28
5
+ * in_windows_eventlog2: Handle empty key case in parsing description method.
6
+
7
+ # Release v0.4.4 - 2019/11/07
8
+ * in_windows_eventlog: Improve error handling and logging when failed to open Windows Event Log.
9
+
10
+ # Release v0.4.3 - 2019/10/31
11
+ * in_windows_eventlog2: Handle privileges record on #parse_desc
12
+ * in_windows_eventlog2: Raise error when handling invalid bookmark xml
13
+
14
+ # Release v0.4.2 - 2019/10/16
15
+ * in_windows_eventlog2: Handle invalid data error from `Winevt::EventLog::Query::Error`
16
+
1
17
  # Release v0.4.1 - 2019/10/11
2
18
  * in_windows_eventlog2: Add a missing ProcessID record
3
19
 
@@ -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.1"
7
+ spec.version = "0.4.6"
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", "< 0.7.0"]
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
@@ -89,9 +89,17 @@ module Fluent::Plugin
89
89
  @chs.each do |ch|
90
90
  bookmarkXml = @bookmarks_storage.get(ch) || ""
91
91
  subscribe = Winevt::EventLog::Subscribe.new
92
- bookmark = Winevt::EventLog::Bookmark.new(bookmarkXml)
92
+ bookmark = unless bookmarkXml.empty?
93
+ Winevt::EventLog::Bookmark.new(bookmarkXml)
94
+ else
95
+ nil
96
+ end
93
97
  subscribe.tail = @tailing
94
- 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
95
103
  subscribe.render_as_xml = @render_as_xml
96
104
  subscribe.rate_limit = @rate_limit
97
105
  timer_execute("in_windows_eventlog_#{escape_channel(ch)}".to_sym, @read_interval) do
@@ -101,7 +109,7 @@ module Fluent::Plugin
101
109
  end
102
110
 
103
111
  def escape_channel(ch)
104
- ch.gsub(/[^a-zA-Z0-9]/, '_')
112
+ ch.gsub(/[^a-zA-Z0-9\s]/, '_')
105
113
  end
106
114
 
107
115
  def on_notify(ch, subscribe)
@@ -110,35 +118,40 @@ module Fluent::Plugin
110
118
 
111
119
  def on_notify_xml(ch, subscribe)
112
120
  es = Fluent::MultiEventStream.new
113
- subscribe.each do |xml, message, string_inserts|
114
- @parser.parse(xml) do |time, record|
115
- # record.has_key?("EventData") for none parser checking.
116
- if @winevt_xml
117
- record["Description"] = message
118
- record["EventData"] = string_inserts
119
-
120
- h = {}
121
- @keynames.each do |k|
122
- type = KEY_MAP[k][1]
123
- value = record[KEY_MAP[k][0]]
124
- h[k]=case type
125
- when :string
126
- value.to_s
127
- when :array
128
- value.map {|v| v.to_s}
129
- else
130
- raise "Unknown value type: #{type}"
131
- 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)
132
149
  end
133
- parse_desc(h) if @parse_description
134
- es.add(Fluent::Engine.now, h)
135
- else
136
- record["Description"] = message
137
- record["EventData"] = string_inserts
138
- # for none parser
139
- es.add(Fluent::Engine.now, record)
140
150
  end
141
151
  end
152
+ rescue Winevt::EventLog::Query::Error => e
153
+ log.warn "Invalid XML data", error: e
154
+ log.warn_backtrace
142
155
  end
143
156
  router.emit_stream(@tag, es)
144
157
  @bookmarks_storage.put(ch, subscribe.bookmark)
@@ -146,24 +159,29 @@ module Fluent::Plugin
146
159
 
147
160
  def on_notify_hash(ch, subscribe)
148
161
  es = Fluent::MultiEventStream.new
149
- subscribe.each do |record, message, string_inserts|
150
- record["Description"] = message
151
- record["EventData"] = string_inserts
152
- h = {}
153
- @keynames.each do |k|
154
- type = KEY_MAP[k][1]
155
- value = record[KEY_MAP[k][0]]
156
- h[k]=case type
157
- when :string
158
- value.to_s
159
- when :array
160
- value.map {|v| v.to_s}
161
- else
162
- raise "Unknown value type: #{type}"
163
- 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)
164
181
  end
165
- parse_desc(h) if @parse_description
166
- 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
167
185
  end
168
186
  router.emit_stream(@tag, es)
169
187
  @bookmarks_storage.put(ch, subscribe.bookmark)
@@ -182,6 +200,7 @@ module Fluent::Plugin
182
200
 
183
201
  elems = desc.split(GROUP_DELIMITER)
184
202
  record['DescriptionTitle'] = elems.shift
203
+ previous_key = nil
185
204
  elems.each { |elem|
186
205
  parent_key = nil
187
206
  elem.split(RECORD_DELIMITER).each { |r|
@@ -190,19 +209,26 @@ module Fluent::Plugin
190
209
  else
191
210
  r.split(NONE_FIELD_DELIMITER)
192
211
  end
212
+ key = "" if key.nil?
193
213
  key.chop! # remove ':' from key
194
214
  if value.nil?
195
215
  parent_key = to_key(key)
196
216
  else
197
217
  # parsed value sometimes contain unexpected "\t". So remove it.
198
218
  value.strip!
199
- 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?
200
223
  record[to_key(key)] = value
201
224
  else
202
225
  k = "#{parent_key}.#{to_key(key)}"
203
226
  record[k] = value
204
227
  end
205
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?
206
232
  }
207
233
  }
208
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
@@ -28,6 +28,16 @@ class WindowsEventLog2InputTest < Test::Unit::TestCase
28
28
  assert_true d.instance.render_as_xml
29
29
  end
30
30
 
31
+ data("application" => ["Application", "Application"],
32
+ "windows powershell" => ["Windows PowerShell", "Windows PowerShell"],
33
+ "escaped" => ["Should_Be_Escaped_", "Should+Be;Escaped/"]
34
+ )
35
+ def test_escape_channel(data)
36
+ expected, actual = data
37
+ d = create_driver CONFIG
38
+ assert_equal expected, d.instance.escape_channel(actual)
39
+ end
40
+
31
41
  def test_parse_desc
32
42
  d = create_driver
33
43
  desc =<<-DESC
@@ -48,6 +58,63 @@ DESC
48
58
  assert_equal(expected, h)
49
59
  end
50
60
 
61
+ def test_parse_privileges_description
62
+ d = create_driver
63
+ desc = ["Special privileges assigned to new logon.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-X-Y-ZZ\r\n\t",
64
+ "AccountName:\t\tSYSTEM\r\n\tAccount Domain:\t\tNT AUTHORITY\r\n\tLogon ID:\t\t0x3E7\r\n\r\n",
65
+ "Privileges:\t\tSeAssignPrimaryTokenPrivilege\r\n\t\t\tSeTcbPrivilege\r\n\t\t\t",
66
+ "SeSecurityPrivilege\r\n\t\t\tSeTakeOwnershipPrivilege\r\n\t\t\tSeLoadDriverPrivilege\r\n\t\t\t",
67
+ "SeBackupPrivilege\r\n\t\t\tSeRestorePrivilege\r\n\t\t\tSeDebugPrivilege\r\n\t\t\t",
68
+ "SeAuditPrivilege\r\n\t\t\tSeSystemEnvironmentPrivilege\r\n\t\t\tSeImpersonatePrivilege\r\n\t\t\t",
69
+ "SeDelegateSessionUserImpersonatePrivilege"].join("")
70
+
71
+ h = {"Description" => desc}
72
+ expected = {"DescriptionTitle" => "Special privileges assigned to new logon.",
73
+ "subject.security_id" => "S-X-Y-ZZ",
74
+ "subject.accountname" => "SYSTEM",
75
+ "subject.account_domain" => "NT AUTHORITY",
76
+ "subject.logon_id" => "0x3E7",
77
+ "privileges" => ["SeAssignPrimaryTokenPrivilege",
78
+ "SeTcbPrivilege",
79
+ "SeSecurityPrivilege",
80
+ "SeTakeOwnershipPrivilege",
81
+ "SeLoadDriverPrivilege",
82
+ "SeBackupPrivilege",
83
+ "SeRestorePrivilege",
84
+ "SeDebugPrivilege",
85
+ "SeAuditPrivilege",
86
+ "SeSystemEnvironmentPrivilege",
87
+ "SeImpersonatePrivilege",
88
+ "SeDelegateSessionUserImpersonatePrivilege"]}
89
+ d.instance.parse_desc(h)
90
+ assert_equal(expected, h)
91
+ end
92
+
93
+ test "A new external device was recognized by the system." do
94
+ # using the event log example: eventopedia.cloudapp.net/EventDetails.aspx?id=17ef124e-eb89-4c01-9ba2-d761e06b2b68
95
+ d = create_driver
96
+ desc = nil
97
+ File.open('./test/data/eventid_6416', 'r') do |f|
98
+ desc = f.read.gsub(/\R/, "\r\n")
99
+ end
100
+ h = {"Description" => desc}
101
+ expected = {"DescriptionTitle" => "A new external device was recognized by the system.",
102
+ "class_id" => "{1ed2bbf9-11f0-4084-b21f-ad83a8e6dcdc}",
103
+ "class_name" => "PrintQueue",
104
+ "compatible_ids" => ["GenPrintQueue", "SWD\\GenericRaw", "SWD\\Generic"],
105
+ "device_id" => "SWD\\PRINTENUM\\{60FA1C6A-1AB2-440A-AEE1-62ABFB9A4650}",
106
+ "device_name" => "Microsoft Print to PDF",
107
+ "subject.account_domain" => "ITSS",
108
+ "subject.account_name" => "IIZHU2016$",
109
+ "subject.logon_id" => "0x3E7",
110
+ "subject.security_id" => "SYSTEM",
111
+ "vendor_ids" => ["PRINTENUM\\{084f01fa-e634-4d77-83ee-074817c03581}",
112
+ "PRINTENUM\\LocalPrintQueue",
113
+ "{084f01fa-e634-4d77-83ee-074817c03581}"]}
114
+ d.instance.parse_desc(h)
115
+ assert_equal(expected, h)
116
+ end
117
+
51
118
  def test_write
52
119
  d = create_driver
53
120
 
@@ -58,7 +125,7 @@ DESC
58
125
  end
59
126
 
60
127
  assert(d.events.length >= 1)
61
- event = d.events.last
128
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
62
129
  record = event.last
63
130
 
64
131
  assert_equal("Application", record["Channel"])
@@ -114,7 +181,7 @@ DESC
114
181
  end
115
182
 
116
183
  assert(d.events.length >= 1)
117
- event = d.events.last
184
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
118
185
  record = event.last
119
186
 
120
187
  assert_false(d.instance.render_as_xml)
@@ -155,7 +222,7 @@ DESC
155
222
  end
156
223
 
157
224
  assert(d.events.length >= 1)
158
- event = d.events.last
225
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
159
226
  record = event.last
160
227
 
161
228
  prev_id = record["EventRecordID"].to_i
@@ -180,6 +247,21 @@ DESC
180
247
 
181
248
  assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
182
249
  end
250
+
251
+ def test_start_with_invalid_bookmark
252
+ invalid_storage_contents = <<-EOS
253
+ <BookmarkList>\r\n <Bookmark Channel='Application' RecordId='20063' IsCurrent='true'/>\r\n
254
+ EOS
255
+ d = create_driver(CONFIG2)
256
+ storage = d.instance.instance_variable_get(:@bookmarks_storage)
257
+ storage.put('application', invalid_storage_contents)
258
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
259
+
260
+ d2 = create_driver(CONFIG2)
261
+ assert_raise(Fluent::ConfigError) do
262
+ d2.instance.start
263
+ end
264
+ end
183
265
  end
184
266
 
185
267
  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.1
4
+ version: 0.4.6
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-11 00:00:00.000000000 Z
13
+ date: 2020-02-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -94,14 +94,20 @@ dependencies:
94
94
  requirements:
95
95
  - - ">="
96
96
  - !ruby/object:Gem::Version
97
- version: 0.6.0
97
+ version: 0.6.1
98
+ - - "<"
99
+ - !ruby/object:Gem::Version
100
+ version: 0.7.0
98
101
  type: :runtime
99
102
  prerelease: false
100
103
  version_requirements: !ruby/object:Gem::Requirement
101
104
  requirements:
102
105
  - - ">="
103
106
  - !ruby/object:Gem::Version
104
- version: 0.6.0
107
+ version: 0.6.1
108
+ - - "<"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.7.0
105
111
  - !ruby/object:Gem::Dependency
106
112
  name: nokogiri
107
113
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +155,7 @@ files:
149
155
  - fluent-plugin-winevtlog.gemspec
150
156
  - lib/fluent/plugin/in_windows_eventlog.rb
151
157
  - lib/fluent/plugin/in_windows_eventlog2.rb
158
+ - test/data/eventid_6416
152
159
  - test/generate-windows-event.rb
153
160
  - test/helper.rb
154
161
  - test/plugin/test_in_windows_eventlog2.rb
@@ -173,11 +180,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
173
180
  version: '0'
174
181
  requirements: []
175
182
  rubyforge_project:
176
- rubygems_version: 2.7.3
183
+ rubygems_version: 2.7.6.2
177
184
  signing_key:
178
185
  specification_version: 4
179
186
  summary: Fluentd Input plugin to read windows event log.
180
187
  test_files:
188
+ - test/data/eventid_6416
181
189
  - test/generate-windows-event.rb
182
190
  - test/helper.rb
183
191
  - test/plugin/test_in_windows_eventlog2.rb