* Copyright (c) 2017-2022 Google, Inc. All rights reserved.
* Copyright (c) 2003-2009 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include "../globals.h"
#include <windows.h>
#include <tchar.h>
#include "../utils.h"
#include "events.h"
#include "ntdll.h"
#define NONCE_LENGTH 20
#define MAX_MESSAGE_SIZE 1024
typedef struct eventlog_state_t {
HANDLE eventlog_pipe;
HANDLE eventlog_completion;
uint message_seq;
char nonce[NONCE_LENGTH];
mutex_t eventlog_mutex;
* all of whom protect them with the above lock, this structure is single
* instance static anyways so not wasting much memory doing it this way */
char outbuf[MAX_MESSAGE_SIZE];
size_t outlen;
char buf[MAX_MESSAGE_SIZE];
int request_length;
} eventlog_state_t;
static void
os_eventlog(syslog_event_type_t priority, uint message_id, uint substitutions_num,
char **arguments, size_t size_data, char *raw_data);
* This enables administrators to control the size of the log file,
* and we can attach SACLs for security purposes, without affecting other applications.
*/
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Araksha]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Araksha\DynamoRIO]
"TypesSupported"=dword:00000007
"EventMessageFile"="C:\\cygwin\\home\\vlk\\exports\\x86_win32_dbg\\dynamorio.dll"
*/
static int
set_event_source_registry_values()
{
int res;
HANDLE heventsource = reg_open_key(L_EVENT_SOURCE_KEY, KEY_SET_VALUE);
char *message_file = get_dynamorio_library_path();
wchar_t wide_message_file[MAXIMUM_PATH];
if (!heventsource) {
return 0;
}
ASSERT(message_file && strlen(message_file) < MAXIMUM_PATH);
_snwprintf(wide_message_file, MAXIMUM_PATH, L"%S", message_file);
NULL_TERMINATE_BUFFER(wide_message_file);
res = reg_set_dword_key_value(heventsource,
L"TypesSupported",
EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
EVENTLOG_INFORMATION_TYPE);
res |= reg_set_dword_key_value(heventsource,
L"CategoryCount",
0);
system variable that can be resolved at the time of use of the
entry. For example: EventMessageFile="%WINDIR%\\dynamorio.dll"
*/
res |= reg_set_key_value(heventsource, L"EventMessageFile",
* a separate file) */
wide_message_file);
res |= reg_set_key_value(heventsource, L"CategoryMessageFile", wide_message_file);
DisplayNameFile
DisplayNameID
ParameterMessageFile
*/
reg_close_key(heventsource);
return 1;
}
static int
init_registry_source(void)
{
static int initialized = 0;
if (!initialized) {
HANDLE heventsource = reg_open_key(L_EVENT_SOURCE_KEY, KEY_READ | KEY_WRITE);
HANDLE heventlogroot = 0;
HANDLE heventlog = 0;
if (!heventsource) {
heventlog = reg_open_key(L_EVENT_LOG_KEY, KEY_READ | KEY_WRITE);
if (!heventlog) {
heventlogroot =
reg_open_key(L_EVENTLOG_REGISTRY_KEY, KEY_READ | KEY_WRITE);
if (!heventlogroot) {
LOG(GLOBAL, LOG_TOP, 1,
"WARNING: Registration failure. Could not open root %ls.",
L_EVENTLOG_REGISTRY_KEY);
return 0;
}
heventlog =
reg_create_key(heventlogroot, L_EVENT_LOG_NAME, KEY_ALL_ACCESS);
}
if (!heventlog) {
LOG(GLOBAL, LOG_TOP, 1, "WARNING: Could not create event log key %s.",
EVENTLOG_NAME);
return 0;
}
* logic simple we take minimal here
*/
heventsource =
reg_create_key(heventlog, L_EVENT_SOURCE_NAME, KEY_QUERY_VALUE);
if (heventlog) {
reg_close_key(heventlog);
}
if (heventlogroot) {
reg_close_key(heventlogroot);
}
}
if (!heventsource) {
LOG(GLOBAL, LOG_TOP, 1, "WARNING: Could not create event source key %s.",
EVENTSOURCE_NAME);
return 0;
}
reg_close_key(heventsource);
initialized = set_event_source_registry_values();
}
return initialized;
}
#define MAX_SYSLOG_ARGS 6
void
os_syslog(syslog_event_type_t priority, uint message_id, uint substitutions_num,
va_list vargs)
{
uint arg;
char *arg_arr[MAX_SYSLOG_ARGS];
char *other_data = "";
size_t size_data = strlen(other_data);
ASSERT(substitutions_num < MAX_SYSLOG_ARGS);
for (arg = 0; arg < substitutions_num; arg++) {
arg_arr[arg] = va_arg(vargs, char *);
}
* checking the mask and synchronizing the options
*/
os_eventlog(priority, message_id, substitutions_num, arg_arr, size_data, other_data);
}
p should point to the current position in the string appended to
pend points to the first location after the end of the buffer */
#define FIELD(p, pend, type, val) \
do { \
if (!(p) || (p) + sizeof(type) > (pend)) \
return 0; \
*(type *)(p) = (type)(val); \
(p) += sizeof(type); \
} while (0)
#define VARFIELD(pp, pend, val, len) \
do { \
if (!(*(pp)) || (*(pp)) + (len) > (pend)) \
return 0; \
memcpy((*(pp)), (val), (len)); \
*(pp) += (len); \
} while (0)
#define PADDING(pp, pend, len, boundary) \
do { \
int skip = (int)PAD((len), (boundary)); \
if (!(*(pp)) || (*(pp)) + (skip) > (pend)) \
return 0; \
while (skip--) \
*(*(pp))++ = '\0'; \
} while (0)
CHECK: Is this a documented M$ string representation?
It seems like there is a lot of redundancy in the encoding,
but it maybe useful in later reincarnations of the message.
This is in fact a plain UNICODE_STRING.
*/
static inline char *
append_string(char **pp , char *pend, char *str)
{
size_t length = strlen(str) + 1;
WORD len;
ASSERT_TRUNCATE(len, ushort, length);
len = (WORD)length;
FIELD(*pp, pend, WORD, len - 1);
FIELD(*pp, pend, WORD, len);
FIELD(*pp, pend, void *, str);
FIELD(*pp, pend, DWORD, len);
VARFIELD(pp, pend, str, len);
PADDING(pp, pend, len, sizeof(DWORD));
return *pp;
}
#define HEADER_SIZE 24
#define HEADER_OFFSET 28
static inline char *
prepend_header(char *p, char *pend, char *header, int length, int sequence, DWORD unknown)
{
if (!p)
return NULL;
VARFIELD(&p, pend, header, 8);
FIELD(p, pend, DWORD, length);
FIELD(p, pend, DWORD, sequence);
FIELD(p, pend, DWORD, length - HEADER_SIZE);
FIELD(p, pend, DWORD, unknown);
FIELD(p, pend, DWORD, 0);
return p;
}
#define EVENTLOG "\20\0\0\0"
* triggers a false positive in McAfee. That's why that byte is set to
* RPC_VERSION_BOGUS and replaced with RPC_VERSION_5 before it is used.
* See case 5002 for more details.*/
#define RPC_VERSION_BOGUS "\xFF"
#define RPC_VERSION_5 '\x05'
if I break the protocol then its hello request starts with H\0\0\0\5... */
static char hello_message[] =
RPC_VERSION_BOGUS
* because of a false positive in McAfee. See case 5002 */
"\x00"
"\x0B"
"\x03"
"\x10\x00\x00\x00"
"\x48\x00"
"\x00\x00"
"\x01\x00\x00\x00"
"\xB8\x10"
"\xB8\x10"
"\x00\x00\x00\x00"
"\x01\x00\x00\x00"
"\x00\x00"
"\x01\x00"
"\xDC\x3F\x27\x82\x2A\xE3\xC3\x18"
"\x3F\x78\x82\x79\x29\xDC\x23\xEA"
"\x00\x00"
"\x00\x00"
"\x04\x5D\x88\x8A\xEB\x1C\xC9\x11"
"\x9F\xE8\x08\x00\x2B\x10\x48\x60"
"\x02\x00\x00\x00";
*
* // DCE RPC response, decoded by Ethereal
* "\x05" // Version: 5
* "\x00" // Version (minor): 0
* "\x0C" // Packet type: Bind_ack (12)
* "\x03" // Packet Flags: 0x03
* "\x10\x00\x00\x00" // Data Representation: 10000000
* "\x44\x00" // Frag Length: 68
* "\x00\x00" // Auth Length: 0
* "\x01\x00\x00\x00" // Call ID: 1
* "\xB8\x10" // Max Xmit Frag: 4280
* "\xB8\x10" // Max Recv Frag: 4280
* "\x54\x13\x01\x00" // Assoc Group: 0x00011354 (may vary)
* "\x0D\x00" // Scndry Addr len: 13
* "\\PIPE\\ntsvcs\x00" // Scndry Addr: \PIPE\ntsvcs
* "\x00" // for alignment? (gets to 4 byte alignment)
* "\x01\x00\x00\x00" // Num results: 1
* "\x00\x00\x00\x00" // Ack result: Acceptance (0)
* "\x04\x5D\x88\x8A\xEB\x1C\xC9\x11" // Transfer Syntax:
* "\x9F\xE8\x08\x00\x2B\x10\x48\x60" // 8a885d04-1ceb-11c9-9fe8-08002b104860
* "\x02\x00\x00\x00"
*
* Note that the hello response has changed slightly in Vista (from hand
* comparison) :
* ...
* ! "\x0F\x00" // Scndry Addr len: 15
* ! "\\PIPE\\eventlog\x00" // Scndry Addr: \PIPE\eventlog
* ! "\x00\x73\x00" // for alignment? (gets to 4 byte alignment)
* ...
*/
#define REPORT "\5\0\0\3"
#define REGISTER_UNKNOWN_HEADER *(int *)"\0\0\17\0"
#define REPORT_UNKNOWN_HEADER *(int *)"\0\0\22\0"
#define DEREGISTER_UNKNOWN_HEADER *(int *)"\0\0\3\0"
then we will be able to get messages out even before the local services are started! */
#define EVENTLOG_NAMED_PIPE L"\\??\\PIPE\\EVENTLOG"
#ifdef DEBUG
# define PRINT(form, arg) LOG(GLOBAL, LOG_TOP, 3, form, arg)
static void
print_buffer_as_bytes(unsigned char *buf, size_t len)
{
size_t i;
int nonprint = 0;
PRINT("%s", "\"");
for (i = 0; i < len; i++) {
if (isdigit(buf[i]) && nonprint) {
PRINT("%s", "\"\"");
}
if (buf[i] == '\\')
PRINT("%s", "\\");
if (isprint(buf[i])) {
PRINT("%c", buf[i]);
nonprint = 0;
} else {
PRINT("\\%o", buf[i]);
nonprint = 1;
}
}
PRINT("%s", "\"");
PRINT("%s", ";\n");
}
# undef PRINT
#endif
#define HELLO_RESPONSE_LENGTH (get_os_version() < WINDOWS_VERSION_VISTA ? 68U : 72U)
#define REGISTER_RESPONSE_LENGTH 48
#define REPORT_RESPONSE_LENGTH 36
int
eventlog_register(eventlog_state_t *evconnection)
{
char *p;
ASSERT(evconnection != NULL);
ASSERT_OWN_MUTEX(true, &evconnection->eventlog_mutex);
evconnection->eventlog_completion = create_iocompletion();
evconnection->eventlog_pipe =
open_pipe(EVENTLOG_NAMED_PIPE, evconnection->eventlog_completion);
if (!evconnection->eventlog_pipe) {
LOG(GLOBAL, LOG_TOP, 1, "Couldn't open EVENTLOG\n");
goto failed_to_register;
}
* is called before eventlog_init()
*/
SELF_UNPROTECT_DATASEC(DATASEC_RARELY_PROT);
* to a bogus value to avoid a McAfee false positive. See case 5002. */
hello_message[0] = RPC_VERSION_5;
SELF_PROTECT_DATASEC(DATASEC_RARELY_PROT);
evconnection->request_length = sizeof(hello_message) - 1;
evconnection->outlen =
nt_pipe_transceive(evconnection->eventlog_pipe, hello_message,
evconnection->request_length, evconnection->outbuf,
sizeof(evconnection->outbuf), DYNAMO_OPTION(eventlog_timeout));
DOLOG(2, LOG_TOP, {
LOG(GLOBAL, LOG_TOP, 3, "inlen= %d; outlen = " SZFMT "\"\n",
evconnection->request_length, evconnection->outlen);
LOG(GLOBAL, LOG_TOP, 3, "char hello[] = ");
print_buffer_as_bytes((byte *)hello_message, evconnection->request_length);
LOG(GLOBAL, LOG_TOP, 3, "char hello_resp[] = ");
print_buffer_as_bytes((byte *)evconnection->outbuf, evconnection->outlen);
});
if (evconnection->outlen != HELLO_RESPONSE_LENGTH) {
LOG(GLOBAL, LOG_TOP, 1,
"eventlog_register: Mismatch on HELLO_RESPONSE outlen=" SZFMT "\n",
evconnection->outlen);
goto failed_to_register;
}
evconnection->message_seq = 1;
p = evconnection->buf + HEADER_OFFSET;
append_string(&p, evconnection->buf + sizeof(evconnection->buf), EVENTSOURCE_NAME);
#define REPORT_IN_LOG "Application"
since the source is registered only under EVENTLOG_NAME subtree,
TODO: yet we may want to have our own event file, and it may matter then.*/
append_string(&p, evconnection->buf + sizeof(evconnection->buf), REPORT_IN_LOG);
VARFIELD(&p, evconnection->buf + sizeof(evconnection->buf), "\1\0\0\0\1\0\0\0",
8);
ASSERT(p);
IF_X64(ASSERT_TRUNCATE(evconnection->request_length, int, p - evconnection->buf));
evconnection->request_length = (int)(p - evconnection->buf);
p = prepend_header(evconnection->buf, evconnection->buf + sizeof(evconnection->buf),
REPORT EVENTLOG, evconnection->request_length,
evconnection->message_seq, REGISTER_UNKNOWN_HEADER);
ASSERT(p);
evconnection->message_seq++;
evconnection->outlen =
nt_pipe_transceive(evconnection->eventlog_pipe, evconnection->buf,
evconnection->request_length, evconnection->outbuf,
sizeof(evconnection->outbuf), DYNAMO_OPTION(eventlog_timeout));
DOLOG(2, LOG_TOP, {
LOG(GLOBAL, LOG_TOP, 3, "inlen= %d; outlen = " SZFMT "\n",
evconnection->request_length, evconnection->outlen);
LOG(GLOBAL, LOG_TOP, 3, "char reg[] = ");
print_buffer_as_bytes((byte *)evconnection->buf, evconnection->request_length);
LOG(GLOBAL, LOG_TOP, 3, "char reg_resp[] = ");
print_buffer_as_bytes((byte *)evconnection->outbuf, evconnection->outlen);
});
if (evconnection->outlen != REGISTER_RESPONSE_LENGTH) {
LOG(GLOBAL, LOG_TOP, 1,
"eventlog_register: Mismatch on REGISTER_RESPONSE outlen=" SZFMT "\n",
evconnection->outlen);
goto failed_to_register;
}
memcpy(evconnection->nonce, &evconnection->outbuf[HEADER_OFFSET], NONCE_LENGTH);
return 1;
failed_to_register:
if (evconnection->eventlog_completion) {
close_handle(evconnection->eventlog_completion);
evconnection->eventlog_completion = 0;
}
if (evconnection->eventlog_pipe) {
close_file(evconnection->eventlog_pipe);
evconnection->eventlog_pipe = 0;
}
return 0;
}
char *
get_computer_name()
{
static char computer_name[MAX_COMPUTERNAME_LENGTH + 5];
if (!computer_name[0]) {
char buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
sizeof(wchar_t) * (MAX_COMPUTERNAME_LENGTH + 1)];
KEY_VALUE_PARTIAL_INFORMATION *kvpi = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
if (reg_query_value(L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\ComputerName\\ActiveComputerName",
L"ComputerName", KeyValuePartialInformation, kvpi,
sizeof(buf), 0) == REG_QUERY_SUCCESS) {
* starts up, and our first event may be post-init as well once
* the eventlog service is up. So we may need to unprotect
* .data here.
*/
if (dynamo_initialized) {
ASSERT(check_should_be_protected(DATASEC_RARELY_PROT));
SELF_UNPROTECT_DATASEC(DATASEC_RARELY_PROT);
} else
ASSERT(!DATASEC_PROTECTED(DATASEC_RARELY_PROT));
snprintf(computer_name, sizeof(computer_name) - 1, "%*ls",
kvpi->DataLength / sizeof(wchar_t) - 1, (wchar_t *)kvpi->Data);
if (dynamo_initialized)
SELF_PROTECT_DATASEC(DATASEC_RARELY_PROT);
}
}
return computer_name;
}
static int
eventlog_report(eventlog_state_t *evconnection, WORD severity, WORD category,
DWORD message_id, void *pSID, uint substitutions_num,
size_t raw_data_size, char **substitutions, char *raw_data)
{
char *p;
uint i;
ULONG sec = query_time_seconds();
ASSERT_OWN_MUTEX(true, &evconnection->eventlog_mutex);
p = evconnection->buf + HEADER_OFFSET;
VARFIELD(&p, evconnection->buf + sizeof(evconnection->buf), evconnection->nonce,
NONCE_LENGTH);
p -= 4;
FIELD(p, evconnection->buf + sizeof(evconnection->buf), DWORD, sec);
FIELD(p, evconnection->buf + sizeof(evconnection->buf), WORD, severity);
FIELD(p, evconnection->buf + sizeof(evconnection->buf), WORD, category);
FIELD(p, evconnection->buf + sizeof(evconnection->buf), DWORD, message_id);
FIELD(p, evconnection->buf + sizeof(evconnection->buf), WORD, substitutions_num);
* with the following broken code we've been writing
* $SG23701 DB 0dbH, 'w', 00H
* which is 0x77db.
* We should either keep using the magic value that has worked,
* or figure out what should have really been written there.
*/
FIELD(p, evconnection->buf + sizeof(evconnection->buf), WORD,
*(WORD *)"\333w");
IF_X64(ASSERT(CHECK_TRUNCATE_TYPE_uint(raw_data_size)));
FIELD(p, evconnection->buf + sizeof(evconnection->buf), DWORD, (DWORD)raw_data_size);
append_string(&p, evconnection->buf + sizeof(evconnection->buf), get_computer_name());
IF_X64(ASSERT_NOT_TESTED());
FIELD(p, evconnection->buf + sizeof(evconnection->buf), void *, pSID);
if (pSID) {
}
FIELD(p, evconnection->buf + sizeof(evconnection->buf), DWORD,
*(DWORD *)"\230y\23\0");
FIELD(p, evconnection->buf + sizeof(evconnection->buf), DWORD, substitutions_num);
for (i = 0; i < substitutions_num; i++) {
FIELD(p, evconnection->buf + sizeof(evconnection->buf), DWORD,
*(DWORD *)"\210y\23\0");
}
for (i = 0; i < substitutions_num; i++) {
append_string(&p, evconnection->buf + sizeof(evconnection->buf),
substitutions[i]);
}
IF_X64(ASSERT_NOT_TESTED());
FIELD(p, evconnection->buf + sizeof(evconnection->buf), char *, raw_data);
FIELD(p, evconnection->buf + sizeof(evconnection->buf), DWORD, raw_data_size);
LOG(GLOBAL, LOG_TOP, 3, "datalen=%d data= %*s\n", raw_data_size, raw_data_size,
raw_data);
if (raw_data_size) {
VARFIELD(&p, evconnection->buf + sizeof(evconnection->buf), raw_data,
raw_data_size);
PADDING(&p, evconnection->buf + sizeof(evconnection->buf), raw_data_size,
sizeof(DWORD));
}
It seems like the server can handle more but not less padding */
VARFIELD(&p, evconnection->buf + sizeof(evconnection->buf), "\0\0\0\0", 4);
VARFIELD(&p, evconnection->buf + sizeof(evconnection->buf), "\0\0\0\0", 4);
VARFIELD(&p, evconnection->buf + sizeof(evconnection->buf), "\0\0\0\0", 4);
IF_X64(ASSERT_TRUNCATE(evconnection->request_length, int, p - evconnection->buf));
evconnection->request_length = (int)(p - evconnection->buf);
p = prepend_header(evconnection->buf, evconnection->buf + sizeof(evconnection->buf),
REPORT EVENTLOG, evconnection->request_length,
evconnection->message_seq, REPORT_UNKNOWN_HEADER);
ASSERT(p);
evconnection->message_seq++;
evconnection->outlen =
nt_pipe_transceive(evconnection->eventlog_pipe, evconnection->buf,
evconnection->request_length, evconnection->outbuf,
sizeof(evconnection->outbuf), DYNAMO_OPTION(eventlog_timeout));
DOLOG(2, LOG_TOP, {
LOG(GLOBAL, LOG_TOP, 3, "inlen= %d; outlen = " SZFMT "\n",
evconnection->request_length, evconnection->outlen);
LOG(GLOBAL, LOG_TOP, 3, "char report[] = ");
print_buffer_as_bytes((byte *)evconnection->buf, evconnection->request_length);
LOG(GLOBAL, LOG_TOP, 3, "char report_resp[] = ");
print_buffer_as_bytes((byte *)evconnection->outbuf, evconnection->outlen);
if (evconnection->outbuf[2] == '\3') {
LOG(GLOBAL, LOG_TOP, 2, "//5 0 3 3 is bad news\n");
}
});
if (evconnection->outlen != REPORT_RESPONSE_LENGTH) {
LOG(GLOBAL, LOG_TOP, 1,
"WARNING: Mismatch on REPORT_RESPONSE outlen=:" SZFMT "\n",
evconnection->outlen);
return 0;
}
return 1;
}
uint
eventlog_deregister(eventlog_state_t *evconnection)
{
char *p;
int res;
ASSERT_OWN_MUTEX(true, &evconnection->eventlog_mutex);
p = evconnection->buf + HEADER_OFFSET;
VARFIELD(&p, evconnection->buf + sizeof(evconnection->buf), evconnection->nonce,
NONCE_LENGTH);
IF_X64(ASSERT_TRUNCATE(evconnection->request_length, int, p - evconnection->buf));
evconnection->request_length = (int)(p - evconnection->buf);
p = prepend_header(evconnection->buf, evconnection->buf + sizeof(evconnection->buf),
REPORT EVENTLOG, evconnection->request_length,
evconnection->message_seq, DEREGISTER_UNKNOWN_HEADER);
ASSERT(p);
evconnection->outlen =
nt_pipe_transceive(evconnection->eventlog_pipe, evconnection->buf,
evconnection->request_length, evconnection->outbuf,
sizeof(evconnection->outbuf), DYNAMO_OPTION(eventlog_timeout));
if (evconnection->outlen != REGISTER_RESPONSE_LENGTH) {
LOG(GLOBAL, LOG_TOP, 1,
"WARNING: Mismatch on DEREGISTER_RESPONSE outlen=" SZFMT "\n",
evconnection->outlen);
}
if (evconnection->eventlog_completion) {
close_handle(evconnection->eventlog_completion);
evconnection->eventlog_completion = 0;
}
ASSERT(evconnection->eventlog_pipe);
res = close_file(evconnection->eventlog_pipe);
evconnection->eventlog_pipe = 0;
return res;
}
* at unexpected times we cache session state across messages and across
* threads */
static eventlog_state_t *shared_eventlog_connection;
static eventlog_state_t temp_shared_eventlog_connection;
static void
eventlog_alloc()
{
* Sometimes eventlog registration fails until post-init (for lsass, e.g.)
* but the alloc should happen during init regardless.
*/
ASSERT(!dynamo_initialized);
if (shared_eventlog_connection != NULL &&
shared_eventlog_connection != &temp_shared_eventlog_connection) {
return;
}
if (!dynamo_heap_initialized) {
* eventlog_init() will call this routine again and we'll copy
* to the heap (else condition below).
*/
ASSERT(shared_eventlog_connection == NULL);
shared_eventlog_connection = &temp_shared_eventlog_connection;
ASSIGN_INIT_LOCK_FREE(shared_eventlog_connection->eventlog_mutex, eventlog_mutex);
} else {
eventlog_state_t *alloc =
HEAP_TYPE_ALLOC(GLOBAL_DCONTEXT, eventlog_state_t, ACCT_OTHER, PROTECTED);
if (shared_eventlog_connection == &temp_shared_eventlog_connection) {
memcpy(alloc, &temp_shared_eventlog_connection,
sizeof(temp_shared_eventlog_connection));
} else {
memset(alloc, 0, sizeof(*shared_eventlog_connection));
ASSIGN_INIT_LOCK_FREE(alloc->eventlog_mutex, eventlog_mutex);
}
shared_eventlog_connection = alloc;
}
}
void
eventlog_init()
{
uint res;
whether to report to the system log on this run, decrement it if present */
* while we are still single threaded */
get_computer_name();
if (DYNAMO_OPTION(syslog_init) &&
!init_registry_source()) {
DOLOG_ONCE(1, LOG_TOP, {
LOG(GLOBAL, LOG_TOP, 1,
"WARNING: Could not add the event source registry keys."
"Events are reported with no message files.\n");
});
}
eventlog_alloc();
d_r_mutex_lock(&shared_eventlog_connection->eventlog_mutex);
if (!shared_eventlog_connection->eventlog_pipe) {
res = eventlog_register(shared_eventlog_connection);
if (!res) {
LOG(GLOBAL, LOG_TOP, 1, "WARNING: Could not register event source.\n");
}
}
d_r_mutex_unlock(&shared_eventlog_connection->eventlog_mutex);
}
void
eventlog_fast_exit(void)
{
uint res = 1;
d_r_mutex_lock(&shared_eventlog_connection->eventlog_mutex);
if (shared_eventlog_connection->eventlog_pipe)
res = eventlog_deregister(shared_eventlog_connection);
shared_eventlog_connection->eventlog_pipe = 0;
d_r_mutex_unlock(&shared_eventlog_connection->eventlog_mutex);
DOLOG(
1, LOG_TOP, if (!res) {
LOG(GLOBAL, LOG_TOP, 1, "WARNING: DeregisterEventSource failed.\n");
});
}
void
eventlog_slow_exit()
{
ASSERT_CURIOSITY(shared_eventlog_connection->eventlog_pipe == 0 &&
"call after eventlog_fast_exit");
DELETE_LOCK(shared_eventlog_connection->eventlog_mutex);
ASSERT(shared_eventlog_connection != NULL &&
shared_eventlog_connection != &temp_shared_eventlog_connection);
HEAP_TYPE_FREE(GLOBAL_DCONTEXT, shared_eventlog_connection, eventlog_state_t,
ACCT_OTHER, PROTECTED);
* FIXME: won't re-deregister in that case
*/
shared_eventlog_connection = &temp_shared_eventlog_connection;
ASSIGN_INIT_LOCK_FREE(shared_eventlog_connection->eventlog_mutex, eventlog_mutex);
}
static void
os_eventlog(syslog_event_type_t priority, uint message_id, uint substitutions_num,
char **arguments, size_t size_data, char *raw_data)
{
WORD native_priority = 0;
WORD category = 0;
uint res = 0;
if (!TEST(priority, dynamo_options.syslog_mask))
return;
switch (priority) {
case SYSLOG_INFORMATION: native_priority = EVENTLOG_INFORMATION_TYPE; break;
case SYSLOG_WARNING: native_priority = EVENTLOG_WARNING_TYPE; break;
case SYSLOG_CRITICAL:
case SYSLOG_ERROR: native_priority = EVENTLOG_ERROR_TYPE; break;
default: ASSERT_NOT_REACHED();
}
if (shared_eventlog_connection == NULL)
eventlog_alloc();
d_r_mutex_lock(&shared_eventlog_connection->eventlog_mutex);
if (!shared_eventlog_connection->eventlog_pipe) {
to do that early on for system services started before EventLog */
res = eventlog_register(shared_eventlog_connection);
if (!res) {
DOLOG_ONCE(1, LOG_TOP, {
LOG(GLOBAL, LOG_TOP, 1,
"WARNING: Could not register event source on second attempt.\n");
});
} else {
LOG(GLOBAL, LOG_TOP, 1,
"Registered event source after program started. "
"Events may be missing. --ok\n");
}
}
if (shared_eventlog_connection->eventlog_pipe) {
res = eventlog_report(shared_eventlog_connection, (WORD)native_priority, category,
message_id, NULL,
(WORD)substitutions_num, size_data, arguments, raw_data);
}
d_r_mutex_unlock(&shared_eventlog_connection->eventlog_mutex);
DOLOG(
1, LOG_TOP, if (!res) {
LOG(GLOBAL, LOG_TOP, 1, "WARNING: Could not report event 0x%x. \n",
message_id);
});
}