Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

730 lines
18 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. eventlog.cpp
  5. Abstract:
  6. This module defines the generic class for logging events.
  7. Because Windows9x does not have system event logging mechanism
  8. we emulate it with text file
  9. Author:
  10. Vlad Sadovsky (VladS) 01-Feb-1997
  11. Environment:
  12. User Mode - Win32
  13. History:
  14. 22-Sep-1997 VladS created
  15. 29-Sep-1997 VladS Added native NT event logging calls
  16. --*/
  17. //
  18. // Include Headers
  19. //
  20. #include "cplusinc.h"
  21. #include "sticomm.h"
  22. #include <eventlog.h>
  23. #include <stisvc.h>
  24. # define PSZ_EVENTLOG_REG_ENTRY \
  25. TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\")
  26. # define PSZ_PARAMETERS_REG_ENTRY TEXT("EventMessageFile")
  27. # define PSZ_TYPES_REG_ENTRY TEXT("TypesSupported")
  28. #ifndef WINNT
  29. #include <lock.h>
  30. //
  31. // Definitions for Win9x event logging ( which is based on text file)
  32. //
  33. # define PSZ_EVENT_LOG_FILE_DIRECTORY_A "EventLogDirectory"
  34. # define PSZ_EVENT_LOG_FILE__A "\\Sti_Event.log"
  35. //
  36. // Static variables, common for all event loggin objects
  37. //
  38. //
  39. static const TCHAR szMutexNamePrefix[] = TEXT("StiEventLogMutex");
  40. MUTEX_OBJ EventLogSync(szMutexNamePrefix);
  41. #endif WINNT
  42. LONG lTotalLoggers = 0;
  43. HANDLE hEventLogFile = INVALID_HANDLE_VALUE;
  44. //
  45. // Functions
  46. //
  47. //
  48. inline BOOL
  49. FormatStdTime( IN const SYSTEMTIME * pstNow,
  50. IN OUT TCHAR * pchBuffer,
  51. IN int cbBuffer)
  52. {
  53. return ( GetTimeFormat( LOCALE_SYSTEM_DEFAULT,
  54. ( LOCALE_NOUSEROVERRIDE | TIME_FORCE24HOURFORMAT|
  55. TIME_NOTIMEMARKER),
  56. pstNow, NULL, pchBuffer, cbBuffer)
  57. != 0);
  58. } // FormatStdTime()
  59. inline BOOL
  60. FormatStdDate( IN const SYSTEMTIME * pstNow,
  61. IN OUT TCHAR * pchBuffer,
  62. IN int cbBuffer)
  63. {
  64. return ( GetDateFormat( LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE,
  65. pstNow, NULL, pchBuffer, cbBuffer)
  66. != 0);
  67. } // FormatStdDate()
  68. EVENT_LOG::EVENT_LOG( LPCTSTR lpszSource)
  69. /*++
  70. Description
  71. Constructor function for given event log object.
  72. Initializes event logging services.
  73. Arguments:
  74. lpszSource: Source string for the Event source module
  75. Note:
  76. This is intended to be executed once only.
  77. This is not to be used for creating multiple event
  78. log handles for same given source name.
  79. But can be used for creating EVENT_LOG objects for
  80. different source names.
  81. --*/
  82. {
  83. m_ErrorCode = NO_ERROR;
  84. m_lpszSource = lpszSource;
  85. m_hEventSource = INVALID_HANDLE_VALUE;
  86. #ifdef WINNT
  87. //
  88. // Register as an event source.
  89. //
  90. m_ErrorCode = NO_ERROR;
  91. m_lpszSource = lpszSource;
  92. m_hEventSource = RegisterEventSource( NULL, lpszSource);
  93. if( m_hEventSource == NULL ) {
  94. //
  95. // An Error in initializing the event log.
  96. //
  97. m_ErrorCode = GetLastError();
  98. }
  99. //
  100. // Success!
  101. //
  102. #else
  103. //
  104. // Windows 9x specific code
  105. //
  106. CHAR szFilePath[MAX_PATH+1];
  107. CHAR szKeyName[MAX_PATH+1];
  108. DWORD cbBuffer;
  109. HKEY hKey;
  110. *szFilePath = TEXT('\0');
  111. //
  112. // If file has not been opened yet - try to do it now
  113. // Nb: Speed is not critical here, because it is unlikely to have threads
  114. // competing, so we use not vey efficient locking
  115. EventLogSync.Lock();
  116. if ( 0 == lTotalLoggers && ( hEventLogFile == INVALID_HANDLE_VALUE)) {
  117. //
  118. // Nobody logging yet - open file
  119. //
  120. lstrcpy(szKeyName,REGSTR_PATH_STICONTROL_A);
  121. cbBuffer = sizeof(szFilePath);
  122. m_ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  123. szKeyName,
  124. 0,
  125. KEY_ALL_ACCESS,
  126. &hKey);
  127. if ( m_ErrorCode == NO_ERROR) {
  128. //
  129. // Read the value into buffer
  130. //
  131. *szFilePath = TEXT('\0');
  132. m_ErrorCode = RegQueryValueEx( hKey,
  133. REGSTR_VAL_EVENT_LOG_DIRECTORY_A,
  134. NULL,
  135. NULL,
  136. (LPBYTE) szFilePath,
  137. &cbBuffer);
  138. RegCloseKey( hKey);
  139. }
  140. // If we did not get log file directory - use system
  141. if ((NOERROR != m_ErrorCode) || !*szFilePath ) {
  142. m_ErrorCode = ExpandEnvironmentStrings(TEXT("USERPROFILE"),
  143. szFilePath,
  144. sizeof(szFilePath) / sizeof(szFilePath[0]));
  145. }
  146. if (*szFilePath ) {
  147. lstrcat(szFilePath,PSZ_EVENT_LOG_FILE__A);
  148. hEventLogFile = CreateFile(szFilePath,
  149. GENERIC_WRITE,
  150. FILE_SHARE_WRITE | FILE_SHARE_READ,
  151. NULL, // security attributes
  152. OPEN_ALWAYS,
  153. FILE_ATTRIBUTE_NORMAL,
  154. NULL); // template file handle
  155. if ( hEventLogFile != INVALID_HANDLE_VALUE) {
  156. // set the file pointer at the end of the file (append mode)
  157. if ( SetFilePointer( hEventLogFile, 0, NULL, FILE_END)
  158. == (DWORD) -1L) {
  159. hEventLogFile = INVALID_HANDLE_VALUE;
  160. CloseHandle(hEventLogFile);
  161. }
  162. }
  163. } /* endif ValidPath */
  164. } /* endif no loggers */
  165. InterlockedIncrement(&lTotalLoggers);
  166. EventLogSync.Unlock();
  167. if( hEventLogFile != INVALID_HANDLE_VALUE) {
  168. //
  169. // If log file successfully opened - register event message source file.
  170. // On Win9x registration simply means locating module handle for DLL , where we will
  171. // load messages from
  172. //
  173. lstrcpy(szKeyName,PSZ_EVENTLOG_REG_ENTRY);
  174. lstrcat(szKeyName,lpszSource);
  175. m_ErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  176. szKeyName,
  177. 0,
  178. KEY_ALL_ACCESS,
  179. &hKey);
  180. if ( m_ErrorCode == NO_ERROR) {
  181. //
  182. // Read the value into buffer
  183. //
  184. cbBuffer = sizeof(szFilePath);
  185. *szFilePath = TEXT('\0');
  186. m_ErrorCode = RegQueryValueEx( hKey,
  187. PSZ_PARAMETERS_REG_ENTRY,
  188. NULL,
  189. NULL,
  190. (LPBYTE) szFilePath,
  191. &cbBuffer);
  192. RegCloseKey( hKey);
  193. if ((NOERROR == m_ErrorCode) && (*szFilePath)) {
  194. m_hEventSource = GetModuleHandle(szFilePath);
  195. //ASSERT( m_hEventSource != NULL);
  196. }
  197. }
  198. if (NO_ERROR == m_ErrorCode) {
  199. }
  200. else {
  201. //
  202. // An Error in initializing the event log.
  203. //
  204. }
  205. }
  206. else {
  207. //
  208. // An Error in initializing the event log.
  209. //
  210. m_ErrorCode = GetLastError();
  211. DPRINTF(DM_ERROR,"Could not create log file (%s) ( Error %lu)\n",
  212. szFilePath,
  213. m_ErrorCode);
  214. }
  215. m_ErrorCode = NO_ERROR;
  216. #endif // WINNT
  217. } /* EVENT_LOG::EVENT_LOG() */
  218. EVENT_LOG::~EVENT_LOG( VOID)
  219. /*++
  220. Description:
  221. Destructor function for given EVENT_LOG object.
  222. Terminates event logging functions and closes
  223. event log handle
  224. --*/
  225. {
  226. #ifdef WINNT
  227. //
  228. // If there is a valid Events handle, deregister it
  229. //
  230. if ( m_hEventSource != NULL) {
  231. BOOL fSuccess;
  232. fSuccess = DeregisterEventSource( m_hEventSource);
  233. if ( !fSuccess) {
  234. //
  235. // An Error in DeRegistering
  236. //
  237. m_ErrorCode = GetLastError();
  238. DPRINTF( DM_ERROR, TEXT("Termination of EventLog for %s failed.error %lu\n"),m_lpszSource,m_ErrorCode);
  239. }
  240. //
  241. // Reset the handle's value. Just as a precaution
  242. //
  243. m_hEventSource = NULL;
  244. }
  245. #else
  246. TAKE_MUTEX_OBJ t(EventLogSync);
  247. InterlockedDecrement(&lTotalLoggers);
  248. if ( 0 == lTotalLoggers ) {
  249. if (hEventLogFile != INVALID_HANDLE_VALUE) {
  250. FlushFileBuffers( hEventLogFile);
  251. CloseHandle(hEventLogFile);
  252. hEventLogFile = INVALID_HANDLE_VALUE;
  253. }
  254. }
  255. #endif
  256. } /* EVENT_LOG::~EVENT_LOG() */
  257. VOID
  258. EVENT_LOG::LogEvent(
  259. IN DWORD idMessage,
  260. IN WORD nSubStrings,
  261. IN const CHAR * rgpszSubStrings[],
  262. IN DWORD errCode)
  263. /*++
  264. Description:
  265. Log an event to the event logger
  266. Arguments:
  267. idMessage Identifies the event message
  268. nSubStrings Number of substrings to include in
  269. this message. (Maybe 0)
  270. rgpszSubStrings array of substrings included in the message
  271. (Maybe NULL if nSubStrings == 0)
  272. errCode An error code from Win32 or NT_STATUS.
  273. If this is not Zero, it is considered as
  274. "raw" data to be included in message
  275. Returns:
  276. None
  277. --*/
  278. {
  279. WORD wType; // Type of Event to be logged
  280. //
  281. // Find type of message for the event log
  282. //
  283. if ( NT_INFORMATION( idMessage)) {
  284. wType = EVENTLOG_INFORMATION_TYPE;
  285. } else
  286. if ( NT_WARNING( idMessage)) {
  287. wType = EVENTLOG_WARNING_TYPE;
  288. } else
  289. if ( NT_ERROR( idMessage)) {
  290. wType = EVENTLOG_ERROR_TYPE;
  291. } else {
  292. wType = EVENTLOG_ERROR_TYPE;
  293. }
  294. //
  295. // Log the event
  296. //
  297. EVENT_LOG::LogEventPrivate( idMessage,
  298. wType,
  299. nSubStrings,
  300. rgpszSubStrings,
  301. errCode);
  302. return;
  303. } /* EVENT_LOG::LogEvent() */
  304. VOID
  305. EVENT_LOG::LogEvent(
  306. IN DWORD idMessage,
  307. IN WORD nSubStrings,
  308. IN WCHAR * rgpszSubStrings[],
  309. IN DWORD errCode)
  310. /*++
  311. Description:
  312. Simple Unicode wrapper
  313. Arguments:
  314. idMessage Identifies the event message
  315. nSubStrings Number of substrings to include in
  316. this message. (Maybe 0)
  317. rgpszSubStrings array of substrings included in the message
  318. (Maybe NULL if nSubStrings == 0)
  319. errCode An error code from Win32 or WinSock or NT_STATUS.
  320. If this is not Zero, it is considered as
  321. "raw" data to be included in message
  322. Returns:
  323. None
  324. --*/
  325. {
  326. LPCSTR * apsz;
  327. DWORD cch;
  328. DWORD i;
  329. WORD nUsedSubStrings = nSubStrings;
  330. static const CHAR *szEmptyString = "";
  331. __try {
  332. apsz = new LPCSTR[nSubStrings];
  333. if ( !apsz ) {
  334. nUsedSubStrings = 0;
  335. __leave;
  336. }
  337. ZeroMemory(apsz, nSubStrings * sizeof(apsz[0]));
  338. //
  339. // Convert the array of Wide char parameters
  340. //
  341. for ( i = 0; i < nSubStrings; i++ ) {
  342. UINT cb;
  343. cb = (wcslen( rgpszSubStrings[i] ) + 1) * sizeof(CHAR);
  344. apsz[i] = new CHAR[cb];
  345. if (!apsz[i]) {
  346. //
  347. // Ouch, we can't event convert the memory for the parameters.
  348. // We'll just log the error without the params then
  349. //
  350. nUsedSubStrings = 0;
  351. __leave;
  352. }
  353. cch = WideCharToMultiByte( CP_ACP,
  354. WC_COMPOSITECHECK,
  355. rgpszSubStrings[i],
  356. -1,
  357. (LPSTR)apsz[i],
  358. cb,
  359. NULL,
  360. NULL );
  361. *((CHAR *) apsz[i] + cb) = '\0';
  362. }
  363. }
  364. __finally {
  365. //
  366. // If no substrings, then nothing to convert
  367. //
  368. LogEvent( idMessage,
  369. nUsedSubStrings,
  370. nUsedSubStrings ? apsz : &szEmptyString,
  371. errCode );
  372. if (apsz) {
  373. for ( i = 0; i < nSubStrings; i++ ) {
  374. if (apsz[i]) {
  375. delete [] (VOID *)apsz[i];
  376. }
  377. }
  378. delete [] apsz;
  379. }
  380. }
  381. }
  382. //
  383. // Private functions.
  384. //
  385. VOID
  386. EVENT_LOG::LogEventPrivate(
  387. IN DWORD idMessage,
  388. IN WORD wEventType,
  389. IN WORD nSubStrings,
  390. IN const CHAR * apszSubStrings[],
  391. IN DWORD errCode )
  392. /*++
  393. Description:
  394. Log an event to the event logger.
  395. ( Private version, includes EventType)
  396. Arguments:
  397. idMessage Identifies the event message
  398. wEventType Specifies the severety of the event
  399. (error, warning, or informational).
  400. nSubStrings Number of substrings to include in
  401. this message. (Maybe 0)
  402. apszSubStrings array of substrings included in the message
  403. (Maybe NULL if nSubStrings == 0)
  404. errCode An error code from Win32 or NT_STATUS.
  405. If this is not Zero, it is considered as
  406. "raw" data to be included in message
  407. Returns:
  408. None
  409. --*/
  410. {
  411. VOID * pRawData = NULL;
  412. DWORD cbRawData = 0;
  413. BOOL fReturn;
  414. DWORD cch,cbWritten;
  415. #ifdef WINNT
  416. BOOL fReport;
  417. ASSERT( (nSubStrings == 0) || (apszSubStrings != NULL));
  418. ASSERTSZ( (m_hEventSource != NULL),TEXT("Event log handle is not valid"));
  419. if( errCode != 0 ) {
  420. pRawData = &errCode;
  421. cbRawData = sizeof(errCode);
  422. }
  423. m_ErrorCode = NO_ERROR;
  424. fReport = ReportEvent( m_hEventSource, // hEventSource
  425. wEventType, // fwEventType
  426. 0, // fwCategory
  427. idMessage, // IDEvent
  428. NULL, // pUserSid,
  429. nSubStrings, // cStrings
  430. cbRawData, // cbData
  431. (LPCTSTR *) apszSubStrings, // plpszStrings
  432. pRawData ); // lpvData
  433. if (!fReport) {
  434. m_ErrorCode = GetLastError();
  435. }
  436. #else
  437. //CHAR szErrCodeString[20];
  438. CHAR *pchBuff = NULL;
  439. SYSTEMTIME stCurrentTime;
  440. CHAR szFmtTime[32];
  441. CHAR szFmtDate[32];
  442. CHAR szErrorText[MAX_PATH] = {'\0'};
  443. if( (hEventLogFile == INVALID_HANDLE_VALUE) ||
  444. (m_hEventSource == INVALID_HANDLE_VALUE) ) {
  445. return;
  446. }
  447. if( errCode != 0 ) {
  448. pRawData = &errCode;
  449. cbRawData = sizeof(errCode);
  450. }
  451. m_ErrorCode = NO_ERROR;
  452. //
  453. // Write name of the service, date and time, severity
  454. //
  455. *szFmtTime = *szFmtDate = '\0';
  456. GetLocalTime(&stCurrentTime);
  457. FormatStdTime( &stCurrentTime, szFmtTime, 15);
  458. FormatStdDate( &stCurrentTime, szFmtDate, 15);
  459. wsprintf(szErrorText,"[%s] %s %s :",m_lpszSource,szFmtDate,szFmtTime);
  460. WriteFile(hEventLogFile,
  461. szErrorText,
  462. lstrlen(szErrorText),
  463. &cbWritten,
  464. NULL);
  465. //
  466. // Read message and add inserts
  467. //
  468. cch = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  469. FORMAT_MESSAGE_MAX_WIDTH_MASK |
  470. FORMAT_MESSAGE_FROM_HMODULE |
  471. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  472. m_hEventSource,
  473. idMessage,
  474. 0,
  475. (LPSTR) &pchBuff,
  476. 1024,
  477. (va_list *)apszSubStrings
  478. );
  479. if (cch ) {
  480. TAKE_MUTEX_OBJ t(EventLogSync);
  481. fReturn = WriteFile(hEventLogFile,pchBuff,cch,&cbWritten,NULL);
  482. LocalFree(pchBuff);
  483. if (cbWritten) {
  484. WriteFile(hEventLogFile,"\n\r",2,&cbWritten,NULL);
  485. return ;
  486. }
  487. }
  488. m_ErrorCode = GetLastError();
  489. #endif
  490. } /* EVENT_LOG::~LogEventPrivate() */
  491. VOID
  492. WINAPI
  493. RegisterStiEventSources(
  494. VOID
  495. )
  496. /*++
  497. Description:
  498. Adds necessary registry entry when installing service
  499. Arguments:
  500. Returns:
  501. None
  502. --*/
  503. {
  504. RegEntry re(PSZ_EVENTLOG_REG_ENTRY,HKEY_LOCAL_MACHINE);
  505. re.SetValue(PSZ_PARAMETERS_REG_ENTRY,STI_IMAGE_NAME);
  506. re.SetValue(PSZ_TYPES_REG_ENTRY,7);
  507. }
  508. /********************************* End of File ***************************/