Source code of Windows XP (NT5)
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.

506 lines
13 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. eventlog.c
  6. Abstract:
  7. This module provides all functions that the Local Print Providor
  8. uses to write to the Event Log.
  9. InitializeEventLogging
  10. DisableEventLogging
  11. LogEvent
  12. GetUserSid
  13. Author:
  14. Dave Snipp (DaveSn) 15-Mar-1991
  15. Revision History:
  16. Matthew Felton ( MattFe ) 15-Mar-1995
  17. Change defaults on Workstation to not log information messages
  18. Also add regsitry key to allow user to filter some types of call
  19. --*/
  20. #include <precomp.h>
  21. #pragma hdrstop
  22. #include "clusspl.h"
  23. #define MAX_MERGE_STRINGS 7
  24. HANDLE hEventSource = NULL;
  25. #if DBG
  26. BOOL EventLogFull = FALSE;
  27. #endif
  28. BOOL
  29. GetUserSid(
  30. PTOKEN_USER *ppTokenUser,
  31. PDWORD pcbTokenUser
  32. );
  33. DWORD
  34. InitializeEventLogging(
  35. PINISPOOLER pIniSpooler
  36. )
  37. {
  38. DWORD Status;
  39. HKEY hkey;
  40. DWORD dwData;
  41. DWORD Flags;
  42. NT_PRODUCT_TYPE NtProductType;
  43. //
  44. // Initialize defaults.
  45. //
  46. pIniSpooler->dwEventLogging = LOG_DEFAULTS_WORKSTATION_EVENTS;
  47. //
  48. // Default is no NetPopup. 0 - Disable NetPopup, 1 - Enable
  49. //
  50. pIniSpooler->bEnableNetPopups = 0;
  51. //
  52. // Caching Providers Might not require Event Logging
  53. //
  54. if ( ( pIniSpooler->SpoolerFlags & SPL_LOG_EVENTS ) == FALSE ) return TRUE;
  55. //
  56. // Turn on logging if we are a server.
  57. //
  58. if (RtlGetNtProductType(&NtProductType)) {
  59. if (NtProductType != NtProductWinNt) {
  60. pIniSpooler->dwEventLogging = LOG_ALL_EVENTS;
  61. }
  62. }
  63. //
  64. // If we aren't event logging or we are a cluster reg, then
  65. // don't initialize per-machine resources.
  66. //
  67. if( pIniSpooler != pLocalIniSpooler ){
  68. return NO_ERROR;
  69. }
  70. Status = RegCreateKey( HKEY_LOCAL_MACHINE,
  71. pIniSpooler->pszRegistryEventLog,
  72. &hkey );
  73. if( Status == NO_ERROR )
  74. {
  75. // Add the Event-ID message-file name to the subkey.
  76. Status = RegSetValueEx( hkey,
  77. L"EventMessageFile",
  78. 0,
  79. REG_EXPAND_SZ,
  80. (LPBYTE)pIniSpooler->pszEventLogMsgFile,
  81. wcslen( pIniSpooler->pszEventLogMsgFile ) * sizeof( WCHAR )
  82. + sizeof( WCHAR ) );
  83. if( Status != NO_ERROR )
  84. {
  85. DBGMSG( DBG_ERROR, ( "Could not set event message file: Error %d\n",
  86. Status ) );
  87. }
  88. dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE
  89. | EVENTLOG_INFORMATION_TYPE;
  90. if( Status == NO_ERROR )
  91. {
  92. Status = RegSetValueEx( hkey,
  93. L"TypesSupported",
  94. 0,
  95. REG_DWORD,
  96. (LPBYTE)&dwData,
  97. sizeof dwData );
  98. if( Status != NO_ERROR )
  99. {
  100. DBGMSG( DBG_ERROR, ( "Could not set supported types: Error %d\n",
  101. Status ) );
  102. }
  103. }
  104. RegCloseKey(hkey);
  105. }
  106. else
  107. {
  108. DBGMSG( DBG_ERROR, ( "Could not create registry key for event logging: Error %d\n",
  109. Status ) );
  110. }
  111. if( Status == NO_ERROR )
  112. {
  113. if( !( hEventSource = RegisterEventSource( NULL, L"Print" ) ) )
  114. Status = GetLastError( );
  115. }
  116. return Status;
  117. }
  118. VOID
  119. SplLogEventWorker(
  120. IN PINISPOOLER pIniSpooler,
  121. IN WORD EventType,
  122. IN NTSTATUS EventID,
  123. IN BOOL bInSplSem,
  124. IN LPWSTR pFirstString,
  125. IN va_list vargs
  126. )
  127. /*++
  128. Function Description:
  129. This provides a common entry point to support event logging. This is now
  130. called by the print processor and Win32spl.
  131. Parameters:
  132. EventType - E.g. LOG_ERROR (defined in local.h)
  133. EventID - Constant as defined in messages.h. This refers to a string
  134. resource located in the event-log message DLL specified in
  135. InitializeEventLogging (which currently is localspl.dll itself).
  136. bInSplSem - flag to indicate if the call was made from inside SplSem
  137. pFirstString- The first of up to MAX_MERGE_STRINGS. This may be NULL,
  138. if no strings are to be inserted. If strings are passed to this
  139. routine, the last one must be followed by NULL.
  140. Don't rely on the fact that the argument copying stops when it
  141. reaches MAX_MERGE_STRINGS, because this could change if future
  142. messages are found to need more replaceable parameters.
  143. vargs - The remaining strings to be passed in.
  144. Return Values: NONE
  145. --*/
  146. {
  147. PTOKEN_USER pTokenUser = NULL;
  148. DWORD cbTokenUser;
  149. PSID pSid = NULL;
  150. LPWSTR pMergeStrings[MAX_MERGE_STRINGS];
  151. WORD cMergeStrings = 0, index;
  152. DWORD LastError = GetLastError();
  153. if (!hEventSource)
  154. return;
  155. //
  156. // If the Inispooler is NULL, don't check whether to log an event, just log one,
  157. // This allows us to log events when failing to start up spooler.
  158. //
  159. if ( pIniSpooler )
  160. {
  161. if (( pIniSpooler->dwEventLogging & EventType ) == FALSE )
  162. return;
  163. if ( ( pIniSpooler->SpoolerFlags & SPL_LOG_EVENTS ) == FALSE )
  164. return;
  165. }
  166. if( GetUserSid( &pTokenUser, &cbTokenUser ) )
  167. pSid = pTokenUser->User.Sid;
  168. // Put the strings into a format accepted by ReportEvent,
  169. // by picking off each non-null argument, and storing it in the array
  170. // of merge strings. Continue till we hit a NULL, or MAX_MERGE_STRINGS.
  171. if( pFirstString )
  172. {
  173. LPWSTR pszInsert;
  174. if (pMergeStrings[cMergeStrings] = AllocSplStr(pFirstString))
  175. {
  176. cMergeStrings++;
  177. }
  178. else
  179. {
  180. goto CleanUp;
  181. }
  182. while ((cMergeStrings < MAX_MERGE_STRINGS) &&
  183. (pszInsert = va_arg(vargs, LPWSTR))) {
  184. if (pMergeStrings[cMergeStrings] = AllocSplStr(pszInsert))
  185. {
  186. cMergeStrings++;
  187. }
  188. else
  189. {
  190. goto CleanUp;
  191. }
  192. }
  193. }
  194. //
  195. // Leave the semaphore before calling into the event logging service
  196. //
  197. if (bInSplSem)
  198. {
  199. LeaveSplSem();
  200. SplOutSem();
  201. }
  202. if ( !ReportEvent( hEventSource, // handle returned by RegisterEventSource
  203. EventType, // event type to log
  204. 0, // event category
  205. EventID, // event identifier
  206. pSid, // user security identifier (optional)
  207. cMergeStrings, // number of strings to merge with message
  208. 0, // size of raw data (in bytes)
  209. pMergeStrings, // array of strings to merge with message
  210. NULL ) ) { // address of raw data
  211. #if DBG
  212. if( GetLastError() == ERROR_LOG_FILE_FULL ) {
  213. // Put out a warning message only the first time this happens:
  214. if( !EventLogFull ) {
  215. DBGMSG( DBG_WARNING, ( "The Event Log is full\n" ) );
  216. EventLogFull = TRUE;
  217. }
  218. } else {
  219. DBGMSG( DBG_WARNING, ( "ReportEvent failed: Error %d\n", GetLastError( ) ));
  220. }
  221. #endif // DBG
  222. }
  223. //
  224. // Reenter the semaphore after logging the event
  225. //
  226. if (bInSplSem)
  227. {
  228. EnterSplSem();
  229. }
  230. CleanUp:
  231. // Free the strings
  232. for (index = 0; index < cMergeStrings ; index++) {
  233. FreeSplStr(pMergeStrings[index]);
  234. }
  235. if( pTokenUser ) {
  236. FreeSplMem( pTokenUser );
  237. }
  238. // GetUserSid() wipes out the Last Error, so restore it before returning
  239. SetLastError(LastError);
  240. }
  241. VOID
  242. SplLogEvent(
  243. PINISPOOLER pIniSpooler,
  244. WORD EventType,
  245. NTSTATUS EventID,
  246. BOOL bInSplSem,
  247. LPWSTR pFirstString,
  248. ...
  249. )
  250. /*++
  251. Function Description: Writes to the event log with up to MAX_MERGE_STRINGS parameter strings.
  252. Parameters: EventType - E.g. LOG_ERROR (defined in local.h)
  253. EventID - Constant as defined in messages.h. This refers to a string
  254. resource located in the event-log message DLL specified in
  255. InitializeEventLogging (which currently is localspl.dll itself).
  256. bInSplSem - flag to indicate if the call was made from inside SplSem
  257. pFirstString - The first of up to MAX_MERGE_STRINGS. This may be NULL,
  258. if no strings are to be inserted. If strings are passed to this
  259. routine, the last one must be followed by NULL.
  260. Don't rely on the fact that the argument copying stops when it
  261. reaches MAX_MERGE_STRINGS, because this could change if future
  262. messages are found to need more replaceable parameters.
  263. Return Values: NONE
  264. --*/
  265. {
  266. va_list vargs;
  267. va_start(vargs, pFirstString);
  268. SplLogEventWorker(pIniSpooler, EventType, EventID, bInSplSem, pFirstString, vargs);
  269. va_end(vargs);
  270. }
  271. VOID
  272. PrintProcLogEvent(
  273. WORD EventType,
  274. NTSTATUS EventID,
  275. LPWSTR pLog
  276. )
  277. /*++
  278. Function Description: This is an export for the print processor to log errors.
  279. Parameters: EventType - E.g. LOG_ERROR (defined in local.h)
  280. EventID - Constant as defined in messages.h
  281. pLog - string containg the log message
  282. Return Values: NONE
  283. --*/
  284. {
  285. // Ensure that the last parameter is NULL
  286. if (pLog == NULL)
  287. {
  288. SplLogEvent(pLocalIniSpooler, EventType, EventID, FALSE, NULL);
  289. }
  290. else
  291. {
  292. SplLogEvent(pLocalIniSpooler, EventType, EventID, FALSE, pLog, NULL);
  293. }
  294. return;
  295. }
  296. VOID
  297. SplLogEventExternal(
  298. IN WORD EventType,
  299. IN DWORD EventID,
  300. IN LPWSTR pFirstString,
  301. ...
  302. )
  303. /*++
  304. Function Description:
  305. This is an export for external components to log an event. (It is currently
  306. used for Win32spl). It supports variable arguments, unlike PrintProcLogEvent.
  307. Parameters:
  308. EventType - E.g. LOG_ERROR (defined in local.h)
  309. EventID - Constant as defined in messages.h
  310. pFirstString - The first string supplied by the system in the log message.
  311. ... - The remaining strings, must be NULL terminated.
  312. Return Values: NONE
  313. --*/
  314. {
  315. va_list vargs;
  316. va_start(vargs, pFirstString);
  317. //
  318. // It might not seem logical to use the local inispooler. However, win32spl's
  319. // inispooler's explicitely turn off event logging. So, this is necessary.
  320. // Passing in NULL seems worse since this would mean you could not tone down
  321. // event logging for those events.
  322. //
  323. SplLogEventWorker(pLocalIniSpooler, EventType, (NTSTATUS)EventID, FALSE, pFirstString, vargs);
  324. va_end(vargs);
  325. }
  326. // GetUserSid
  327. //
  328. // Well, actually it gets a pointer to a newly allocated TOKEN_USER,
  329. // which contains a SID, somewhere.
  330. // Caller must remember to free it when it's been used.
  331. BOOL
  332. GetUserSid(
  333. PTOKEN_USER *ppTokenUser,
  334. PDWORD pcbTokenUser
  335. )
  336. {
  337. HANDLE TokenHandle;
  338. HANDLE ImpersonationToken;
  339. PTOKEN_USER pTokenUser = NULL;
  340. DWORD cbTokenUser = 0;
  341. DWORD cbNeeded;
  342. BOOL bRet = FALSE;
  343. if ( !GetTokenHandle( &TokenHandle) ) {
  344. return FALSE;
  345. }
  346. ImpersonationToken = RevertToPrinterSelf();
  347. bRet = GetTokenInformation( TokenHandle,
  348. TokenUser,
  349. pTokenUser,
  350. cbTokenUser,
  351. &cbNeeded);
  352. // We've passed a NULL pointer and 0 for the amount of memory
  353. // allocated. We expect to fail with bRet = FALSE and
  354. // GetLastError = ERROR_INSUFFICIENT_BUFFER. If we do not
  355. // have these conditions we will return FALSE
  356. if ( !bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) ) {
  357. pTokenUser = AllocSplMem( cbNeeded );
  358. if ( pTokenUser == NULL ) {
  359. goto GetUserSidDone;
  360. }
  361. cbTokenUser = cbNeeded;
  362. bRet = GetTokenInformation( TokenHandle,
  363. TokenUser,
  364. pTokenUser,
  365. cbTokenUser,
  366. &cbNeeded );
  367. } else {
  368. //
  369. // Any other case -- return FALSE
  370. //
  371. bRet = FALSE;
  372. }
  373. GetUserSidDone:
  374. if ( bRet == TRUE ) {
  375. *ppTokenUser = pTokenUser;
  376. *pcbTokenUser = cbTokenUser;
  377. } else if ( pTokenUser ) {
  378. FreeSplMem( pTokenUser );
  379. }
  380. ImpersonatePrinterClient( ImpersonationToken );
  381. CloseHandle( TokenHandle );
  382. return bRet;
  383. }