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.

848 lines
20 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1991 - 1992
  6. //
  7. // File: util.c
  8. //
  9. // Contents: General Purpose functions for the security interface
  10. //
  11. // Functions: SPException -- Handler for exceptions in packages
  12. // WLsaControlFunction -- Worker for SecurityPackageControl()
  13. // LsaControlFunction -- User mode stub
  14. // LsaQueryPackage -- User mode stub
  15. //
  16. //
  17. // History: 14 Aug 92 RichardW Created
  18. //
  19. //------------------------------------------------------------------------
  20. #include <lsapch.hxx>
  21. extern "C"
  22. {
  23. #include "sesmgr.h"
  24. #include "spdebug.h"
  25. #include "perf.hxx"
  26. }
  27. NTSTATUS GetMemStats(PUCHAR, DWORD *);
  28. #if DBG
  29. SpmExceptDbg ExceptDebug;
  30. DWORD FaultingTid;
  31. extern SpmDbg_MemoryFailure MemFail;
  32. #endif // DBG
  33. typedef SecurityUserData SECURITY_USER_DATA, *PSECURITY_USER_DATA;
  34. //+---------------------------------------------------------------------------
  35. //
  36. // Function: SpExceptionFilter
  37. //
  38. // Synopsis: General Exception filter, invoked by the SP_EXCEPTION macro.
  39. //
  40. // Arguments: [pSession] --
  41. // [pException] --
  42. //
  43. //
  44. // History: 8-09-95 RichardW Created
  45. //
  46. // Notes:
  47. //
  48. //----------------------------------------------------------------------------
  49. LONG
  50. SpExceptionFilter( PVOID pSession,
  51. EXCEPTION_POINTERS * pException)
  52. {
  53. DWORD_PTR CurrentPackage;
  54. PLSAP_SECURITY_PACKAGE pPackage = NULL;
  55. UNICODE_STRING LsaString = { 3 * sizeof( WCHAR ), 4 * sizeof( WCHAR ), L"LSA" };
  56. #if DBG
  57. DsysException(pException);
  58. PSpmExceptDbg pExcept;
  59. pExcept = (PSpmExceptDbg) TlsGetValue(dwExceptionInfo);
  60. if (!pExcept)
  61. {
  62. pExcept = &ExceptDebug;
  63. TlsSetValue(dwExceptionInfo, pExcept);
  64. }
  65. FaultingTid = GetCurrentThreadId();
  66. pExcept->ThreadId = GetCurrentThreadId();
  67. pExcept->pInstruction = pException->ExceptionRecord->ExceptionAddress;
  68. pExcept->Access = pException->ExceptionRecord->ExceptionInformation[0];
  69. pExcept->pMemory = (void *) pException->ExceptionRecord->ExceptionInformation[1];
  70. #endif
  71. CurrentPackage = GetCurrentPackageId();
  72. if (CurrentPackage != SPMGR_ID)
  73. {
  74. pPackage = SpmpLocatePackage( CurrentPackage );
  75. }
  76. SpmpReportEventU(
  77. EVENTLOG_ERROR_TYPE,
  78. SPMEVENT_PACKAGE_FAULT,
  79. CATEGORY_SPM,
  80. sizeof(EXCEPTION_RECORD),
  81. pException->ExceptionRecord,
  82. 1,
  83. ((CurrentPackage == SPMGR_ID || pPackage == NULL) ?
  84. &LsaString :
  85. &pPackage->Name )
  86. );
  87. return(EXCEPTION_EXECUTE_HANDLER);
  88. }
  89. //+-------------------------------------------------------------------------
  90. //
  91. // Function: SPException
  92. //
  93. // Synopsis: Handles an exception in a security package
  94. //
  95. // Effects: Varies, but may force an unload of a package.
  96. //
  97. // Arguments:
  98. //
  99. // Requires:
  100. //
  101. // Returns:
  102. //
  103. // Notes:
  104. //
  105. //--------------------------------------------------------------------------
  106. NTSTATUS
  107. SPException(NTSTATUS scRet,
  108. ULONG_PTR dwPackageID)
  109. {
  110. PSession pSession;
  111. PLSAP_SECURITY_PACKAGE pPackage;
  112. #if DBG
  113. PSpmExceptDbg pException = (PSpmExceptDbg) TlsGetValue(dwExceptionInfo);
  114. #endif
  115. pSession = GetCurrentSession();
  116. DebugLog((DEB_ERROR, "[%x] Exception in a package, code %x\n", pSession->dwProcessID, scRet));
  117. DebugLog((DEB_ERROR, "[%x] Address was @%x, %s address %x\n",
  118. pSession->dwProcessID,
  119. pException->pInstruction,
  120. (pException->Access ? "write" : "read"),
  121. pException->pMemory));
  122. if (dwPackageID == SPMGR_ID)
  123. {
  124. DebugLog((DEB_ERROR, " LSA itself hit a fault, thread %d\n", GetCurrentThreadId()));
  125. DebugLog((DEB_ERROR, " (ExceptionInfo @%x)\n", TlsGetValue(dwExceptionInfo)));
  126. #if DBG
  127. DsysAssertMsg( 0, "exception in LSA" );
  128. #endif
  129. return(scRet);
  130. }
  131. pPackage = SpmpLocatePackage( dwPackageID );
  132. if (!pPackage)
  133. {
  134. DebugLog((DEB_ERROR, " Invalid package ID passed\n"));
  135. return(scRet);
  136. }
  137. if ((scRet == STATUS_ACCESS_VIOLATION) ||
  138. (scRet == E_POINTER))
  139. {
  140. DebugLog((DEB_ERROR, " Package %ws created an access violation\n",
  141. pPackage->Name.Buffer));
  142. // Flag package as invalid
  143. pPackage->fPackage |= SP_INVALID;
  144. }
  145. if ((scRet == STATUS_NO_MEMORY) ||
  146. (scRet == STATUS_INSUFFICIENT_RESOURCES))
  147. {
  148. DebugLog((DEB_ERROR, " Out of memory situation exists\n"));
  149. DebugLog((DEB_ERROR, " Further requests may fail unless memory is freed\n"));
  150. }
  151. //
  152. // if the code is a success code, it is probably a WIN32 error so we
  153. // map it as such
  154. return(scRet);
  155. }
  156. //+-------------------------------------------------------------------------
  157. //
  158. // Function: WLsaQueryPackage
  159. //
  160. // Synopsis: Get info on a package (short enum), copy to client's address
  161. // space
  162. //
  163. // Effects: none
  164. //
  165. // Arguments:
  166. //
  167. // Requires:
  168. //
  169. // Returns:
  170. //
  171. // Notes:
  172. //
  173. //--------------------------------------------------------------------------
  174. NTSTATUS
  175. WLsaQueryPackageInfo(
  176. PSECURITY_STRING pPackageName,
  177. PSecPkgInfo * ppInfo
  178. )
  179. {
  180. NTSTATUS scRet;
  181. PLSAP_SECURITY_PACKAGE pPackage;
  182. WCHAR * pszString;
  183. PSession pSession = GetCurrentSession();
  184. ULONG cbData;
  185. PSecPkgInfo pClientInfo = NULL;
  186. PBYTE Where;
  187. UNICODE_STRING CommentString;
  188. UNICODE_STRING NameString;
  189. PSecPkgInfo pLocalInfo = NULL;
  190. SecPkgInfo PackageInfo = { 0 };
  191. LONG_PTR ClientOffset;
  192. ULONG ulStructureSize = sizeof(SecPkgInfo);
  193. DebugLog((DEB_TRACE, "QueryPackage\n"));
  194. *ppInfo = NULL;
  195. pPackage = SpmpLookupPackage(pPackageName);
  196. if (!pPackage)
  197. {
  198. return(STATUS_NO_SUCH_PACKAGE);
  199. }
  200. SetCurrentPackageId(pPackage->dwPackageID);
  201. StartCallToPackage( pPackage );
  202. __try
  203. {
  204. scRet = pPackage->FunctionTable.GetInfo(&PackageInfo);
  205. }
  206. __except (SP_EXCEPTION)
  207. {
  208. scRet = GetExceptionCode();
  209. scRet = SPException(scRet, pPackage->dwPackageID);
  210. }
  211. EndCallToPackage( pPackage );
  212. if (FAILED(scRet))
  213. {
  214. return(scRet);
  215. }
  216. //
  217. // Marshall the data to copy to the client
  218. //
  219. RtlInitUnicodeString(
  220. &NameString,
  221. PackageInfo.Name
  222. );
  223. RtlInitUnicodeString(
  224. &CommentString,
  225. PackageInfo.Comment
  226. );
  227. cbData = ulStructureSize +
  228. NameString.MaximumLength +
  229. CommentString.MaximumLength;
  230. pLocalInfo = (PSecPkgInfo) LsapAllocatePrivateHeap(cbData);
  231. if (pLocalInfo == NULL)
  232. {
  233. return(STATUS_INSUFFICIENT_RESOURCES);
  234. }
  235. pClientInfo = (PSecPkgInfo) LsapClientAllocate(cbData);
  236. if (pClientInfo == NULL)
  237. {
  238. LsapFreePrivateHeap(pLocalInfo);
  239. return(STATUS_INSUFFICIENT_RESOURCES);
  240. }
  241. ClientOffset = (LONG_PTR) ((PBYTE) pClientInfo - (PBYTE) pLocalInfo);
  242. Where = (PBYTE) (pLocalInfo + 1);
  243. *pLocalInfo = PackageInfo;
  244. pLocalInfo->Name = (LPWSTR) (Where + ClientOffset);
  245. RtlCopyMemory(
  246. Where,
  247. NameString.Buffer,
  248. NameString.MaximumLength
  249. );
  250. Where += NameString.MaximumLength;
  251. pLocalInfo->Comment = (LPWSTR) (Where + ClientOffset);
  252. RtlCopyMemory(
  253. Where,
  254. CommentString.Buffer,
  255. CommentString.MaximumLength
  256. );
  257. Where += CommentString.MaximumLength;
  258. DsysAssert(Where - (PBYTE) pLocalInfo == (LONG) cbData);
  259. scRet = LsapCopyToClient(
  260. pLocalInfo,
  261. pClientInfo,
  262. cbData);
  263. LsapFreePrivateHeap(pLocalInfo);
  264. if (FAILED(scRet))
  265. {
  266. LsapClientFree(pClientInfo);
  267. }
  268. *ppInfo = pClientInfo;
  269. return(scRet);
  270. }
  271. //+-------------------------------------------------------------------------
  272. //
  273. // Function: WLsaGetSecurityUserInfo
  274. //
  275. // Synopsis: worker function to get info about a logon session
  276. //
  277. // Effects:
  278. //
  279. // Arguments:
  280. //
  281. // Requires:
  282. //
  283. // Returns:
  284. //
  285. // Notes:
  286. //
  287. //
  288. //--------------------------------------------------------------------------
  289. NTSTATUS
  290. WLsaGetSecurityUserInfo(
  291. IN PLUID pLogonId,
  292. IN ULONG fFlags,
  293. OUT PSECURITY_USER_DATA * pUserInfo
  294. )
  295. {
  296. PLSAP_LOGON_SESSION pSession;
  297. NTSTATUS Status;
  298. PSECURITY_USER_DATA LocalUserData = NULL;
  299. PSECURITY_USER_DATA ClientBuffer = NULL;
  300. SECPKG_CLIENT_INFO ClientInfo;
  301. ULONG BufferSize;
  302. PUCHAR Where;
  303. LONG_PTR Offset;
  304. ULONG ulStructureSize = sizeof(SECURITY_USER_DATA);
  305. DebugLog((DEB_TRACE_WAPI,"WLsaGetSecurityUserInfo called\n"));
  306. //
  307. // if the logon ID is null, it is for the caller
  308. // so we know to go to the primary package.
  309. //
  310. if (pLogonId == NULL)
  311. {
  312. Status = LsapGetClientInfo(&ClientInfo);
  313. if (!NT_SUCCESS(Status))
  314. {
  315. return(Status);
  316. }
  317. pLogonId = &ClientInfo.LogonId;
  318. }
  319. pSession = LsapLocateLogonSession( pLogonId );
  320. if (!pSession)
  321. {
  322. DebugLog((DEB_WARN,"WLsaGetSecurityUserInfo called for non-existent LUID 0x%x:0x%x\n",
  323. pLogonId->LowPart,pLogonId->HighPart));
  324. Status = STATUS_NO_SUCH_LOGON_SESSION;
  325. goto Cleanup;
  326. }
  327. BufferSize = ulStructureSize +
  328. pSession->AccountName.Length +
  329. pSession->AuthorityName.Length +
  330. pSession->LogonServer.Length +
  331. RtlLengthSid(pSession->UserSid);
  332. LocalUserData = (PSECURITY_USER_DATA) LsapAllocatePrivateHeap(BufferSize);
  333. if (LocalUserData == NULL)
  334. {
  335. Status = STATUS_INSUFFICIENT_RESOURCES;
  336. goto Cleanup;
  337. }
  338. ClientBuffer = (PSECURITY_USER_DATA) LsapClientAllocate(BufferSize);
  339. if (ClientBuffer == NULL)
  340. {
  341. Status = STATUS_INSUFFICIENT_RESOURCES;
  342. goto Cleanup;
  343. }
  344. Offset = (LONG_PTR) ((PUCHAR) ClientBuffer - (PUCHAR) LocalUserData);
  345. Where = (PUCHAR) (LocalUserData + 1);
  346. //
  347. // Copy in all the fields from the logon session.
  348. //
  349. LocalUserData->pSid = (PSID) (Where + Offset);
  350. RtlCopyMemory(
  351. Where,
  352. pSession->UserSid,
  353. RtlLengthSid(pSession->UserSid)
  354. );
  355. Where += RtlLengthSid(pSession->UserSid);
  356. //
  357. // Copy in the user name
  358. //
  359. LocalUserData->UserName.Length =
  360. LocalUserData->UserName.MaximumLength = pSession->AccountName.Length;
  361. LocalUserData->UserName.Buffer = (LPWSTR) (Where + Offset);
  362. RtlCopyMemory(
  363. Where,
  364. pSession->AccountName.Buffer,
  365. pSession->AccountName.Length
  366. );
  367. Where += pSession->AccountName.Length;
  368. //
  369. // Copy in the domain name
  370. //
  371. LocalUserData->LogonDomainName.Length =
  372. LocalUserData->LogonDomainName.MaximumLength = pSession->AuthorityName.Length;
  373. LocalUserData->LogonDomainName.Buffer = (LPWSTR) (Where + Offset);
  374. RtlCopyMemory(
  375. Where,
  376. pSession->AuthorityName.Buffer,
  377. pSession->AuthorityName.Length
  378. );
  379. Where += pSession->AuthorityName.Length;
  380. //
  381. // Copy in the logon server
  382. //
  383. LocalUserData->LogonServer.Length =
  384. LocalUserData->LogonServer.MaximumLength = pSession->LogonServer.Length;
  385. LocalUserData->LogonServer.Buffer = (LPWSTR) (Where + Offset);
  386. RtlCopyMemory(
  387. Where,
  388. pSession->LogonServer.Buffer,
  389. pSession->LogonServer.Length
  390. );
  391. Where += pSession->LogonServer.Length;
  392. //
  393. // Copy this to the client
  394. //
  395. LsapReleaseLogonSession( pSession );
  396. Status = LsapCopyToClient(
  397. LocalUserData,
  398. ClientBuffer,
  399. BufferSize
  400. );
  401. if (!NT_SUCCESS(Status))
  402. {
  403. goto Cleanup;
  404. }
  405. *pUserInfo = ClientBuffer;
  406. ClientBuffer = NULL;
  407. Cleanup:
  408. if (LocalUserData != NULL)
  409. {
  410. LsapFreePrivateHeap(LocalUserData);
  411. }
  412. if (ClientBuffer != NULL)
  413. {
  414. LsapClientFree(ClientBuffer);
  415. }
  416. DebugLog((DEB_TRACE_WAPI,"GetUserInfo returned %x\n",Status));
  417. return(Status);
  418. }
  419. HANDLE hEventLog = INVALID_HANDLE_VALUE;
  420. DWORD LoggingLevel = (1 << EVENTLOG_ERROR_TYPE) | (1 << EVENTLOG_WARNING_TYPE) |
  421. (1 << EVENTLOG_INFORMATION_TYPE) ;
  422. WCHAR EventSourceName[] = TEXT("LsaSrv");
  423. #define MAX_EVENT_STRINGS 8
  424. //+---------------------------------------------------------------------------
  425. //
  426. // Function: SpmpInitializeEvents
  427. //
  428. // Synopsis: Connects to event log service
  429. //
  430. // Arguments: (none)
  431. //
  432. // History: 1-03-95 RichardW Created
  433. //
  434. // Notes:
  435. //
  436. //----------------------------------------------------------------------------
  437. BOOL
  438. SpmpInitializeEvents(void)
  439. {
  440. HKEY hKey;
  441. int err;
  442. DWORD disp;
  443. err = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  444. TEXT("System\\CurrentControlSet\\Services\\EventLog\\System\\LsaSrv"),
  445. 0,
  446. TEXT(""),
  447. REG_OPTION_NON_VOLATILE,
  448. KEY_WRITE,
  449. NULL,
  450. &hKey,
  451. &disp);
  452. if (err)
  453. {
  454. return(FALSE);
  455. }
  456. if (disp == REG_CREATED_NEW_KEY)
  457. {
  458. RegSetValueEx( hKey,
  459. TEXT("EventMessageFile"),
  460. 0,
  461. REG_EXPAND_SZ,
  462. (PBYTE) TEXT("%SystemRoot%\\system32\\lsasrv.dll"),
  463. sizeof(TEXT("%SystemRoot%\\system32\\lsasrv.dll")) );
  464. RegSetValueEx( hKey,
  465. TEXT("CategoryMessageFile"),
  466. 0,
  467. REG_EXPAND_SZ,
  468. (PBYTE) TEXT("%SystemRoot%\\system32\\lsasrv.dll"),
  469. sizeof(TEXT("%SystemRoot%\\system32\\lsasrv.dll")) );
  470. disp = 7;
  471. RegSetValueEx( hKey,
  472. TEXT("TypesSupported"),
  473. 0,
  474. REG_DWORD,
  475. (PBYTE) &disp,
  476. sizeof(DWORD) );
  477. disp = CATEGORY_MAX_CATEGORY - 1;
  478. RegSetValueEx( hKey,
  479. TEXT("CategoryCount"),
  480. 0,
  481. REG_DWORD,
  482. (PBYTE) &disp,
  483. sizeof(DWORD) );
  484. }
  485. RegCloseKey(hKey);
  486. hEventLog = RegisterEventSource(NULL, EventSourceName);
  487. if (hEventLog)
  488. {
  489. return(TRUE);
  490. }
  491. hEventLog = INVALID_HANDLE_VALUE;
  492. DebugLog((DEB_ERROR, "Could not open event log, error %d\n", GetLastError()));
  493. return(FALSE);
  494. }
  495. //+---------------------------------------------------------------------------
  496. //
  497. // Function: ReportServiceEvent
  498. //
  499. // Synopsis: Reports an event to the event log
  500. //
  501. // Arguments: [EventType] -- EventType (ERROR, WARNING, etc.)
  502. // [EventId] -- Event ID
  503. // [SizeOfRawData] -- Size of raw data
  504. // [RawData] -- Raw data
  505. // [NumberOfStrings] -- number of strings
  506. // ... -- PWSTRs to string data
  507. //
  508. // History: 1-03-95 RichardW Created
  509. //
  510. // Notes:
  511. //
  512. //----------------------------------------------------------------------------
  513. DWORD
  514. SpmpReportEvent(
  515. IN BOOL Unicode,
  516. IN WORD EventType,
  517. IN DWORD EventId,
  518. IN DWORD Category,
  519. IN DWORD SizeOfRawData,
  520. IN PVOID RawData,
  521. IN DWORD NumberOfStrings,
  522. ...
  523. )
  524. {
  525. va_list arglist;
  526. ULONG i;
  527. PWSTR Strings[ MAX_EVENT_STRINGS ];
  528. PSTR StringsA[ MAX_EVENT_STRINGS ];
  529. DWORD rv;
  530. if (hEventLog == INVALID_HANDLE_VALUE)
  531. {
  532. if (!SpmpInitializeEvents())
  533. {
  534. return((DWORD) -1);
  535. }
  536. }
  537. //
  538. // We're not supposed to be logging this, so nuke it
  539. //
  540. if ((LoggingLevel & (1 << EventType)) == 0)
  541. {
  542. return(0);
  543. }
  544. //
  545. // Look at the strings, if they were provided
  546. //
  547. va_start( arglist, NumberOfStrings );
  548. if (NumberOfStrings > MAX_EVENT_STRINGS) {
  549. NumberOfStrings = MAX_EVENT_STRINGS;
  550. }
  551. for (i=0; i<NumberOfStrings; i++) {
  552. if (Unicode)
  553. {
  554. Strings[ i ] = va_arg( arglist, PWSTR );
  555. }
  556. else
  557. {
  558. StringsA[ i ] = va_arg( arglist, PSTR );
  559. }
  560. }
  561. //
  562. // Report the event to the eventlog service
  563. //
  564. if (Unicode)
  565. {
  566. if (!ReportEventW( hEventLog,
  567. EventType,
  568. (WORD) Category,
  569. EventId,
  570. NULL,
  571. (WORD)NumberOfStrings,
  572. SizeOfRawData,
  573. (const WCHAR * *) Strings,
  574. RawData) )
  575. {
  576. rv = GetLastError();
  577. DebugLog((DEB_ERROR, "ReportEvent( %u ) failed - %u\n", EventId, GetLastError() ));
  578. }
  579. else
  580. {
  581. rv = ERROR_SUCCESS;
  582. }
  583. }
  584. else
  585. {
  586. if (!ReportEventA( hEventLog,
  587. EventType,
  588. (WORD) Category,
  589. EventId,
  590. NULL,
  591. (WORD)NumberOfStrings,
  592. SizeOfRawData,
  593. (const char * *) StringsA,
  594. RawData) )
  595. {
  596. rv = GetLastError();
  597. DebugLog((DEB_ERROR, "ReportEvent( %u ) failed - %u\n", EventId, GetLastError() ));
  598. }
  599. else
  600. {
  601. rv = ERROR_SUCCESS;
  602. }
  603. }
  604. return rv;
  605. }
  606. //+---------------------------------------------------------------------------
  607. //
  608. // Function: SpmpReportEventU
  609. //
  610. // Synopsis: Reports an event to the event log
  611. //
  612. // Arguments: [EventType] -- EventType (ERROR, WARNING, etc.)
  613. // [EventId] -- Event ID
  614. // [SizeOfRawData] -- Size of raw data
  615. // [RawData] -- Raw data
  616. // [NumberOfStrings] -- number of strings
  617. // ... -- PUNICODE_STRINGs to string data
  618. //
  619. // Notes:
  620. //
  621. //----------------------------------------------------------------------------
  622. DWORD
  623. SpmpReportEventU(
  624. IN WORD EventType,
  625. IN DWORD EventId,
  626. IN DWORD Category,
  627. IN DWORD SizeOfRawData,
  628. IN PVOID RawData,
  629. IN DWORD NumberOfStrings,
  630. ...
  631. )
  632. {
  633. va_list arglist;
  634. ULONG i;
  635. PUNICODE_STRING Strings[ MAX_EVENT_STRINGS ];
  636. DWORD rv;
  637. if (hEventLog == INVALID_HANDLE_VALUE) {
  638. if ( !SpmpInitializeEvents()) {
  639. return( -1 );
  640. }
  641. }
  642. //
  643. // We're not supposed to be logging this, so nuke it
  644. //
  645. if (( LoggingLevel & ( 1 << EventType )) == 0 ) {
  646. return( 0 );
  647. }
  648. //
  649. // Look at the strings, if they were provided
  650. //
  651. va_start( arglist, NumberOfStrings );
  652. if ( NumberOfStrings > MAX_EVENT_STRINGS ) {
  653. NumberOfStrings = MAX_EVENT_STRINGS;
  654. }
  655. for ( i = 0 ; i < NumberOfStrings ; i++ ) {
  656. Strings[ i ] = va_arg( arglist, PUNICODE_STRING );
  657. }
  658. //
  659. // Report the event to the eventlog service
  660. //
  661. rv = ElfReportEventW(
  662. hEventLog,
  663. EventType,
  664. ( USHORT )Category,
  665. EventId,
  666. NULL,
  667. ( USHORT )NumberOfStrings,
  668. SizeOfRawData,
  669. Strings,
  670. RawData,
  671. 0,
  672. NULL,
  673. NULL
  674. );
  675. if ( !NT_SUCCESS( rv )) {
  676. DebugLog((DEB_ERROR, "ReportEvent( %u ) failed - %u\n", EventId, rv ));
  677. goto Cleanup;
  678. }
  679. rv = ERROR_SUCCESS;
  680. Cleanup:
  681. return rv;
  682. }
  683. BOOL
  684. SpmpShutdownEvents(void)
  685. {
  686. return(DeregisterEventSource(hEventLog));
  687. }