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.

3267 lines
82 KiB

  1. /*
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ui.c
  5. Abstract:
  6. This file contains the mainloop for the Client Side Caching agent. The code has to mesh
  7. with the system startup, logon and logoff and these are different on NT and win9x.
  8. This file and all others in the reint directory have been written such that for NT they
  9. call the wide character win32 APIs while for win9x they call ANSI APIs.
  10. The agent runs as a thread in the context of winlogon.exe. CSCDLL.DLL resgisters itself
  11. to recieve a call from winlogon when a user logs on. The call is on a separate thread and
  12. is impersonated as the logged on user. This thread eventually calls reint_winmain which
  13. loops for ever, till the system is about to shutdown.
  14. file ntstuff.c contains the interface which is exposed to winlogon. On every logon
  15. this interface gets called, at which point, all the info necessary to impersonate the
  16. logged on user is obtained and kept in an in memory list of logged on users. The list
  17. also contains the SID for Local System.
  18. For doing sparse filling and Inode, the agent looks in the database to see which of
  19. the users on the list have read access right for the given file and uses that to fill
  20. the file.
  21. Author(s):
  22. Trent Gray Donald/Felix Andrews/Shishir Pardikar
  23. 1-9-1994
  24. Environment:
  25. Win32 (user-mode) DLL
  26. Revision History:
  27. NT source formatting
  28. Shishir Pardikar 2-19-97
  29. Winlogon Integration
  30. Shishir Pardikar 10-19-97
  31. --*/
  32. #include "pch.h"
  33. #pragma hdrstop
  34. #include "resource.h"
  35. #include "traynoti.h"
  36. #include <dbt.h>
  37. #include "lib3.h"
  38. #include "reint.h"
  39. #include "utils.h"
  40. #include "strings.h"
  41. #include "cscuiext.h"
  42. #include <userenv.h>
  43. #include <safeboot.h>
  44. //
  45. // defines/macros useed in this file
  46. //
  47. #if (_TCHAR != wchar_t)
  48. #error "Bad _TCHAR definition"
  49. #endif
  50. #if (_TEXT != L)
  51. #error "BAD _Text definiton"
  52. #endif
  53. // Timer to deal with double clicks and stuff like that.
  54. #define TRAY_ID 100
  55. // timer ID to make sure the Tray icon appears!
  56. #define TIMER_ADD_TRAY 101
  57. #define minOfFour(one,two,three,four) (min(min(one,two),min(three,four)))
  58. #define FILE_OPEN_THRESHOLD 16
  59. #define CI_LOGON 1
  60. #define CI_LOGOFF 2
  61. // #define STWM_CSCCLOSEDIALOGS (WM_USER + 212)
  62. typedef HWND (WINAPI *CSCUIINITIALIZE)(HANDLE hToken, DWORD dwFlags);
  63. typedef LRESULT (WINAPI *CSCUISETSTATE)(UINT uMsg, WPARAM wParam, LPARAM lParam);
  64. #define REG_VALUE_NT_BUILD_NUMBER _TEXT("NTBuildNumber")
  65. #define REG_VALUE_DISABLE_AUTOCHECK _TEXT("DisableAutoCheck")
  66. #define REG_KEY_NETCACHE_SETTINGS _TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\NetCache")
  67. #define AGENT_ALIVE (vfCSCEnabled && !vfStopRecieved)
  68. #define AGENT_ALIVE_AND_ACTIVE (AGENT_ALIVE && !vfAgentQuiet)
  69. #define AGENT_ALIVE_AND_HAVE_NET (AGENT_ALIVE && vcntNetDevices)
  70. #define FIVE_MINUTES (5 * 1000 * 60)
  71. #define MAX_LIST_SIZE 1024
  72. #define PI_LITELOAD 0x00000004 // Lite load of the profile (for system use only)
  73. //
  74. // Data declarations/definitions
  75. //
  76. #pragma data_seg(DATASEG_READONLY)
  77. _TCHAR vszKernel32[] = _TEXT("KERNEL32.DLL");
  78. _TCHAR vszOpenVxDHandle[]=_TEXT("OpenVxDHandle");
  79. static const _TCHAR szWkssvcToAgentStartEvent[] = _T("WkssvcToAgentStartEvent");
  80. static const _TCHAR szWkssvcToAgentStopEvent[] = _T("WkssvcToAgentStopEvent");
  81. static const _TCHAR szAgentToWkssvcEvent[] = _T("AgentToWkssvcEvent");
  82. static const _TCHAR szAgentExistsEvent[] = _T("AgentExistsEvent");
  83. static const _TCHAR vtzCSCUI[] = _TEXT("cscui.dll");
  84. static const char vszCSCUIInitialize[] = "CSCUIInitialize";
  85. static const char vszCSCUISetState[] = "CSCUISetState";
  86. static const _TCHAR vtzDefaultExclusionList[] = L" *.SLM *.MDB *.LDB *.MDW *.MDE *.PST *.DB?";
  87. DWORD vdwManualFileDetectionCount = 0;
  88. #pragma data_seg()
  89. #pragma data_seg(DATASEG_PERINSTANCE)
  90. static _TCHAR vrgchBuff[1024], vrwBuff[4096], vrgchSrcName[350], vrgchDstName[300];
  91. static HMENU g_MainMenu;
  92. char vszDBDir[MAX_PATH]={0};
  93. DWORD vdwDBCapacity = 0, vdwClusterSize = 0;
  94. DWORD vdwRedirStartTime = 0;
  95. AssertData;
  96. AssertError;
  97. #pragma data_seg()
  98. HWND vhwndMain = NULL; // main window
  99. BOOL vfAgentEnabledCSC=FALSE; // this is used to detect whether the remoteboot enabled CSC
  100. BOOL vfCSCEnabled=FALSE; // csc is enabled
  101. BOOL vfOKToEnableCSC = FALSE;
  102. HANDLE vhProfile = NULL;
  103. #pragma data_seg()
  104. BOOL vfFormatDatabase = FALSE; // set at init time
  105. #ifdef DEBUG
  106. ULONG ReintKdPrintVector = REINT_KDP_GOOD_DEFAULT;
  107. ULONG ReintKdPrintVectorDef = REINT_KDP_GOOD_DEFAULT;
  108. #endif
  109. unsigned ulFreePercent=30; // Amount of % cache freeing to be attempted
  110. // if the cache is full
  111. UINT vcntNetDevices = 0; // count of net devices
  112. BOOL g_bShowMergeIcon; // menu icon
  113. BOOL vfAgentRegistered = FALSE;
  114. BOOL vfClassRegistered = TRUE;
  115. BOOL vfMerging = FALSE;
  116. BOOL vfAgentQuiet = FALSE;
  117. DWORD vdwAgentThreadId = 0;
  118. DWORD vdwAgentSessionId = 0xffff;
  119. GLOBALSTATUS vsGS;
  120. BOOL allowAttempt; // set if we want to allow AttemptCacheFill now
  121. //
  122. // event handles of named events shared between usermode and kernel mode
  123. //
  124. HANDLE heventPerSess = NULL;
  125. HANDLE heventSharedFill = NULL;
  126. HANDLE vhMutex = NULL;
  127. DWORD dwVxDEvent = 0; // handle for VxD event obtained from heventShared
  128. HANDLE vhShadowDBForEvent = INVALID_HANDLE_VALUE;
  129. extern LPCONNECTINFO vlpLogonConnectList;
  130. extern _TCHAR * vrgchCRLF;
  131. HWND vhdlgShdLogon=NULL;
  132. // net start-stop vars
  133. HANDLE heventWkssvcToAgentStart = NULL;// event set by Workstation service on redir start
  134. HANDLE heventWkssvcToAgentStop = NULL; // event set by Workstation service on redir stop
  135. HANDLE heventAgentToWkssvc = NULL; // event used by agent to respond to wkssvc to tell it that
  136. // it is OK to stop the redir
  137. HANDLE heventShutDownAgent = NULL;
  138. HANDLE heventShutDownThread = NULL;
  139. HANDLE hCopyChunkThread = NULL;
  140. DWORD vdwCopyChunkThreadId = 0;
  141. BOOL vfRedirStarted = -1;
  142. BOOL vfStartRecieved = FALSE;
  143. BOOL vfStopRecieved = FALSE;
  144. BOOL fAgentShutDownRequested = FALSE;
  145. BOOL fAgentShutDown = FALSE;
  146. // CSCUI related
  147. HANDLE vhlibCSCUI = NULL;
  148. CSCUIINITIALIZE vlpfnCSCUIInitialize = NULL;
  149. CSCUISETSTATE vlpfnCSCUISetState = NULL;
  150. BOOL vfShowingOfflineDlg = FALSE;
  151. ULONG uOldDatabaseErrorFlags = 0;
  152. //
  153. // Function Prototypes
  154. //
  155. LRESULT
  156. CALLBACK
  157. ReInt_WndProc(
  158. HWND hwnd,
  159. UINT message,
  160. WPARAM wParam,
  161. LPARAM lParam
  162. );
  163. DWORD ReInt_AttemptCacheFill(
  164. LPVOID lpContext
  165. );
  166. BOOL
  167. ReInt_RefreshTray(
  168. BOOL bHide
  169. );
  170. BOOL
  171. ReInt_AnythingToMerge(
  172. VOID
  173. );
  174. int InitMaint(
  175. VOID
  176. ); // Initialize the maintenance subsystem
  177. BOOL
  178. CheckCSCDatabaseVersion(
  179. BOOL *lpfWasDirty
  180. );
  181. BOOL
  182. UpgradeCSCDatabase(
  183. LPSTR lpszDir
  184. );
  185. BOOL
  186. IsNetConnected(
  187. VOID
  188. );
  189. int
  190. ExtractSpaceStats(
  191. IN GLOBALSTATUS *lpsGS,
  192. OUT unsigned long *lpulMaxSpace,
  193. OUT unsigned long *lpulCurSpace,
  194. OUT unsigned long *lpulFreeSpace
  195. );
  196. int
  197. InitCacheSize(
  198. VOID
  199. );
  200. int
  201. SetDefaultSpace(
  202. LPSTR lpShadowDir
  203. );
  204. BOOL
  205. NEAR
  206. PASCAL
  207. ReInt_InitApp(
  208. HANDLE hInstance
  209. );
  210. BOOL
  211. NEAR
  212. PASCAL
  213. ReInt_InitInstance(
  214. HANDLE hInstance,
  215. HANDLE hPrevInstance,
  216. int cmdShow);
  217. BOOL
  218. NEAR
  219. PASCAL
  220. ReInt_TermInstance(
  221. VOID
  222. );
  223. int
  224. DoEventProcessing(
  225. VOID
  226. );
  227. BOOL
  228. FindCreateDBDir(
  229. BOOL *lpfCreated,
  230. BOOL fCleanup // empty the directory if found
  231. );
  232. BOOL
  233. CreatePerSessSyncObjects(
  234. VOID
  235. );
  236. BOOL
  237. CreateSharedFillSyncObjects(
  238. VOID
  239. );
  240. BOOL
  241. EnableCSC(
  242. VOID
  243. );
  244. BOOL
  245. DisableCSC(
  246. VOID
  247. );
  248. BOOL
  249. IsCSCOn(
  250. VOID
  251. );
  252. VOID
  253. ProcessStartStopAgent(
  254. VOID
  255. );
  256. BOOL
  257. FStartAgent(
  258. VOID
  259. );
  260. int
  261. StartStopCheck(
  262. VOID
  263. );
  264. BOOL
  265. Reint_RegisterAgent(
  266. VOID
  267. );
  268. VOID
  269. Reint_UnregisterAgent(
  270. VOID
  271. );
  272. BOOL
  273. QueryEnableCSC(
  274. VOID
  275. );
  276. VOID
  277. QueryMiscRegistryValues(
  278. VOID
  279. );
  280. BOOL
  281. CreateStartStopEvents(
  282. VOID
  283. );
  284. VOID
  285. DestroyStartStopEvents(
  286. VOID
  287. );
  288. BOOL
  289. ProcessNetArrivalMessage(
  290. VOID
  291. );
  292. BOOL
  293. ProcessNetDepartureMessage(
  294. BOOL fInvokeAutoDial
  295. );
  296. BOOL
  297. WINAPI
  298. CheckCSC(
  299. LPSTR,
  300. BOOL
  301. );
  302. BOOL
  303. ReportShareNetArrivalDeparture(
  304. BOOL fOneServer,
  305. HSHARE hShare,
  306. BOOL fInvokeAutoDial,
  307. BOOL fArrival
  308. );
  309. LRESULT
  310. ReportEventsToSystray(
  311. DWORD dwMessage,
  312. WPARAM dwWParam,
  313. LPARAM dwLParam
  314. );
  315. BOOL
  316. CheckServerOnline(
  317. VOID
  318. );
  319. VOID
  320. SetAgentShutDown(
  321. VOID
  322. );
  323. BOOL
  324. IsAgentShutDownRequested(
  325. VOID
  326. );
  327. BOOL
  328. LaunchSystrayForLoggedonUser(
  329. VOID
  330. );
  331. BOOL
  332. ImpersonateALoggedOnUser(
  333. VOID
  334. );
  335. VOID
  336. ReportCreateDelete(
  337. HSHADOW hDir,
  338. HSHADOW hShadow,
  339. BOOL fCreated
  340. );
  341. BOOL
  342. GetNameOfServerGoingOfflineEx(
  343. HANDLE hShadowDB,
  344. _TCHAR **lplptzServerName,
  345. DWORD *lpdwSize,
  346. BOOL *lpfAllocated
  347. );
  348. BOOL
  349. AreAnyServersOffline(
  350. VOID);
  351. BOOL
  352. IsPersonal(
  353. VOID);
  354. BOOL
  355. IsMultipleUsersEnabled(
  356. void);
  357. BOOL
  358. IsFastUserSwitchingEnabled(
  359. VOID);
  360. BOOL
  361. AreConnectionsAllowed (
  362. VOID);
  363. BOOL
  364. CanCSCLivewithTS(
  365. VOID);
  366. BOOL
  367. IsWorkstation(
  368. VOID);
  369. //
  370. // Functions
  371. //
  372. int
  373. PASCAL
  374. ReInt_WinMain(
  375. HANDLE hInstance,
  376. HANDLE hPrevInstance,
  377. LPSTR lpszCommandLine,
  378. int cmdShow)
  379. /*++
  380. Routine Description:
  381. This is the mainloop for the agent processing. It "schedules" different agent activities
  382. based on either an event set by the rdr or by predefined time intervals for these
  383. activities. The activities include
  384. a) Filling partially filled files
  385. b) checking for stale files
  386. c) maintaining space within limits
  387. d) reducing reference priority of all files for every FILE_OPEN_THRESHOLD fileopens
  388. --*/
  389. {
  390. MSG msg;
  391. DWORD result; // result from Wait...
  392. BOOL done = FALSE; // to detect a quit message.
  393. BOOL staleInited = FALSE; // ensure that Staleness code runs
  394. DWORD timeToWait;
  395. DWORD nextGlobalStatusTime;
  396. DWORD newTick;
  397. DWORD nextSkipPurgeTime; // to figure out if we should perform an action.
  398. HANDLE hT[4];
  399. if (hPrevInstance) {
  400. return FALSE;
  401. }
  402. vdwAgentThreadId = GetCurrentThreadId();
  403. ReintKdPrint(MAINLOOP, ("Agent(1):----------ReInt_WinMain----------\n"));
  404. if (ReInt_InitApp(hInstance) && ReInt_InitInstance(hInstance, hPrevInstance, cmdShow)) {
  405. if (!AnyActiveNets(NULL))
  406. vcntNetDevices = 1;
  407. newTick = GetTickCount();
  408. nextGlobalStatusTime = newTick + WAIT_INTERVAL_GLOBALSTATUS_MS;
  409. nextSkipPurgeTime = newTick + WAIT_INTERVAL_SKIP_MS;
  410. hT[0] = heventPerSess;
  411. hT[1] = heventWkssvcToAgentStart;
  412. hT[2] = heventWkssvcToAgentStop;
  413. hT[3] = heventShutDownAgent;
  414. StartStopCheck();
  415. ProcessStartStopAgent();
  416. while (!done) {
  417. timeToWait = INFINITE;
  418. ReintKdPrint(MAINLOOP, ("Agent(1): Wait INFINITE\n"));
  419. result = WaitForMultipleObjects(4, hT, FALSE, timeToWait);
  420. newTick=GetTickCount();
  421. if ((result == WAIT_OBJECT_0) || (result == (WAIT_OBJECT_0+4))) {
  422. ReintKdPrint(MAINLOOP, ("Agent(1):Event %d was fired or ReadGlobalStatus set\n",
  423. result));
  424. DoEventProcessing();
  425. // During event processing, we also do globalstatus check and
  426. // any other maintenance tasks. So let us restart the timer for
  427. // globalstatus
  428. nextGlobalStatusTime = newTick + WAIT_INTERVAL_GLOBALSTATUS_MS;
  429. } else if ((result == (WAIT_OBJECT_0+1)) || (result == (WAIT_OBJECT_0+2))) {
  430. ReintKdPrint(MAINLOOP, ("Agent(1): Received startstop \r\n"));
  431. vfStartRecieved = (result == (WAIT_OBJECT_0+1));
  432. vfStopRecieved = (result == (WAIT_OBJECT_0+2));
  433. ProcessStartStopAgent();
  434. continue;
  435. } else if (result == (WAIT_OBJECT_0+3)) {
  436. ReintKdPrint(MAINLOOP, ("Agent(1):Agent ShutdownRequested, terminating agent\r\n"));
  437. SetAgentShutDown();
  438. goto AllDone;
  439. }
  440. // do work only if CSC enabled
  441. if (vfCSCEnabled && AGENT_ALIVE_AND_ACTIVE) {
  442. // reset the staleness check time interval
  443. if(((int)(newTick - nextSkipPurgeTime)) >= 0) {
  444. // Unmark failures for servers that are known to be
  445. // disconnected and connection has not been attempted on them
  446. // for the last WAIT_INTERVAL_SKIP_MS milliseconds
  447. PurgeSkipQueue(FALSE, 0, 0, 0);
  448. vhcursor = NULL;
  449. nextSkipPurgeTime = newTick + WAIT_INTERVAL_SKIP_MS;
  450. ReintKdPrint(MAINLOOP, ("Agent(1):nextSkipPurgeTime = %d\n", nextSkipPurgeTime));
  451. }
  452. if(((int)(newTick - nextGlobalStatusTime)) >= 0) {
  453. nextGlobalStatusTime = newTick + WAIT_INTERVAL_GLOBALSTATUS_MS;
  454. ReintKdPrint(MAINLOOP,("Agent(1):nextGlobalStatusTime = %d\n", nextGlobalStatusTime));
  455. // We haven't gotten an event for sometime now from the
  456. // rdr, so let us go look what is up with him
  457. DoEventProcessing();
  458. // reset the globalstatus time interval
  459. nextGlobalStatusTime = newTick + WAIT_INTERVAL_GLOBALSTATUS_MS;
  460. }
  461. }
  462. }
  463. }
  464. AllDone:
  465. // do termination processing
  466. ReintKdPrint(MAINLOOP, ("Agent(1):Exiting mainloop \r\n"));
  467. ReInt_TermInstance();
  468. return 0;
  469. }
  470. BOOL
  471. NEAR
  472. PASCAL
  473. ReInt_InitApp(
  474. HANDLE hInstance
  475. )
  476. /*++
  477. Routine Description:
  478. Parameters:
  479. Return Value:
  480. Notes:
  481. --*/
  482. {
  483. if (
  484. CreateSharedFillSyncObjects()
  485. &&
  486. CreatePerSessSyncObjects()
  487. ) {
  488. if (!CreateStartStopEvents()) {
  489. ReintKdPrint(BADERRORS, ("Agent:Failed to create Sync events \r\n"));
  490. return FALSE;
  491. }
  492. if (!(hCopyChunkThread = CreateThread(
  493. NULL,
  494. 8192,
  495. ReInt_AttemptCacheFill,
  496. NULL,
  497. 0,
  498. &vdwCopyChunkThreadId))
  499. ) {
  500. ReintKdPrint(BADERRORS, ("Agent:Failed to create copychunk thread\r\n"));
  501. return FALSE;
  502. }
  503. return TRUE;
  504. } else {
  505. ReintKdPrint(BADERRORS, ("Failed to Create shared events\n"));
  506. return FALSE;
  507. }
  508. }
  509. BOOL
  510. NEAR
  511. PASCAL
  512. ReInt_InitInstance(
  513. HANDLE hInstance,
  514. HANDLE hPrevInstance,
  515. int cmdShow)
  516. /*++
  517. Routine Description:
  518. Parameters:
  519. Return Value:
  520. Notes:
  521. --*/
  522. {
  523. BOOL fRet;
  524. fRet = InitValues(vszDBDir, sizeof(vszDBDir), &vdwDBCapacity, &vdwClusterSize);
  525. Assert(fRet);
  526. fAgentShutDown = FALSE;
  527. fAgentShutDownRequested = FALSE;
  528. if (!(vfOKToEnableCSC = QueryEnableCSC()))
  529. {
  530. ReintKdPrint(INIT, ("cscdll: Registry says disable CSC, not enabling\r\n"));
  531. }
  532. vfFormatDatabase = QueryFormatDatabase();
  533. ReintKdPrint(INIT, ("Format=%d\n", vfFormatDatabase));
  534. return (TRUE);
  535. }
  536. /*--------------------------------------------------------------------------*/
  537. BOOL
  538. NEAR
  539. PASCAL
  540. ReInt_TermInstance(
  541. VOID
  542. )
  543. /*++
  544. Routine Description:
  545. Parameters:
  546. Return Value:
  547. Notes:
  548. --*/
  549. {
  550. DisableCSC();
  551. if (heventPerSess) {
  552. CloseHandle(heventPerSess);
  553. heventPerSess = NULL;
  554. }
  555. if (heventSharedFill) {
  556. CloseHandle(heventSharedFill);
  557. heventSharedFill = NULL;
  558. }
  559. PurgeSkipQueue(TRUE, 0, 0, 0);
  560. if (vhMutex) {
  561. ReleaseMutex(vhMutex);
  562. vhMutex = NULL;
  563. }
  564. // tell the workstation service that the agent is
  565. // going away
  566. if (heventAgentToWkssvc) {
  567. SetEvent(heventAgentToWkssvc);
  568. }
  569. if (heventShutDownThread) {
  570. DWORD dwRet;
  571. //Assert(hCopyChunkThread);
  572. SetEvent(heventShutDownThread);
  573. //If CopyChunk thread was created then cleanup - bug 562543
  574. if (hCopyChunkThread) {
  575. dwRet = WaitForSingleObject(hCopyChunkThread, WAIT_INTERVAL_ATTEMPT_MS);
  576. ReintKdPrint(MAINLOOP, ("wait on thread handle %d \r\n", dwRet));
  577. CloseHandle(hCopyChunkThread);
  578. }
  579. }
  580. DestroyStartStopEvents();
  581. if (vfClassRegistered) {
  582. UnregisterClass(vszReintClass, vhinstCur);
  583. vfClassRegistered = FALSE;
  584. }
  585. return TRUE;
  586. }
  587. DWORD
  588. ReInt_AttemptCacheFill(
  589. LPVOID lpParams
  590. )
  591. /*++
  592. Routine Description:
  593. A wrapper for AttemptCacheFill. On NT many agent threads can do copychunk
  594. simultaneously, so there is no need to do mutual exclusion.
  595. --*/
  596. {
  597. DWORD nextCheckServerOnlineTime;
  598. DWORD dwWaitResult;
  599. DWORD dwWaitResult2;
  600. DWORD dwWaitTime;
  601. DWORD newTick;
  602. ULONG nFiles = 0;
  603. ULONG nYoungFiles = 0;
  604. HANDLE hT[2];
  605. DWORD dwManualFileDetectionCount = 0xffff;
  606. // on NT we run as a winlogon thread which has a very high process priority
  607. // so we have to get to the lowest
  608. if(!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST)) {
  609. ReintKdPrint(BADERRORS, ("RE: SetTheadPriority failed, reason: 0x%08x\n", GetLastError()));
  610. }
  611. ReintKdPrint(MAINLOOP, ("Agent(2): Launched.\n"));
  612. hT[0] = heventShutDownThread;
  613. hT[1] = heventSharedFill;
  614. nextCheckServerOnlineTime = GetTickCount() +
  615. WAIT_INTERVAL_CHECK_SERVER_ONLINE_MS +
  616. WAIT_INTERVAL_FILL_THROTTLE_MS;
  617. for (;;) {
  618. ReintKdPrint(MAINLOOP, ("Agent(2): nYoungFiles=%d\n", nYoungFiles));
  619. if (nYoungFiles > 0 || AreAnyServersOffline() == TRUE) {
  620. dwWaitTime = WAIT_INTERVAL_CHECK_SERVER_ONLINE_MS;
  621. ReintKdPrint(MAINLOOP, ("Agent(2): Wait 8 min\n"));
  622. } else {
  623. dwWaitTime = INFINITE;
  624. ReintKdPrint(MAINLOOP, ("Agent(2): Wait INFINITE\n"));
  625. }
  626. dwWaitResult = WaitForMultipleObjects(2, hT, FALSE, dwWaitTime);
  627. if (dwWaitResult == (WAIT_OBJECT_0+0)) { // shutdown event
  628. ReintKdPrint(MAINLOOP, ("Agent(2): Termination event...\n"));
  629. if (AGENT_ALIVE && vdwAgentSessionId == 0)
  630. CSCPurgeUnpinnedFiles(100, &nFiles, &nYoungFiles);
  631. goto AllDone;
  632. }
  633. ReintKdPrint(MAINLOOP, ("Agent(2): Wait 2 min\n"));
  634. dwWaitResult2 = WaitForSingleObject(heventShutDownThread, WAIT_INTERVAL_FILL_THROTTLE_MS);
  635. if (dwWaitResult2 == (WAIT_OBJECT_0+0)) { // shutdown event
  636. ReintKdPrint(MAINLOOP, ("Agent(2): Termination event...\n"));
  637. if (AGENT_ALIVE && vdwAgentSessionId == 0)
  638. CSCPurgeUnpinnedFiles(100, &nFiles, &nYoungFiles);
  639. goto AllDone;
  640. }
  641. if (dwWaitResult == WAIT_TIMEOUT) { // timeout
  642. if (AGENT_ALIVE) {
  643. ReintKdPrint(MAINLOOP, ("Agent(2): Timeout...\n"));
  644. AttemptCacheFill(0, DO_ONE_OBJECT, FALSE, CSC_INVALID_PRINCIPAL_ID, NULL, 0);
  645. if (vdwAgentSessionId == 0) {
  646. GetManualFileDetectionCounter(INVALID_HANDLE_VALUE,&dwManualFileDetectionCount);
  647. vdwManualFileDetectionCount = dwManualFileDetectionCount;
  648. CSCPurgeUnpinnedFiles(100, &nFiles, &nYoungFiles);
  649. }
  650. }
  651. } else if (dwWaitResult == (WAIT_OBJECT_0+1)) { // kernel told us to run
  652. if (AGENT_ALIVE) {
  653. ReintKdPrint(MAINLOOP, ("Agent(2): Shared Event signal...\n"));
  654. AttemptCacheFill(0, DO_ONE_OBJECT, FALSE, CSC_INVALID_PRINCIPAL_ID, NULL, 0);
  655. GetManualFileDetectionCounter(INVALID_HANDLE_VALUE,&dwManualFileDetectionCount);
  656. if (dwManualFileDetectionCount != vdwManualFileDetectionCount) {
  657. vdwManualFileDetectionCount = dwManualFileDetectionCount;
  658. CSCPurgeUnpinnedFiles(100, &nFiles, &nYoungFiles);
  659. }
  660. }
  661. }
  662. newTick = GetTickCount();
  663. if(((int)(newTick - nextCheckServerOnlineTime)) >= 0) {
  664. if (AGENT_ALIVE) {
  665. // check whether one or more shares that are presently in
  666. // disconnected state have come online.
  667. // If they are, report them to the UI
  668. CheckServerOnline();
  669. nextCheckServerOnlineTime = newTick +
  670. WAIT_INTERVAL_CHECK_SERVER_ONLINE_MS +
  671. WAIT_INTERVAL_FILL_THROTTLE_MS;
  672. }
  673. }
  674. }
  675. AllDone:
  676. ReintKdPrint(MAINLOOP, ("Agent(2):Thread exit\n"));
  677. return 0;
  678. }
  679. VOID
  680. ReInt_DoFreeShadowSpace(
  681. GLOBALSTATUS *lpsGS,
  682. int fForce
  683. )
  684. /*++
  685. Routine Description:
  686. The function is called from the main
  687. loop every "n" minutes to see if we are running out of space.
  688. If so, it tries to free up some percentage of the shadow cache.
  689. Parameters:
  690. fForce: 0 => do it only if we don't have space and we are
  691. on the net
  692. 1 => do it if we are on the net
  693. 2 => just do it
  694. Return Value:
  695. Notes:
  696. --*/
  697. {
  698. ULONG ulMax;
  699. ULONG ulCur;
  700. ULONG ulFree;
  701. WIN32_FIND_DATA sFind32;
  702. LPCOPYPARAMS lpCP = NULL;
  703. if (!lpsGS) {
  704. lpsGS = &vsGS;
  705. }
  706. ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(1)\r\n"));
  707. // Get space stats
  708. if (ExtractSpaceStats(lpsGS, &ulMax, &ulCur, &ulFree) >= 0){
  709. ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(2)\r\n"));
  710. // do we have space and are not forced to free up?
  711. if ((fForce < 1) && (ulFree > 0)){
  712. ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(3)\r\n"));
  713. return;
  714. }
  715. //
  716. // We are forced or there is no space
  717. //
  718. // NB!!!! We check for a net device and if it exists we assume that
  719. // it is OK to freespace on all shares.
  720. if ((fForce < 2) && !vcntNetDevices){
  721. ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace: No net, aborting \r\n"));
  722. return;
  723. }
  724. // Maximum force, or all conditions for freeing are being met
  725. // ie. there is no space and we are on the net
  726. memset(&sFind32, 0, sizeof(sFind32));
  727. // NB the math below is done to avoid overflow.
  728. // The consequence is that the resulting value is less than
  729. // the percentage of cache space to be freed.
  730. ulFree = (ulMax/100) * ulFreePercent;
  731. // if the cached data is more than the earmarked space
  732. // then add the extra too.
  733. if (ulCur > ulMax) {
  734. ulFree += (ulCur - ulMax);
  735. }
  736. DosToWin32FileSize(ulFree, &sFind32.nFileSizeHigh, &sFind32.nFileSizeLow);
  737. ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(): freeing %d\n", ulFree));
  738. ReintKdPrint(MERGE, (" nFileSizeLow=%d\n", sFind32.nFileSizeLow));
  739. FreeShadowSpace(INVALID_HANDLE_VALUE,
  740. sFind32.nFileSizeHigh,
  741. sFind32.nFileSizeLow,
  742. FALSE); // don't clear all
  743. ReintKdPrint(MERGE, ("ReInt_DoFreeShadowSpace(): ending.\n"));
  744. }
  745. }
  746. /*********************** Merging related routines **************************/
  747. //
  748. // DoubleClick/Menu handler.
  749. //
  750. VOID
  751. ReInt_DoNetProp(
  752. VOID
  753. )
  754. /*++
  755. Routine Description:
  756. Parameters:
  757. Return Value:
  758. Notes:
  759. --*/
  760. {
  761. HINSTANCE hLib=LoadLibrary(_TEXT("shhndl.dll"));
  762. ReintKdPrint(BADERRORS, ("LoadLibrary of shhndl returned %d\n",hLib));
  763. if(hLib)
  764. {
  765. FARPROC lpFn=GetProcAddress(hLib,"NetProp_Create");
  766. ReintKdPrint(BADERRORS, ("NetProp_Create is 0x%x\n",lpFn));
  767. if(lpFn)
  768. lpFn();
  769. FreeLibrary(hLib);
  770. }
  771. }
  772. //
  773. // Command Handler
  774. //
  775. BOOL
  776. NEAR
  777. PASCAL
  778. ReInt_CommandHandler(
  779. HWND hwnd,
  780. WPARAM wParam,
  781. LPARAM lParam
  782. )
  783. /*++
  784. Routine Description:
  785. Parameters:
  786. Return Value:
  787. Notes:
  788. --*/
  789. {
  790. unsigned long ulSwitch, ulSav;
  791. switch (wParam)
  792. {
  793. case IDM_PROPERTIES:
  794. ReInt_DoNetProp();
  795. break;
  796. case IDM_SHADOW_LOG:
  797. {
  798. if(ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_GET_STATE))
  799. {
  800. ulSav = (ulSwitch & SHADOW_SWITCH_LOGGING);
  801. ulSwitch = SHADOW_SWITCH_LOGGING;
  802. if (ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, (ulSav)?SHADOW_SWITCH_OFF:SHADOW_SWITCH_ON))
  803. CheckMenuItem(GetMenu(hwnd), IDM_SHADOW_LOG , MF_BYCOMMAND|((ulSav)?MF_UNCHECKED:MF_CHECKED));
  804. }
  805. }
  806. break;
  807. case IDM_LOG_COPYING:
  808. {
  809. #ifdef TEST
  810. HKEY hKey=0;
  811. _TCHAR szDoCopy[MAX_NAME_LEN];
  812. vfLogCopying = vfLogCopying?0:1;
  813. CheckMenuItem(GetMenu(hwnd), IDM_LOG_COPYING , MF_BYCOMMAND|((vfLogCopying)?MF_UNCHECKED:MF_CHECKED));
  814. if(RegOpenKey(HKEY_LOCAL_MACHINE, REG_KEY_CSC_SETTINGS, &hKey) != ERROR_SUCCESS)
  815. {
  816. ReintKdPrint(BADERRORS, ("IDM_LOG_COPYING: RegOpenKey failed\n"));
  817. goto done;
  818. }
  819. if(vfLogCopying)
  820. strcpy(szDoCopy, SZ_TRUE);
  821. else
  822. strcpy(szDoCopy, SZ_FALSE);
  823. if(RegSetValueEx(hKey, vszDoLogCopy, (DWORD) 0, REG_SZ, szDoCopy, strlen(szDoCopy)+1) != ERROR_SUCCESS)
  824. {
  825. ReintKdPrint(BADERRORS, ("IDM_LOG_COPYING: RegSetValueEx failed\n"));
  826. }
  827. done:
  828. if(hKey)
  829. RegCloseKey(hKey);
  830. #endif //TEST
  831. }
  832. break;
  833. case IDM_SHADOWING:
  834. break;
  835. case IDM_SPEED_OPT:
  836. break;
  837. case IDM_TRAY_FILL_SHADOW:
  838. break;
  839. case IDM_TRAY_MERGE:
  840. break;
  841. case IDM_TRAY_FREE_SPACE:
  842. break;
  843. case IDM_TRAY_FORCE_LOG:
  844. break;
  845. case IDM_REFRESH_CONNECTIONS:
  846. break;
  847. case IDM_BREAK_CONNECTIONS:
  848. break;
  849. case IDM_LOGON:
  850. if (lParam)
  851. {
  852. vfStartRecieved = TRUE;
  853. // logon is done, try enabling CSC
  854. // if CSC is already enabled, the routine will do the right thing
  855. //
  856. EnableCSC();
  857. }
  858. break;
  859. case IDM_LOGOFF:
  860. // no need to trap this, we get WM_QUERYENDSESSION and WM_ENDSESSION
  861. break;
  862. default:
  863. return FALSE;
  864. }
  865. return TRUE;
  866. }
  867. LRESULT
  868. CALLBACK
  869. ReInt_WndProc(
  870. HWND hwnd,
  871. UINT message,
  872. WPARAM wParam,
  873. LPARAM lParam
  874. )
  875. /*++
  876. Routine Description:
  877. Parameters:
  878. Return Value:
  879. Notes:
  880. --*/
  881. {
  882. LPARAM lRet = 0L;
  883. switch (message)
  884. {
  885. case RWM_UPDATE:
  886. ReintKdPrint(BADERRORS, ("Update hShare:%0x hWnd=%0x\n",wParam, lParam));
  887. PurgeSkipQueue(TRUE, (HSHARE)wParam, 0, 0);
  888. // return ReintOneShare((HSHARE)wParam,(HWND)lParam);
  889. break;
  890. case RWM_UPDATEALL:
  891. break;
  892. case WM_TIMER:
  893. break;
  894. case TRAY_NOTIFY:
  895. break;
  896. case WM_DEVICECHANGE:
  897. {
  898. switch (wParam)
  899. {
  900. case DBT_DEVICEARRIVAL:
  901. if (((DEV_BROADCAST_NET *)lParam)->dbcn_devicetype == DBT_DEVTYP_NET)
  902. {
  903. // ProcessNetArrivalMessage();
  904. }
  905. break;
  906. case DBT_DEVICEREMOVECOMPLETE:
  907. if (((DEV_BROADCAST_NET *)lParam)->dbcn_devicetype == DBT_DEVTYP_NET)
  908. {
  909. // ProcessNetDepartureMessage(FALSE);
  910. }
  911. break;
  912. }
  913. break;
  914. }
  915. case WM_INITMENU:
  916. return TRUE;
  917. break;
  918. case WM_INITMENUPOPUP:
  919. break;
  920. case WM_COMMAND:
  921. if(lRet = ReInt_CommandHandler(hwnd, wParam, lParam))
  922. return lRet;
  923. break;
  924. case WM_CLOSE:
  925. ReintKdPrint(BADERRORS, ("WM_CLOSE hit.\n"));
  926. break;
  927. case WM_DESTROY:
  928. ReintKdPrint(BADERRORS, ("WM_DESTROY hit.\n"));
  929. PostQuitMessage((int)wParam);
  930. return 1L;
  931. case WM_SETCURSOR:
  932. break;
  933. case WM_QUERYENDSESSION:
  934. return TRUE;
  935. case WM_ENDSESSION:
  936. ReintKdPrint(BADERRORS, ("Turning off shadowing on WM_ENDSESSION\r\n"));
  937. DisableCSC();
  938. break;
  939. case WM_FILE_OPENS:
  940. break;
  941. case WM_SHADOW_ADDED:
  942. case WM_SHADOW_DELETED:
  943. ReintKdPrint(BADERRORS, ("allowAttempt = TRUE\n"));
  944. allowAttempt = TRUE;
  945. break;
  946. case WM_SHARE_DISCONNECTED:
  947. ReintKdPrint(BADERRORS, ("REINT: VxD notification(0x%08x)\n",message));
  948. break;
  949. default:
  950. break;
  951. }
  952. return DefWindowProc(hwnd, message, wParam, lParam);
  953. }
  954. BOOL ReInt_AnythingToMerge(
  955. VOID
  956. )
  957. /*++
  958. Routine Description:
  959. Parameters:
  960. Return Value:
  961. Notes:
  962. --*/
  963. {
  964. return (CheckDirtyShares() != 0);
  965. }
  966. //
  967. //
  968. BOOL
  969. ReInt_RefreshTray(
  970. BOOL bHide
  971. )
  972. /*++
  973. Routine Description:
  974. Called to update the tray ICON to reflect the merge status.
  975. Parameters:
  976. bHide = TRUE means hide it
  977. = FALSE means work it out.
  978. Return Value:
  979. Notes:
  980. --*/
  981. {
  982. return TRUE;
  983. }
  984. // See if shadfowing is ON
  985. // Returns: TRUE=> ON, FALSE=> OFF, -1 => soem error happened
  986. BOOL
  987. IsCSCOn(
  988. VOID
  989. )
  990. {
  991. if (vfCSCEnabled)
  992. {
  993. #ifdef DEBUG
  994. unsigned ulSwitch = SHADOW_SWITCH_SHADOWING;
  995. if(ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_GET_STATE))
  996. {
  997. Assert((ulSwitch & SHADOW_SWITCH_SHADOWING)!=0);
  998. }
  999. #endif
  1000. return (TRUE);
  1001. }
  1002. return (FALSE);
  1003. }
  1004. // Disable Shadowing
  1005. // Returns: 1 => done, -1 => some error happened
  1006. int
  1007. DisableCSC()
  1008. {
  1009. unsigned ulSwitch = SHADOW_SWITCH_SHADOWING;
  1010. if (vfCSCEnabled && vfAgentEnabledCSC) {
  1011. if(ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_OFF))
  1012. {
  1013. vfCSCEnabled = FALSE;
  1014. if (vhShadowDBForEvent != INVALID_HANDLE_VALUE)
  1015. {
  1016. CloseHandle(vhShadowDBForEvent);
  1017. vhShadowDBForEvent = INVALID_HANDLE_VALUE;
  1018. }
  1019. Reint_UnregisterAgent();
  1020. // SetDisabledReg();
  1021. return (1);
  1022. }
  1023. }
  1024. return (-1);
  1025. }
  1026. BOOL
  1027. EnableCSC(
  1028. VOID
  1029. )
  1030. /*++
  1031. Routine Description:
  1032. Parameters:
  1033. Return Value:
  1034. Notes:
  1035. --*/
  1036. {
  1037. char szBuff[MAX_PATH];
  1038. DWORD dwBuffSize;
  1039. BOOL fDirCreated=FALSE, fRedirCSCEnabled=TRUE, fWasDirty = FALSE;
  1040. unsigned uShadowSwitches;
  1041. ReintKdPrint(INIT, ("CSC Enabled %d \r\n", vfCSCEnabled));
  1042. if (vfCSCEnabled==FALSE)
  1043. {
  1044. dwBuffSize = sizeof(szBuff);
  1045. if(!GetUserNameA(szBuff, &dwBuffSize))
  1046. {
  1047. // not logged on yet
  1048. return FALSE;
  1049. }
  1050. if(ShadowSwitches(INVALID_HANDLE_VALUE, &uShadowSwitches, SHADOW_SWITCH_GET_STATE))
  1051. {
  1052. if (uShadowSwitches & SHADOW_SWITCH_SHADOWING)
  1053. {
  1054. ReintKdPrint(INIT, ("cscdll: CSC already started\r\n"));
  1055. }
  1056. else
  1057. {
  1058. ReintKdPrint(INIT, ("cscdll: redir is not doing CSC yet, OK\r\n"));
  1059. fRedirCSCEnabled = FALSE;
  1060. if (!vfOKToEnableCSC)
  1061. {
  1062. return FALSE;
  1063. }
  1064. vfAgentEnabledCSC = TRUE;
  1065. }
  1066. }
  1067. else
  1068. {
  1069. ReintKdPrint(BADERRORS, ("cscdll: couldn't get the CSC state from the redir\r\n"));
  1070. }
  1071. if (Reint_RegisterAgent())
  1072. {
  1073. SetFileAttributesA(vszDBDir, FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN);
  1074. ReintKdPrint(INIT,
  1075. ("cscdll: enabling CSC at %s for %s with capacity %d and clustersize %d\r\n",
  1076. vszDBDir, szBuff, vdwDBCapacity, vdwClusterSize));
  1077. if (EnableShadowing(
  1078. INVALID_HANDLE_VALUE,
  1079. vszDBDir,
  1080. szBuff,
  1081. 0,
  1082. vdwDBCapacity,
  1083. vdwClusterSize,
  1084. vfFormatDatabase))
  1085. {
  1086. vfCSCEnabled = TRUE;
  1087. if (vhShadowDBForEvent == INVALID_HANDLE_VALUE)
  1088. {
  1089. vhShadowDBForEvent = OpenShadowDatabaseIO();
  1090. }
  1091. }
  1092. else
  1093. {
  1094. ReintKdPrint(BADERRORS, ("cscdll: EnableShadowing failed, CSC not enabled!!!!\r\n"));
  1095. }
  1096. if (vfCSCEnabled==FALSE)
  1097. {
  1098. Reint_UnregisterAgent();
  1099. }
  1100. }
  1101. else
  1102. {
  1103. ReintKdPrint(BADERRORS, ("cscdll: EnableCSC.Agent registration failed, CSC not enabled!!!!\r\n"));
  1104. }
  1105. }
  1106. if (!vfCSCEnabled)
  1107. {
  1108. // NTRAID-455253-1/31/2000-shishirp need to add it to the event log with the right error
  1109. ReintKdPrint(BADERRORS, ("cscdll: CSC not enabled \r\n"));
  1110. }
  1111. return (vfCSCEnabled);
  1112. }
  1113. BOOL
  1114. IsNetConnected(
  1115. VOID
  1116. )
  1117. /*++
  1118. Routine Description:
  1119. The function checks to see whether at this moment
  1120. we are connected to any resources on the real net.
  1121. Parameters:
  1122. Return Value:
  1123. Notes:
  1124. This is used to decide whether to start purging stuff from the
  1125. cache. If we are in a completely disconnected state then we
  1126. may not want to purge data that is potentially useful.
  1127. --*/
  1128. {
  1129. CSC_ENUMCOOKIE ulEnumCookie=NULL;
  1130. WIN32_FIND_DATA sFind32;
  1131. BOOL fConnected = FALSE;
  1132. SHADOWINFO sSI;
  1133. HANDLE hShadowDB;
  1134. memset(&sFind32, 0, sizeof(sFind32));
  1135. lstrcpy(sFind32.cFileName, _TEXT("*.*"));
  1136. if ((hShadowDB = OpenShadowDatabaseIO()) == INVALID_HANDLE_VALUE)
  1137. {
  1138. return FALSE;
  1139. }
  1140. if(FindOpenShadow(hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL, &sFind32, &sSI))
  1141. {
  1142. ulEnumCookie = sSI.uEnumCookie;
  1143. do
  1144. {
  1145. if (sSI.uStatus & SHARE_CONNECTED) {
  1146. if (!(sSI.uStatus & SHARE_DISCONNECTED_OP)) {
  1147. fConnected = TRUE;
  1148. break;
  1149. }
  1150. }
  1151. } while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
  1152. FindCloseShadow(hShadowDB, ulEnumCookie);
  1153. }
  1154. CloseShadowDatabaseIO(hShadowDB);
  1155. return fConnected;
  1156. }
  1157. int
  1158. ExtractSpaceStats(
  1159. GLOBALSTATUS *lpsGS,
  1160. unsigned long *lpulMaxSpace,
  1161. unsigned long *lpulCurSpace,
  1162. unsigned long *lpulFreeSpace
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. The function returns the max, current and free
  1167. space as known by the shadow cache.
  1168. Parameters:
  1169. Return Value:
  1170. 1 if there is any free space
  1171. 0 if there is no free space
  1172. -1 if there is some error
  1173. Notes:
  1174. --*/
  1175. {
  1176. int iRet = 1;
  1177. if (!lpsGS)
  1178. {
  1179. lpsGS = &vsGS;
  1180. }
  1181. if (lpulMaxSpace){
  1182. *lpulMaxSpace = lpsGS->sST.sMax.ulSize;
  1183. }
  1184. if (lpulCurSpace){
  1185. *lpulCurSpace = lpsGS->sST.sCur.ulSize;
  1186. }
  1187. if (lpulFreeSpace){
  1188. *lpulFreeSpace = 0;
  1189. }
  1190. // do we have any space?
  1191. if (lpsGS->sST.sMax.ulSize > lpsGS->sST.sCur.ulSize){
  1192. if (lpulFreeSpace){
  1193. *lpulFreeSpace = (lpsGS->sST.sMax.ulSize - lpsGS->sST.sCur.ulSize);
  1194. }
  1195. iRet = 1;
  1196. }
  1197. else{
  1198. iRet = 0;
  1199. }
  1200. return iRet;
  1201. }
  1202. int
  1203. InitCacheSize(
  1204. VOID
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. The function returns the max, current and free
  1209. space as known by the shadow cache.
  1210. Parameters:
  1211. Return Value:
  1212. 1 if there is any free space
  1213. 0 if there is no free space
  1214. -1 if there is some error
  1215. Notes:
  1216. --*/
  1217. {
  1218. unsigned ulMaxStore;
  1219. int iRet = 0;
  1220. if(!GetGlobalStatus(INVALID_HANDLE_VALUE, &vsGS))
  1221. {
  1222. return -1;
  1223. }
  1224. if (ExtractSpaceStats(&vsGS, &ulMaxStore, NULL, NULL)>=0){
  1225. if (ulMaxStore==0xffffffff){
  1226. ReintKdPrint(BADERRORS, ("Agent: Found newly created cache, setting cache size \r\n"));
  1227. Assert(vszDBDir[0]);
  1228. iRet = SetDefaultSpace(vszDBDir);
  1229. }
  1230. }
  1231. return iRet;
  1232. }
  1233. int
  1234. SetDefaultSpace(
  1235. LPSTR lpShadowDir
  1236. )
  1237. /*++
  1238. Routine Description:
  1239. Parameters:
  1240. Return Value:
  1241. Notes:
  1242. --*/
  1243. {
  1244. DWORD dwSPC, dwBPS, dwFreeC, dwTotalC, dwCapacity;
  1245. _TCHAR szDrive[4];
  1246. int iRet = 0;
  1247. Assert(lpShadowDir[1]==':');
  1248. memset(szDrive, 0, sizeof(szDrive));
  1249. memcpy(szDrive, lpShadowDir, 3);
  1250. if(GetDiskFreeSpace(szDrive, &dwSPC, &dwBPS, &dwFreeC, &dwTotalC )){
  1251. dwCapacity = ((dwSPC * dwBPS * 10)/100)*dwTotalC;
  1252. SetMaxShadowSpace(INVALID_HANDLE_VALUE, 0, dwCapacity);
  1253. iRet = 1;
  1254. }
  1255. return (iRet);
  1256. }
  1257. int
  1258. DoEventProcessing(
  1259. VOID
  1260. )
  1261. /*++
  1262. Routine Description:
  1263. When the named event is triggered by the kernel mode component, this routine
  1264. looks to see what needs to be taken care of and does the job.
  1265. Parameters:
  1266. Return Value:
  1267. Notes:
  1268. This routine is called from various places in the mailoop and other loops such as
  1269. AttemptCacheFill. It may end up showing up dialog boxes and such, so care has to be taken
  1270. while invoking it.
  1271. --*/
  1272. {
  1273. int iRet;
  1274. GLOBALSTATUS sGS;
  1275. ReintKdPrint(
  1276. INIT,
  1277. ("CSC Agent: CSC Enabled=%d vhShadowDBForEvent \n",
  1278. vfCSCEnabled,
  1279. vhShadowDBForEvent));
  1280. ReintKdPrint(MAINLOOP, ("Agent(1):DoEventProcessing()\n"));
  1281. if (iRet = GetGlobalStatus(vhShadowDBForEvent, &sGS)) {
  1282. ReintKdPrint(MAINLOOP, (
  1283. "Agent(1):uFlagsEvents:0x%x\n"
  1284. " uDatabaseErrorFlags:0x%x\n"
  1285. " hShadowAdded:0x%x\n"
  1286. " hDirAdded:0x%x\n"
  1287. " hShadowDeleted:0x%x\n"
  1288. " hDirDeleted:0x%x\n"
  1289. " cntFileOpen:%d\n"
  1290. " hShareDisconnected:0x%x\n",
  1291. sGS.uFlagsEvents,
  1292. sGS.uDatabaseErrorFlags,
  1293. sGS.hShadowAdded,
  1294. sGS.hDirAdded,
  1295. sGS.hShadowDeleted,
  1296. sGS.hDirDeleted,
  1297. sGS.cntFileOpen,
  1298. sGS.hShareDisconnected,
  1299. sGS.uFlagsEvents));
  1300. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_START)
  1301. ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_START received\r\n"));
  1302. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_STOP)
  1303. ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_STOP received\r\n"));
  1304. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_NO_NET)
  1305. ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_NO_NET received\r\n"));
  1306. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_GOT_NET)
  1307. ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_GOT_NET received\r\n"));
  1308. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_FREESPACE)
  1309. ReintKdPrint(MAINLOOP, ("Agent(1):FLAG_GLOBALSTATUS_INVOKE_FREESPACE received\r\n"));
  1310. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_SHARE_DISCONNECTED)
  1311. ReintKdPrint(
  1312. MAINLOOP,
  1313. ("Agent(1):FLAG_GLOBALSTATUS_SHARE_DISCONNECTED (share=%d) received\r\n",
  1314. sGS.hShareDisconnected));
  1315. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_START) {
  1316. vfCSCEnabled = TRUE;
  1317. if (vhShadowDBForEvent == INVALID_HANDLE_VALUE) {
  1318. vhShadowDBForEvent = OpenShadowDatabaseIO();
  1319. }
  1320. Reint_RegisterAgent();
  1321. } else if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_STOP) {
  1322. vfCSCEnabled = FALSE;
  1323. if (vhShadowDBForEvent != INVALID_HANDLE_VALUE) {
  1324. CloseHandle(vhShadowDBForEvent);
  1325. vhShadowDBForEvent = INVALID_HANDLE_VALUE;
  1326. }
  1327. Reint_UnregisterAgent();
  1328. }
  1329. if (AGENT_ALIVE) {
  1330. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_GOT_NET) {
  1331. ProcessNetArrivalMessage();
  1332. } else if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_NO_NET) {
  1333. ProcessNetDepartureMessage(
  1334. ((sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_AUTODIAL)!=0));
  1335. }
  1336. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_SHARE_DISCONNECTED) {
  1337. ReportShareNetArrivalDeparture(
  1338. 1,
  1339. sGS.hShareDisconnected,
  1340. ((sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_AUTODIAL)!=0),
  1341. FALSE); // departed
  1342. }
  1343. if (uOldDatabaseErrorFlags != sGS.uDatabaseErrorFlags) {
  1344. ReportEventsToSystray(STWM_CACHE_CORRUPTED, 0, 0);
  1345. uOldDatabaseErrorFlags = sGS.uDatabaseErrorFlags;
  1346. }
  1347. // see if space needs freeing
  1348. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_FREESPACE) {
  1349. ReintKdPrint(MAINLOOP, ("Agent(1): Calling DoFreeShadowSpace(1)\r\n"));
  1350. ReInt_DoFreeShadowSpace(&sGS, 0);
  1351. } else {
  1352. ReintKdPrint(MAINLOOP, ("Agent(1): Calling DoFreeShadowSpace(2)\r\n"));
  1353. ReInt_DoFreeShadowSpace(&sGS, 0);
  1354. }
  1355. } else {
  1356. if (sGS.uFlagsEvents & FLAG_GLOBALSTATUS_SHARE_DISCONNECTED) {
  1357. ReintKdPrint(MAINLOOP, ("Agent(1): Calling ReportShareNetArrivalDeparture\r\n"));
  1358. ReportShareNetArrivalDeparture(
  1359. 1,
  1360. 0,
  1361. ((sGS.uFlagsEvents & FLAG_GLOBALSTATUS_INVOKE_AUTODIAL)!=0),
  1362. FALSE); // departed
  1363. }
  1364. }
  1365. vsGS = sGS;
  1366. vsGS.uFlagsEvents = 0; // clear all event indicators
  1367. }
  1368. return iRet;
  1369. }
  1370. BOOL
  1371. CreatePerSessSyncObjects(
  1372. VOID
  1373. )
  1374. {
  1375. NTSTATUS Status;
  1376. UNICODE_STRING EventName;
  1377. OBJECT_ATTRIBUTES ObjectAttributes;
  1378. WCHAR SessEventName[100];
  1379. // DbgPrint("CreatePerSessSyncObjects:vdwAgentSessionId = %d\n", vdwAgentSessionId);
  1380. Assert(heventPerSess == NULL);
  1381. wsprintf(SessEventName, L"%ws_%d", SESSION_EVENT_NAME_NT, vdwAgentSessionId);
  1382. // DbgPrint("CreatePerSessSyncObjects:SessEventName = [%ws]\n", SessEventName);
  1383. RtlInitUnicodeString(&EventName, SessEventName);
  1384. InitializeObjectAttributes( &ObjectAttributes,
  1385. &EventName,
  1386. OBJ_OPENIF, //got this const from base\client\support.c
  1387. (HANDLE) NULL,
  1388. (PSECURITY_DESCRIPTOR) NULL );
  1389. Status = NtCreateEvent(
  1390. &heventPerSess,
  1391. EVENT_ALL_ACCESS,
  1392. &ObjectAttributes,
  1393. SynchronizationEvent,
  1394. FALSE
  1395. );
  1396. if (!NT_SUCCESS(Status)) {
  1397. DbgPrint("CreatePerSessSyncObjects:NtCreateEvent returned %08lx\n",Status);
  1398. }
  1399. return (heventPerSess==0)?FALSE:TRUE;
  1400. }
  1401. BOOL
  1402. CreateSharedFillSyncObjects(
  1403. VOID
  1404. )
  1405. {
  1406. NTSTATUS Status;
  1407. UNICODE_STRING EventName;
  1408. OBJECT_ATTRIBUTES ObjectAttributes;
  1409. Assert(heventSharedFill == NULL);
  1410. RtlInitUnicodeString(&EventName,SHARED_FILL_EVENT_NAME_NT);
  1411. InitializeObjectAttributes( &ObjectAttributes,
  1412. &EventName,
  1413. OBJ_OPENIF, //got this const from base\client\support.c
  1414. (HANDLE) NULL,
  1415. (PSECURITY_DESCRIPTOR) NULL );
  1416. Status = NtCreateEvent(
  1417. &heventSharedFill,
  1418. EVENT_ALL_ACCESS,
  1419. &ObjectAttributes,
  1420. SynchronizationEvent,
  1421. FALSE
  1422. );
  1423. if (!NT_SUCCESS(Status)) {
  1424. DbgPrint("ntcreateeventstatus=%08lx\n",Status);
  1425. }
  1426. return (heventSharedFill==0)?FALSE:TRUE;
  1427. }
  1428. VOID
  1429. ProcessStartStopAgent(
  1430. VOID
  1431. )
  1432. {
  1433. if (vfStartRecieved)
  1434. {
  1435. ReintKdPrint(MAINLOOP, ("Agent(1): start received, enabling CSC\r\n"));
  1436. if (EnableCSC() == FALSE)
  1437. {
  1438. ReintKdPrint(ALWAYS, ("Ageint(1):Couldn't turn CSC ON!!!!!!!!! \n"));
  1439. }
  1440. else
  1441. {
  1442. UpdateExclusionList();
  1443. UpdateBandwidthConservationList();
  1444. }
  1445. // set the event to indicate to wkssvc that we are alive
  1446. if (heventAgentToWkssvc)
  1447. {
  1448. SetEvent(heventAgentToWkssvc);
  1449. }
  1450. vfStartRecieved = FALSE;
  1451. vfRedirStarted = TRUE;
  1452. }
  1453. else if (vfStopRecieved)
  1454. {
  1455. ReintKdPrint(MAINLOOP, ("Agent(1):Stop recieved \r\n"));
  1456. DisableCSC();
  1457. if(heventAgentToWkssvc)
  1458. {
  1459. SetEvent(heventAgentToWkssvc);
  1460. }
  1461. vcntNetDevices = 0;
  1462. vfStopRecieved = FALSE;
  1463. vfRedirStarted = FALSE;
  1464. }
  1465. }
  1466. BOOL
  1467. FStopAgent(
  1468. VOID
  1469. )
  1470. {
  1471. if (StartStopCheck() && vfStopRecieved)
  1472. {
  1473. return TRUE;
  1474. }
  1475. return FALSE;
  1476. }
  1477. BOOL
  1478. StartStopCheck(
  1479. VOID
  1480. )
  1481. {
  1482. DWORD dwError;
  1483. BOOL fRet = FALSE;
  1484. HANDLE hT[2];
  1485. unsigned ulSwitch=0;
  1486. // the way we are finding out about the start makes the start event
  1487. // redundant, but we will leave it, because it is generically the right thing to have a
  1488. // start event and a stop event.
  1489. if ((vfRedirStarted == -1) && // if newly launched agent
  1490. (ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_GET_STATE)))
  1491. {
  1492. ReintKdPrint(INIT, ("Agent: redir already started\r\n"));
  1493. vfStartRecieved = TRUE;
  1494. }
  1495. else if (heventWkssvcToAgentStart)
  1496. {
  1497. // we know that when it comes to events it is all or nothing
  1498. Assert(heventWkssvcToAgentStop);
  1499. hT[0] = heventWkssvcToAgentStart;
  1500. hT[1] = heventWkssvcToAgentStop;
  1501. dwError = MsgWaitForMultipleObjects(2, hT, FALSE, 0, QS_ALLINPUT);
  1502. if (vfRedirStarted == TRUE)
  1503. {
  1504. vfStopRecieved = (dwError == WAIT_OBJECT_0+1);
  1505. if (vfStopRecieved)
  1506. {
  1507. ReintKdPrint(INIT, ("Agent: stop recieved\r\n"));
  1508. }
  1509. }
  1510. else
  1511. {
  1512. vfStartRecieved = (dwError == WAIT_OBJECT_0);
  1513. if (vfStartRecieved)
  1514. {
  1515. ReintKdPrint(INIT, ("Agent: start recieved\r\n"));
  1516. }
  1517. }
  1518. }
  1519. return fRet;
  1520. }
  1521. BOOL
  1522. Reint_RegisterAgent(
  1523. VOID
  1524. )
  1525. {
  1526. if (!vfAgentRegistered)
  1527. {
  1528. if (!RegisterAgent(INVALID_HANDLE_VALUE, vhwndMain, LongToHandle(dwVxDEvent)))
  1529. {
  1530. ReintKdPrint(BADERRORS, ("Agent registration failed \n"));
  1531. return FALSE;
  1532. }
  1533. else
  1534. {
  1535. vfAgentRegistered = TRUE;
  1536. }
  1537. }
  1538. return vfAgentRegistered;
  1539. }
  1540. VOID
  1541. Reint_UnregisterAgent(
  1542. VOID
  1543. )
  1544. {
  1545. if (vfAgentRegistered)
  1546. {
  1547. // don't do any checking
  1548. UnregisterAgent(INVALID_HANDLE_VALUE, vhwndMain);
  1549. vfAgentRegistered = FALSE;
  1550. }
  1551. }
  1552. BOOL
  1553. QueryEnableCSC(
  1554. VOID
  1555. )
  1556. {
  1557. DWORD dwDisposition, dwSize, dwEnabled=0;
  1558. HKEY hKey = NULL;
  1559. BOOL fRet = TRUE;
  1560. int i;
  1561. _TCHAR *lpKey;
  1562. NT_PRODUCT_TYPE productType;
  1563. if( !RtlGetNtProductType( &productType ) ) {
  1564. productType = NtProductWinNt;
  1565. }
  1566. switch ( productType ) {
  1567. case NtProductWinNt:
  1568. /* WORKSTATION */
  1569. ReintKdPrint(INIT, ("Agent:CSC running workstation\r\n"));
  1570. break;
  1571. default:
  1572. ReintKdPrint(INIT, ("Agent:CSC NOT running workstation\r\n"));
  1573. fRet = FALSE; // default is fail
  1574. }
  1575. //Check if CSC can work with current settings for TS
  1576. //Test for TS added by Navjot as per Bug#468391
  1577. if (IsPersonal() == TRUE || !CanCSCLivewithTS() )
  1578. return FALSE;
  1579. for (i=0; i<2; ++i)
  1580. {
  1581. if (i==0)
  1582. {
  1583. lpKey = REG_STRING_POLICY_NETCACHE_KEY;
  1584. }
  1585. else
  1586. {
  1587. lpKey = REG_STRING_NETCACHE_KEY;
  1588. }
  1589. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1590. lpKey,
  1591. 0,
  1592. KEY_READ | KEY_WRITE,
  1593. &hKey
  1594. ) == ERROR_SUCCESS)
  1595. {
  1596. dwSize = sizeof(dwEnabled);
  1597. if (RegQueryValueEx(hKey, REG_VALUE_ENABLED, NULL, NULL, (void *)&dwEnabled, &dwSize) == ERROR_SUCCESS)
  1598. {
  1599. fRet = (dwEnabled != 0);
  1600. break;
  1601. }
  1602. RegCloseKey(hKey);
  1603. hKey = NULL;
  1604. }
  1605. else
  1606. {
  1607. hKey = NULL;
  1608. }
  1609. }
  1610. if(hKey)
  1611. {
  1612. RegCloseKey(hKey);
  1613. }
  1614. return (fRet);
  1615. }
  1616. BOOL
  1617. CreateStartStopEvents(
  1618. VOID
  1619. )
  1620. {
  1621. BOOL fOK = FALSE;
  1622. // ensure that there are thre named autoreset events
  1623. if (!heventWkssvcToAgentStart)
  1624. {
  1625. heventWkssvcToAgentStart = CreateEvent(NULL, FALSE, FALSE, szWkssvcToAgentStartEvent);
  1626. if (!heventWkssvcToAgentStart)
  1627. {
  1628. ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventWkssvcToAgentStart, error = %d\n", GetLastError()));
  1629. goto bailout;
  1630. }
  1631. Assert(!heventAgentToWkssvc);
  1632. heventWkssvcToAgentStop = CreateEvent(NULL, FALSE, FALSE, szWkssvcToAgentStopEvent);
  1633. if (!heventWkssvcToAgentStop)
  1634. {
  1635. ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventWkssvcToAgentStop, error = %d\n", GetLastError()));
  1636. goto bailout;
  1637. }
  1638. heventAgentToWkssvc = CreateEvent(NULL, FALSE, FALSE, szAgentToWkssvcEvent);
  1639. if (!heventAgentToWkssvc)
  1640. {
  1641. ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventAgentToWkssvc, error = %d\n", GetLastError()));
  1642. goto bailout;
  1643. }
  1644. // event to detect whether the agent is alive (used by wkssvc) and
  1645. // to signal termination (used by winlogon)
  1646. heventShutDownAgent = CreateEvent(NULL, FALSE, FALSE, szAgentExistsEvent);
  1647. if (!heventShutDownAgent)
  1648. {
  1649. ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventShutDownAgent, error = %d\n", GetLastError()));
  1650. goto bailout;
  1651. }
  1652. heventShutDownThread = CreateEvent(NULL, FALSE, FALSE, NULL);
  1653. if (!heventShutDownThread)
  1654. {
  1655. ReintKdPrint(BADERRORS, ("CSC.Agent: Failed to create heventShutDownThread, error = %d\n", GetLastError()));
  1656. goto bailout;
  1657. }
  1658. }
  1659. fOK = TRUE;
  1660. bailout:
  1661. if (!fOK)
  1662. {
  1663. DestroyStartStopEvents();
  1664. }
  1665. return fOK;
  1666. }
  1667. VOID
  1668. DestroyStartStopEvents(
  1669. VOID
  1670. )
  1671. {
  1672. if (heventWkssvcToAgentStart)
  1673. {
  1674. CloseHandle(heventWkssvcToAgentStart);
  1675. heventWkssvcToAgentStart = NULL;
  1676. }
  1677. if (heventWkssvcToAgentStop)
  1678. {
  1679. CloseHandle(heventWkssvcToAgentStop);
  1680. heventWkssvcToAgentStop = NULL;
  1681. }
  1682. if (heventAgentToWkssvc)
  1683. {
  1684. CloseHandle(heventAgentToWkssvc);
  1685. heventAgentToWkssvc = NULL;
  1686. }
  1687. if (heventShutDownAgent)
  1688. {
  1689. CloseHandle(heventShutDownAgent);
  1690. heventShutDownAgent = NULL;
  1691. }
  1692. if (heventShutDownThread)
  1693. {
  1694. CloseHandle(heventShutDownThread);
  1695. heventShutDownThread = NULL;
  1696. }
  1697. }
  1698. BOOL
  1699. UpdateExclusionList(
  1700. VOID
  1701. )
  1702. /*++
  1703. Routine Description:
  1704. Tell the kernel mode code about the exclusion list. If there is none set in the registry
  1705. then we set the default one
  1706. Parameters:
  1707. Return Value:
  1708. Notes:
  1709. --*/
  1710. {
  1711. LPWSTR lpwExclusionList = NULL;
  1712. DWORD cbSize = 0;
  1713. char buff[MAX_LIST_SIZE]; // max exclusion list
  1714. BOOL fRet = FALSE;
  1715. if (!vfCSCEnabled)
  1716. {
  1717. ReintKdPrint(INIT, ("CSC not enabled \r\n"));
  1718. return FALSE;
  1719. }
  1720. ReintKdPrint(INIT, ("Getting ExclusionList \r\n"));
  1721. // get the exclusion list from the policy key.
  1722. // if that doesn't work then try the one from the netcache key
  1723. if (GetWideStringFromRegistryString(REG_STRING_POLICY_NETCACHE_KEY_A,
  1724. REG_STRING_EXCLUSION_LIST_A,
  1725. &lpwExclusionList,
  1726. &cbSize) ||
  1727. GetWideStringFromRegistryString(REG_STRING_NETCACHE_KEY_A,
  1728. REG_STRING_EXCLUSION_LIST_A,
  1729. &lpwExclusionList,
  1730. &cbSize)
  1731. )
  1732. {
  1733. ReintKdPrint(INIT, ("Got ExclusionList \r\n"));
  1734. if (cbSize < sizeof(buff))
  1735. {
  1736. memcpy(buff, lpwExclusionList, cbSize);
  1737. ReintKdPrint(INIT, ("Setting User defined exclusion list %ls size=%d\r\n", buff, cbSize));
  1738. if (SetExclusionList(INVALID_HANDLE_VALUE, (USHORT *)buff, cbSize))
  1739. {
  1740. fRet = TRUE;
  1741. }
  1742. }
  1743. }
  1744. else
  1745. {
  1746. // set the default
  1747. // take the string and it's terminating null char
  1748. cbSize = sizeof(vtzDefaultExclusionList);
  1749. Assert(cbSize < MAX_LIST_SIZE);
  1750. memcpy(buff, vtzDefaultExclusionList, cbSize);
  1751. ReintKdPrint(INIT, ("Setting default exclusion list %ls size=%d\r\n", buff, cbSize));
  1752. if (SetExclusionList(INVALID_HANDLE_VALUE, (USHORT *)buff, cbSize))
  1753. {
  1754. fRet = TRUE;
  1755. }
  1756. }
  1757. if (lpwExclusionList)
  1758. {
  1759. LocalFree(lpwExclusionList);
  1760. }
  1761. return fRet;
  1762. }
  1763. BOOL
  1764. UpdateBandwidthConservationList(
  1765. VOID
  1766. )
  1767. /*++
  1768. Routine Description:
  1769. Update the list of extensions on which bitcopy should be turned ON. We do not set any default
  1770. Parameters:
  1771. Return Value:
  1772. Notes:
  1773. --*/
  1774. {
  1775. LPWSTR lpwBandwidthConservationList = NULL;
  1776. DWORD cbSize = 0;
  1777. char buff[MAX_LIST_SIZE]; // max exclusion list
  1778. BOOL fRet = FALSE;
  1779. if (!vfCSCEnabled)
  1780. {
  1781. ReintKdPrint(INIT, ("CSC not enabled \r\n"));
  1782. return FALSE;
  1783. }
  1784. ReintKdPrint(INIT, ("Getting BandwidthConservationList \r\n"));
  1785. // get the exclusion list from the policy key.
  1786. // if that doesn't work then try the one from the netcache key
  1787. if (GetWideStringFromRegistryString(REG_STRING_POLICY_NETCACHE_KEY_A,
  1788. REG_STRING_BANDWIDTH_CONSERVATION_LIST_A,
  1789. &lpwBandwidthConservationList,
  1790. &cbSize) ||
  1791. GetWideStringFromRegistryString(REG_STRING_NETCACHE_KEY_A,
  1792. REG_STRING_BANDWIDTH_CONSERVATION_LIST_A,
  1793. &lpwBandwidthConservationList,
  1794. &cbSize)
  1795. )
  1796. {
  1797. ReintKdPrint(INIT, ("Got BandwidthConservationList \r\n"));
  1798. if (cbSize < sizeof(buff))
  1799. {
  1800. memcpy(buff, lpwBandwidthConservationList, cbSize);
  1801. ReintKdPrint(INIT, ("Setting User defined bandwidth conservation list %ls size=%d\r\n", buff, cbSize));
  1802. if (SetBandwidthConservationList(INVALID_HANDLE_VALUE, (USHORT *)buff, cbSize))
  1803. {
  1804. fRet = TRUE;
  1805. }
  1806. }
  1807. }
  1808. else
  1809. {
  1810. fRet = FALSE;
  1811. #if 0
  1812. // set the default
  1813. // take the string and it's terminating null char
  1814. cbSize = sizeof(vtzDefaultBandwidthConservationList);
  1815. Assert(cbSize < MAX_LIST_SIZE);
  1816. memcpy(buff, vtzDefaultBandwidthConservationList, cbSize);
  1817. ReintKdPrint(INIT, ("Setting default exclusion list %ls size=%d\r\n", buff, cbSize));
  1818. if (SetBandwidthConservationList(INVALID_HANDLE_VALUE, (USHORT *)buff, cbSize))
  1819. {
  1820. fRet = TRUE;
  1821. }
  1822. #endif
  1823. }
  1824. if (lpwBandwidthConservationList)
  1825. {
  1826. LocalFree(lpwBandwidthConservationList);
  1827. }
  1828. return fRet;
  1829. }
  1830. BOOL
  1831. ProcessNetArrivalMessage(
  1832. VOID
  1833. )
  1834. /*++
  1835. Routine Description:
  1836. Parameters:
  1837. Return Value:
  1838. Notes:
  1839. --*/
  1840. {
  1841. vcntNetDevices = 1;
  1842. ReportShareNetArrivalDeparture( 0, // all shares
  1843. 0,
  1844. FALSE, // don't invoke autodial
  1845. TRUE // arrived
  1846. );
  1847. ReintKdPrint(INIT, ("WM_DEVICECHANGE:Net arrived, %d nets so far\r\n", vcntNetDevices));
  1848. return (TRUE);
  1849. }
  1850. BOOL
  1851. ProcessNetDepartureMessage(
  1852. BOOL fInvokeAutodial
  1853. )
  1854. /*++
  1855. Routine Description:
  1856. Parameters:
  1857. Return Value:
  1858. Notes:
  1859. --*/
  1860. {
  1861. ReintKdPrint(MAINLOOP, ("WM_DEVICECHANGE:Net removed, %d nets so far\r\n", vcntNetDevices));
  1862. vcntNetDevices = 0;
  1863. ReportShareNetArrivalDeparture( 0, // all shares
  1864. 0,
  1865. fInvokeAutodial, // invoke auto dial
  1866. FALSE // departed
  1867. );
  1868. return TRUE;
  1869. }
  1870. BOOL
  1871. ReportShareNetArrivalDeparture(
  1872. BOOL fOneServer,
  1873. HSHARE hShare,
  1874. BOOL fInvokeAutoDial,
  1875. BOOL fArrival
  1876. )
  1877. /*++
  1878. Routine Description:
  1879. Parameters:
  1880. Return Value:
  1881. Notes:
  1882. --*/
  1883. {
  1884. SHAREINFO sSR;
  1885. _TCHAR *lptzServerName;
  1886. unsigned ulStatus;
  1887. DWORD dwSize;
  1888. BOOL fGotName = FALSE;
  1889. BOOL fAllocated = FALSE;
  1890. BOOL fRet = FALSE;
  1891. LRESULT lResult = LRESULT_CSCFAIL;
  1892. LPTSTR lp = NULL;
  1893. DWORD dwMessage = 0;
  1894. WPARAM dwWParam = (WPARAM) 0;
  1895. LPARAM dwLParam = (LPARAM) 0;
  1896. lptzServerName = sSR.rgSharePath;
  1897. if (fOneServer) {
  1898. if (fArrival) {
  1899. if(GetShareInfo(vhShadowDBForEvent, hShare, &sSR, &ulStatus)<= 0) {
  1900. PrintFn("ReportShareNetArrivalDeparture: couldn't get status for server 0x%x\r\n",
  1901. hShare);
  1902. ReintKdPrint(
  1903. BADERRORS,
  1904. ("ReportShareNetArrivalDeparture: couldn't get status for server 0x%x\r\n",
  1905. hShare));
  1906. return FALSE;
  1907. }
  1908. lp = MyStrChr(sSR.rgSharePath+2, _T('\\'));
  1909. if (!lp) {
  1910. ReintKdPrint(
  1911. BADERRORS,
  1912. ("ReportShareNetArrivalDeparture: Invalid server name %ls\r\n",
  1913. sSR.rgSharePath));
  1914. Assert(FALSE);
  1915. return FALSE;
  1916. }
  1917. *lp = 0;
  1918. } else { // A share departure
  1919. int i;
  1920. dwSize = sizeof(sSR.rgSharePath);
  1921. fGotName = GetNameOfServerGoingOfflineEx(
  1922. vhShadowDBForEvent,
  1923. &lptzServerName,
  1924. &dwSize,
  1925. &fAllocated);
  1926. if(!fGotName) {
  1927. TransitionShareToOffline(vhShadowDBForEvent, fOneServer, 0xffffffff);
  1928. goto bailout;
  1929. }
  1930. }
  1931. }
  1932. fRet = TRUE;
  1933. ReintKdPrint(
  1934. INIT,
  1935. ("ReportShareNetArrivalDeparture: reporting %s to the systray\r\n",
  1936. (fArrival) ? "arrival" : "departure"));
  1937. dwMessage = (fArrival) ? STWM_CSCNETUP : STWM_CSCQUERYNETDOWN;
  1938. dwWParam = (fInvokeAutoDial)
  1939. ? ((hShare != 0)
  1940. ? CSCUI_AUTODIAL_FOR_CACHED_SHARE
  1941. : CSCUI_AUTODIAL_FOR_UNCACHED_SHARE)
  1942. : CSCUI_NO_AUTODIAL;
  1943. dwLParam = (fOneServer) ? (DWORD_PTR)(lptzServerName) : 0;
  1944. lResult = ReportEventsToSystray(dwMessage, dwWParam, dwLParam);
  1945. // if the redir is stuck waiting to be told whether to go offline on a share
  1946. // tell him yes or no
  1947. if (!fArrival) {
  1948. if (fOneServer) {
  1949. TransitionShareToOffline(
  1950. vhShadowDBForEvent,
  1951. fOneServer,
  1952. (lResult == LRESULT_CSCWORKOFFLINE)
  1953. ? 1
  1954. : ((lResult == LRESULT_CSCRETRY)
  1955. ? 0
  1956. : 0xffffffff)
  1957. );
  1958. if (lResult == LRESULT_CSCWORKOFFLINE) {
  1959. dwMessage = STWM_CSCNETDOWN;
  1960. dwWParam = fInvokeAutoDial;
  1961. dwLParam = (fOneServer)
  1962. ? ((hShare != 0)
  1963. ? (DWORD_PTR)(lptzServerName)
  1964. : 0xffffffff)
  1965. : 0;
  1966. ReportEventsToSystray(dwMessage, dwWParam, dwLParam);
  1967. ReportTransitionToDfs(lptzServerName, TRUE, 0xffffffff);
  1968. }
  1969. }
  1970. }
  1971. bailout:
  1972. if (fAllocated) {
  1973. LocalFree(lptzServerName);
  1974. }
  1975. return (fRet);
  1976. }
  1977. BOOL
  1978. CheckServerOnline(
  1979. VOID
  1980. )
  1981. /*++
  1982. Routine Description:
  1983. Parameters:
  1984. Return Value:
  1985. Notes:
  1986. --*/
  1987. {
  1988. unsigned long ulStatus;
  1989. WIN32_FIND_DATA sFind32;
  1990. int cntReconnected=0;
  1991. SHADOWINFO sSI;
  1992. HANDLE hShadowDB;
  1993. _TCHAR tzDriveMap[4];
  1994. CSC_ENUMCOOKIE ulEnumCookie=NULL;
  1995. DWORD dwError;
  1996. if (!ImpersonateALoggedOnUser())
  1997. {
  1998. return 0;
  1999. }
  2000. if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
  2001. {
  2002. ResetAgentThreadImpersonation();
  2003. return 0;
  2004. }
  2005. memset(&sFind32, 0, sizeof(sFind32));
  2006. lstrcpy(sFind32.cFileName, _TEXT("*"));
  2007. if(FindOpenShadow( hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL,
  2008. &sFind32, &sSI))
  2009. {
  2010. ulEnumCookie = sSI.uEnumCookie;
  2011. do {
  2012. if(GetShareStatus(hShadowDB, sSI.hShare, &ulStatus)) {
  2013. if(ulStatus & SHARE_DISCONNECTED_OP){
  2014. dwError = DWConnectNet(sFind32.cFileName, tzDriveMap, NULL, NULL, NULL, 0, NULL);
  2015. if ((dwError == NO_ERROR)||(dwError == ERROR_ACCESS_DENIED)||(dwError==WN_CONNECTED_OTHER_PASSWORD_DEFAULT))
  2016. {
  2017. if (sSI.ulHintFlags & FLAG_CSC_HINT_PIN_SYSTEM)
  2018. {
  2019. TransitionShareToOnline(INVALID_HANDLE_VALUE, 0);
  2020. }
  2021. else
  2022. {
  2023. ReportShareNetArrivalDeparture( TRUE,
  2024. sSI.hShare, // this share
  2025. FALSE, // don't autodial
  2026. TRUE); // Arrived
  2027. }
  2028. ++cntReconnected;
  2029. if (dwError == NO_ERROR || dwError == WN_CONNECTED_OTHER_PASSWORD_DEFAULT)
  2030. {
  2031. DWDisconnectDriveMappedNet(tzDriveMap, TRUE); // force disconnect
  2032. }
  2033. }
  2034. }
  2035. }
  2036. Sleep(200);
  2037. } while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
  2038. FindCloseShadow(hShadowDB, ulEnumCookie);
  2039. }
  2040. CloseShadowDatabaseIO(hShadowDB);
  2041. ResetAgentThreadImpersonation();
  2042. return (cntReconnected?TRUE:FALSE);
  2043. }
  2044. BOOL
  2045. AreAnyServersOffline(
  2046. VOID)
  2047. {
  2048. ULONG ulStatus;
  2049. WIN32_FIND_DATA sFind32 = {0};
  2050. SHADOWINFO sSI;
  2051. HANDLE hShadowDB;
  2052. CSC_ENUMCOOKIE ulEnumCookie = NULL;
  2053. BOOL bFoundOne = FALSE;
  2054. if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
  2055. return FALSE;
  2056. wcscpy(sFind32.cFileName, L"*");
  2057. if (FindOpenShadow(hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL, &sFind32, &sSI)) {
  2058. ulEnumCookie = sSI.uEnumCookie;
  2059. do {
  2060. if (GetShareStatus(hShadowDB, sSI.hShare, &ulStatus)) {
  2061. if ((ulStatus & SHARE_DISCONNECTED_OP) != 0) {
  2062. bFoundOne = TRUE;
  2063. break;
  2064. }
  2065. }
  2066. } while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
  2067. FindCloseShadow(hShadowDB, ulEnumCookie);
  2068. }
  2069. CloseShadowDatabaseIO(hShadowDB);
  2070. return bFoundOne;
  2071. }
  2072. BOOL
  2073. FAbortOperation(
  2074. VOID
  2075. )
  2076. {
  2077. if (!vdwAgentThreadId)
  2078. {
  2079. return FALSE;
  2080. }
  2081. if (IsAgentShutDownRequested() || HasAgentShutDown())
  2082. {
  2083. ReintKdPrint(MAINLOOP, ("CSC.FAbortOperation: Agentshutdown detected aborting \r\n"));
  2084. return TRUE;
  2085. }
  2086. return (FStopAgent());
  2087. }
  2088. VOID
  2089. SetAgentShutDownRequest(
  2090. VOID
  2091. )
  2092. {
  2093. fAgentShutDownRequested = TRUE;
  2094. SetEvent(heventShutDownAgent);
  2095. }
  2096. BOOL
  2097. IsAgentShutDownRequested(
  2098. VOID
  2099. )
  2100. {
  2101. return (fAgentShutDownRequested == TRUE);
  2102. }
  2103. VOID
  2104. SetAgentShutDown(
  2105. VOID
  2106. )
  2107. {
  2108. fAgentShutDown = TRUE;
  2109. }
  2110. BOOL
  2111. HasAgentShutDown(
  2112. VOID
  2113. )
  2114. {
  2115. return (fAgentShutDown == TRUE );
  2116. }
  2117. // HWND CSCUIInitialize(HANDLE hToken, DWORD dwFlags)
  2118. BOOL
  2119. InitCSCUI(
  2120. HANDLE hToken
  2121. )
  2122. {
  2123. ReintKdPrint(INIT, (" Initializing cscui\r\n"));
  2124. EnterAgentCrit();
  2125. if (!vhlibCSCUI)
  2126. {
  2127. vhlibCSCUI = LoadLibrary(vtzCSCUI);
  2128. if (vhlibCSCUI)
  2129. {
  2130. if (vlpfnCSCUIInitialize = (CSCUIINITIALIZE)GetProcAddress(vhlibCSCUI, (const char *)vszCSCUIInitialize))
  2131. {
  2132. if(!(vlpfnCSCUISetState = (CSCUISETSTATE)GetProcAddress(vhlibCSCUI, (const char *)vszCSCUISetState)))
  2133. {
  2134. ReintKdPrint(BADERRORS, ("Failed to get proc addres for %s, Error = %d \r\n", vszCSCUISetState, GetLastError()));
  2135. }
  2136. else
  2137. {
  2138. (*vlpfnCSCUIInitialize)(hToken, CI_INITIALIZE);
  2139. }
  2140. }
  2141. else
  2142. {
  2143. ReintKdPrint(BADERRORS, ("Failed to get proc addres for %s, Error = %d \r\n", vszCSCUIInitialize, GetLastError()));
  2144. }
  2145. }
  2146. else
  2147. {
  2148. ReintKdPrint(BADERRORS, ("Failed to load %ls, Error = %d \r\n", vtzCSCUI, GetLastError()));
  2149. }
  2150. }
  2151. LeaveAgentCrit();
  2152. return (vlpfnCSCUISetState != NULL);
  2153. }
  2154. VOID
  2155. TerminateCSCUI(
  2156. VOID
  2157. )
  2158. {
  2159. BOOL fShowing;
  2160. // snapshot the state of the showing dialog
  2161. // if we are about to show an offline dialog, ReportEventsToSystray
  2162. // will also do the action below but will try to set the vfShowingOfflineDlg
  2163. // variable to 1
  2164. // If fShowing was not set to 1, then we know that we are not showing UI
  2165. // and we set vfShowingOfflineDlg to 0xffffffff. This will make ReportEventsToSystray
  2166. // to not show the offline popup, so we will be free to do FreeLibrary
  2167. fShowing = (BOOL)InterlockedExchange((PLONG)&vfShowingOfflineDlg, 0xffffffff);
  2168. if (fShowing==1)
  2169. {
  2170. Assert(vhlibCSCUI && vlpfnCSCUISetState);
  2171. (vlpfnCSCUISetState)(STWM_CSCCLOSEDIALOGS, 0, 0);
  2172. while (vfShowingOfflineDlg != 0xfffffffe)
  2173. {
  2174. Sleep(10);
  2175. }
  2176. }
  2177. if (vhlibCSCUI)
  2178. {
  2179. (*vlpfnCSCUIInitialize)(0, CI_TERMINATE);
  2180. vlpfnCSCUIInitialize = NULL;
  2181. vlpfnCSCUISetState = NULL;
  2182. FreeLibrary(vhlibCSCUI);
  2183. vhlibCSCUI = NULL;
  2184. }
  2185. vfShowingOfflineDlg = 0;
  2186. }
  2187. LRESULT
  2188. ReportEventsToSystray(
  2189. DWORD dwMessage,
  2190. WPARAM dwWParam,
  2191. LPARAM dwLParam
  2192. )
  2193. /*++
  2194. Routine Description:
  2195. Parameters:
  2196. Return Value:
  2197. Notes:
  2198. --*/
  2199. {
  2200. LRESULT lResult = LRESULT_CSCFAIL;
  2201. BOOL fOk;
  2202. HWND hwnd;
  2203. extern HDESK hdesktopUser, hdesktopCur;
  2204. EnterAgentCrit();
  2205. // is there a currently logged on user?
  2206. if (!hdesktopUser)
  2207. {
  2208. LeaveAgentCrit();
  2209. ReintKdPrint(INIT, ("ReportEventsToSystray: no-user logged, not-reporting\r\n"));
  2210. return lResult;
  2211. }
  2212. else
  2213. {
  2214. if(!SetThreadDesktop(hdesktopUser))
  2215. {
  2216. LeaveAgentCrit();
  2217. PrintFn("ReportEventsToSystray: failed to set desktop for agent thread error=%d\r\n", GetLastError());
  2218. ReintKdPrint(BADERRORS, ("ReportEventsToSystray: failed to set desktop for agent thread error=%d\r\n", GetLastError()));
  2219. return lResult;
  2220. }
  2221. // set our desktop to be that of the loggedon users desktop
  2222. hdesktopCur = hdesktopUser;
  2223. }
  2224. LeaveAgentCrit();
  2225. ReintKdPrint(INIT, ("ReportEventsToSystray: reporting message dwMessage=0x%x to the systray\r\n", dwMessage));
  2226. // snapshot the state of the showing dialog
  2227. // if we are about to terminate, the the terminateCSCUI will have
  2228. // will also do the action below but will try to set the vfShowingOfflineDlg
  2229. // variable to 0xffffffff
  2230. // If fOk was not set to 0xffffffff, then we know that we are not terminating
  2231. // and we set vfShowingOfflineDlg to 1. This will block the terminating guy
  2232. // and he will not free the library till thei variable gets set to FALSE;
  2233. fOk = (BOOL)InterlockedExchange((PLONG)&vfShowingOfflineDlg, 1);
  2234. if (fOk == 0)
  2235. {
  2236. if (vlpfnCSCUISetState)
  2237. {
  2238. lResult = (vlpfnCSCUISetState)(dwMessage, dwWParam, dwLParam);
  2239. // change the value of vfShowingOfflineDlg to 0 only if it is 1 right now
  2240. // it can be something other than 1 if we are about to terminate
  2241. if((DWORD)InterlockedCompareExchange(&vfShowingOfflineDlg, 0, 1) == 0xffffffff)
  2242. {
  2243. // if we came here then we are terminating, set a termination value
  2244. // so that the logoff thread will stop doing a sleep loop
  2245. // and if we came here again fOk will never be 0
  2246. vfShowingOfflineDlg = 0xfffffffe;
  2247. }
  2248. }
  2249. else
  2250. {
  2251. // Not showing any dialog, restore the variable back to what it should be
  2252. vfShowingOfflineDlg = 0;
  2253. PrintFn("ReportEventsToSystray: CSCUI not initalized\r\n");
  2254. }
  2255. }
  2256. return lResult;
  2257. }
  2258. BOOL
  2259. GetNameOfServerGoingOfflineEx(
  2260. HANDLE hShadowDB,
  2261. _TCHAR **lplptzServerName,
  2262. DWORD *lpdwSize,
  2263. BOOL *lpfAllocated
  2264. )
  2265. /*++
  2266. Routine Description:
  2267. This routine is called in winlogon thread to findout which server is about to go offline
  2268. The routine may allocate memory, which must be freed by the caller
  2269. Parameters:
  2270. Return Value:
  2271. Notes:
  2272. --*/
  2273. {
  2274. DWORD dwSize, i;
  2275. BOOL fRet = FALSE;
  2276. dwSize = *lpdwSize;
  2277. *lpfAllocated = FALSE;
  2278. for (i=0;i<2;++i)
  2279. {
  2280. if(!GetNameOfServerGoingOffline(
  2281. hShadowDB,
  2282. (LPBYTE)(*lplptzServerName), &dwSize))
  2283. {
  2284. // if we need a bigger buffer go get one
  2285. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  2286. {
  2287. // we shouldn't be trying to get a bigger buffer twice
  2288. // it should have been sufficient the first time around
  2289. if (i==1)
  2290. {
  2291. Assert(FALSE);
  2292. break;
  2293. }
  2294. ReintKdPrint(MAINLOOP, ("GetNameOfServerGoingOfflineEx: Need %d sized Buffer \n", dwSize));
  2295. *lplptzServerName = LocalAlloc(LPTR, dwSize);
  2296. if (!*lplptzServerName)
  2297. {
  2298. return FALSE;
  2299. }
  2300. *lpfAllocated = TRUE;
  2301. *lpdwSize = dwSize;
  2302. continue;
  2303. }
  2304. else
  2305. {
  2306. break;
  2307. }
  2308. }
  2309. else
  2310. {
  2311. // ReintKdPrint(MAINLOOP,("GetNameOfServerGoingOfflineEx:name=%ws\n", *lplptzServerName));
  2312. fRet = TRUE;
  2313. break;
  2314. }
  2315. }
  2316. // cleanup on error
  2317. if (!fRet && *lpfAllocated)
  2318. {
  2319. LocalFree(*lplptzServerName);
  2320. *lpfAllocated = FALSE;
  2321. }
  2322. return fRet;
  2323. }
  2324. BOOL
  2325. IsWinlogonRegValueSet(HKEY hKey, LPSTR pszKeyName, LPSTR pszPolicyKeyName, LPSTR pszValueName)
  2326. {
  2327. BOOL bRet = FALSE;
  2328. DWORD dwType;
  2329. DWORD dwSize;
  2330. HKEY hkey;
  2331. //
  2332. // first check the per-machine location.
  2333. //
  2334. if (RegOpenKeyExA(hKey, pszKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  2335. {
  2336. dwSize = sizeof(bRet);
  2337. if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
  2338. {
  2339. if (dwType != REG_DWORD)
  2340. {
  2341. bRet = FALSE;
  2342. }
  2343. }
  2344. RegCloseKey(hkey);
  2345. }
  2346. //
  2347. // then let the policy value override
  2348. //
  2349. if (RegOpenKeyExA(hKey, pszPolicyKeyName, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  2350. {
  2351. dwSize = sizeof(bRet);
  2352. if (RegQueryValueExA(hkey, pszValueName, NULL, &dwType, (LPBYTE)&bRet, &dwSize) == ERROR_SUCCESS)
  2353. {
  2354. if (dwType != REG_DWORD)
  2355. {
  2356. bRet = FALSE;
  2357. }
  2358. }
  2359. RegCloseKey(hkey);
  2360. }
  2361. return bRet;
  2362. }
  2363. BOOL
  2364. CheckIsSafeModeType(DWORD dwSafeModeType)
  2365. {
  2366. BOOL bResult = FALSE;
  2367. HKEY hkey;
  2368. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2369. TEXT("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option"),
  2370. 0,
  2371. KEY_QUERY_VALUE,
  2372. &hkey))
  2373. {
  2374. DWORD dwType;
  2375. DWORD dwValue;
  2376. DWORD cbValue = sizeof(dwValue);
  2377. if (ERROR_SUCCESS == RegQueryValueEx(hkey,
  2378. TEXT("OptionValue"),
  2379. NULL,
  2380. &dwType,
  2381. (LPBYTE)&dwValue,
  2382. &cbValue))
  2383. {
  2384. bResult = (dwValue == dwSafeModeType);
  2385. }
  2386. RegCloseKey(hkey);
  2387. }
  2388. return bResult;
  2389. }
  2390. BOOL
  2391. AllowMultipleTsSessions(void)
  2392. {
  2393. return IsWinlogonRegValueSet(HKEY_LOCAL_MACHINE,
  2394. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
  2395. "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system",
  2396. "AllowMultipleTSSessions");
  2397. }
  2398. BOOL
  2399. IsSafeMode(void)
  2400. {
  2401. return CheckIsSafeModeType(SAFEBOOT_MINIMAL) ||
  2402. CheckIsSafeModeType(SAFEBOOT_NETWORK);
  2403. }
  2404. BOOL
  2405. IsTerminalServicesEnabled(void)
  2406. {
  2407. OSVERSIONINFOEX osVersionInfo;
  2408. DWORDLONG dwlConditionMask;
  2409. dwlConditionMask = 0;
  2410. ZeroMemory(&osVersionInfo, sizeof(osVersionInfo));
  2411. osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
  2412. osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS;
  2413. VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
  2414. return(VerifyVersionInfo(&osVersionInfo, VER_SUITENAME, dwlConditionMask) != FALSE);
  2415. }
  2416. BOOL
  2417. IsMultipleUsersEnabled(void)
  2418. {
  2419. return IsTerminalServicesEnabled() &&
  2420. !IsSafeMode() &&
  2421. AllowMultipleTsSessions();
  2422. }
  2423. BOOL CanCSCLivewithTS(
  2424. VOID)
  2425. /*++
  2426. Routine Description:
  2427. Checks if TS settings are ok to turn on csc.
  2428. Arguments:
  2429. None
  2430. Return Value:
  2431. TRUE - Enable CSC
  2432. FALSE - Disable CSC
  2433. --*/
  2434. {
  2435. if (IsWorkstation ()) // for pro and per
  2436. {
  2437. // csc does not work with Fast user switching.
  2438. return !IsFastUserSwitchingEnabled();
  2439. }
  2440. else // for servers
  2441. {
  2442. //Both conditions have to be true
  2443. return !(IsTerminalServicesEnabled() && AreConnectionsAllowed());
  2444. }
  2445. }
  2446. BOOL AreConnectionsAllowed (
  2447. VOID)
  2448. /*++
  2449. Routine Description:
  2450. Checks if TS accepts connections.
  2451. Arguments:
  2452. None
  2453. Return Value:
  2454. TRUE - Accepts connections
  2455. FALSE - Denys connections
  2456. --*/
  2457. {
  2458. DWORD dwError;
  2459. HKEY hkey;
  2460. dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2461. TEXT("SYSTEM\\CurrentControlSet\\Control\\Terminal Server"),
  2462. 0,
  2463. KEY_QUERY_VALUE,
  2464. &hkey);
  2465. if (ERROR_SUCCESS == dwError)
  2466. {
  2467. DWORD dwType;
  2468. DWORD dwValue;
  2469. DWORD cbValue = sizeof(dwValue);
  2470. if (ERROR_SUCCESS == RegQueryValueEx(hkey,
  2471. TEXT("fDenyTSConnections"),
  2472. NULL,
  2473. &dwType,
  2474. (LPBYTE)&dwValue,
  2475. &cbValue))
  2476. {
  2477. return !dwValue;
  2478. }
  2479. }
  2480. //
  2481. // could not read registry, this means connections were allowed.
  2482. //
  2483. return TRUE;
  2484. }
  2485. BOOL
  2486. IsFastUserSwitchingEnabled(
  2487. VOID)
  2488. /*++
  2489. Routine Description:
  2490. Checks to see if Terminal Services Fast User Switching is enabled. This is
  2491. to check if we should use the physical console session for UI dialogs, or
  2492. always use session 0.
  2493. Fast User Switching exists only on workstation product version, where terminal
  2494. services are available, when AllowMultipleTSSessions is set.
  2495. On server and above, or when multiple TS users are not allowed, session 0
  2496. can only be attached remotely be special request, in which case it should be
  2497. considered the "Console" session.
  2498. Arguments:
  2499. None.
  2500. Return Value:
  2501. Returns TRUE if Fast User Switching is currently enabled, FALSE otherwise.
  2502. --*/
  2503. {
  2504. static BOOL bVerified = FALSE;
  2505. static BOOL bIsTSWorkstation = FALSE;
  2506. HKEY hKey;
  2507. ULONG ulSize, ulValue;
  2508. BOOL bFusEnabled;
  2509. //
  2510. // Verify the product version if we haven't already.
  2511. //
  2512. if (!bVerified) {
  2513. OSVERSIONINFOEX osvix;
  2514. DWORDLONG dwlConditionMask = 0;
  2515. ZeroMemory(&osvix, sizeof(OSVERSIONINFOEX));
  2516. osvix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  2517. osvix.wProductType = VER_NT_WORKSTATION;
  2518. VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_LESS_EQUAL);
  2519. osvix.wSuiteMask = VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS;
  2520. VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
  2521. if (VerifyVersionInfo(&osvix,
  2522. VER_PRODUCT_TYPE | VER_SUITENAME,
  2523. dwlConditionMask)) {
  2524. bIsTSWorkstation = TRUE;
  2525. }
  2526. bVerified = TRUE;
  2527. }
  2528. //
  2529. // Fast user switching (FUS) only applies to the Workstation product where
  2530. // Terminal Services are enabled (i.e. Personal, Professional).
  2531. //
  2532. if (!bIsTSWorkstation) {
  2533. return FALSE;
  2534. }
  2535. //
  2536. // Check if multiple TS sessions are currently allowed. We can't make this
  2537. // info static because it can change dynamically.
  2538. //
  2539. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2540. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  2541. 0,
  2542. KEY_READ,
  2543. &hKey) != ERROR_SUCCESS) {
  2544. return FALSE;
  2545. }
  2546. ulValue = 0;
  2547. ulSize = sizeof(ulValue);
  2548. bFusEnabled = FALSE;
  2549. if (RegQueryValueEx(hKey,
  2550. TEXT("AllowMultipleTSSessions"),
  2551. NULL,
  2552. NULL,
  2553. (LPBYTE)&ulValue,
  2554. &ulSize) == ERROR_SUCCESS) {
  2555. bFusEnabled = (ulValue != 0);
  2556. }
  2557. RegCloseKey(hKey);
  2558. return bFusEnabled;
  2559. } // IsFastUserSwitchingEnabled
  2560. BOOL
  2561. IsWorkstation(
  2562. VOID)
  2563. /*++
  2564. Routine Description:
  2565. Checks if the machine is a workstation.
  2566. Arguments:
  2567. None
  2568. Return Value:
  2569. TRUE - is workstation.
  2570. FALSE - is not a workstation.
  2571. --*/
  2572. {
  2573. OSVERSIONINFOEX osvix;
  2574. DWORDLONG dwlConditionMask = 0;
  2575. ZeroMemory(&osvix, sizeof(OSVERSIONINFOEX));
  2576. osvix.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  2577. osvix.wProductType = VER_NT_WORKSTATION;
  2578. VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_LESS_EQUAL);
  2579. if (VerifyVersionInfo(&osvix,
  2580. VER_PRODUCT_TYPE,
  2581. dwlConditionMask)) {
  2582. return TRUE;
  2583. }
  2584. return FALSE;
  2585. }