summaryrefslogtreecommitdiffstats
path: root/src/fluent-bit/plugins/in_winlog/pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fluent-bit/plugins/in_winlog/pack.c')
-rw-r--r--src/fluent-bit/plugins/in_winlog/pack.c451
1 files changed, 451 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/in_winlog/pack.c b/src/fluent-bit/plugins/in_winlog/pack.c
new file mode 100644
index 000000000..4547d5514
--- /dev/null
+++ b/src/fluent-bit/plugins/in_winlog/pack.c
@@ -0,0 +1,451 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Fluent Bit
+ * ==========
+ * Copyright (C) 2015-2022 The Fluent Bit Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fluent-bit/flb_compat.h>
+#include <fluent-bit/flb_mem.h>
+#include <fluent-bit/flb_utils.h>
+#include <fluent-bit/flb_pack.h>
+#include <fluent-bit/flb_input_plugin.h>
+#include <msgpack.h>
+#include <sddl.h>
+#include <locale.h>
+#include "winlog.h"
+
+#define REGKEY_MAXLEN 256
+#define FMT_ISO8601 "%Y-%m-%d %H:%M:%S %z"
+#define FMT_EVTLOG L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\%S\\%s"
+#define FMT_EVTALT L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\Publishers\\%s"
+
+/* 127 is the max number of function params */
+#define PARAM_MAXNUM 127
+
+#define SRCNAME(evt) ((wchar_t *) ((char *) (evt) + sizeof(EVENTLOGRECORD)))
+#define BINDATA(evt) ((unsigned char *) (evt) + (evt)->DataOffset)
+
+static void pack_nullstr(msgpack_packer *mp_pck)
+{
+ msgpack_pack_str(mp_pck, 0);
+ msgpack_pack_str_body(mp_pck, "", 0);
+}
+
+static int pack_wstr(msgpack_packer *mp_pck, wchar_t *wstr, int use_ansi)
+{
+ int size;
+ char *buf;
+ UINT codePage = CP_UTF8;
+ if (use_ansi) {
+ codePage = CP_ACP;
+ }
+
+ /* Compute the buffer size first */
+ size = WideCharToMultiByte(codePage, 0, wstr, -1, NULL, 0, NULL, NULL);
+ if (size == 0) {
+ return -1;
+ }
+
+ buf = flb_malloc(size);
+ if (buf == NULL) {
+ flb_errno();
+ return -1;
+ }
+
+ /* Convert UTF-16 into UTF-8/System code Page encoding */
+ size = WideCharToMultiByte(codePage, 0, wstr, -1, buf, size, NULL, NULL);
+ if (size == 0) {
+ flb_free(buf);
+ return -1;
+ }
+
+ /* Pack buf except the trailing '\0' */
+ msgpack_pack_str(mp_pck, size - 1);
+ msgpack_pack_str_body(mp_pck, buf, size - 1);
+ flb_free(buf);
+ return 0;
+}
+
+static int pack_time(msgpack_packer *mp_pck, int time)
+{
+ size_t len;
+ struct tm tm;
+ char buf[64];
+ _locale_t locale;
+
+ if (_localtime32_s(&tm, &time)) {
+ flb_errno();
+ return -1;
+ }
+
+ locale = _get_current_locale();
+ if (locale == NULL) {
+ return -1;
+ }
+
+ len = _strftime_l(buf, 64, FMT_ISO8601, &tm, locale);
+ if (len == 0) {
+ flb_errno();
+ _free_locale(locale);
+ return -1;
+ }
+ _free_locale(locale);
+ msgpack_pack_str(mp_pck, len);
+ msgpack_pack_str_body(mp_pck, buf, len);
+
+ return 0;
+}
+
+static int pack_event_type(msgpack_packer *mp_pck, int type)
+{
+ switch (type) {
+ case EVENTLOG_SUCCESS:
+ msgpack_pack_str(mp_pck, 7);
+ msgpack_pack_str_body(mp_pck, "Success", 7);
+ break;
+ case EVENTLOG_INFORMATION_TYPE:
+ msgpack_pack_str(mp_pck, 11);
+ msgpack_pack_str_body(mp_pck, "Information", 11);
+ break;
+ case EVENTLOG_WARNING_TYPE:
+ msgpack_pack_str(mp_pck, 7);
+ msgpack_pack_str_body(mp_pck, "Warning", 7);
+ break;
+ case EVENTLOG_ERROR_TYPE:
+ msgpack_pack_str(mp_pck, 5);
+ msgpack_pack_str_body(mp_pck, "Error", 5);
+ break;
+ case EVENTLOG_AUDIT_SUCCESS:
+ msgpack_pack_str(mp_pck, 12);
+ msgpack_pack_str_body(mp_pck, "SuccessAudit", 12);
+ break;
+ case EVENTLOG_AUDIT_FAILURE:
+ msgpack_pack_str(mp_pck, 12);
+ msgpack_pack_str_body(mp_pck, "FailureAudit", 12);
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int pack_binary(msgpack_packer *mp_pck, unsigned char *bin, int len)
+{
+ const char *hex = "0123456789abcdef";
+ char *buf;
+ int size = len * 2;
+ int i;
+
+ if (len == 0) {
+ pack_nullstr(mp_pck);
+ return 0;
+ }
+
+ buf = flb_malloc(size);
+ if (buf == NULL) {
+ flb_errno();
+ return -1;
+ }
+
+ for (i = 0; i < len; i++) {
+ buf[2*i] = hex[bin[i] / 16];
+ buf[2*i+1] = hex[bin[i] % 16];
+ }
+ msgpack_pack_str(mp_pck, size);
+ msgpack_pack_str_body(mp_pck, buf, size);
+ flb_free(buf);
+ return 0;
+}
+
+static int pack_sid(msgpack_packer *mp_pck, PEVENTLOGRECORD evt,
+ struct winlog_config *ctx)
+{
+ size_t size;
+ char *buf;
+ char *sid = (char *) evt + evt->UserSidOffset;
+
+ if (evt->UserSidLength == 0) {
+ pack_nullstr(mp_pck);
+ return 0;
+ }
+
+ if (!ConvertSidToStringSidA(sid, &buf)) {
+ flb_plg_error(ctx->ins, "fail to convert SID: %i", GetLastError());
+ return -1;
+ }
+
+ size = strlen(buf);
+ msgpack_pack_str(mp_pck, size);
+ msgpack_pack_str_body(mp_pck, buf, size);
+
+ LocalFree(buf);
+ return 0;
+}
+
+static wchar_t *read_registry(HKEY hkey, wchar_t *key, wchar_t *val)
+{
+ int ret;
+ int size;
+ wchar_t *buf;
+ unsigned int flags = RRF_RT_REG_EXPAND_SZ | RRF_RT_REG_SZ;
+
+ /* Get the buffer size first */
+ ret = RegGetValueW(hkey, key, val, flags, NULL, NULL, &size);
+ if (ret != ERROR_SUCCESS) {
+ return NULL;
+ }
+
+ buf = flb_malloc(size);
+ if (buf == NULL) {
+ flb_errno();
+ return NULL;
+ }
+
+ /* Read data into buffer */
+ ret = RegGetValueW(hkey, key, val, flags, NULL, buf, &size);
+ if (ret != ERROR_SUCCESS) {
+ flb_free(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+static wchar_t *query_guid(wchar_t *guid)
+{
+ int ret;
+ wchar_t key[REGKEY_MAXLEN];
+
+ ret = swprintf_s(key, REGKEY_MAXLEN, FMT_EVTALT, guid);
+ if (ret == -1) {
+ flb_errno();
+ return NULL;
+ }
+
+ return read_registry(HKEY_LOCAL_MACHINE, key, L"MessageFileName");
+}
+
+static int pack_message(msgpack_packer *mp_pck, PEVENTLOGRECORD evt,
+ struct winlog_channel *ch, struct winlog_config *ctx)
+{
+ int ret;
+ int i;
+ HMODULE hfile;
+ wchar_t key[REGKEY_MAXLEN];
+ wchar_t *msg;
+ wchar_t *paths;
+ wchar_t *path;
+ wchar_t *guid;
+ wchar_t *state;
+ wchar_t *tmp;
+ DWORD_PTR *args = NULL;
+
+ ret = swprintf_s(key, REGKEY_MAXLEN, FMT_EVTLOG, ch->name, SRCNAME(evt));
+ if (ret == -1) {
+ flb_errno();
+ return -1;
+ }
+
+ guid = read_registry(HKEY_LOCAL_MACHINE, key, L"ProviderGuid");
+ if (guid) {
+ paths = query_guid(guid);
+ flb_free(guid);
+ }
+ else {
+ paths = read_registry(HKEY_LOCAL_MACHINE, key, L"EventMessageFile");
+ }
+
+ if (paths == NULL) {
+ return -1;
+ }
+
+ if (evt->NumStrings) {
+ args = flb_calloc(PARAM_MAXNUM, sizeof(DWORD_PTR));
+ if (args == NULL) {
+ flb_errno();
+ flb_free(paths);
+ return -1;
+ }
+
+ tmp = (wchar_t *) ((char *) evt + evt->StringOffset);
+ for (i = 0; i < evt->NumStrings; i++) {
+ args[i] = (DWORD_PTR) tmp;
+ tmp += wcslen(tmp) + 1;
+ }
+ }
+
+ path = paths;
+ wcstok_s(path, L";", &state);
+ while (path) {
+ hfile = LoadLibraryExW(path, NULL, LOAD_LIBRARY_AS_DATAFILE);
+ if (hfile == NULL) {
+ path = wcstok_s(NULL , L";", &state);
+ continue;
+ }
+
+ ret = FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ hfile, /* lpSource */
+ evt->EventID, /* dwMessageId */
+ 0, /* dwLanguageId */
+ (LPWSTR) &msg,/* lpBuffer */
+ 0, /* nSize */
+ (va_list *) args);
+ if (ret > 0) {
+ ret = pack_wstr(mp_pck, msg, ctx->use_ansi);
+ LocalFree(msg);
+ FreeLibrary(hfile);
+ flb_free(paths);
+ flb_free(args);
+ return ret;
+ }
+ FreeLibrary(hfile);
+ path = wcstok_s(NULL , L";", &state);
+ }
+
+ flb_free(paths);
+ flb_free(args);
+ return -1;
+}
+
+static void pack_strings(msgpack_packer *mp_pck, PEVENTLOGRECORD evt, int use_ansi)
+{
+ int i;
+ int len;
+ wchar_t *wstr = (wchar_t *) ((char *) evt + evt->StringOffset);
+
+ msgpack_pack_array(mp_pck, evt->NumStrings);
+
+ for (i = 0; i < evt->NumStrings; i++) {
+ if (pack_wstr(mp_pck, wstr, use_ansi)) {
+ pack_nullstr(mp_pck);
+ }
+ wstr += wcslen(wstr) + 1;
+ }
+}
+
+void winlog_pack_event(msgpack_packer *mp_pck, PEVENTLOGRECORD evt,
+ struct winlog_channel *ch, struct winlog_config *ctx)
+{
+ wchar_t *source_name = SRCNAME(evt);
+ wchar_t *computer_name = source_name + wcslen(source_name) + 1;
+ size_t len;
+ int count = 13;
+
+ if (ctx->string_inserts) {
+ count++;
+ }
+
+ msgpack_pack_array(mp_pck, 2);
+ flb_pack_time_now(mp_pck);
+
+ msgpack_pack_map(mp_pck, count);
+
+ /* RecordNumber */
+ msgpack_pack_str(mp_pck, 12);
+ msgpack_pack_str_body(mp_pck, "RecordNumber", 12);
+ msgpack_pack_uint32(mp_pck, evt->RecordNumber);
+
+ /* TimeGenerated */
+ msgpack_pack_str(mp_pck, 13);
+ msgpack_pack_str_body(mp_pck, "TimeGenerated", 13);
+ if (pack_time(mp_pck, evt->TimeGenerated)) {
+ flb_plg_error(ctx->ins, "invalid TimeGenerated %i", evt->TimeGenerated);
+ pack_nullstr(mp_pck);
+ }
+
+ /* TimeWritten */
+ msgpack_pack_str(mp_pck, 11);
+ msgpack_pack_str_body(mp_pck, "TimeWritten", 11);
+ if (pack_time(mp_pck, evt->TimeWritten)) {
+ flb_plg_error(ctx->ins, "invalid TimeWritten %i", evt->TimeWritten);
+ pack_nullstr(mp_pck);
+ }
+
+ /* EventId */
+ msgpack_pack_str(mp_pck, 7);
+ msgpack_pack_str_body(mp_pck, "EventID", 7);
+ msgpack_pack_uint16(mp_pck, evt->EventID & 0xffff);
+
+ /* Qualifiers */
+ msgpack_pack_str(mp_pck, 10);
+ msgpack_pack_str_body(mp_pck, "Qualifiers", 10);
+ msgpack_pack_uint16(mp_pck, evt->EventID >> 16);
+
+ /* EventType */
+ msgpack_pack_str(mp_pck, 9);
+ msgpack_pack_str_body(mp_pck, "EventType", 9);
+ if (pack_event_type(mp_pck, evt->EventType)) {
+ flb_plg_error(ctx->ins, "invalid EventType %i", evt->EventType);
+ pack_nullstr(mp_pck);
+ }
+
+ /* EventCategory */
+ msgpack_pack_str(mp_pck, 13);
+ msgpack_pack_str_body(mp_pck, "EventCategory", 13);
+ msgpack_pack_uint16(mp_pck, evt->EventCategory);
+
+ /* Channel */
+ len = strlen(ch->name);
+ msgpack_pack_str(mp_pck, 7);
+ msgpack_pack_str_body(mp_pck, "Channel", 7);
+ msgpack_pack_str(mp_pck, len);
+ msgpack_pack_str_body(mp_pck, ch->name, len);
+
+ /* Source Name */
+ msgpack_pack_str(mp_pck, 10);
+ msgpack_pack_str_body(mp_pck, "SourceName", 10);
+ if (pack_wstr(mp_pck, source_name, ctx->use_ansi)) {
+ flb_plg_error(ctx->ins, "invalid SourceName '%ls'", source_name);
+ pack_nullstr(mp_pck);
+ }
+
+ /* Computer Name */
+ msgpack_pack_str(mp_pck, 12);
+ msgpack_pack_str_body(mp_pck, "ComputerName", 12);
+ if (pack_wstr(mp_pck, computer_name, ctx->use_ansi)) {
+ flb_plg_error(ctx->ins, "invalid ComputerName '%ls'", computer_name);
+ pack_nullstr(mp_pck);
+ }
+
+ /* Event-specific Data */
+ msgpack_pack_str(mp_pck, 4);
+ msgpack_pack_str_body(mp_pck, "Data", 4);
+ if (pack_binary(mp_pck, BINDATA(evt), evt->DataLength)) {
+ pack_nullstr(mp_pck);
+ }
+
+ /* Sid */
+ msgpack_pack_str(mp_pck, 3);
+ msgpack_pack_str_body(mp_pck, "Sid", 3);
+ if (pack_sid(mp_pck, evt, ctx)) {
+ pack_nullstr(mp_pck);
+ }
+
+ /* Message */
+ msgpack_pack_str(mp_pck, 7);
+ msgpack_pack_str_body(mp_pck, "Message", 7);
+ if (pack_message(mp_pck, evt, ch, ctx)) {
+ pack_nullstr(mp_pck);
+ }
+
+ /* StringInserts (optional) */
+ if (ctx->string_inserts) {
+ msgpack_pack_str(mp_pck, 13);
+ msgpack_pack_str_body(mp_pck, "StringInserts", 13);
+ pack_strings(mp_pck, evt, ctx->use_ansi);
+ }
+}