master
h 296 lines 9.35 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_WINDOWS_EVENTS_QUERY_H
4 #define NETDATA_WINDOWS_EVENTS_QUERY_H
5
6 #include "libnetdata/libnetdata.h"
7 #include "windows-events.h"
8
9 #define BATCH_NEXT_EVENT 500
10
11 typedef struct wevt_event {
12 uint64_t id; // EventRecordId (unique and sequential per channel)
13 uint8_t version;
14 uint8_t level; // The severity of event
15 uint8_t opcode; // we receive this as 8bit, but providers use 32bit
16 uint16_t event_id; // This is the template that defines the message to be shown
17 uint16_t task;
18 uint16_t qualifiers;
19 uint32_t process_id;
20 uint32_t thread_id;
21 uint64_t keywords; // Categorization of the event
22 ND_UUID provider;
23 ND_UUID activity_id;
24 ND_UUID related_activity_id;
25 nsec_t created_ns;
26 WEVT_PROVIDER_PLATFORM platform;
27 } WEVT_EVENT;
28
29 #define WEVT_EVENT_EMPTY (WEVT_EVENT){ .id = 0, .created_ns = 0, }
30
31 typedef struct {
32 EVT_VARIANT *data;
33 DWORD size;
34 DWORD used;
35 DWORD count;
36 } WEVT_VARIANT;
37
38 typedef struct {
39 WEVT_EVENT first_event;
40 WEVT_EVENT last_event;
41
42 uint64_t entries;
43 nsec_t duration_ns;
44 uint64_t size_bytes;
45 } EVT_RETENTION;
46
47 struct provider_meta_handle;
48
49 typedef enum __attribute__((packed)) {
50 WEVT_QUERY_BASIC = (1 << 0),
51 WEVT_QUERY_EXTENDED = (1 << 1),
52 WEVT_QUERY_EVENT_DATA = (1 << 2),
53 } WEVT_QUERY_TYPE;
54
55 #define WEVT_QUERY_RETENTION WEVT_QUERY_BASIC
56 #define WEVT_QUERY_NORMAL (WEVT_QUERY_BASIC | WEVT_QUERY_EXTENDED)
57 #define WEVT_QUERY_FTS (WEVT_QUERY_BASIC | WEVT_QUERY_EXTENDED | WEVT_QUERY_EVENT_DATA)
58
59 typedef struct wevt_log {
60 struct {
61 DWORD size;
62 DWORD used;
63 EVT_HANDLE hEvents[BATCH_NEXT_EVENT];
64 } batch;
65
66 EVT_HANDLE hEvent;
67 EVT_HANDLE hQuery;
68 EVT_HANDLE hRenderSystemContext;
69 EVT_HANDLE hRenderUserContext;
70 struct provider_meta_handle *provider;
71
72 WEVT_QUERY_TYPE type;
73
74 struct {
75 struct {
76 // temp buffer used for rendering event log messages
77 // never use directly
78 WEVT_VARIANT system;
79 WEVT_VARIANT user;
80 } raw;
81
82 // temp buffer used for fetching and converting UNICODE and UTF-8
83 // every string operation overwrites it, multiple times per event log entry
84 // it can be used within any function, for its own purposes,
85 // but never share between functions
86 TXT_UTF16 unicode;
87
88 // string attributes of the current event log entry
89 // valid until another event if fetched
90
91 // IMPORTANT:
92 // EVERY FIELD NEEDS ITS OWN BUFFER!
93 // the way facets work, all the field value pointers need to be valid
94 // until the entire row closes, so reusing a buffer for the same field
95 // actually copies the same value to all fields using the same buffer.
96
97 TXT_UTF8 channel;
98 TXT_UTF8 provider;
99 TXT_UTF8 computer;
100 TXT_UTF8 account;
101 TXT_UTF8 domain;
102 TXT_UTF8 sid;
103
104 TXT_UTF8 event; // the message to be shown to the user
105 TXT_UTF8 level;
106 TXT_UTF8 keywords;
107 TXT_UTF8 opcode;
108 TXT_UTF8 task;
109 TXT_UTF8 xml;
110
111 BUFFER *event_data;
112 } ops;
113
114 struct {
115 size_t event_count;
116 size_t failed_count;
117 } query_stats;
118
119 struct {
120 size_t queries_count;
121 size_t queries_failed;
122
123 size_t event_count;
124 size_t failed_count;
125 } log_stats;
126
127 } WEVT_LOG;
128
129 WEVT_LOG *wevt_openlog6(WEVT_QUERY_TYPE type);
130 void wevt_closelog6(WEVT_LOG *log);
131
132 bool wevt_channel_retention(WEVT_LOG *log, const wchar_t *channel, const wchar_t *query, EVT_RETENTION *retention);
133
134 bool wevt_query(WEVT_LOG *log, LPCWSTR channel, LPCWSTR query, EVT_QUERY_FLAGS direction);
135 void wevt_query_done(WEVT_LOG *log);
136
137 bool wevt_get_next_event(WEVT_LOG *log, WEVT_EVENT *ev);
138
139 bool EvtFormatMessage_utf16(
140 TXT_UTF16 *dst, EVT_HANDLE hMetadata, EVT_HANDLE hEvent, DWORD dwMessageId, EVT_FORMAT_MESSAGE_FLAGS flags);
141
142 bool EvtFormatMessage_Event_utf8(TXT_UTF16 *tmp, struct provider_meta_handle *p, EVT_HANDLE hEvent, TXT_UTF8 *dst);
143 bool EvtFormatMessage_Xml_utf8(TXT_UTF16 *tmp, struct provider_meta_handle *p, EVT_HANDLE hEvent, TXT_UTF8 *dst);
144
145 void evt_variant_to_buffer(BUFFER *b, EVT_VARIANT *ev, const char *separator);
146
147 static inline void wevt_variant_cleanup(WEVT_VARIANT *v) {
148 freez(v->data);
149 }
150
151 static inline void wevt_variant_resize(WEVT_VARIANT *v, size_t required_size) {
152 if(required_size < v->size)
153 return;
154
155 wevt_variant_cleanup(v);
156 v->size = txt_compute_new_size(v->size, required_size);
157 v->data = mallocz(v->size);
158 }
159
160 static inline void wevt_variant_count_from_used(WEVT_VARIANT *v) {
161 v->count = v->used / sizeof(*v->data);
162 }
163
164 static inline uint8_t wevt_field_get_uint8(EVT_VARIANT *ev) {
165 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull)
166 return 0;
167
168 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeByte);
169 return ev->ByteVal;
170 }
171
172 static inline uint16_t wevt_field_get_uint16(EVT_VARIANT *ev) {
173 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull)
174 return 0;
175
176 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeUInt16);
177 return ev->UInt16Val;
178 }
179
180 static inline uint32_t wevt_field_get_uint32(EVT_VARIANT *ev) {
181 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull)
182 return 0;
183
184 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeUInt32);
185 return ev->UInt32Val;
186 }
187
188 static inline uint64_t wevt_field_get_uint64(EVT_VARIANT *ev) {
189 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull)
190 return 0;
191
192 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeUInt64);
193 return ev->UInt64Val;
194 }
195
196 static inline uint64_t wevt_field_get_uint64_hex(EVT_VARIANT *ev) {
197 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull)
198 return 0;
199
200 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeHexInt64);
201 return ev->UInt64Val;
202 }
203
204 static inline bool wevt_field_get_string_utf8(EVT_VARIANT *ev, TXT_UTF8 *dst) {
205 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull) {
206 txt_utf8_empty(dst);
207 return false;
208 }
209
210 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeString);
211 return wchar_to_txt_utf8(dst, ev->StringVal, -1);
212 }
213
214 bool cached_sid_to_account_domain_sidstr(PSID sid, TXT_UTF8 *dst_account, TXT_UTF8 *dst_domain, TXT_UTF8 *dst_sid_str);
215 static inline bool wevt_field_get_sid(EVT_VARIANT *ev, TXT_UTF8 *dst_account, TXT_UTF8 *dst_domain, TXT_UTF8 *dst_sid_str) {
216 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull) {
217 txt_utf8_empty(dst_account);
218 txt_utf8_empty(dst_domain);
219 txt_utf8_empty(dst_sid_str);
220 return false;
221 }
222
223 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeSid);
224 return cached_sid_to_account_domain_sidstr(ev->SidVal, dst_account, dst_domain, dst_sid_str);
225 }
226
227 static inline uint64_t wevt_field_get_filetime_to_ns(EVT_VARIANT *ev) {
228 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull)
229 return 0;
230
231 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeFileTime);
232 return os_windows_ulonglong_to_unix_epoch_ns(ev->FileTimeVal);
233 }
234
235 static inline bool wevt_GUID_to_ND_UUID(ND_UUID *nd_uuid, const GUID *guid) {
236 if(guid && sizeof(GUID) == sizeof(ND_UUID)) {
237 memcpy(nd_uuid->uuid, guid, sizeof(ND_UUID));
238 return true;
239 }
240 else {
241 *nd_uuid = UUID_ZERO;
242 return false;
243 }
244 }
245
246 static inline bool wevt_get_uuid_by_type(EVT_VARIANT *ev, ND_UUID *dst) {
247 if((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeNull) {
248 wevt_GUID_to_ND_UUID(dst, NULL);
249 return false;
250 }
251
252 fatal_assert((ev->Type & EVT_VARIANT_TYPE_MASK) == EvtVarTypeGuid);
253 return wevt_GUID_to_ND_UUID(dst, ev->GuidVal);
254 }
255
256 // https://learn.microsoft.com/en-us/windows/win32/wes/defining-severity-levels
257 static inline bool is_valid_provider_level(uint64_t level, bool strict) {
258 if(strict)
259 // when checking if the name is provider independent
260 return level >= 16 && level <= 255;
261 else
262 // when checking acceptable values in provider manifests
263 return level <= 255;
264 }
265
266 // https://learn.microsoft.com/en-us/windows/win32/wes/defining-tasks-and-opcodes
267 static inline bool is_valid_provider_opcode(uint64_t opcode, bool strict) {
268 if(strict)
269 // when checking if the name is provider independent
270 return opcode >= 10 && opcode <= 239;
271 else
272 // when checking acceptable values in provider manifests
273 return opcode <= 255;
274 }
275
276 // https://learn.microsoft.com/en-us/windows/win32/wes/defining-tasks-and-opcodes
277 static inline bool is_valid_provider_task(uint64_t task, bool strict) {
278 if(strict)
279 // when checking if the name is provider independent
280 return task > 0 && task <= 0xFFFF;
281 else
282 // when checking acceptable values in provider manifests
283 return task <= 0xFFFF;
284 }
285
286 // https://learn.microsoft.com/en-us/windows/win32/wes/defining-keywords-used-to-classify-types-of-events
287 static inline bool is_valid_provider_keyword(uint64_t keyword, bool strict) {
288 if(strict)
289 // when checking if the name is provider independent
290 return keyword > 0 && keyword <= 0x0000FFFFFFFFFFFF;
291 else
292 // when checking acceptable values in provider manifests
293 return true;
294 }
295
296 #endif //NETDATA_WINDOWS_EVENTS_QUERY_H