fluent-plugin-windows-eventlog 0.4.1 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
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