c81f9af4dcb8a2262e417c4755d30f74fd13b8bb
[reactos.git] / reactos / base / services / eventlog / eventlog.c
1 /*
2 * PROJECT: ReactOS kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: services/eventlog/eventlog.c
5 * PURPOSE: Event logging service
6 * COPYRIGHT: Copyright 2002 Eric Kohl
7 * Copyright 2005 Saveliy Tretiakov
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "eventlog.h"
13
14 /* GLOBALS ******************************************************************/
15
16 static VOID CALLBACK ServiceMain(DWORD, LPWSTR *);
17 static WCHAR ServiceName[] = L"EventLog";
18 static SERVICE_TABLE_ENTRYW ServiceTable[2] =
19 {
20 { ServiceName, ServiceMain },
21 { NULL, NULL }
22 };
23
24 SERVICE_STATUS ServiceStatus;
25 SERVICE_STATUS_HANDLE ServiceStatusHandle;
26
27 BOOL onLiveCD = FALSE; // On livecd events will go to debug output only
28 HANDLE MyHeap = NULL;
29
30 /* FUNCTIONS ****************************************************************/
31
32 static VOID
33 UpdateServiceStatus(DWORD dwState)
34 {
35 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
36 ServiceStatus.dwCurrentState = dwState;
37 ServiceStatus.dwControlsAccepted = 0;
38 ServiceStatus.dwWin32ExitCode = 0;
39 ServiceStatus.dwServiceSpecificExitCode = 0;
40 ServiceStatus.dwCheckPoint = 0;
41
42 if (dwState == SERVICE_START_PENDING ||
43 dwState == SERVICE_STOP_PENDING ||
44 dwState == SERVICE_PAUSE_PENDING ||
45 dwState == SERVICE_CONTINUE_PENDING)
46 ServiceStatus.dwWaitHint = 10000;
47 else
48 ServiceStatus.dwWaitHint = 0;
49
50 SetServiceStatus(ServiceStatusHandle,
51 &ServiceStatus);
52 }
53
54 static DWORD WINAPI
55 ServiceControlHandler(DWORD dwControl,
56 DWORD dwEventType,
57 LPVOID lpEventData,
58 LPVOID lpContext)
59 {
60 DPRINT("ServiceControlHandler() called\n");
61
62 switch (dwControl)
63 {
64 case SERVICE_CONTROL_STOP:
65 DPRINT(" SERVICE_CONTROL_STOP received\n");
66 UpdateServiceStatus(SERVICE_STOPPED);
67 return ERROR_SUCCESS;
68
69 case SERVICE_CONTROL_PAUSE:
70 DPRINT(" SERVICE_CONTROL_PAUSE received\n");
71 UpdateServiceStatus(SERVICE_PAUSED);
72 return ERROR_SUCCESS;
73
74 case SERVICE_CONTROL_CONTINUE:
75 DPRINT(" SERVICE_CONTROL_CONTINUE received\n");
76 UpdateServiceStatus(SERVICE_RUNNING);
77 return ERROR_SUCCESS;
78
79 case SERVICE_CONTROL_INTERROGATE:
80 DPRINT(" SERVICE_CONTROL_INTERROGATE received\n");
81 SetServiceStatus(ServiceStatusHandle,
82 &ServiceStatus);
83 return ERROR_SUCCESS;
84
85 case SERVICE_CONTROL_SHUTDOWN:
86 DPRINT(" SERVICE_CONTROL_SHUTDOWN received\n");
87 UpdateServiceStatus(SERVICE_STOPPED);
88 return ERROR_SUCCESS;
89
90 default :
91 DPRINT1(" Control %lu received\n");
92 return ERROR_CALL_NOT_IMPLEMENTED;
93 }
94 }
95
96
97 static DWORD
98 ServiceInit(VOID)
99 {
100 HANDLE hThread;
101
102 hThread = CreateThread(NULL,
103 0,
104 (LPTHREAD_START_ROUTINE)
105 PortThreadRoutine,
106 NULL,
107 0,
108 NULL);
109
110 if (!hThread)
111 {
112 DPRINT("Can't create PortThread\n");
113 return GetLastError();
114 }
115 else
116 CloseHandle(hThread);
117
118 hThread = CreateThread(NULL,
119 0,
120 (LPTHREAD_START_ROUTINE)
121 RpcThreadRoutine,
122 NULL,
123 0,
124 NULL);
125
126 if (!hThread)
127 {
128 DPRINT("Can't create RpcThread\n");
129 return GetLastError();
130 }
131 else
132 CloseHandle(hThread);
133
134 return ERROR_SUCCESS;
135 }
136
137
138 static VOID CALLBACK
139 ServiceMain(DWORD argc,
140 LPWSTR *argv)
141 {
142 DWORD dwError;
143
144 UNREFERENCED_PARAMETER(argc);
145 UNREFERENCED_PARAMETER(argv);
146
147 DPRINT("ServiceMain() called\n");
148
149 ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
150 ServiceControlHandler,
151 NULL);
152 if (!ServiceStatusHandle)
153 {
154 dwError = GetLastError();
155 DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError);
156 return;
157 }
158
159 UpdateServiceStatus(SERVICE_START_PENDING);
160
161 dwError = ServiceInit();
162 if (dwError != ERROR_SUCCESS)
163 {
164 DPRINT("Service stopped (dwError: %lu\n", dwError);
165 UpdateServiceStatus(SERVICE_START_PENDING);
166 }
167 else
168 {
169 DPRINT("Service started\n");
170 UpdateServiceStatus(SERVICE_RUNNING);
171 }
172
173 DPRINT("ServiceMain() done\n");
174 }
175
176
177 PLOGFILE LoadLogFile(HKEY hKey, WCHAR * LogName)
178 {
179 DWORD MaxValueLen, ValueLen, Type, ExpandedLen;
180 WCHAR *Buf = NULL, *Expanded = NULL;
181 LONG Result;
182 PLOGFILE pLogf;
183
184 DPRINT("LoadLogFile: %S\n", LogName);
185
186 RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
187 NULL, NULL, &MaxValueLen, NULL, NULL);
188
189 Buf = HeapAlloc(MyHeap, 0, MaxValueLen);
190 if (!Buf)
191 {
192 DPRINT1("Can't allocate heap!\n");
193 return NULL;
194 }
195
196 ValueLen = MaxValueLen;
197
198 Result = RegQueryValueEx(hKey,
199 L"File",
200 NULL,
201 &Type,
202 (LPBYTE) Buf,
203 &ValueLen);
204 if (Result != ERROR_SUCCESS)
205 {
206 DPRINT1("RegQueryValueEx failed: %d\n", GetLastError());
207 HeapFree(MyHeap, 0, Buf);
208 return NULL;
209 }
210
211 if (Type != REG_EXPAND_SZ && Type != REG_SZ)
212 {
213 DPRINT1("%S\\File - value of wrong type %x.\n", LogName, Type);
214 HeapFree(MyHeap, 0, Buf);
215 return NULL;
216 }
217
218 ExpandedLen = ExpandEnvironmentStrings(Buf, NULL, 0);
219 Expanded = HeapAlloc(MyHeap, 0, ExpandedLen * sizeof(WCHAR));
220 if (!Expanded)
221 {
222 DPRINT1("Can't allocate heap!\n");
223 HeapFree(MyHeap, 0, Buf);
224 return NULL;
225 }
226
227 ExpandEnvironmentStrings(Buf, Expanded, ExpandedLen);
228
229 DPRINT("%S -> %S\n", Buf, Expanded);
230
231 pLogf = LogfCreate(LogName, Expanded);
232
233 if (pLogf == NULL)
234 {
235 DPRINT1("Failed to create %S!\n", Expanded);
236 }
237
238 HeapFree(MyHeap, 0, Buf);
239 HeapFree(MyHeap, 0, Expanded);
240 return pLogf;
241 }
242
243 BOOL LoadLogFiles(HKEY eventlogKey)
244 {
245 LONG result;
246 DWORD MaxLognameLen, LognameLen;
247 WCHAR *Buf = NULL;
248 INT i;
249 PLOGFILE pLogFile;
250
251 RegQueryInfoKey(eventlogKey,
252 NULL, NULL, NULL, NULL,
253 &MaxLognameLen,
254 NULL, NULL, NULL, NULL, NULL, NULL);
255
256 MaxLognameLen++;
257
258 Buf = HeapAlloc(MyHeap, 0, MaxLognameLen * sizeof(WCHAR));
259
260 if (!Buf)
261 {
262 DPRINT1("Error: can't allocate heap!\n");
263 return FALSE;
264 }
265
266 i = 0;
267 LognameLen = MaxLognameLen;
268
269 while (RegEnumKeyEx(eventlogKey,
270 i,
271 Buf,
272 &LognameLen,
273 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
274 {
275 HKEY SubKey;
276
277 DPRINT("%S\n", Buf);
278
279 result = RegOpenKeyEx(eventlogKey, Buf, 0, KEY_ALL_ACCESS, &SubKey);
280 if (result != ERROR_SUCCESS)
281 {
282 DPRINT1("Failed to open %S key.\n", Buf);
283 HeapFree(MyHeap, 0, Buf);
284 return FALSE;
285 }
286
287 pLogFile = LoadLogFile(SubKey, Buf);
288 if (pLogFile != NULL)
289 {
290 DPRINT("Loaded %S\n", Buf);
291 LoadEventSources(SubKey, pLogFile);
292 }
293 else
294 {
295 DPRINT1("Failed to load %S\n", Buf);
296 }
297
298 RegCloseKey(SubKey);
299 LognameLen = MaxLognameLen;
300 i++;
301 }
302
303 HeapFree(MyHeap, 0, Buf);
304 return TRUE;
305 }
306
307 INT wmain()
308 {
309 WCHAR LogPath[MAX_PATH];
310 INT RetCode = 0;
311 LONG result;
312 HKEY elogKey;
313
314 LogfListInitialize();
315 InitEventSourceList();
316
317 MyHeap = HeapCreate(0, 1024 * 256, 0);
318
319 if (!MyHeap)
320 {
321 DPRINT1("FATAL ERROR, can't create heap.\n");
322 RetCode = 1;
323 goto bye_bye;
324 }
325
326 GetWindowsDirectory(LogPath, MAX_PATH);
327
328 if (GetDriveType(LogPath) == DRIVE_CDROM)
329 {
330 DPRINT("LiveCD detected\n");
331 onLiveCD = TRUE;
332 }
333 else
334 {
335 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
336 L"SYSTEM\\CurrentControlSet\\Services\\EventLog",
337 0,
338 KEY_ALL_ACCESS,
339 &elogKey);
340
341 if (result != ERROR_SUCCESS)
342 {
343 DPRINT1("Fatal error: can't open eventlog registry key.\n");
344 RetCode = 1;
345 goto bye_bye;
346 }
347
348 LoadLogFiles(elogKey);
349 }
350
351 StartServiceCtrlDispatcher(ServiceTable);
352
353 bye_bye:
354 LogfCloseAll();
355
356 if (MyHeap)
357 HeapDestroy(MyHeap);
358
359 return RetCode;
360 }
361
362 VOID EventTimeToSystemTime(DWORD EventTime, SYSTEMTIME * pSystemTime)
363 {
364 SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
365 FILETIME ftLocal;
366 union
367 {
368 FILETIME ft;
369 ULONGLONG ll;
370 } u1970, uUCT;
371
372 uUCT.ft.dwHighDateTime = 0;
373 uUCT.ft.dwLowDateTime = EventTime;
374 SystemTimeToFileTime(&st1970, &u1970.ft);
375 uUCT.ll = uUCT.ll * 10000000 + u1970.ll;
376 FileTimeToLocalFileTime(&uUCT.ft, &ftLocal);
377 FileTimeToSystemTime(&ftLocal, pSystemTime);
378 }
379
380 VOID SystemTimeToEventTime(SYSTEMTIME * pSystemTime, DWORD * pEventTime)
381 {
382 SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
383 union
384 {
385 FILETIME ft;
386 ULONGLONG ll;
387 } Time, u1970;
388
389 SystemTimeToFileTime(pSystemTime, &Time.ft);
390 SystemTimeToFileTime(&st1970, &u1970.ft);
391 *pEventTime = (Time.ll - u1970.ll) / 10000000;
392 }
393
394 VOID PRINT_HEADER(PEVENTLOGHEADER header)
395 {
396 DPRINT("HeaderSize = %d\n", header->HeaderSize);
397 DPRINT("Signature = 0x%x\n", header->Signature);
398 DPRINT("MajorVersion = %d\n", header->MajorVersion);
399 DPRINT("MinorVersion = %d\n", header->MinorVersion);
400 DPRINT("StartOffset = %d\n", header->StartOffset);
401 DPRINT("EndOffset = 0x%x\n", header->EndOffset);
402 DPRINT("CurrentRecordNumber = %d\n", header->CurrentRecordNumber);
403 DPRINT("OldestRecordNumber = %d\n", header->OldestRecordNumber);
404 DPRINT("MaxSize = 0x%x\n", header->MaxSize);
405 DPRINT("Retention = 0x%x\n", header->Retention);
406 DPRINT("EndHeaderSize = %d\n", header->EndHeaderSize);
407 DPRINT("Flags: ");
408 if (header->Flags & ELF_LOGFILE_HEADER_DIRTY) DPRINT("ELF_LOGFILE_HEADER_DIRTY");
409 if (header->Flags & ELF_LOGFILE_HEADER_WRAP) DPRINT("| ELF_LOGFILE_HEADER_WRAP ");
410 if (header->Flags & ELF_LOGGFILE_LOGFULL_WRITTEN) DPRINT("| ELF_LOGGFILE_LOGFULL_WRITTEN ");
411 if (header->Flags & ELF_LOGFILE_ARCHIVE_SET) DPRINT("| ELF_LOGFILE_ARCHIVE_SET ");
412 DPRINT("\n");
413 }
414
415 VOID PRINT_RECORD(PEVENTLOGRECORD pRec)
416 {
417 UINT i;
418 WCHAR *str;
419 SYSTEMTIME time;
420
421 DPRINT("Length = %d\n", pRec->Length);
422 DPRINT("Reserved = 0x%x\n", pRec->Reserved);
423 DPRINT("RecordNumber = %d\n", pRec->RecordNumber);
424
425 EventTimeToSystemTime(pRec->TimeGenerated, &time);
426 DPRINT("TimeGenerated = %d.%d.%d %d:%d:%d\n",
427 time.wDay, time.wMonth, time.wYear,
428 time.wHour, time.wMinute, time.wSecond);
429
430 EventTimeToSystemTime(pRec->TimeWritten, &time);
431 DPRINT("TimeWritten = %d.%d.%d %d:%d:%d\n",
432 time.wDay, time.wMonth, time.wYear,
433 time.wHour, time.wMinute, time.wSecond);
434
435 DPRINT("EventID = %d\n", pRec->EventID);
436
437 switch (pRec->EventType)
438 {
439 case EVENTLOG_ERROR_TYPE:
440 DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
441 break;
442 case EVENTLOG_WARNING_TYPE:
443 DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
444 break;
445 case EVENTLOG_INFORMATION_TYPE:
446 DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
447 break;
448 case EVENTLOG_AUDIT_SUCCESS:
449 DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
450 break;
451 case EVENTLOG_AUDIT_FAILURE:
452 DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
453 break;
454 default:
455 DPRINT("EventType = %d\n", pRec->EventType);
456 }
457
458 DPRINT("NumStrings = %d\n", pRec->NumStrings);
459 DPRINT("EventCategory = %d\n", pRec->EventCategory);
460 DPRINT("ReservedFlags = 0x%x\n", pRec->ReservedFlags);
461 DPRINT("ClosingRecordNumber = %d\n", pRec->ClosingRecordNumber);
462 DPRINT("StringOffset = %d\n", pRec->StringOffset);
463 DPRINT("UserSidLength = %d\n", pRec->UserSidLength);
464 DPRINT("UserSidOffset = %d\n", pRec->UserSidOffset);
465 DPRINT("DataLength = %d\n", pRec->DataLength);
466 DPRINT("DataOffset = %d\n", pRec->DataOffset);
467
468 DPRINT("SourceName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD)));
469
470 i = (lstrlenW((WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD))) + 1) *
471 sizeof(WCHAR);
472
473 DPRINT("ComputerName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD) + i));
474
475 if (pRec->StringOffset < pRec->Length && pRec->NumStrings)
476 {
477 DPRINT("Strings:\n");
478 str = (WCHAR *) (((PBYTE) pRec) + pRec->StringOffset);
479 for (i = 0; i < pRec->NumStrings; i++)
480 {
481 DPRINT("[%d] %S\n", i, str);
482 str = str + lstrlenW(str) + 1;
483 }
484 }
485
486 DPRINT("Length2 = %d\n", *(PDWORD) (((PBYTE) pRec) + pRec->Length - 4));
487 }