* Sync the recent cmake branch changes.
[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 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 LogfReportEvent(EVENTLOG_INFORMATION_TYPE,
173 0,
174 EVENT_EventlogStarted);
175 }
176
177 DPRINT("ServiceMain() done\n");
178 }
179
180
181 PLOGFILE LoadLogFile(HKEY hKey, WCHAR * LogName)
182 {
183 DWORD MaxValueLen, ValueLen, Type, ExpandedLen;
184 WCHAR *Buf = NULL, *Expanded = NULL;
185 LONG Result;
186 PLOGFILE pLogf;
187
188 DPRINT("LoadLogFile: %S\n", LogName);
189
190 RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
191 NULL, NULL, &MaxValueLen, NULL, NULL);
192
193 Buf = HeapAlloc(MyHeap, 0, MaxValueLen);
194 if (!Buf)
195 {
196 DPRINT1("Can't allocate heap!\n");
197 return NULL;
198 }
199
200 ValueLen = MaxValueLen;
201
202 Result = RegQueryValueEx(hKey,
203 L"File",
204 NULL,
205 &Type,
206 (LPBYTE) Buf,
207 &ValueLen);
208 if (Result != ERROR_SUCCESS)
209 {
210 DPRINT1("RegQueryValueEx failed: %d\n", GetLastError());
211 HeapFree(MyHeap, 0, Buf);
212 return NULL;
213 }
214
215 if (Type != REG_EXPAND_SZ && Type != REG_SZ)
216 {
217 DPRINT1("%S\\File - value of wrong type %x.\n", LogName, Type);
218 HeapFree(MyHeap, 0, Buf);
219 return NULL;
220 }
221
222 ExpandedLen = ExpandEnvironmentStrings(Buf, NULL, 0);
223 Expanded = HeapAlloc(MyHeap, 0, ExpandedLen * sizeof(WCHAR));
224 if (!Expanded)
225 {
226 DPRINT1("Can't allocate heap!\n");
227 HeapFree(MyHeap, 0, Buf);
228 return NULL;
229 }
230
231 ExpandEnvironmentStrings(Buf, Expanded, ExpandedLen);
232
233 DPRINT("%S -> %S\n", Buf, Expanded);
234
235 pLogf = LogfCreate(LogName, Expanded);
236
237 if (pLogf == NULL)
238 {
239 DPRINT1("Failed to create %S!\n", Expanded);
240 }
241
242 HeapFree(MyHeap, 0, Buf);
243 HeapFree(MyHeap, 0, Expanded);
244 return pLogf;
245 }
246
247 BOOL LoadLogFiles(HKEY eventlogKey)
248 {
249 LONG result;
250 DWORD MaxLognameLen, LognameLen;
251 WCHAR *Buf = NULL;
252 INT i;
253 PLOGFILE pLogFile;
254
255 RegQueryInfoKey(eventlogKey,
256 NULL, NULL, NULL, NULL,
257 &MaxLognameLen,
258 NULL, NULL, NULL, NULL, NULL, NULL);
259
260 MaxLognameLen++;
261
262 Buf = HeapAlloc(MyHeap, 0, MaxLognameLen * sizeof(WCHAR));
263
264 if (!Buf)
265 {
266 DPRINT1("Error: can't allocate heap!\n");
267 return FALSE;
268 }
269
270 i = 0;
271 LognameLen = MaxLognameLen;
272
273 while (RegEnumKeyEx(eventlogKey,
274 i,
275 Buf,
276 &LognameLen,
277 NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
278 {
279 HKEY SubKey;
280
281 DPRINT("%S\n", Buf);
282
283 result = RegOpenKeyEx(eventlogKey, Buf, 0, KEY_ALL_ACCESS, &SubKey);
284 if (result != ERROR_SUCCESS)
285 {
286 DPRINT1("Failed to open %S key.\n", Buf);
287 HeapFree(MyHeap, 0, Buf);
288 return FALSE;
289 }
290
291 pLogFile = LoadLogFile(SubKey, Buf);
292 if (pLogFile != NULL)
293 {
294 DPRINT("Loaded %S\n", Buf);
295 LoadEventSources(SubKey, pLogFile);
296 }
297 else
298 {
299 DPRINT1("Failed to load %S\n", Buf);
300 }
301
302 RegCloseKey(SubKey);
303 LognameLen = MaxLognameLen;
304 i++;
305 }
306
307 HeapFree(MyHeap, 0, Buf);
308 return TRUE;
309 }
310
311 INT wmain()
312 {
313 WCHAR LogPath[MAX_PATH];
314 INT RetCode = 0;
315 LONG result;
316 HKEY elogKey;
317
318 LogfListInitialize();
319 InitEventSourceList();
320
321 MyHeap = HeapCreate(0, 1024 * 256, 0);
322
323 if (!MyHeap)
324 {
325 DPRINT1("FATAL ERROR, can't create heap.\n");
326 RetCode = 1;
327 goto bye_bye;
328 }
329
330 GetWindowsDirectory(LogPath, MAX_PATH);
331
332 if (GetDriveType(LogPath) == DRIVE_CDROM)
333 {
334 DPRINT("LiveCD detected\n");
335 onLiveCD = TRUE;
336 }
337 else
338 {
339 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
340 L"SYSTEM\\CurrentControlSet\\Services\\EventLog",
341 0,
342 KEY_ALL_ACCESS,
343 &elogKey);
344
345 if (result != ERROR_SUCCESS)
346 {
347 DPRINT1("Fatal error: can't open eventlog registry key.\n");
348 RetCode = 1;
349 goto bye_bye;
350 }
351
352 LoadLogFiles(elogKey);
353 }
354
355 StartServiceCtrlDispatcher(ServiceTable);
356
357 bye_bye:
358 LogfCloseAll();
359
360 if (MyHeap)
361 HeapDestroy(MyHeap);
362
363 return RetCode;
364 }
365
366 VOID EventTimeToSystemTime(DWORD EventTime, SYSTEMTIME * pSystemTime)
367 {
368 SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
369 FILETIME ftLocal;
370 union
371 {
372 FILETIME ft;
373 ULONGLONG ll;
374 } u1970, uUCT;
375
376 uUCT.ft.dwHighDateTime = 0;
377 uUCT.ft.dwLowDateTime = EventTime;
378 SystemTimeToFileTime(&st1970, &u1970.ft);
379 uUCT.ll = uUCT.ll * 10000000 + u1970.ll;
380 FileTimeToLocalFileTime(&uUCT.ft, &ftLocal);
381 FileTimeToSystemTime(&ftLocal, pSystemTime);
382 }
383
384 VOID SystemTimeToEventTime(SYSTEMTIME * pSystemTime, DWORD * pEventTime)
385 {
386 SYSTEMTIME st1970 = { 1970, 1, 0, 1, 0, 0, 0, 0 };
387 union
388 {
389 FILETIME ft;
390 ULONGLONG ll;
391 } Time, u1970;
392
393 SystemTimeToFileTime(pSystemTime, &Time.ft);
394 SystemTimeToFileTime(&st1970, &u1970.ft);
395 *pEventTime = (Time.ll - u1970.ll) / 10000000;
396 }
397
398 VOID PRINT_HEADER(PEVENTLOGHEADER header)
399 {
400 DPRINT("HeaderSize = %d\n", header->HeaderSize);
401 DPRINT("Signature = 0x%x\n", header->Signature);
402 DPRINT("MajorVersion = %d\n", header->MajorVersion);
403 DPRINT("MinorVersion = %d\n", header->MinorVersion);
404 DPRINT("StartOffset = %d\n", header->StartOffset);
405 DPRINT("EndOffset = 0x%x\n", header->EndOffset);
406 DPRINT("CurrentRecordNumber = %d\n", header->CurrentRecordNumber);
407 DPRINT("OldestRecordNumber = %d\n", header->OldestRecordNumber);
408 DPRINT("MaxSize = 0x%x\n", header->MaxSize);
409 DPRINT("Retention = 0x%x\n", header->Retention);
410 DPRINT("EndHeaderSize = %d\n", header->EndHeaderSize);
411 DPRINT("Flags: ");
412 if (header->Flags & ELF_LOGFILE_HEADER_DIRTY) DPRINT("ELF_LOGFILE_HEADER_DIRTY");
413 if (header->Flags & ELF_LOGFILE_HEADER_WRAP) DPRINT("| ELF_LOGFILE_HEADER_WRAP ");
414 if (header->Flags & ELF_LOGGFILE_LOGFULL_WRITTEN) DPRINT("| ELF_LOGGFILE_LOGFULL_WRITTEN ");
415 if (header->Flags & ELF_LOGFILE_ARCHIVE_SET) DPRINT("| ELF_LOGFILE_ARCHIVE_SET ");
416 DPRINT("\n");
417 }
418
419 VOID PRINT_RECORD(PEVENTLOGRECORD pRec)
420 {
421 UINT i;
422 WCHAR *str;
423 SYSTEMTIME time;
424
425 DPRINT("Length = %d\n", pRec->Length);
426 DPRINT("Reserved = 0x%x\n", pRec->Reserved);
427 DPRINT("RecordNumber = %d\n", pRec->RecordNumber);
428
429 EventTimeToSystemTime(pRec->TimeGenerated, &time);
430 DPRINT("TimeGenerated = %d.%d.%d %d:%d:%d\n",
431 time.wDay, time.wMonth, time.wYear,
432 time.wHour, time.wMinute, time.wSecond);
433
434 EventTimeToSystemTime(pRec->TimeWritten, &time);
435 DPRINT("TimeWritten = %d.%d.%d %d:%d:%d\n",
436 time.wDay, time.wMonth, time.wYear,
437 time.wHour, time.wMinute, time.wSecond);
438
439 DPRINT("EventID = %d\n", pRec->EventID);
440
441 switch (pRec->EventType)
442 {
443 case EVENTLOG_ERROR_TYPE:
444 DPRINT("EventType = EVENTLOG_ERROR_TYPE\n");
445 break;
446 case EVENTLOG_WARNING_TYPE:
447 DPRINT("EventType = EVENTLOG_WARNING_TYPE\n");
448 break;
449 case EVENTLOG_INFORMATION_TYPE:
450 DPRINT("EventType = EVENTLOG_INFORMATION_TYPE\n");
451 break;
452 case EVENTLOG_AUDIT_SUCCESS:
453 DPRINT("EventType = EVENTLOG_AUDIT_SUCCESS\n");
454 break;
455 case EVENTLOG_AUDIT_FAILURE:
456 DPRINT("EventType = EVENTLOG_AUDIT_FAILURE\n");
457 break;
458 default:
459 DPRINT("EventType = %d\n", pRec->EventType);
460 }
461
462 DPRINT("NumStrings = %d\n", pRec->NumStrings);
463 DPRINT("EventCategory = %d\n", pRec->EventCategory);
464 DPRINT("ReservedFlags = 0x%x\n", pRec->ReservedFlags);
465 DPRINT("ClosingRecordNumber = %d\n", pRec->ClosingRecordNumber);
466 DPRINT("StringOffset = %d\n", pRec->StringOffset);
467 DPRINT("UserSidLength = %d\n", pRec->UserSidLength);
468 DPRINT("UserSidOffset = %d\n", pRec->UserSidOffset);
469 DPRINT("DataLength = %d\n", pRec->DataLength);
470 DPRINT("DataOffset = %d\n", pRec->DataOffset);
471
472 DPRINT("SourceName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD)));
473
474 i = (lstrlenW((WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD))) + 1) *
475 sizeof(WCHAR);
476
477 DPRINT("ComputerName: %S\n", (WCHAR *) (((PBYTE) pRec) + sizeof(EVENTLOGRECORD) + i));
478
479 if (pRec->StringOffset < pRec->Length && pRec->NumStrings)
480 {
481 DPRINT("Strings:\n");
482 str = (WCHAR *) (((PBYTE) pRec) + pRec->StringOffset);
483 for (i = 0; i < pRec->NumStrings; i++)
484 {
485 DPRINT("[%d] %S\n", i, str);
486 str = str + lstrlenW(str) + 1;
487 }
488 }
489
490 DPRINT("Length2 = %d\n", *(PDWORD) (((PBYTE) pRec) + pRec->Length - 4));
491 }