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