c988e1257b05e8df4366b8b8cc878138edbcd9e9
[reactos.git] / 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
139 ReportProductInfoEvent(VOID)
140 {
141 OSVERSIONINFOW versionInfo;
142 WCHAR szBuffer[512];
143 DWORD dwLength;
144 HKEY hKey;
145 DWORD dwValueLength;
146 DWORD dwType;
147 LONG lResult = ERROR_SUCCESS;
148
149 ZeroMemory(&versionInfo, sizeof(OSVERSIONINFO));
150 versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
151
152 /* Get version information */
153 if (!GetVersionExW(&versionInfo))
154 return;
155
156 ZeroMemory(szBuffer, 512 * sizeof(WCHAR));
157
158 /* Write version into the buffer */
159 dwLength = swprintf(szBuffer,
160 L"%lu.%lu",
161 versionInfo.dwMajorVersion,
162 versionInfo.dwMinorVersion) + 1;
163
164 /* Write build number into the buffer */
165 dwLength += swprintf(&szBuffer[dwLength],
166 L"%lu",
167 versionInfo.dwBuildNumber) + 1;
168
169 /* Write service pack info into the buffer */
170 wcscpy(&szBuffer[dwLength], versionInfo.szCSDVersion);
171 dwLength += wcslen(versionInfo.szCSDVersion) + 1;
172
173 /* Read 'CurrentType' from the registry and write it into the buffer */
174 lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
175 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
176 0,
177 KEY_QUERY_VALUE,
178 &hKey);
179 if (lResult == ERROR_SUCCESS)
180 {
181 dwValueLength = 512 - dwLength;
182 lResult = RegQueryValueEx(hKey,
183 L"CurrentType",
184 NULL,
185 &dwType,
186 (LPBYTE)&szBuffer[dwLength],
187 &dwValueLength);
188
189 RegCloseKey(hKey);
190 }
191
192 /* Log the product information */
193 LogfReportEvent(EVENTLOG_INFORMATION_TYPE,
194 0,
195 EVENT_EventLogProductInfo,
196 4,
197 szBuffer,
198 0,
199 NULL);
200 }
201
202
203 static VOID CALLBACK
204 ServiceMain(DWORD argc,
205 LPWSTR *argv)
206 {
207 DWORD dwError;
208
209 UNREFERENCED_PARAMETER(argc);
210 UNREFERENCED_PARAMETER(argv);
211
212 DPRINT("ServiceMain() called\n");
213
214 ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
215 ServiceControlHandler,
216 NULL);
217 if (!ServiceStatusHandle)
218 {
219 dwError = GetLastError();
220 DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError);
221 return;
222 }
223
224 UpdateServiceStatus(SERVICE_START_PENDING);
225
226 dwError = ServiceInit();
227 if (dwError != ERROR_SUCCESS)
228 {
229 DPRINT("Service stopped (dwError: %lu\n", dwError);
230 UpdateServiceStatus(SERVICE_START_PENDING);
231 }
232 else
233 {
234 DPRINT("Service started\n");
235 UpdateServiceStatus(SERVICE_RUNNING);
236
237 ReportProductInfoEvent();
238
239 LogfReportEvent(EVENTLOG_INFORMATION_TYPE,
240 0,
241 EVENT_EventlogStarted,
242 0,
243 NULL,
244 0,
245 NULL);
246 }
247
248 DPRINT("ServiceMain() done\n");
249 }
250
251
252 PLOGFILE LoadLogFile(HKEY hKey, WCHAR * LogName)
253 {
254 DWORD MaxValueLen, ValueLen, Type, ExpandedLen;
255 WCHAR *Buf = NULL, *Expanded = NULL;
256 LONG Result;
257 PLOGFILE pLogf;
258
259 DPRINT("LoadLogFile: %S\n", LogName);
260
261 RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
262 NULL, NULL, &MaxValueLen, NULL, NULL);
263
264 Buf = HeapAlloc(MyHeap, 0, MaxValueLen);
265 if (!Buf)
266 {
267 DPRINT1("Can't allocate heap!\n");
268 return NULL;
269 }
270
271 ValueLen = MaxValueLen;
272
273 Result = RegQueryValueEx(hKey,
274 L"File",
275 NULL,
276 &Type,
277 (LPBYTE) Buf,
278 &ValueLen);
279 if (Result != ERROR_SUCCESS)
280 {
281 DPRINT1("RegQueryValueEx failed: %d\n", GetLastError());
282 HeapFree(MyHeap, 0, Buf);
283 return NULL;
284 }
285
286 if (Type != REG_EXPAND_SZ && Type != REG_SZ)
287 {
288 DPRINT1("%S\\File - value of wrong type %x.\n", LogName, Type);
289 HeapFree(MyHeap, 0, Buf);
290 return NULL;
291 }
292
293 ExpandedLen = ExpandEnvironmentStrings(Buf, NULL, 0);
294 Expanded = HeapAlloc(MyHeap, 0, ExpandedLen * sizeof(WCHAR));
295 if (!Expanded)
296 {
297 DPRINT1("Can't allocate heap!\n");
298 HeapFree(MyHeap, 0, Buf);
299 return NULL;
300 }
301
302 ExpandEnvironmentStrings(Buf, Expanded, ExpandedLen);
303
304 DPRINT("%S -> %S\n", Buf, Expanded);
305
306 pLogf = LogfCreate(LogName, Expanded);
307
308 if (pLogf == NULL)
309 {
310 DPRINT1("Failed to create %S!\n", Expanded);
311 }
312
313 HeapFree(MyHeap, 0, Buf);
314 HeapFree(MyHeap, 0, Expanded);
315 return pLogf;
316 }
317
318 BOOL LoadLogFiles(HKEY eventlogKey)
319 {
320 LONG result;
321 DWORD MaxLognameLen, LognameLen;
322 WCHAR *Buf = NULL;
323 INT i;
324 PLOGFILE pLogFile;
325
326 RegQueryInfoKey(eventlogKey,
327 NULL, NULL, NULL, NULL,
328 &MaxLognameLen,
329 NULL, NULL, NULL, NULL, NULL, NULL);
330
331 MaxLognameLen++;
332
333 Buf = HeapAlloc(MyHeap, 0, MaxLognameLen * sizeof(WCHAR));
334
335 if (!Buf)
336 {
337 DPRINT1("Error: can't allocate heap!\n");
338 return FALSE;
339 }
340
341 i = 0;
342 LognameLen = MaxLognameLen;
343
344 while (RegEnumKeyEx(eventlogKey,
345 i,
346 Buf,
347 &LognameLen,
348 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
349 {
350 HKEY SubKey;
351
352 DPRINT("%S\n", Buf);
353
354 result = RegOpenKeyEx(eventlogKey, Buf, 0, KEY_ALL_ACCESS, &SubKey);
355 if (result != ERROR_SUCCESS)
356 {
357 DPRINT1("Failed to open %S key.\n", Buf);
358 HeapFree(MyHeap, 0, Buf);
359 return FALSE;
360 }
361
362 pLogFile = LoadLogFile(SubKey, Buf);
363 if (pLogFile != NULL)
364 {
365 DPRINT("Loaded %S\n", Buf);
366 LoadEventSources(SubKey, pLogFile);
367 }
368 else
369 {
370 DPRINT1("Failed to load %S\n", Buf);
371 }
372
373 RegCloseKey(SubKey);
374 LognameLen = MaxLognameLen;
375 i++;
376 }
377
378 HeapFree(MyHeap, 0, Buf);
379 return TRUE;
380 }
381
382 INT wmain()
383 {
384 WCHAR LogPath[MAX_PATH];
385 INT RetCode = 0;
386 LONG result;
387 HKEY elogKey;
388
389 LogfListInitialize();
390 InitEventSourceList();
391
392 MyHeap = HeapCreate(0, 1024 * 256, 0);
393
394 if (!MyHeap)
395 {
396 DPRINT1("FATAL ERROR, can't create heap.\n");
397 RetCode = 1;
398 goto bye_bye;
399 }
400
401 GetWindowsDirectory(LogPath, MAX_PATH);
402
403 if (GetDriveType(LogPath) == DRIVE_CDROM)
404 {
405 DPRINT("LiveCD detected\n");
406 onLiveCD = TRUE;
407 }
408 else
409 {
410 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
411 L"SYSTEM\\CurrentControlSet\\Services\\EventLog",
412 0,
413 KEY_ALL_ACCESS,
414 &elogKey);
415
416 if (result != ERROR_SUCCESS)
417 {
418 DPRINT1("Fatal error: can't open eventlog registry key.\n");
419 RetCode = 1;
420 goto bye_bye;
421 }
422
423 LoadLogFiles(elogKey);
424 }
425
426 StartServiceCtrlDispatcher(ServiceTable);
427
428 bye_bye:
429 LogfCloseAll();
430
431 if (MyHeap)
432 HeapDestroy(MyHeap);
433
434 return RetCode;
435 }
436
437 VOID EventTimeToSystemTime(DWORD EventTime, SYSTEMTIME * pSystemTime)
438 {
439 SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
440 FILETIME ftLocal;
441 union
442 {
443 FILETIME ft;
444 ULONGLONG ll;
445 } u1970, uUCT;
446
447 uUCT.ft.dwHighDateTime = 0;
448 uUCT.ft.dwLowDateTime = EventTime;
449 SystemTimeToFileTime(&st1970, &u1970.ft);
450 uUCT.ll = uUCT.ll * 10000000 + u1970.ll;
451 FileTimeToLocalFileTime(&uUCT.ft, &ftLocal);
452 FileTimeToSystemTime(&ftLocal, pSystemTime);
453 }
454
455 VOID SystemTimeToEventTime(SYSTEMTIME * pSystemTime, DWORD * pEventTime)
456 {
457 SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
458 union
459 {
460 FILETIME ft;
461 ULONGLONG ll;
462 } Time, u1970;
463
464 SystemTimeToFileTime(pSystemTime, &Time.ft);
465 SystemTimeToFileTime(&st1970, &u1970.ft);
466 *pEventTime = (DWORD)((Time.ll - u1970.ll) / 10000000ull);
467 }
468
469 VOID PRINT_HEADER(PEVENTLOGHEADER header)
470 {
471 DPRINT("HeaderSize = %d\n", header->HeaderSize);
472 DPRINT("Signature = 0x%x\n", header->Signature);
473 DPRINT("MajorVersion = %d\n", header->MajorVersion);
474 DPRINT("MinorVersion = %d\n", header->MinorVersion);
475 DPRINT("StartOffset = %d\n", header->StartOffset);
476 DPRINT("EndOffset = 0x%x\n", header->EndOffset);
477 DPRINT("CurrentRecordNumber = %d\n", header->CurrentRecordNumber);
478 DPRINT("OldestRecordNumber = %d\n", header->OldestRecordNumber);
479 DPRINT("MaxSize = 0x%x\n", header->MaxSize);
480 DPRINT("Retention = 0x%x\n", header->Retention);
481 DPRINT("EndHeaderSize = %d\n", header->EndHeaderSize);
482 DPRINT("Flags: ");
483 if (header->Flags & ELF_LOGFILE_HEADER_DIRTY) DPRINT("ELF_LOGFILE_HEADER_DIRTY");
484 if (header->Flags & ELF_LOGFILE_HEADER_WRAP) DPRINT("| ELF_LOGFILE_HEADER_WRAP ");
485 if (header->Flags & ELF_LOGGFILE_LOGFULL_WRITTEN) DPRINT("| ELF_LOGGFILE_LOGFULL_WRITTEN ");
486 if (header->Flags & ELF_LOGFILE_ARCHIVE_SET) DPRINT("| ELF_LOGFILE_ARCHIVE_SET ");
487 DPRINT("\n");
488 }
489
490 VOID PRINT_RECORD(PEVENTLOGRECORD pRec)
491 {
492 UINT i;
493 WCHAR *str;
494 SYSTEMTIME time;
495
496 DPRINT("Length = %d\n", pRec->Length);
497 DPRINT("Reserved = 0x%x\n", pRec->Reserved);
498 DPRINT("RecordNumber = %d\n", pRec->RecordNumber);
499
500 EventTimeToSystemTime(pRec->TimeGenerated, &time);
501 DPRINT("TimeGenerated = %d.%d.%d %d:%d:%d\n",
502 time.wDay, time.wMonth, time.wYear,
503 time.wHour, time.wMinute, time.wSecond);
504
505 EventTimeToSystemTime(pRec->TimeWritten, &time);
506 DPRINT("TimeWritten = %d.%d.%d %d:%d:%d\n",
507 time.wDay, time.wMonth, time.wYear,
508 time.wHour, time.wMinute, time.wSecond);
509
510 DPRINT("EventID = %d\n", pRec->EventID);
511
512 switch (pRec->EventType)
513 {
514 case EVENTLOG_ERROR_TYPE:
515 DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
516 break;
517 case EVENTLOG_WARNING_TYPE:
518 DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
519 break;
520 case EVENTLOG_INFORMATION_TYPE:
521 DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
522 break;
523 case EVENTLOG_AUDIT_SUCCESS:
524 DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
525 break;
526 case EVENTLOG_AUDIT_FAILURE:
527 DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
528 break;
529 default:
530 DPRINT("EventType = %d\n", pRec->EventType);
531 }
532
533 DPRINT("NumStrings = %d\n", pRec->NumStrings);
534 DPRINT("EventCategory = %d\n", pRec->EventCategory);
535 DPRINT("ReservedFlags = 0x%x\n", pRec->ReservedFlags);
536 DPRINT("ClosingRecordNumber = %d\n", pRec->ClosingRecordNumber);
537 DPRINT("StringOffset = %d\n", pRec->StringOffset);
538 DPRINT("UserSidLength = %d\n", pRec->UserSidLength);
539 DPRINT("UserSidOffset = %d\n", pRec->UserSidOffset);
540 DPRINT("DataLength = %d\n", pRec->DataLength);
541 DPRINT("DataOffset = %d\n", pRec->DataOffset);
542
543 DPRINT("SourceName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD)));
544
545 i = (lstrlenW((WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD))) + 1) *
546 sizeof(WCHAR);
547
548 DPRINT("ComputerName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD) + i));
549
550 if (pRec->StringOffset < pRec->Length && pRec->NumStrings)
551 {
552 DPRINT("Strings:\n");
553 str = (WCHAR *) (((PBYTE) pRec) + pRec->StringOffset);
554 for (i = 0; i < pRec->NumStrings; i++)
555 {
556 DPRINT("[%d] %S\n", i, str);
557 str = str + lstrlenW(str) + 1;
558 }
559 }
560
561 DPRINT("Length2 = %d\n", *(PDWORD) (((PBYTE) pRec) + pRec->Length - 4));
562 }