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.

1373 lines
35 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. init.c
  5. Abstract:
  6. Implementation of System File Checker initialization code.
  7. Author:
  8. Wesley Witt (wesw) 18-Dec-1998
  9. Revision History:
  10. Andrew Ritz (andrewr) 6-Jul-1999 : added comments
  11. --*/
  12. #include "sfcp.h"
  13. #pragma hdrstop
  14. //
  15. // globals
  16. //
  17. //
  18. // List of files that are to be protected
  19. //
  20. PSFC_REGISTRY_VALUE SfcProtectedDllsList;
  21. //
  22. // total number of protected files
  23. //
  24. ULONG SfcProtectedDllCount;
  25. //
  26. // This is a handle to the directory where the dll cache resides. The dll
  27. // cache is a store of valid versions of files that allows a quick restore
  28. // of files that change. The dll cache can be on the local machine or it
  29. // can be remote.
  30. //
  31. HANDLE SfcProtectedDllFileDirectory;
  32. //
  33. // This is a value indicating how much space to dedicate to the dllcache
  34. // this is expressed in bytes, but we store in MB in the registry and convert
  35. // to bytes at runtime
  36. //
  37. ULONGLONG SFCQuota;
  38. //
  39. // value that controls SFC's disable behavior
  40. //
  41. ULONG SFCDisable;
  42. //
  43. // value that controls how often SFC should perform scans
  44. //
  45. ULONG SFCScan;
  46. //
  47. // policy value that controls whether UI should show up on the system.
  48. // Note that this is different than the SFCNoPopUps global in that the
  49. // SFCNoPopUps policy is a union between the user being logged on and
  50. // the existing policy (ie., SFCNoPopUpsPolicy can be FALSE, but if a
  51. // user is not logged on, then SFCNoPopUps will be TRUE.)
  52. //
  53. ULONG SFCNoPopUpsPolicy;
  54. //
  55. // value that controls whether UI should show up on the system
  56. //
  57. ULONG SFCNoPopUps;
  58. //
  59. // values that controls the amount of debug output
  60. //
  61. WORD SFCDebugDump;
  62. WORD SFCDebugLog;
  63. //
  64. // path to the log file
  65. //
  66. WCHAR g_szLogFile[MAX_PATH];
  67. #ifdef SFCLOGFILE
  68. //
  69. // value that controls if we create a logfile of changes on the system.
  70. //
  71. ULONG SFCChangeLog;
  72. #endif
  73. //
  74. // value that controls how long we wait after a change notification before
  75. // attempting a reinstall of the files
  76. //
  77. ULONG SFCStall;
  78. //
  79. // value that indicates if we booted in safe mode or not. WFP doesn't run
  80. // in safe mode
  81. //
  82. ULONG SFCSafeBootMode;
  83. //
  84. // value that determines if we installed from a CD or from a network share
  85. //
  86. ULONG InstallFromCD;
  87. //
  88. // value that determines if we installed the servicepack from a CD or from a
  89. // network share
  90. //
  91. ULONG InstallSpFromCD;
  92. //
  93. // turn off WFP for 64 bit targets for awhile.
  94. // we do this by reversing the polarity of the SFCDisable key.
  95. //
  96. //#if defined(_AMD64_) || defined (_IA64_)
  97. //#define TURN_OFF_WFP
  98. //#endif
  99. #if DBG || defined(TURN_OFF_WFP)
  100. //
  101. // debug value that indicates if we're running in winlogon mode or test mode
  102. //
  103. ULONG RunningAsTest;
  104. #endif
  105. //
  106. // event that is signalled when the desktop (WinSta0_DesktopSwitch) changes.
  107. //
  108. HANDLE hEventDeskTop;
  109. //
  110. // event that is signalled when the user logs on
  111. //
  112. HANDLE hEventLogon;
  113. //
  114. // event that is signalled when the user logs off
  115. //
  116. HANDLE hEventLogoff;
  117. //
  118. // event that is signalled when we should stop watching for file changes
  119. //
  120. HANDLE WatchTermEvent;
  121. //
  122. // event that is signalled when we should terminate the queue validation
  123. // thread
  124. //
  125. HANDLE ValidateTermEvent;
  126. //
  127. // A named event that is signalled to force us to call DebugBreak().
  128. // this is convenient for breaking into certain threads.
  129. //
  130. #if DBG
  131. HANDLE SfcDebugBreakEvent;
  132. #endif
  133. //
  134. // full path to the golden os install source
  135. //
  136. WCHAR OsSourcePath[MAX_PATH*2];
  137. //
  138. // full path to the service pack install source
  139. //
  140. WCHAR ServicePackSourcePath[MAX_PATH*2];
  141. //
  142. // full path to the base driver cabinet cache (note that this will NOT have
  143. // i386 appended to it)
  144. //
  145. WCHAR DriverCacheSourcePath[MAX_PATH*2];
  146. //
  147. // path to system inf files (%systemroot%\inf)
  148. //
  149. WCHAR InfDirectory[MAX_PATH];
  150. //
  151. // set to TRUE if SFC prompted the user for credentials
  152. //
  153. BOOL SFCLoggedOn;
  154. //
  155. // path to the network share that we established network connection to
  156. //
  157. WCHAR SFCNetworkLoginLocation[MAX_PATH];
  158. //
  159. // Path to the protected DLL directory
  160. //
  161. UNICODE_STRING SfcProtectedDllPath;
  162. //
  163. // global module handle
  164. //
  165. HMODULE SfcInstanceHandle;
  166. //
  167. // Not zero if Sfc was completely initialized
  168. //
  169. LONG g_lIsSfcInitialized = 0;
  170. //
  171. // keeps track of windows that SFC creates in the system.
  172. //
  173. LIST_ENTRY SfcWindowList;
  174. RTL_CRITICAL_SECTION WindowCriticalSection;
  175. //
  176. // the queue validation thread id
  177. //
  178. DWORD g_dwValidationThreadID = 0;
  179. //
  180. // Non zero if first boot after a system restore
  181. //
  182. ULONG m_gulAfterRestore = 0;
  183. //
  184. // prototypes
  185. //
  186. BOOL
  187. pSfcCloseAllWindows(
  188. VOID
  189. );
  190. DWORD
  191. SfcDllEntry(
  192. HINSTANCE hInstance,
  193. DWORD Reason,
  194. LPVOID Context
  195. )
  196. /*++
  197. Routine Description:
  198. main dll entrypoint.
  199. Arguments:
  200. standard dllmain arguments.
  201. Return Value:
  202. WIN32 error code indicating whether dll load may occur.
  203. --*/
  204. {
  205. if (Reason == DLL_PROCESS_ATTACH) {
  206. //
  207. // record the module handle for later
  208. //
  209. SfcInstanceHandle = hInstance;
  210. //
  211. // we dont' care about thread creation notifications
  212. //
  213. DisableThreadLibraryCalls( hInstance );
  214. ClientApiInit();
  215. }
  216. else if (Reason == DLL_PROCESS_DETACH) {
  217. //
  218. // we have some state that should be cleaned up if we were loaded in
  219. // the client side of a dll
  220. //
  221. ClientApiCleanup();
  222. }
  223. return TRUE;
  224. }
  225. VOID
  226. SfcTerminateWatcherThread(
  227. VOID
  228. )
  229. /*++
  230. Routine Description:
  231. Routine cleans up sfc state and terminates all SFC threads so the system
  232. can be cleanly shutdown. The routine waits for all SFC threads to
  233. terminate before returning to winlogon.
  234. Arguments:
  235. none.
  236. Return Value:
  237. none.
  238. --*/
  239. {
  240. LONG lInit;
  241. if (SFCSafeBootMode) {
  242. DebugPrint( LVL_MINIMAL, L"We're in safe boot mode, so there are no threads to shutdown");
  243. return;
  244. }
  245. //
  246. // SFC_DISABLE_ONCE meaning says that we should turn off SFC for this boot,
  247. // but revert to normal SFC policy after this boot.
  248. //
  249. if (SFCDisable == SFC_DISABLE_ONCE) {
  250. SfcWriteRegDword( REGKEY_WINLOGON, REGVAL_SFCDISABLE, SFC_DISABLE_NORMAL );
  251. }
  252. //
  253. // if SFC wasn't successfully initialized, then we don't need to clean up
  254. // any worker threads
  255. //
  256. lInit = InterlockedExchange(&g_lIsSfcInitialized, 0);
  257. if ( 0 == lInit ) {
  258. return;
  259. }
  260. DebugPrint( LVL_MINIMAL, L"Shutting down all SFC threads...");
  261. //
  262. // The first thing to do is get rid of any UI that may be up on the system
  263. //
  264. pSfcCloseAllWindows();
  265. //
  266. // signal the other threads to cleanup and go away...
  267. //
  268. ASSERT(WatchTermEvent && ValidateTermEvent);
  269. //
  270. // clean up the scanning thread if it's running
  271. //
  272. if (hEventScanCancel) {
  273. ASSERT( hEventScanCancelComplete != NULL );
  274. SetEvent(hEventScanCancel);
  275. WaitForSingleObject(hEventScanCancelComplete,SFC_THREAD_SHUTDOWN_TIMEOUT);
  276. }
  277. //
  278. // wait for the validation thread only if not called by itself
  279. //
  280. if(hErrorThread != NULL)
  281. {
  282. if(GetCurrentThreadId() != g_dwValidationThreadID)
  283. {
  284. SetEvent(ValidateTermEvent);
  285. WaitForSingleObject( hErrorThread, SFC_THREAD_SHUTDOWN_TIMEOUT );
  286. }
  287. CloseHandle(hErrorThread);
  288. }
  289. SetEvent(WatchTermEvent);
  290. //
  291. // wait for them to end
  292. //
  293. if (WatcherThread) {
  294. WaitForSingleObject( WatcherThread, SFC_THREAD_SHUTDOWN_TIMEOUT );
  295. CloseHandle(WatcherThread);
  296. }
  297. CloseHandle(ValidateTermEvent);
  298. CloseHandle(WatchTermEvent);
  299. if (hEventIdle) {
  300. HANDLE h = hEventIdle;
  301. hEventIdle = NULL;
  302. CloseHandle(h);
  303. }
  304. #if DBG
  305. if (SfcDebugBreakEvent) {
  306. CloseHandle( SfcDebugBreakEvent );
  307. }
  308. #endif
  309. if (hEventDeskTop) {
  310. CloseHandle( hEventDeskTop );
  311. }
  312. if (hEventSrc) {
  313. DeregisterEventSource( hEventSrc );
  314. }
  315. SfcpSetSpecialEnvironmentVariables();
  316. DebugPrint( LVL_MINIMAL, L"All threads terminated, SFC exiting...");
  317. }
  318. #if DBG
  319. ULONG
  320. GetTimestampForImage(
  321. ULONG_PTR Module
  322. )
  323. /*++
  324. Routine Description:
  325. Routine for retrieving the timestamp of the specified image.
  326. Arguments:
  327. Module - module handle.
  328. Return Value:
  329. timestamp if available, otherwise zero.
  330. --*/
  331. {
  332. PIMAGE_DOS_HEADER DosHdr;
  333. ULONG dwTimeStamp;
  334. ASSERT( Module != 0 );
  335. try {
  336. DosHdr = (PIMAGE_DOS_HEADER) Module;
  337. if (DosHdr->e_magic == IMAGE_DOS_SIGNATURE) {
  338. dwTimeStamp = ((PIMAGE_NT_HEADERS32) ((LPBYTE)Module + DosHdr->e_lfanew))->FileHeader.TimeDateStamp;
  339. } else if (DosHdr->e_magic == IMAGE_NT_SIGNATURE) {
  340. dwTimeStamp = ((PIMAGE_NT_HEADERS32) DosHdr)->FileHeader.TimeDateStamp;
  341. } else {
  342. dwTimeStamp = 0;
  343. }
  344. } except (EXCEPTION_EXECUTE_HANDLER) {
  345. dwTimeStamp = 0;
  346. }
  347. return dwTimeStamp;
  348. }
  349. void
  350. PrintStartupBanner(
  351. void
  352. )
  353. /*++
  354. Routine Description:
  355. Routine for outputting a debug banner to the debugger.
  356. Arguments:
  357. none.
  358. Return Value:
  359. none.
  360. --*/
  361. {
  362. static WCHAR mnames[] = { L"JanFebMarAprMayJunJulAugSepOctNovDec" };
  363. LARGE_INTEGER MyTime;
  364. TIME_FIELDS TimeFields;
  365. ULONG TimeStamp;
  366. WCHAR buf[128];
  367. PWSTR TimeBuf;
  368. TimeStamp = GetTimestampForImage( (ULONG_PTR)SfcInstanceHandle );
  369. wcscpy( buf, L"System File Protection DLL, built on " );
  370. TimeBuf = &buf[wcslen(buf)];
  371. RtlSecondsSince1970ToTime( TimeStamp, &MyTime );
  372. RtlSystemTimeToLocalTime( &MyTime, &MyTime );
  373. RtlTimeToTimeFields( &MyTime, &TimeFields );
  374. wcsncpy( TimeBuf, &mnames[(TimeFields.Month - 1) * 3], 3 );
  375. swprintf(
  376. &TimeBuf[3],
  377. L" %02d, %04d @ %02d:%02d:%02d",
  378. TimeFields.Day,
  379. TimeFields.Year,
  380. TimeFields.Hour,
  381. TimeFields.Minute,
  382. TimeFields.Second
  383. );
  384. DebugPrint( LVL_MINIMAL, L"****************************************************************************************" );
  385. DebugPrint1( LVL_MINIMAL, L"%ws", buf );
  386. DebugPrint( LVL_MINIMAL, L"****************************************************************************************" );
  387. }
  388. #endif
  389. ULONG
  390. SfcInitProt(
  391. IN ULONG OverrideRegistry,
  392. IN ULONG RegDisable, OPTIONAL
  393. IN ULONG RegScan, OPTIONAL
  394. IN ULONG RegQuota, OPTIONAL
  395. IN HWND ProgressWindow, OPTIONAL
  396. IN PCWSTR SourcePath, OPTIONAL
  397. IN PCWSTR IgnoreFiles OPTIONAL
  398. )
  399. /*++
  400. Routine Description:
  401. Initializes the protected DLL verification code. Should be called before
  402. other entrypoints since it initializes many global variables that are
  403. needed by the WFP system
  404. Arguments:
  405. OverrideRegistry - if set to TRUE, use the passed in data instead of
  406. registry state. Set by GUI-mode setup since all of the
  407. registry isn't consistent yet.
  408. RegDisable - if OverrideRegistry is set, this value supercedes the
  409. SfcDisable registry value.
  410. RegScan - if OverrideRegistry is set, this value supercedes the
  411. SfcScan registry value.
  412. RegQuota - if OverrideRegistry is set, this value supercedes the
  413. SfcQuota registry value.
  414. ProgressWindow - specifies the progress window to send updates to. GUI
  415. mode setup specifies this since it already has a
  416. progress dialog on the screen.
  417. SourcePath - specifies the proper OS source path to be used during
  418. gui-mode setup if specified
  419. Return Value:
  420. NT status code indicating outcome.
  421. --*/
  422. {
  423. static BOOL Initialized = FALSE;
  424. WCHAR buf[MAX_PATH];
  425. PWSTR s;
  426. NTSTATUS Status;
  427. ULONG Response = 0;
  428. ULONG Tmp;
  429. HKEY hKey = NULL;
  430. ULONG SFCDebug;
  431. PSFC_GET_FILES pfGetFiles;
  432. #if 0
  433. OSVERSIONINFOEX osv;
  434. #endif
  435. SCAN_PARAMS ScanParams;
  436. //
  437. // make sure we only initialize ourselves once per process
  438. //
  439. if (Initialized) {
  440. return STATUS_SUCCESS;
  441. }
  442. Initialized = TRUE;
  443. SFCNoPopUps = 1;
  444. #if 0
  445. osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  446. GetVersionEx( (LPOSVERSIONINFO)&osv );
  447. #endif
  448. SfcpSetSpecialEnvironmentVariables();
  449. //
  450. // we will need this privelege later on
  451. //
  452. EnablePrivilege( SE_SECURITY_NAME, TRUE );
  453. InitializeListHead( &SfcErrorQueue );
  454. InitializeListHead( &SfcWindowList );
  455. RtlInitializeCriticalSection( &ErrorCs );
  456. RtlInitializeCriticalSection( &SilentRestoreQueue.CriticalSection );
  457. RtlInitializeCriticalSection( &UIRestoreQueue.CriticalSection );
  458. RtlInitializeCriticalSection( &WindowCriticalSection );
  459. RtlInitializeCriticalSection( &g_GeneralCS );
  460. SilentRestoreQueue.FileQueue = INVALID_HANDLE_VALUE;
  461. UIRestoreQueue.FileQueue = INVALID_HANDLE_VALUE;
  462. //
  463. // retreive all of our registry settings
  464. //
  465. if (OverrideRegistry) {
  466. SFCDisable = RegDisable;
  467. SFCScan = RegScan;
  468. Tmp = RegQuota;
  469. }
  470. else
  471. {
  472. SFCDisable = SfcQueryRegDwordWithAlternate( REGKEY_POLICY, REGKEY_WINLOGON, REGVAL_SFCDISABLE, 0 );
  473. SFCScan = SfcQueryRegDwordWithAlternate( REGKEY_POLICY, REGKEY_WINLOGON, REGVAL_SFCSCAN, 0 );
  474. Tmp = SfcQueryRegDwordWithAlternate( REGKEY_POLICY, REGKEY_WINLOGON, REGVAL_SFCQUOTA, 0 );
  475. }
  476. //
  477. // sfcquota is expressed in MB... convert to bytes
  478. //
  479. if (Tmp == SFC_QUOTA_ALL_FILES) {
  480. SFCQuota = (ULONGLONG)-1;
  481. } else {
  482. SFCQuota = Tmp * (1024*1024);
  483. }
  484. SFCDebug = SfcQueryRegDwordWithAlternate( REGKEY_POLICY, REGKEY_WINLOGON, REGVAL_SFCDEBUG, 0 );
  485. SFCDebugDump = LOWORD(SFCDebug);
  486. SFCDebugLog = HIWORD(SFCDebug);
  487. SfcQueryRegPath(REGKEY_WINLOGON, REGVAL_SFCLOGFILE, REGVAL_SFCLOGFILE_DEFAULT, g_szLogFile, UnicodeChars(g_szLogFile));
  488. #ifdef SFCLOGFILE
  489. SFCChangeLog = SfcQueryRegDwordWithAlternate( REGKEY_POLICY, REGKEY_WINLOGON, REGVAL_SFCCHANGELOG, 0 );
  490. #endif
  491. SFCStall = SfcQueryRegDwordWithAlternate( REGKEY_POLICY, REGKEY_WINLOGON, REGVAL_SFCSTALL, 0 );
  492. SFCSafeBootMode = SfcQueryRegDword( REGKEY_SAFEBOOT, REGVAL_OPTIONVALUE, 0 );
  493. m_gulAfterRestore = SfcQueryRegDword( REGKEY_WINLOGON, REGVAL_SFCRESTORED, 0 );
  494. //
  495. // We also do this in SfcTerminateWatcherThread
  496. //
  497. if (SFCScan == SFC_SCAN_ONCE) {
  498. SfcWriteRegDword( REGKEY_WINLOGON, REGVAL_SFCSCAN, SFC_SCAN_NORMAL );
  499. }
  500. //
  501. // handle the source path variable for file copies
  502. //
  503. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_SETUP, 0, KEY_ALL_ACCESS, &hKey ) == ERROR_SUCCESS) {
  504. ULONG Size = sizeof(buf);
  505. if (RegQueryValueEx( hKey, REGVAL_SOURCEPATH, NULL, NULL, (LPBYTE)buf, &Size ) == ERROR_SUCCESS) {
  506. ExpandEnvironmentStrings( buf, OsSourcePath, UnicodeChars(OsSourcePath) );
  507. } else {
  508. DebugPrint( LVL_VERBOSE, L"Init: RegQueryValueEx failed" );
  509. }
  510. Size = sizeof(buf);
  511. if (RegQueryValueEx( hKey, REGVAL_SERVICEPACKSOURCEPATH, NULL, NULL, (LPBYTE)buf, &Size ) == ERROR_SUCCESS) {
  512. ExpandEnvironmentStrings( buf, ServicePackSourcePath, UnicodeChars(ServicePackSourcePath) );
  513. } else {
  514. DebugPrint( LVL_VERBOSE, L"Init: RegQueryValueEx(1) failed" );
  515. }
  516. //
  517. // save off the source path if the caller passed it in. this is only
  518. // passed in by GUI-setup, so we set the ServicePackSourcePath as well
  519. // as the os source path to the same value.
  520. //
  521. if (SourcePath) {
  522. wcsncpy(
  523. OsSourcePath,
  524. SourcePath,
  525. UnicodeChars(OsSourcePath) );
  526. wcsncpy(
  527. ServicePackSourcePath,
  528. SourcePath,
  529. UnicodeChars(ServicePackSourcePath) );
  530. }
  531. Size = sizeof(buf);
  532. if (RegQueryValueEx( hKey, REGVAL_DRIVERCACHEPATH, NULL, NULL, (LPBYTE)buf, &Size ) == ERROR_SUCCESS) {
  533. ExpandEnvironmentStrings( buf, DriverCacheSourcePath, UnicodeChars(DriverCacheSourcePath) );
  534. } else {
  535. DebugPrint( LVL_VERBOSE, L"Init: RegQueryValueEx(2) failed" );
  536. }
  537. Size = sizeof(DWORD);
  538. RegQueryValueEx( hKey, REGVAL_INSTALLFROMCD, NULL, NULL, (LPBYTE)&InstallFromCD, &Size );
  539. Size = sizeof(DWORD);
  540. RegQueryValueEx( hKey, REGVAL_INSTALLSPFROMCD, NULL, NULL, (LPBYTE)&InstallSpFromCD, &Size );
  541. RegCloseKey( hKey );
  542. } else {
  543. DebugPrint( LVL_VERBOSE, L"Init: RegOpenKey failed" );
  544. }
  545. ExpandEnvironmentStrings( L"%systemroot%\\inf\\", InfDirectory, UnicodeChars(InfDirectory) );
  546. if (!OsSourcePath[0]) {
  547. //
  548. // if we don't have an OS source path, default to the cdrom drive
  549. //
  550. // if the cdrom isn't present, just initialize to A:\, which is better
  551. // than an unitialized variable.
  552. //
  553. if (!SfcGetCdRomDrivePath( OsSourcePath )) {
  554. wcscpy( OsSourcePath, L"A:\\" );
  555. }
  556. }
  557. DebugPrint1( LVL_MINIMAL, L"OsSourcePath = [%ws]", OsSourcePath );
  558. DebugPrint1( LVL_MINIMAL, L"ServicePackSourcePath = [%ws]", ServicePackSourcePath );
  559. DebugPrint1( LVL_MINIMAL, L"DriverCacheSourcePath = [%ws]", DriverCacheSourcePath );
  560. #if DBG
  561. PrintStartupBanner();
  562. #endif
  563. //
  564. // if we're in safe mode, we don't protect files
  565. //
  566. if (SFCSafeBootMode) {
  567. return STATUS_SUCCESS;
  568. }
  569. //
  570. // default the stall value if one wasn't in the registry
  571. //
  572. if (!SFCStall) {
  573. SFCStall = SFC_QUEUE_STALL;
  574. }
  575. //
  576. // create the required events
  577. //
  578. hEventDeskTop = OpenEvent( SYNCHRONIZE, FALSE, L"WinSta0_DesktopSwitch" );
  579. Status = NtCreateEvent( &hEventLogon, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE );
  580. if (!NT_SUCCESS(Status)) {
  581. DebugPrint1( LVL_MINIMAL, L"Unable to create logon event, ec=0x%08x", Status );
  582. goto f0;
  583. }
  584. Status = NtCreateEvent( &hEventLogoff, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE );
  585. if (!NT_SUCCESS(Status)) {
  586. DebugPrint1( LVL_MINIMAL, L"Unable to create logoff event, ec=0x%08x", Status );
  587. goto f1;
  588. }
  589. hEventIdle = CreateEvent( NULL, TRUE, TRUE, SFC_IDLE_TRIGGER );
  590. if (!hEventIdle) {
  591. DebugPrint1( LVL_MINIMAL, L"Unable to create idle event, ec=0x%08x", GetLastError() );
  592. Status = STATUS_UNSUCCESSFUL;
  593. goto f2;
  594. }
  595. #if DBG
  596. {
  597. SECURITY_ATTRIBUTES sa;
  598. DWORD dwError;
  599. //
  600. // create the security descriptor
  601. //
  602. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  603. sa.bInheritHandle = TRUE;
  604. dwError = CreateSd(&sa.lpSecurityDescriptor);
  605. if(dwError != ERROR_SUCCESS)
  606. {
  607. DebugPrint1( LVL_MINIMAL, L"CreateSd failed, ec=%d", dwError );
  608. Status = STATUS_NO_MEMORY;
  609. goto f3;
  610. }
  611. SfcDebugBreakEvent = CreateEvent( &sa, FALSE, FALSE, L"SfcDebugBreakEvent" );
  612. MemFree(sa.lpSecurityDescriptor);
  613. if (SfcDebugBreakEvent == NULL) {
  614. DebugPrint1( LVL_MINIMAL, L"Unable to create debug break event, ec=%d", GetLastError() );
  615. Status = STATUS_NO_MEMORY;
  616. goto f3;
  617. }
  618. GetModuleFileName( NULL, buf, UnicodeChars(buf) );
  619. s = wcsrchr( buf, L'\\' );
  620. if (s && _wcsicmp( s+1, L"sfctest.exe" ) == 0) {
  621. SetEvent( hEventLogon );
  622. RunningAsTest = TRUE;
  623. UserLoggedOn = TRUE;
  624. SFCNoPopUps = 0;
  625. wcscpy( LoggedOnUserName, L"sfctest.exe" );
  626. }
  627. }
  628. #endif
  629. #ifdef TURN_OFF_WFP
  630. if (!RunningAsTest) {
  631. if (SFCDisable == SFC_DISABLE_QUIET) {
  632. //
  633. // if it's disabled let's make it enabled
  634. //
  635. SFCDisable = SFC_DISABLE_NORMAL;
  636. } else if (SFCDisable != SFC_DISABLE_SETUP) {
  637. //
  638. // if we're not setup mode, then disable WFP.
  639. //
  640. SFCDisable = SFC_DISABLE_QUIET;
  641. }
  642. }
  643. #else
  644. if (SFCDisable == SFC_DISABLE_QUIET) {
  645. SFCDisable = SFC_DISABLE_ASK;
  646. }
  647. #endif
  648. //
  649. // now determine how to initialize WFP
  650. //
  651. switch (SFCDisable) {
  652. case SFC_DISABLE_SETUP:
  653. #if 0
  654. //
  655. // if we're on some sort of server variant, then we never want
  656. // popups so we set "no popups" and on workstation we want the
  657. // normally spec'ed behavior.
  658. //
  659. SfcWriteRegDword(
  660. REGKEY_WINLOGON,
  661. L"SFCDisable",
  662. osv.wProductType == VER_NT_SERVER ? SFC_DISABLE_NOPOPUPS : SFC_DISABLE_NORMAL
  663. );
  664. #else
  665. //
  666. // that's no longer necessary. we always set SFCDisable to normal
  667. // mode regardless of server or workstation
  668. //
  669. SfcWriteRegDword(
  670. REGKEY_WINLOGON,
  671. L"SFCDisable",
  672. SFC_DISABLE_NORMAL
  673. );
  674. #endif
  675. GetModuleFileName( NULL, buf, UnicodeChars(buf) );
  676. s = wcsrchr( buf, L'\\' );
  677. //
  678. // if this is setup or the test harness, then set behavior to
  679. // "no popups", otherwise set WFP to normal behavior and log
  680. // in the eventlog that WFP is disabled
  681. //
  682. if ((s && _wcsicmp( s+1, L"setup.exe" ) == 0) ||
  683. (s && _wcsicmp( s+1, L"sfctest.exe" ) == 0))
  684. {
  685. SFCNoPopUps = 1;
  686. SFCNoPopUpsPolicy = 1;
  687. } else {
  688. SFCDisable = SFC_DISABLE_NORMAL;
  689. }
  690. break;
  691. case SFC_DISABLE_ONCE:
  692. //
  693. // if we're on some sort of server variant, then we never want
  694. // popups so we set "no popups" and on workstation we want the
  695. // normally spec'ed behavior.
  696. //
  697. if (!OverrideRegistry) {
  698. #if 0
  699. SfcWriteRegDword(
  700. REGKEY_WINLOGON,
  701. L"SFCDisable",
  702. osv.wProductType == VER_NT_SERVER ? SFC_DISABLE_NOPOPUPS : SFC_DISABLE_NORMAL
  703. );
  704. #else
  705. //
  706. // above code is no longer necessary. we always set SFCDisable
  707. // to normal mode regardless of server or workstation
  708. //
  709. SfcWriteRegDword(
  710. REGKEY_WINLOGON,
  711. L"SFCDisable",
  712. SFC_DISABLE_NORMAL
  713. );
  714. #endif
  715. }
  716. //
  717. // The only way to disable WFP with this behavior is to have a
  718. // kernel debugger present and installed. The idea here is that
  719. // testers and developers should have a kernel debugger attached
  720. // so we allow them to get their work done without putting a big
  721. // hole in WFP
  722. //
  723. if (KernelDebuggerEnabled) {
  724. SfcReportEvent( MSG_DISABLE, NULL, NULL, 0 );
  725. if (hEventIdle) {
  726. CloseHandle(hEventIdle);
  727. hEventIdle = NULL;
  728. }
  729. return STATUS_SUCCESS;
  730. }
  731. break;
  732. case SFC_DISABLE_NOPOPUPS:
  733. //
  734. // no popups just turns off popups but default behavior is the same
  735. // as usual.
  736. //
  737. SFCNoPopUps = 1;
  738. SFCNoPopUpsPolicy = 1;
  739. break;
  740. case SFC_DISABLE_QUIET:
  741. //
  742. // quiet disable turns off all of WFP
  743. //
  744. SfcReportEvent( MSG_DISABLE, NULL, NULL, 0 );
  745. if (hEventIdle) {
  746. CloseHandle(hEventIdle);
  747. hEventIdle = NULL;
  748. }
  749. return STATUS_SUCCESS;
  750. case SFC_DISABLE_ASK:
  751. //
  752. // put up a popup and ask if the user wants to override
  753. //
  754. // again, you must have a kernel debugger attached to override this
  755. // behavior
  756. //
  757. if (KernelDebuggerEnabled) {
  758. #if 0
  759. if (!SfcWaitForValidDesktop()) {
  760. DebugPrint1(LVL_MINIMAL, L"Failed waiting for the logon event, ec=0x%08x",Status);
  761. } else {
  762. if (UserLoggedOn) {
  763. HDESK hDeskOld;
  764. ASSERT( hUserDesktop != NULL );
  765. hDeskOld = GetThreadDesktop(GetCurrentThreadId());
  766. SetThreadDesktop( hUserDesktop );
  767. Response = MyMessageBox( NULL, IDS_PROTDLL_DISABLED, MB_YESNO );
  768. SetThreadDesktop( hDeskOld );
  769. if (Response == IDNO) {
  770. SfcReportEvent( MSG_DISABLE, NULL, NULL, 0 );
  771. return STATUS_SUCCESS;
  772. }
  773. } else {
  774. DebugPrint(LVL_MINIMAL,
  775. L"valid user is not logged on, ignoring S_D_A flag");
  776. }
  777. }
  778. #else
  779. SfcReportEvent( MSG_DISABLE, NULL, NULL, 0 );
  780. if (hEventIdle) {
  781. CloseHandle(hEventIdle);
  782. hEventIdle = NULL;
  783. }
  784. return STATUS_SUCCESS;
  785. #endif
  786. }
  787. break;
  788. case SFC_DISABLE_NORMAL:
  789. break;
  790. default:
  791. DebugPrint1(LVL_MINIMAL, L"SFCDisable is unknown value %d, defaulting to S_D_N",SFCDisable);
  792. #if 0
  793. SfcWriteRegDword(
  794. REGKEY_WINLOGON,
  795. REGVAL_SFCDISABLE,
  796. osv.wProductType == VER_NT_SERVER ? SFC_DISABLE_NOPOPUPS : SFC_DISABLE_NORMAL
  797. );
  798. #else
  799. //
  800. // above code is no longer necessary. we always set SFCDisable
  801. // to normal mode regardless of server or workstation
  802. //
  803. SfcWriteRegDword(
  804. REGKEY_WINLOGON,
  805. REGVAL_SFCDISABLE,
  806. SFC_DISABLE_NORMAL
  807. );
  808. #endif
  809. SFCDisable = SFC_DISABLE_NORMAL;
  810. break;
  811. }
  812. //
  813. // create our termination events...note that WatchTermEvent must be a
  814. // notification event because there will be more than one thread worker
  815. // thread waiting on that event
  816. //
  817. WatchTermEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  818. if (!WatchTermEvent) {
  819. Status = STATUS_UNSUCCESSFUL;
  820. DebugPrint1( LVL_MINIMAL, L"Unable to create WatchTermEvent event, ec=0x%08x", GetLastError() );
  821. goto f3;
  822. }
  823. ValidateTermEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  824. if (!ValidateTermEvent) {
  825. Status = STATUS_UNSUCCESSFUL;
  826. DebugPrint1( LVL_MINIMAL, L"Unable to create ValidateTermEvent event, ec=0x%08x", GetLastError() );
  827. goto f4;
  828. }
  829. ASSERT(WatchTermEvent && ValidateTermEvent);
  830. //
  831. // get our crypto libraries loaded and ready to go
  832. //
  833. //Status = LoadCrypto();
  834. //if (!NT_SUCCESS( Status )) {
  835. // goto f5;
  836. //}
  837. // at this point, sfcfiles.dll must be present on the system; load it
  838. pfGetFiles = SfcLoadSfcFiles(TRUE);
  839. if(NULL == pfGetFiles)
  840. {
  841. DebugPrint( LVL_MINIMAL, L"Could not load sfc.dll" );
  842. Status = STATUS_CORRUPT_SYSTEM_FILE;
  843. goto f5;
  844. }
  845. //
  846. // build up the list of files to protect
  847. //
  848. Status = SfcInitializeDllLists(pfGetFiles);
  849. if (!NT_SUCCESS( Status )) {
  850. DebugPrint1( LVL_MINIMAL, L"SfcInitializeDllLists failed, ec=0x%08x", Status );
  851. goto f6;
  852. }
  853. //
  854. // Now we can safely unload sfcfiles.dll since we've copied over the information
  855. //
  856. SfcLoadSfcFiles(FALSE);
  857. //
  858. // build up the directory watch list.
  859. //
  860. // We must do this before we can start watching the directories.
  861. //
  862. // This is also necessary in the GUI-mode setup case as well, where we
  863. // need to do a scan of the protected files; building the directory
  864. // list also initializes some per-file data that is necessary to complete
  865. // a scan
  866. //
  867. //
  868. if (!SfcBuildDirectoryWatchList()) {
  869. DWORD LastError = GetLastError();
  870. Status = STATUS_NO_MEMORY;
  871. DebugPrint1(LVL_MINIMAL, L"SfcBuildDirectoryWatchList failed, ec = %x",LastError);
  872. goto f6;
  873. }
  874. //
  875. // during setup, we populate the dll cache with files
  876. //
  877. if (SFCDisable == SFC_DISABLE_SETUP) {
  878. if (SfcPopulateCache(ProgressWindow, TRUE, FALSE, IgnoreFiles)) {
  879. Status = STATUS_SUCCESS;
  880. goto f7;
  881. } else {
  882. Status = STATUS_UNSUCCESSFUL;
  883. goto f7;
  884. }
  885. }
  886. if (SFCScan || m_gulAfterRestore != 0) {
  887. //
  888. // the progress window should be NULL or we won't show
  889. // any UI and the scan will be syncronous.
  890. //
  891. ASSERT(ProgressWindow == NULL);
  892. ScanParams.ProgressWindow = ProgressWindow;
  893. ScanParams.AllowUI = (0 == m_gulAfterRestore);
  894. ScanParams.FreeMemory = FALSE;
  895. Status = SfcScanProtectedDlls( &ScanParams );
  896. //
  897. // don't bother to bail out if the scan fails, as it's not a fatal
  898. // condition.
  899. //
  900. // reset the value since it will be checked in subsequent calls to SfcScanProtectedDlls
  901. // also reset the registry value
  902. if(m_gulAfterRestore != 0)
  903. SfcWriteRegDword(REGKEY_WINLOGON, REGVAL_SFCRESTORED, m_gulAfterRestore = 0);
  904. }
  905. //
  906. // finally start protecting dlls
  907. Status = SfcStartProtectedDirectoryWatch();
  908. g_lIsSfcInitialized = 1;
  909. goto f0;
  910. f7:
  911. // SfcBuildDirectoryWatchList cleanup here
  912. f6:
  913. // SfcInitializeDllLists cleanup here
  914. if (SfcProtectedDllsList) {
  915. MemFree(SfcProtectedDllsList);
  916. SfcProtectedDllsList = NULL;
  917. }
  918. if(IgnoreNextChange != NULL) {
  919. MemFree(IgnoreNextChange);
  920. IgnoreNextChange = NULL;
  921. }
  922. f5:
  923. ASSERT(ValidateTermEvent != NULL);
  924. CloseHandle( ValidateTermEvent );
  925. ValidateTermEvent = NULL;
  926. f4:
  927. ASSERT(WatchTermEvent != NULL);
  928. CloseHandle( WatchTermEvent );
  929. WatchTermEvent = NULL;
  930. f3:
  931. #if DBG
  932. if (SfcDebugBreakEvent) {
  933. CloseHandle( SfcDebugBreakEvent );
  934. SfcDebugBreakEvent = NULL;
  935. }
  936. #endif
  937. ASSERT(hEventIdle != NULL);
  938. CloseHandle( hEventIdle );
  939. hEventIdle = NULL;
  940. f2:
  941. ASSERT(hEventLogoff != NULL);
  942. CloseHandle( hEventLogoff );
  943. hEventLogoff = NULL;
  944. f1:
  945. ASSERT(hEventDeskTop != NULL);
  946. CloseHandle( hEventDeskTop );
  947. hEventDeskTop = NULL;
  948. f0:
  949. if (Status != STATUS_SUCCESS) {
  950. SfcReportEvent( MSG_INITIALIZATION_FAILED, 0, NULL, Status );
  951. }
  952. return(Status);
  953. }
  954. BOOL
  955. SfcpSetSpecialEnvironmentVariables(
  956. VOID
  957. )
  958. /*++
  959. Routine Description:
  960. This function sets some environment variables that are not part of the
  961. default environment. (These environment variables are normally set by
  962. winlogon.) The environment variables need to be set for us to resolve
  963. all the environment variables in our protected files list.
  964. Note that this routine simply mirrors variables from one location in
  965. the registry into a location that the session manager can access at
  966. it's initialization time.
  967. --*/
  968. {
  969. PWSTR string;
  970. DWORD count;
  971. BOOL retval;
  972. PCWSTR RegistryValues[] = {
  973. L"ProgramFilesDir"
  974. , L"CommonFilesDir"
  975. #ifdef WX86
  976. , L"ProgramFilesDir(x86)"
  977. , L"CommonFilesDir(x86)"
  978. #endif
  979. };
  980. #define EnvVarCount (sizeof(RegistryValues)/sizeof(PCWSTR))
  981. retval = TRUE;
  982. for (count = 0; count< EnvVarCount; count++) {
  983. string = SfcQueryRegString( REGKEY_WINDOWS, RegistryValues[count] );
  984. if (string) {
  985. if (SfcWriteRegString(
  986. REGKEY_SESSIONMANAGERSFC,
  987. RegistryValues[count],
  988. string) != ERROR_SUCCESS) {
  989. retval = FALSE;
  990. }
  991. MemFree( string );
  992. } else {
  993. retval = FALSE;
  994. }
  995. }
  996. return(retval);
  997. }
  998. BOOL
  999. pSfcCloseAllWindows(
  1000. VOID
  1001. )
  1002. /*++
  1003. Routine Description:
  1004. This function cycles through a global list of window structures, sending a
  1005. message to each of the windows to shutdown.
  1006. Arguments: None.
  1007. Return Value: TRUE indicates that all windows were successfully closed. If any
  1008. window cannot be closes, the return value is FALSE.
  1009. --*/
  1010. {
  1011. PLIST_ENTRY Current;
  1012. PSFC_WINDOW_DATA WindowData;
  1013. DWORD rc;
  1014. BOOL RetVal = TRUE;
  1015. RtlEnterCriticalSection( &WindowCriticalSection );
  1016. Current = SfcWindowList.Flink;
  1017. while (Current != &SfcWindowList) {
  1018. SetThreadDesktop( hUserDesktop );
  1019. WindowData = CONTAINING_RECORD( Current, SFC_WINDOW_DATA, Entry );
  1020. ASSERT( WindowData != NULL);
  1021. ASSERT( IsWindow(WindowData->hWnd) );
  1022. Current = Current->Flink;
  1023. rc = (DWORD) SendMessage(WindowData->hWnd, WM_WFPENDDIALOG, 0, 0);
  1024. if (rc != ERROR_SUCCESS) {
  1025. RetVal = FALSE;
  1026. DebugPrint2(
  1027. LVL_MINIMAL,
  1028. L"WM_WFPENDDIALOG failed [thread id 0x%08x], ec = %x",
  1029. WindowData->ThreadId,
  1030. rc );
  1031. }
  1032. RemoveEntryList( &WindowData->Entry );
  1033. MemFree( WindowData );
  1034. }
  1035. RtlLeaveCriticalSection( &WindowCriticalSection );
  1036. return(RetVal);
  1037. }
  1038. PSFC_WINDOW_DATA
  1039. pSfcCreateWindowDataEntry(
  1040. HWND hWnd
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. This function creates a new SFC_WINDOW_DATA structure and inserts it into a
  1045. list of structures. This is so that we can post a "cleanup" message to all
  1046. of our windows on shutdown, etc.
  1047. Arguments: hWnd - the window handle of the window we want to insert into the
  1048. list.
  1049. Return Value: NULL indicates failure, else we return a pointer to the newly
  1050. created SFC_WINDOW_DATA structure
  1051. --*/
  1052. {
  1053. PSFC_WINDOW_DATA WindowData;
  1054. ASSERT(IsWindow(hWnd));
  1055. WindowData = MemAlloc( sizeof(SFC_WINDOW_DATA) );
  1056. if (!WindowData) {
  1057. DebugPrint1(
  1058. LVL_MINIMAL,
  1059. L"Couldn't allocate memory for SFC_WINDOW_DATA for %x",
  1060. hWnd );
  1061. return(NULL);
  1062. }
  1063. WindowData->hWnd = hWnd;
  1064. WindowData->ThreadId = GetCurrentThreadId();
  1065. RtlEnterCriticalSection( &WindowCriticalSection );
  1066. InsertTailList( &SfcWindowList, &WindowData->Entry );
  1067. RtlLeaveCriticalSection( &WindowCriticalSection );
  1068. return(WindowData);
  1069. }
  1070. BOOL
  1071. pSfcRemoveWindowDataEntry(
  1072. PSFC_WINDOW_DATA WindowData
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. This function removes an SFC_WINDOW_DATA structure from our global list of
  1077. these structures and frees the memory associated with this structure.
  1078. This list is necessary so that we can post a "cleanup" message to all of
  1079. our windows on shutdown, etc.
  1080. This function is called by the actual window proc right before it goes away.
  1081. Arguments: WindowData - pointer to the SFC_WINDOW_DATA structure to be removed.
  1082. Return Value: TRUE indicates that the structure was removed successfully. FALSE
  1083. indicates that the structure was not in the global list and was
  1084. --*/
  1085. {
  1086. PLIST_ENTRY CurrentEntry;
  1087. PSFC_WINDOW_DATA WindowDataEntry;
  1088. BOOL RetVal = FALSE;
  1089. ASSERT(WindowData != NULL);
  1090. RtlEnterCriticalSection( &WindowCriticalSection );
  1091. CurrentEntry = SfcWindowList.Flink;
  1092. while (CurrentEntry != &SfcWindowList) {
  1093. WindowDataEntry = CONTAINING_RECORD( CurrentEntry, SFC_WINDOW_DATA, Entry );
  1094. if (WindowDataEntry == WindowData) {
  1095. RemoveEntryList( &WindowData->Entry );
  1096. MemFree( WindowData );
  1097. RetVal = TRUE;
  1098. break;
  1099. }
  1100. CurrentEntry = CurrentEntry->Flink;
  1101. }
  1102. RtlLeaveCriticalSection( &WindowCriticalSection );
  1103. return(RetVal);
  1104. }