master
c 652 lines 33.6 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "windows-events.h"
4
5 //struct {
6 // const char *name;
7 // const wchar_t *query;
8 //} custom_queries[] = {
9 // {
10 // .name = "All-Administrative-Events",
11 // .query = L"<QueryList>\n"
12 // " <Query Id=\"0\" Path=\"Application\">\n"
13 // " <Select Path=\"Application\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
14 // " <Select Path=\"Security\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
15 // " <Select Path=\"System\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
16 // " <Select Path=\"HardwareEvents\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
17 // " <Select Path=\"Internet Explorer\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
18 // " <Select Path=\"Key Management Service\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
19 // " <Select Path=\"Microsoft-AppV-Client/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
20 // " <Select Path=\"Microsoft-AppV-Client/Virtual Applications\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
21 // " <Select Path=\"Microsoft-Windows-All-User-Install-Agent/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
22 // " <Select Path=\"Microsoft-Windows-AppHost/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
23 // " <Select Path=\"Microsoft-Windows-Application Server-Applications/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
24 // " <Select Path=\"Microsoft-Windows-AppModel-Runtime/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
25 // " <Select Path=\"Microsoft-Windows-AppReadiness/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
26 // " <Select Path=\"Microsoft-Windows-AssignedAccess/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
27 // " <Select Path=\"Microsoft-Windows-AssignedAccessBroker/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
28 // " <Select Path=\"Microsoft-Windows-Storage-ATAPort/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
29 // " <Select Path=\"Microsoft-Windows-BitLocker-DrivePreparationTool/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
30 // " <Select Path=\"Microsoft-Client-Licensing-Platform/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
31 // " <Select Path=\"Microsoft-Windows-DataIntegrityScan/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
32 // " <Select Path=\"Microsoft-Windows-DataIntegrityScan/CrashRecovery\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
33 // " <Select Path=\"Microsoft-Windows-DSC/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
34 // " <Select Path=\"Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
35 // " <Select Path=\"Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Autopilot\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
36 // " <Select Path=\"Microsoft-Windows-DeviceSetupManager/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
37 // " <Select Path=\"Microsoft-Windows-Dhcp-Client/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
38 // " <Select Path=\"Microsoft-Windows-Dhcpv6-Client/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
39 // " <Select Path=\"Microsoft-Windows-Diagnosis-Scripted/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
40 // " <Select Path=\"Microsoft-Windows-Storage-Disk/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
41 // " <Select Path=\"Microsoft-Windows-DxgKrnl-Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
42 // " <Select Path=\"Microsoft-Windows-EDP-Application-Learning/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
43 // " <Select Path=\"Microsoft-Windows-EDP-Audit-Regular/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
44 // " <Select Path=\"Microsoft-Windows-EDP-Audit-TCB/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
45 // " <Select Path=\"Microsoft-Client-License-Flexible-Platform/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
46 // " <Select Path=\"Microsoft-Windows-GenericRoaming/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
47 // " <Select Path=\"Microsoft-Windows-Hyper-V-Guest-Drivers/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
48 // " <Select Path=\"Microsoft-Windows-Hyper-V-Hypervisor-Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
49 // " <Select Path=\"Microsoft-Windows-Hyper-V-VID-Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
50 // " <Select Path=\"Microsoft-Windows-Kernel-EventTracing/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
51 // " <Select Path=\"Microsoft-Windows-KeyboardFilter/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
52 // " <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
53 // " <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Autopilot\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
54 // " <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/Diagnostics\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
55 // " <Select Path=\"Microsoft-Windows-ModernDeployment-Diagnostics-Provider/ManagementService\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
56 // " <Select Path=\"Microsoft-Windows-MUI/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
57 // " <Select Path=\"Microsoft-Windows-PowerShell/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
58 // " <Select Path=\"Microsoft-Windows-PrintBRM/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
59 // " <Select Path=\"Microsoft-Windows-PrintService/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
60 // " <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
61 // " <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/AutoPilot\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
62 // " <Select Path=\"Microsoft-Windows-Provisioning-Diagnostics-Provider/ManagementService\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
63 // " <Select Path=\"Microsoft-Windows-PushNotification-Platform/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
64 // " <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connections/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
65 // " <Select Path=\"Microsoft-Windows-RemoteAssistance/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
66 // " <Select Path=\"Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
67 // " <Select Path=\"Microsoft-Windows-RetailDemo/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
68 // " <Select Path=\"Microsoft-Windows-SecurityMitigationsBroker/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
69 // " <Select Path=\"Microsoft-Windows-SmartCard-TPM-VCard-Module/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
70 // " <Select Path=\"Microsoft-Windows-SMBDirect/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
71 // " <Select Path=\"Microsoft-Windows-SMBWitnessClient/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
72 // " <Select Path=\"Microsoft-Windows-Storage-Tiering/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
73 // " <Select Path=\"Microsoft-Windows-Storage-ClassPnP/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
74 // " <Select Path=\"Microsoft-Windows-Storage-Storport/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
75 // " <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
76 // " <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
77 // " <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
78 // " <Select Path=\"Microsoft-Windows-TerminalServices-Printers/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
79 // " <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
80 // " <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
81 // " <Select Path=\"Microsoft-Windows-Troubleshooting-Recommended/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
82 // " <Select Path=\"Microsoft-Windows-User Device Registration/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
83 // " <Select Path=\"Microsoft-Windows-VerifyHardwareSecurity/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
84 // " <Select Path=\"Microsoft-Windows-WindowsBackup/ActionCenter\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
85 // " <Select Path=\"Microsoft-Windows-Workplace Join/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
86 // " <Select Path=\"OAlerts\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
87 // " <Select Path=\"OneApp_IGCC\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
88 // " <Select Path=\"OpenSSH/Admin\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
89 // " <Select Path=\"USER_ESRV_SVC_QUEENCREEK\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
90 // " <Select Path=\"Visual Studio\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
91 // " <Select Path=\"Windows PowerShell\">*[System[(Level=1 or Level=2 or Level=3)]]</Select>\n"
92 // " </Query>\n"
93 // "</QueryList>",
94 // },
95 // {
96 // .name = "All-Remote-Desktop-Services",
97 // .query = L"<QueryList>\n"
98 // " <Query Id=\"0\" Path=\"Microsoft-Rdms-UI/Admin\">\n"
99 // " <Select Path=\"Microsoft-Rdms-UI/Admin\">*</Select>\n"
100 // " <Select Path=\"Microsoft-Rdms-UI/Operational\">*</Select>\n"
101 // " <Select Path=\"Remote-Desktop-Management-Service/Admin\">*</Select>\n"
102 // " <Select Path=\"Remote-Desktop-Management-Service/Operational\">*</Select>\n"
103 // " <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker-Client/Admin\">*</Select>\n"
104 // " <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker-Client/Operational\">*</Select>\n"
105 // " <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Admin\">*</Select>\n"
106 // " <Select Path=\"Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational\">*</Select>\n"
107 // " <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Admin\">*</Select>\n"
108 // " <Select Path=\"Microsoft-Windows-TerminalServices-PnPDevices/Operational\">*</Select>\n"
109 // " <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connections/Admin\">*</Select>\n"
110 // " <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connection Management/Admin\">*</Select>\n"
111 // " <Select Path=\"Microsoft-Windows-RemoteApp and Desktop Connection Management/Operational\">*</Select>\n"
112 // " <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker/Admin\">*</Select>\n"
113 // " <Select Path=\"Microsoft-Windows-TerminalServices-SessionBroker/Operational\">*</Select>\n"
114 // " <Select Path=\"Microsoft-Windows-TerminalServices-TSV-VmHostAgent/Operational\">*</Select>\n"
115 // " <Select Path=\"Microsoft-Windows-TerminalServices-TSV-VmHostAgent/Admin\">*</Select>\n"
116 // " <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Operational\">*</Select>\n"
117 // " <Select Path=\"Microsoft-Windows-TerminalServices-ServerUSBDevices/Admin\">*</Select>\n"
118 // " <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Operational\">*</Select>\n"
119 // " <Select Path=\"Microsoft-Windows-TerminalServices-LocalSessionManager/Admin\">*</Select>\n"
120 // " <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Operational\">*</Select>\n"
121 // " <Select Path=\"Microsoft-Windows-TerminalServices-ClientUSBDevices/Admin\">*</Select>\n"
122 // " <Select Path=\"Microsoft-Windows-TerminalServices-RDPClient/Operational\">*</Select>\n"
123 // " <Select Path=\"Microsoft-Windows-TerminalServices-Licensing/Admin\">*</Select>\n"
124 // " <Select Path=\"Microsoft-Windows-TerminalServices-Licensing/Operational\">*</Select>\n"
125 // " <Select Path=\"Microsoft-Windows-TerminalServices-Gateway/Admin\">*</Select>\n"
126 // " <Select Path=\"Microsoft-Windows-TerminalServices-Gateway/Operational\">*</Select>\n"
127 // " </Query>\n"
128 // "</QueryList>",
129 // },
130 // {
131 // .name = "All-Security-SPP",
132 // .query = L"<QueryList>\n"
133 // " <Query Id=\"0\" Path=\"Microsoft-Windows-HelloForBusiness/Operational\">\n"
134 // " <Select Path=\"Microsoft-Windows-HelloForBusiness/Operational\">*[System[(Level&gt;5 )]]</Select>\n"
135 // " </Query>\n"
136 // "</QueryList>",
137 // }
138 //};
139
140 ENUM_STR_MAP_DEFINE(WEVT_SOURCE_TYPE) = {
141 { .id = WEVTS_ALL, .name = WEVT_SOURCE_ALL_NAME },
142 { .id = WEVTS_ADMIN, .name = WEVT_SOURCE_ALL_ADMIN_NAME },
143 { .id = WEVTS_OPERATIONAL, .name = WEVT_SOURCE_ALL_OPERATIONAL_NAME },
144 { .id = WEVTS_ANALYTIC, .name = WEVT_SOURCE_ALL_ANALYTIC_NAME },
145 { .id = WEVTS_DEBUG, .name = WEVT_SOURCE_ALL_DEBUG_NAME },
146 { .id = WEVTS_WINDOWS, .name = WEVT_SOURCE_ALL_WINDOWS_NAME },
147 { .id = WEVTS_ENABLED, .name = WEVT_SOURCE_ALL_ENABLED_NAME },
148 { .id = WEVTS_DISABLED, .name = WEVT_SOURCE_ALL_DISABLED_NAME },
149 { .id = WEVTS_FORWARDED, .name = WEVT_SOURCE_ALL_FORWARDED_NAME },
150 { .id = WEVTS_CLASSIC, .name = WEVT_SOURCE_ALL_CLASSIC_NAME },
151 { .id = WEVTS_BACKUP_MODE, .name = WEVT_SOURCE_ALL_BACKUP_MODE_NAME },
152 { .id = WEVTS_OVERWRITE_MODE, .name = WEVT_SOURCE_ALL_OVERWRITE_MODE_NAME },
153 { .id = WEVTS_STOP_WHEN_FULL_MODE, .name = WEVT_SOURCE_ALL_STOP_WHEN_FULL_MODE_NAME },
154 { .id = WEVTS_RETAIN_AND_BACKUP_MODE, .name = WEVT_SOURCE_ALL_RETAIN_AND_BACKUP_MODE_NAME },
155
156 // terminator
157 { . id = 0, .name = NULL }
158 };
159
160 BITMAP_STR_DEFINE_FUNCTIONS(WEVT_SOURCE_TYPE, WEVTS_NONE, "");
161
162 DICTIONARY *wevt_sources = NULL;
163 DICTIONARY *used_hashes_registry = NULL;
164 static usec_t wevt_session = 0;
165
166 void wevt_sources_del_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
167 LOGS_QUERY_SOURCE *src = value;
168 freez((void *)src->fullname);
169 string_freez(src->source);
170
171 src->fullname = NULL;
172 src->source = NULL;
173 }
174
175 static bool wevt_sources_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value, void *data __maybe_unused) {
176 LOGS_QUERY_SOURCE *src_old = old_value;
177 LOGS_QUERY_SOURCE *src_new = new_value;
178
179 bool ret = false;
180 if(src_new->last_scan_monotonic_ut > src_old->last_scan_monotonic_ut) {
181 src_old->last_scan_monotonic_ut = src_new->last_scan_monotonic_ut;
182
183 if (src_old->source != src_new->source) {
184 string_freez(src_old->source);
185 src_old->source = src_new->source;
186 src_new->source = NULL;
187 }
188 src_old->source_type = src_new->source_type;
189
190 src_old->msg_first_ut = src_new->msg_first_ut;
191 src_old->msg_last_ut = src_new->msg_last_ut;
192 src_old->msg_first_id = src_new->msg_first_id;
193 src_old->msg_last_id = src_new->msg_last_id;
194 src_old->entries = src_new->entries;
195 src_old->size = src_new->size;
196
197 ret = true;
198 }
199
200 freez((void *)src_new->fullname);
201 string_freez(src_new->source);
202 src_new->fullname = NULL;
203 src_new->source = NULL;
204
205 return ret;
206 }
207
208 void wevt_sources_init(void) {
209 wevt_session = now_realtime_usec();
210
211 used_hashes_registry = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
212
213 wevt_sources = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE,
214 NULL, sizeof(LOGS_QUERY_SOURCE));
215
216 dictionary_register_delete_callback(wevt_sources, wevt_sources_del_cb, NULL);
217 dictionary_register_conflict_callback(wevt_sources, wevt_sources_conflict_cb, NULL);
218 }
219
220 void buffer_json_wevt_versions(BUFFER *wb __maybe_unused) {
221 buffer_json_member_add_object(wb, "versions");
222 {
223 buffer_json_member_add_uint64(wb, "sources",
224 wevt_session + dictionary_version(wevt_sources));
225 }
226 buffer_json_object_close(wb);
227 }
228
229 // --------------------------------------------------------------------------------------------------------------------
230
231 int wevt_sources_dict_items_backward_compar(const void *a, const void *b) {
232 const DICTIONARY_ITEM **da = (const DICTIONARY_ITEM **)a, **db = (const DICTIONARY_ITEM **)b;
233 LOGS_QUERY_SOURCE *sa = dictionary_acquired_item_value(*da);
234 LOGS_QUERY_SOURCE *sb = dictionary_acquired_item_value(*db);
235
236 // compare the last message timestamps
237 if(sa->msg_last_ut < sb->msg_last_ut)
238 return 1;
239
240 if(sa->msg_last_ut > sb->msg_last_ut)
241 return -1;
242
243 // compare the first message timestamps
244 if(sa->msg_first_ut < sb->msg_first_ut)
245 return 1;
246
247 if(sa->msg_first_ut > sb->msg_first_ut)
248 return -1;
249
250 return 0;
251 }
252
253 int wevt_sources_dict_items_forward_compar(const void *a, const void *b) {
254 return -wevt_sources_dict_items_backward_compar(a, b);
255 }
256
257 // --------------------------------------------------------------------------------------------------------------------
258
259 typedef enum {
260 wevt_source_type_internal,
261 wevt_source_type_provider,
262 wevt_source_type_channel,
263 } wevt_source_type;
264
265 struct wevt_source {
266 wevt_source_type type;
267 usec_t first_ut;
268 usec_t last_ut;
269 size_t count;
270 size_t entries;
271 uint64_t size;
272 };
273
274 static int wevt_source_to_json_array_cb(const DICTIONARY_ITEM *item, void *entry, void *data) {
275 const struct wevt_source *s = entry;
276 BUFFER *wb = data;
277
278 const char *name = dictionary_acquired_item_name(item);
279
280 if(s->count == 1 && strncmp(name, WEVT_SOURCE_ALL_OF_PROVIDER_PREFIX, sizeof(WEVT_SOURCE_ALL_OF_PROVIDER_PREFIX) - 1) == 0)
281 // do not include "All-Of-X" when there is only 1 channel
282 return 0;
283
284 bool default_selected = (s->type == wevt_source_type_channel);
285 if(default_selected && (strcmp(name, "NetdataWEL") == 0 || strcmp(name, "Netdata/Access") == 0))
286 // do not select Netdata Access logs by default
287 default_selected = false;
288
289 buffer_json_add_array_item_object(wb);
290 {
291 char size_for_humans[128];
292 size_snprintf(size_for_humans, sizeof(size_for_humans), s->size, "B", false);
293
294 char duration_for_humans[128];
295 duration_snprintf(duration_for_humans, sizeof(duration_for_humans),
296 (time_t)((s->last_ut - s->first_ut) / USEC_PER_SEC), "s", true);
297
298 char entries_for_humans[128];
299 entries_snprintf(entries_for_humans, sizeof(entries_for_humans), s->entries, "", false);
300
301 char last_ut[RFC3339_MAX_LENGTH];
302 rfc3339_datetime_ut(last_ut, sizeof(last_ut), s->last_ut, 0, true);
303
304 char info[1024];
305 snprintfz(info, sizeof(info), "%zu channel%s, total size %s, covering %s%s%s%s, last entry at %s",
306 s->count, s->count > 1 ? "s":"", size_for_humans, duration_for_humans,
307 s->entries ? ", having " : "", s->entries ? entries_for_humans : "", s->entries ? " entries" : "",
308 last_ut);
309
310 buffer_json_member_add_string(wb, "id", name);
311 buffer_json_member_add_string(wb, "name", name);
312 buffer_json_member_add_string(wb, "pill", size_for_humans);
313 buffer_json_member_add_string(wb, "info", info);
314 buffer_json_member_add_boolean(wb, "default_selected", default_selected);
315 }
316 buffer_json_object_close(wb); // options object
317
318 return 1;
319 }
320
321 static bool wevt_source_merge_sizes(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value , void *data __maybe_unused) {
322 struct wevt_source *old_v = old_value;
323 const struct wevt_source *new_v = new_value;
324
325 old_v->count += new_v->count;
326 old_v->size += new_v->size;
327 old_v->entries += new_v->entries;
328
329 if(new_v->first_ut && new_v->first_ut < old_v->first_ut)
330 old_v->first_ut = new_v->first_ut;
331
332 if(new_v->last_ut && new_v->last_ut > old_v->last_ut)
333 old_v->last_ut = new_v->last_ut;
334
335 return false;
336 }
337
338 void wevt_sources_to_json_array(BUFFER *wb) {
339 DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_NAME_LINK_DONT_CLONE|DICT_OPTION_DONT_OVERWRITE_VALUE);
340 dictionary_register_conflict_callback(dict, wevt_source_merge_sizes, NULL);
341
342 struct wevt_source t = { 0 };
343
344 LOGS_QUERY_SOURCE *src;
345 dfe_start_read(wevt_sources, src) {
346 t.first_ut = src->msg_first_ut;
347 t.last_ut = src->msg_last_ut;
348 t.count = 1;
349 t.size = src->size;
350 t.entries = src->entries;
351
352 src->source_type |= WEVTS_ALL;
353 t.type = wevt_source_type_internal;
354 for(size_t i = 0; WEVT_SOURCE_TYPE_names[i].name ;i++) {
355 if(src->source_type & WEVT_SOURCE_TYPE_names[i].id)
356 dictionary_set(dict, WEVT_SOURCE_TYPE_names[i].name, &t, sizeof(t));
357 }
358
359 if(src->provider) {
360 t.type = wevt_source_type_provider;
361 dictionary_set(dict, string2str(src->provider), &t, sizeof(t));
362 }
363
364 if(src->source) {
365 t.type = wevt_source_type_channel;
366 dictionary_set(dict, string2str(src->source), &t, sizeof(t));
367 }
368 }
369 dfe_done(jf);
370
371 dictionary_sorted_walkthrough_read(dict, wevt_source_to_json_array_cb, wb);
372 }
373
374 static bool ndEvtGetChannelConfigProperty(EVT_HANDLE hChannelConfig, WEVT_VARIANT *pr, EVT_CHANNEL_CONFIG_PROPERTY_ID id) {
375 if (!EvtGetChannelConfigProperty(hChannelConfig, id, 0, pr->size, pr->data, &pr->used)) {
376 DWORD status = GetLastError();
377 if (ERROR_INSUFFICIENT_BUFFER == status) {
378 wevt_variant_resize(pr, pr->used);
379 if(!EvtGetChannelConfigProperty(hChannelConfig, id, 0, pr->size, pr->data, &pr->used)) {
380 pr->used = 0;
381 pr->count = 0;
382 return false;
383 }
384 }
385 }
386
387 wevt_variant_count_from_used(pr);
388 return true;
389 }
390
391 WEVT_SOURCE_TYPE categorize_channel(const wchar_t *channel_path, const char **provider, WEVT_VARIANT *property) {
392 EVT_HANDLE hChannelConfig = NULL;
393 WEVT_SOURCE_TYPE result = WEVTS_ALL;
394
395 // Open the channel configuration
396 hChannelConfig = EvtOpenChannelConfig(NULL, channel_path, 0);
397 if (!hChannelConfig)
398 goto cleanup;
399
400 if(ndEvtGetChannelConfigProperty(hChannelConfig, property, EvtChannelConfigType) &
401 property->count &&
402 property->data[0].Type == EvtVarTypeUInt32) {
403 switch (property->data[0].UInt32Val) {
404 case EvtChannelTypeAdmin:
405 result |= WEVTS_ADMIN;
406 break;
407
408 case EvtChannelTypeOperational:
409 result |= WEVTS_OPERATIONAL;
410 break;
411
412 case EvtChannelTypeAnalytic:
413 result |= WEVTS_ANALYTIC;
414 break;
415
416 case EvtChannelTypeDebug:
417 result |= WEVTS_DEBUG;
418 break;
419
420 default:
421 break;
422 }
423 }
424
425 if(ndEvtGetChannelConfigProperty(hChannelConfig, property, EvtChannelConfigClassicEventlog) &&
426 property->count &&
427 property->data[0].Type == EvtVarTypeBoolean &&
428 property->data[0].BooleanVal)
429 result |= WEVTS_CLASSIC;
430
431 if(ndEvtGetChannelConfigProperty(hChannelConfig, property, EvtChannelConfigOwningPublisher) &&
432 property->count &&
433 property->data[0].Type == EvtVarTypeString) {
434 *provider = provider2utf8(property->data[0].StringVal);
435 if(wcscasecmp(property->data[0].StringVal, L"Microsoft-Windows-EventCollector") == 0)
436 result |= WEVTS_FORWARDED;
437 }
438 else
439 *provider = NULL;
440
441 if(ndEvtGetChannelConfigProperty(hChannelConfig, property, EvtChannelConfigEnabled) &&
442 property->count &&
443 property->data[0].Type == EvtVarTypeBoolean) {
444 if(property->data[0].BooleanVal)
445 result |= WEVTS_ENABLED;
446 else
447 result |= WEVTS_DISABLED;
448 }
449
450 bool got_retention = false;
451 bool retained = false;
452 if(ndEvtGetChannelConfigProperty(hChannelConfig, property, EvtChannelLoggingConfigRetention) &&
453 property->count &&
454 property->data[0].Type == EvtVarTypeBoolean) {
455 got_retention = true;
456 retained = property->data[0].BooleanVal;
457 }
458
459 bool got_auto_backup = false;
460 bool auto_backup = false;
461 if(ndEvtGetChannelConfigProperty(hChannelConfig, property, EvtChannelLoggingConfigAutoBackup) &&
462 property->count &&
463 property->data[0].Type == EvtVarTypeBoolean) {
464 got_auto_backup = true;
465 auto_backup = property->data[0].BooleanVal;
466 }
467
468 if(got_retention && got_auto_backup) {
469 if(!retained) {
470 if(auto_backup)
471 result |= WEVTS_BACKUP_MODE;
472 else
473 result |= WEVTS_OVERWRITE_MODE;
474 }
475 else {
476 if(auto_backup)
477 result |= WEVTS_STOP_WHEN_FULL_MODE;
478 else
479 result |= WEVTS_RETAIN_AND_BACKUP_MODE;
480 }
481 }
482
483 cleanup:
484 if (hChannelConfig)
485 EvtClose(hChannelConfig);
486
487 return result;
488 }
489
490 void wevt_sources_scan(void) {
491 static SPINLOCK spinlock = SPINLOCK_INITIALIZER;
492 LPWSTR channel = NULL;
493 EVT_HANDLE hChannelEnum = NULL;
494
495 if(spinlock_trylock(&spinlock)) {
496 const usec_t started_ut = now_monotonic_usec();
497
498 WEVT_VARIANT property = { 0 };
499 DWORD dwChannelBufferSize = 0;
500 DWORD dwChannelBufferUsed = 0;
501 DWORD status = ERROR_SUCCESS;
502
503 // Open a handle to enumerate the event channels
504 hChannelEnum = EvtOpenChannelEnum(NULL, 0);
505 if (!hChannelEnum) {
506 nd_log(NDLS_COLLECTORS, NDLP_ERR, "WINDOWS EVENTS: EvtOpenChannelEnum() failed with %" PRIu64 "\n",
507 (uint64_t)GetLastError());
508 goto cleanup;
509 }
510
511 WEVT_LOG *log = wevt_openlog6(WEVT_QUERY_RETENTION);
512 if(!log) goto cleanup;
513
514 while (true) {
515 if (!EvtNextChannelPath(hChannelEnum, dwChannelBufferSize, channel, &dwChannelBufferUsed)) {
516 status = GetLastError();
517 if (status == ERROR_NO_MORE_ITEMS)
518 break; // No more channels
519 else if (status == ERROR_INSUFFICIENT_BUFFER) {
520 dwChannelBufferSize = dwChannelBufferUsed;
521 freez(channel);
522 channel = mallocz(dwChannelBufferSize * sizeof(WCHAR));
523 continue;
524 } else {
525 nd_log(NDLS_COLLECTORS, NDLP_ERR,
526 "WINDOWS EVENTS: EvtNextChannelPath() failed\n");
527 break;
528 }
529 }
530
531 EVT_RETENTION retention;
532 if(!wevt_channel_retention(log, channel, NULL, &retention))
533 continue;
534
535 LOGS_QUERY_SOURCE *found = dictionary_get(wevt_sources, channel2utf8(channel));
536 if(found) {
537 // we just need to update its retention
538
539 found->last_scan_monotonic_ut = now_monotonic_usec();
540 found->msg_first_id = retention.first_event.id;
541 found->msg_last_id = retention.last_event.id;
542 found->msg_first_ut = retention.first_event.created_ns / NSEC_PER_USEC;
543 found->msg_last_ut = retention.last_event.created_ns / NSEC_PER_USEC;
544 found->size = retention.size_bytes;
545 continue;
546 }
547
548 const char *name = channel2utf8(channel);
549 const char *fullname = strdupz(name);
550 const char *provider;
551
552 WEVT_SOURCE_TYPE sources = categorize_channel(channel, &provider, &property);
553 char *slash = strchr(name, '/');
554 if(slash) *slash = '\0';
555
556 if(strcasecmp(name, "Application") == 0)
557 sources |= WEVTS_WINDOWS;
558 if(strcasecmp(name, "Security") == 0)
559 sources |= WEVTS_WINDOWS;
560 if(strcasecmp(name, "Setup") == 0)
561 sources |= WEVTS_WINDOWS;
562 if(strcasecmp(name, "System") == 0)
563 sources |= WEVTS_WINDOWS;
564
565 LOGS_QUERY_SOURCE src = {
566 .entries = retention.entries,
567 .fullname = fullname,
568 .fullname_len = strlen(fullname),
569 .last_scan_monotonic_ut = now_monotonic_usec(),
570 .msg_first_id = retention.first_event.id,
571 .msg_last_id = retention.last_event.id,
572 .msg_first_ut = retention.first_event.created_ns / NSEC_PER_USEC,
573 .msg_last_ut = retention.last_event.created_ns / NSEC_PER_USEC,
574 .size = retention.size_bytes,
575 .source_type = sources,
576 .source = string_strdupz(fullname),
577 };
578
579 if(strncmp(fullname, "Netdata", 7) == 0)
580 // WEL based providers of Netdata are named NetdataX
581 provider = "Netdata";
582
583 if(provider && *provider) {
584 size_t buf_size = sizeof(WEVT_SOURCE_ALL_OF_PROVIDER_PREFIX) + strlen(provider); // sizeof() includes terminator
585 char *buf = mallocz(buf_size);
586 snprintf(buf, buf_size, WEVT_SOURCE_ALL_OF_PROVIDER_PREFIX "%s", provider);
587
588 trim_all(buf);
589 if(buf[0]) {
590 for (size_t i = 0; i < buf_size - 1 && buf[i]; i++) {
591 // remove character that may interfere with our parsing
592 if (isspace((uint8_t) buf[i]) || buf[i] == '%' || buf[i] == '+' || buf[i] == '|' || buf[i] == ':')
593 buf[i] = '_';
594 }
595 src.provider = string_strdupz(buf);
596 }
597
598 freez(buf);
599 }
600
601 dictionary_set(wevt_sources, src.fullname, &src, sizeof(src));
602 }
603
604 // // add custom queries
605 // for(size_t i = 0; i < sizeof(custom_queries) / sizeof(custom_queries[0]) ;i++) {
606 // EVT_RETENTION retention;
607 // if(!wevt_channel_retention(log, NULL, custom_queries[i].query, &retention))
608 // continue;
609 //
610 // LOGS_QUERY_SOURCE src = {
611 // .entries = 0,
612 // .fullname = strdupz(custom_queries[i].name),
613 // .fullname_len = strlen(custom_queries[i].name),
614 // .last_scan_monotonic_ut = now_monotonic_usec(),
615 // .msg_first_id = retention.first_event.id,
616 // .msg_last_id = retention.last_event.id,
617 // .msg_first_ut = retention.first_event.created_ns / NSEC_PER_USEC,
618 // .msg_last_ut = retention.last_event.created_ns / NSEC_PER_USEC,
619 // .size = retention.size_bytes,
620 // .source_type = WEVTS_ALL,
621 // .source = string_strdupz(custom_queries[i].name),
622 // };
623 //
624 // dictionary_set(wevt_sources, src.fullname, &src, sizeof(src));
625 // }
626 //
627 wevt_closelog6(log);
628
629 LOGS_QUERY_SOURCE *src;
630 dfe_start_write(wevt_sources, src)
631 {
632 if(src->last_scan_monotonic_ut < started_ut) {
633 src->msg_first_id = 0;
634 src->msg_last_id = 0;
635 src->msg_first_ut = 0;
636 src->msg_last_ut = 0;
637 src->size = 0;
638 dictionary_del(wevt_sources, src->fullname);
639 }
640 }
641 dfe_done(src);
642 dictionary_garbage_collect(wevt_sources);
643
644 spinlock_unlock(&spinlock);
645
646 wevt_variant_cleanup(&property);
647 }
648
649 cleanup:
650 freez(channel);
651 EvtClose(hChannelEnum);
652 }