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.

1144 lines
39 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: SystemSettings.cpp
  3. //
  4. // Copyright (c) 1999-2000, Microsoft Corporation
  5. //
  6. // A class to handle opening and reading/writing from the Winlogon key.
  7. //
  8. // History: 1999-09-09 vtan created
  9. // 1999-11-16 vtan separate file
  10. // 2000-02-01 vtan moved from Neptune to Whistler
  11. // --------------------------------------------------------------------------
  12. #include "StandardHeader.h"
  13. #include "SystemSettings.h"
  14. #include <regstr.h>
  15. #include <safeboot.h>
  16. #include <winsta.h>
  17. #include <allproc.h> // TS_COUNTER
  18. #include <shlwapi.h>
  19. #include "RegistryResources.h"
  20. const TCHAR CSystemSettings::s_szSafeModeKeyName[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option");
  21. const TCHAR CSystemSettings::s_szSafeModeOptionValueName[] = TEXT("OptionValue");
  22. const TCHAR CSystemSettings::s_szWinlogonKeyName[] = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon");
  23. const TCHAR CSystemSettings::s_szSystemPolicyKeyName[] = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\policies\\system");
  24. const TCHAR CSystemSettings::s_szTerminalServerKeyName[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\Terminal Server");
  25. const TCHAR CSystemSettings::s_szTerminalServerPolicyKeyName[] = TEXT("SOFTWARE\\Policies\\Microsoft\\Windows NT\\Terminal Services");
  26. const TCHAR CSystemSettings::s_szNetwareClientKeyName[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order");
  27. const TCHAR CSystemSettings::s_szLogonTypeValueName[] = TEXT("LogonType");
  28. const TCHAR CSystemSettings::s_szBackgroundValueName[] = TEXT("Background");
  29. const TCHAR CSystemSettings::s_szMultipleUsersValueName[] = TEXT("AllowMultipleTSSessions");
  30. const TCHAR CSystemSettings::s_szDenyRemoteConnectionsValueName[] = TEXT("fDenyTSConnections");
  31. int CSystemSettings::s_iIsSafeModeMinimal = -1;
  32. int CSystemSettings::s_iIsSafeModeNetwork = -1;
  33. // --------------------------------------------------------------------------
  34. // CSystemSettings::IsSafeMode
  35. //
  36. // Arguments: <none>
  37. //
  38. // Returns: bool
  39. //
  40. // Purpose: Was the machine started in safe mode (minimal or network) ?
  41. //
  42. // History: 2000-03-06 vtan created
  43. // --------------------------------------------------------------------------
  44. bool CSystemSettings::IsSafeMode (void)
  45. {
  46. return(IsSafeModeMinimal() || IsSafeModeNetwork());
  47. }
  48. // --------------------------------------------------------------------------
  49. // CSystemSettings::IsSafeModeMinimal
  50. //
  51. // Arguments: <none>
  52. //
  53. // Returns: bool
  54. //
  55. // Purpose: Was the machine started in safe mode minimal?
  56. //
  57. // History: 1999-09-13 vtan created
  58. // 2000-05-25 vtan cache result in static member variable
  59. // --------------------------------------------------------------------------
  60. bool CSystemSettings::IsSafeModeMinimal (void)
  61. {
  62. if (-1 == s_iIsSafeModeMinimal)
  63. {
  64. bool fResult;
  65. CRegKey regKey;
  66. fResult = false;
  67. if (ERROR_SUCCESS == regKey.Open(HKEY_LOCAL_MACHINE,
  68. s_szSafeModeKeyName,
  69. KEY_QUERY_VALUE))
  70. {
  71. DWORD dwValue, dwValueSize;
  72. dwValueSize = sizeof(dwValue);
  73. if (ERROR_SUCCESS == regKey.GetDWORD(s_szSafeModeOptionValueName,
  74. dwValue))
  75. {
  76. fResult = (dwValue == SAFEBOOT_MINIMAL);
  77. }
  78. }
  79. s_iIsSafeModeMinimal = fResult;
  80. }
  81. return(s_iIsSafeModeMinimal != 0);
  82. }
  83. // --------------------------------------------------------------------------
  84. // CSystemSettings::IsSafeModeNetwork
  85. //
  86. // Arguments: <none>
  87. //
  88. // Returns: bool
  89. //
  90. // Purpose: Was the machine started in safe mode with networking?
  91. //
  92. // History: 1999-11-09 vtan created
  93. // 2000-05-25 vtan cache result in static member variable
  94. // --------------------------------------------------------------------------
  95. bool CSystemSettings::IsSafeModeNetwork (void)
  96. {
  97. if (-1 == s_iIsSafeModeNetwork)
  98. {
  99. bool fResult;
  100. CRegKey regKey;
  101. fResult = false;
  102. if (ERROR_SUCCESS == regKey.Open(HKEY_LOCAL_MACHINE,
  103. s_szSafeModeKeyName,
  104. KEY_QUERY_VALUE))
  105. {
  106. DWORD dwValue, dwValueSize;
  107. dwValueSize = sizeof(dwValue);
  108. if (ERROR_SUCCESS == regKey.GetDWORD(s_szSafeModeOptionValueName,
  109. dwValue))
  110. {
  111. fResult = (dwValue == SAFEBOOT_NETWORK);
  112. }
  113. }
  114. s_iIsSafeModeNetwork = fResult;
  115. }
  116. return(s_iIsSafeModeNetwork != 0);
  117. }
  118. // --------------------------------------------------------------------------
  119. // CSystemSettings::IsNetwareActive
  120. //
  121. // Arguments: <none>
  122. //
  123. // Returns: bool
  124. //
  125. // Purpose: Returns whether this machine is a workstation running
  126. // Netware client services or not.
  127. //
  128. // History: 2001-05-16 cevans created
  129. // --------------------------------------------------------------------------
  130. bool CSystemSettings::IsNetwareActive (void)
  131. {
  132. bool fResult;
  133. LONG lErrorCode;
  134. TCHAR szProviders[MAX_PATH] = {0};
  135. CRegKey regKey;
  136. fResult = false;
  137. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  138. s_szNetwareClientKeyName,
  139. KEY_QUERY_VALUE);
  140. if (ERROR_SUCCESS == lErrorCode)
  141. {
  142. if((regKey.GetString(TEXT("ProviderOrder"), szProviders, ARRAYSIZE(szProviders)) == ERROR_SUCCESS))
  143. {
  144. if (StrStrI(szProviders, TEXT("NWCWorkstation")) != NULL)
  145. {
  146. fResult = true;
  147. }
  148. else if (StrStrI(szProviders, TEXT("NetwareWorkstation")) != NULL)
  149. {
  150. fResult = true;
  151. }
  152. }
  153. }
  154. return fResult;
  155. }
  156. // --------------------------------------------------------------------------
  157. // CSystemSettings::IsWorkStationProduct
  158. //
  159. // Arguments: <none>
  160. //
  161. // Returns: bool
  162. //
  163. // Purpose: Returns whether this machine is a workstation product vs.
  164. // a server product.
  165. //
  166. // History: 2000-08-30 vtan created
  167. // --------------------------------------------------------------------------
  168. bool CSystemSettings::IsWorkStationProduct (void)
  169. {
  170. OSVERSIONINFOEXA osVersionInfo;
  171. ZeroMemory(&osVersionInfo, sizeof(osVersionInfo));
  172. osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
  173. return((GetVersionExA(reinterpret_cast<OSVERSIONINFOA*>(&osVersionInfo)) != FALSE) &&
  174. (VER_NT_WORKSTATION == osVersionInfo.wProductType));
  175. }
  176. // --------------------------------------------------------------------------
  177. // CSystemSettings::IsDomainMember
  178. //
  179. // Arguments: <none>
  180. //
  181. // Returns: bool
  182. //
  183. // Purpose: Is this machine a member of a domain? Use the LSA to get this
  184. // information.
  185. //
  186. // History: 1999-09-14 vtan created
  187. // --------------------------------------------------------------------------
  188. bool CSystemSettings::IsDomainMember (void)
  189. {
  190. bool fResult;
  191. int iCounter;
  192. NTSTATUS status;
  193. OBJECT_ATTRIBUTES objectAttributes;
  194. LSA_HANDLE lsaHandle;
  195. SECURITY_QUALITY_OF_SERVICE securityQualityOfService;
  196. PPOLICY_DNS_DOMAIN_INFO pDNSDomainInfo;
  197. fResult = false;
  198. securityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  199. securityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  200. securityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  201. securityQualityOfService.EffectiveOnly = FALSE;
  202. InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
  203. objectAttributes.SecurityQualityOfService = &securityQualityOfService;
  204. iCounter = 0;
  205. do
  206. {
  207. status = LsaOpenPolicy(NULL, &objectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &lsaHandle);
  208. if (RPC_NT_SERVER_TOO_BUSY == status)
  209. {
  210. Sleep(10);
  211. }
  212. } while ((RPC_NT_SERVER_TOO_BUSY == status) && (++iCounter < 10));
  213. if (NT_SUCCESS(status))
  214. {
  215. status = LsaQueryInformationPolicy(lsaHandle, PolicyDnsDomainInformation, reinterpret_cast<void**>(&pDNSDomainInfo));
  216. if (NT_SUCCESS(status) && (pDNSDomainInfo != NULL))
  217. {
  218. fResult = ((pDNSDomainInfo->DnsDomainName.Length != 0) ||
  219. (pDNSDomainInfo->DnsForestName.Length != 0) ||
  220. (pDNSDomainInfo->Sid != NULL));
  221. TSTATUS(LsaFreeMemory(pDNSDomainInfo));
  222. }
  223. TSTATUS(LsaClose(lsaHandle));
  224. }
  225. return(fResult);
  226. }
  227. // --------------------------------------------------------------------------
  228. // CSystemSettings::IsActiveConsoleSession
  229. //
  230. // Arguments: <none>
  231. //
  232. // Returns: bool
  233. //
  234. // Purpose: Returns whether current process session is the active console
  235. // session.
  236. //
  237. // History: 2001-03-04 vtan created
  238. // --------------------------------------------------------------------------
  239. bool CSystemSettings::IsActiveConsoleSession (void)
  240. {
  241. return(NtCurrentPeb()->SessionId == USER_SHARED_DATA->ActiveConsoleId);
  242. }
  243. // --------------------------------------------------------------------------
  244. // CSystemSettings::IsTerminalServicesEnabled
  245. //
  246. // Arguments: <none>
  247. //
  248. // Returns: bool
  249. //
  250. // Purpose: Does this machine have an enabled terminal services service?
  251. // This function is for Windows 2000 and later ONLY.
  252. //
  253. // History: 2000-03-02 vtan created
  254. // --------------------------------------------------------------------------
  255. bool CSystemSettings::IsTerminalServicesEnabled (void)
  256. {
  257. OSVERSIONINFOEX osVersionInfo;
  258. DWORDLONG dwlConditionMask;
  259. dwlConditionMask = 0;
  260. ZeroMemory(&osVersionInfo, sizeof(osVersionInfo));
  261. osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
  262. osVersionInfo.wSuiteMask = VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS;
  263. VER_SET_CONDITION(dwlConditionMask, VER_SUITENAME, VER_OR);
  264. return((VerifyVersionInfo(&osVersionInfo, VER_SUITENAME, dwlConditionMask) != FALSE) &&
  265. !IsSCMTerminalServicesDisabled());
  266. }
  267. // --------------------------------------------------------------------------
  268. // CSystemSettings::IsFriendlyUIActive
  269. //
  270. // Arguments: <none>
  271. //
  272. // Returns: bool
  273. //
  274. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  275. // CurrentVersion\Winlogon\LogonType and if this value is 0x01
  276. // then activate the external UI host. This function returns the
  277. // setting. This can never be true for domain member machines.
  278. //
  279. // History: 2000-02-04 vtan created
  280. // --------------------------------------------------------------------------
  281. bool CSystemSettings::IsFriendlyUIActive (void)
  282. {
  283. int iResult;
  284. return(IsWorkStationProduct() &&
  285. (!IsDomainMember() || IsForceFriendlyUI()) &&
  286. IsMicrosoftGINA() &&
  287. !IsNetwareActive() &&
  288. (ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  289. s_szWinlogonKeyName,
  290. s_szSystemPolicyKeyName,
  291. s_szLogonTypeValueName,
  292. iResult)) &&
  293. (iResult != 0));
  294. }
  295. // --------------------------------------------------------------------------
  296. // CSystemSettings::IsMultipleUsersEnabled
  297. //
  298. // Arguments: <none>
  299. //
  300. // Returns: bool
  301. //
  302. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  303. // CurrentVersion\Winlogon\AllowMultipleTSSessions and if the
  304. // value is 0x01 *AND* terminal services is installed on this
  305. // machine then the conditions are satisfied.
  306. //
  307. // History: 2000-03-02 vtan created
  308. // --------------------------------------------------------------------------
  309. bool CSystemSettings::IsMultipleUsersEnabled (void)
  310. {
  311. int iResult;
  312. return(IsTerminalServicesEnabled() &&
  313. !IsSafeMode() &&
  314. (ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  315. s_szWinlogonKeyName,
  316. s_szSystemPolicyKeyName,
  317. s_szMultipleUsersValueName,
  318. iResult)) &&
  319. (iResult != 0));
  320. }
  321. // --------------------------------------------------------------------------
  322. // CSystemSettings::IsRemoteConnectionsEnabled
  323. //
  324. // Arguments: <none>
  325. //
  326. // Returns: bool
  327. //
  328. // Purpose: Read the registry HKLM\System\CurrentControlSet\Control\
  329. // Terminal Server\fDenyTSConnections and returns the
  330. // value back to the caller.
  331. //
  332. // History: 2000-07-28 vtan created
  333. // --------------------------------------------------------------------------
  334. bool CSystemSettings::IsRemoteConnectionsEnabled (void)
  335. {
  336. int iResult;
  337. CRegKey regKey;
  338. return(IsTerminalServicesEnabled() &&
  339. (ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  340. s_szTerminalServerKeyName,
  341. s_szTerminalServerPolicyKeyName,
  342. s_szDenyRemoteConnectionsValueName,
  343. iResult)) &&
  344. (iResult == 0));
  345. }
  346. // --------------------------------------------------------------------------
  347. // CSystemSettings::IsRemoteConnectionPresent
  348. //
  349. // Arguments: <none>
  350. //
  351. // Returns: bool
  352. //
  353. // Purpose: Returns whether there is a remote connection active on the
  354. // current system.
  355. //
  356. // History: 2000-07-28 vtan created
  357. // --------------------------------------------------------------------------
  358. bool CSystemSettings::IsRemoteConnectionPresent (void)
  359. {
  360. bool fRemoteConnectionPresent;
  361. HANDLE hServer;
  362. PLOGONID pLogonID, pLogonIDs;
  363. ULONG ul, ulEntries;
  364. fRemoteConnectionPresent = false;
  365. // Open a connection to terminal services and get the number of sessions.
  366. hServer = WinStationOpenServerW(reinterpret_cast<WCHAR*>(SERVERNAME_CURRENT));
  367. if (hServer != NULL)
  368. {
  369. if (WinStationEnumerate(hServer, &pLogonIDs, &ulEntries) != FALSE)
  370. {
  371. // Iterate the sessions looking for active and shadow sessions only.
  372. for (ul = 0, pLogonID = pLogonIDs; !fRemoteConnectionPresent && (ul < ulEntries); ++ul, ++pLogonID)
  373. {
  374. if ((pLogonID->State == State_Active) || (pLogonID->State == State_Shadow))
  375. {
  376. fRemoteConnectionPresent = (lstrcmpi(pLogonID->WinStationName, TEXT("console")) != 0);
  377. }
  378. }
  379. // Free any resources used.
  380. (BOOLEAN)WinStationFreeMemory(pLogonIDs);
  381. }
  382. (BOOLEAN)WinStationCloseServer(hServer);
  383. }
  384. // Return result.
  385. return(fRemoteConnectionPresent);
  386. }
  387. // --------------------------------------------------------------------------
  388. // CSystemSettings::IsShutdownWithoutLogonAllowed
  389. //
  390. // Arguments: <none>
  391. //
  392. // Returns: bool
  393. //
  394. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  395. // CurrentVersion\Winlogon\ShutdownWithoutLogon and returns the
  396. // value back to the caller.
  397. //
  398. // History: 2000-04-27 vtan created
  399. // --------------------------------------------------------------------------
  400. bool CSystemSettings::IsShutdownWithoutLogonAllowed (void)
  401. {
  402. int iResult;
  403. return((ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  404. s_szWinlogonKeyName,
  405. s_szSystemPolicyKeyName,
  406. TEXT("ShutdownWithoutLogon"),
  407. iResult)) &&
  408. (iResult != 0));
  409. }
  410. // --------------------------------------------------------------------------
  411. // CSystemSettings::IsUndockWithoutLogonAllowed
  412. //
  413. // Arguments: <none>
  414. //
  415. // Returns: bool
  416. //
  417. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  418. // CurrentVersion\Winlogon\UndockWithoutLogon and returns the
  419. // value back to the caller.
  420. //
  421. // History: 2001-03-17 vtan created
  422. // --------------------------------------------------------------------------
  423. bool CSystemSettings::IsUndockWithoutLogonAllowed (void)
  424. {
  425. int iResult;
  426. return((ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  427. s_szWinlogonKeyName,
  428. s_szSystemPolicyKeyName,
  429. REGSTR_VAL_UNDOCK_WITHOUT_LOGON,
  430. iResult)) &&
  431. (iResult != 0));
  432. }
  433. // --------------------------------------------------------------------------
  434. // CSystemSettings::IsForceFriendlyUI
  435. //
  436. // Arguments: <none>
  437. //
  438. // Returns: bool
  439. //
  440. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  441. // CurrentVersion\Winlogon\ForceFriendlyUI and returns the
  442. // value back to the caller.
  443. //
  444. // History: 2000-04-27 vtan created
  445. // --------------------------------------------------------------------------
  446. bool CSystemSettings::IsForceFriendlyUI (void)
  447. {
  448. int iResult;
  449. return((ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  450. s_szWinlogonKeyName,
  451. s_szSystemPolicyKeyName,
  452. TEXT("ForceFriendlyUI"),
  453. iResult)) &&
  454. (iResult != 0));
  455. }
  456. // --------------------------------------------------------------------------
  457. // CSystemSettings::GetUIHost
  458. //
  459. // Arguments: pszPath = TCHAR array to receive UI host path.
  460. //
  461. // Returns: LONG
  462. //
  463. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  464. // CurrentVersion\Winlogon\UIHost and returns the value.
  465. //
  466. // History: 2000-04-12 vtan created
  467. // --------------------------------------------------------------------------
  468. LONG CSystemSettings::GetUIHost (TCHAR *pszPath)
  469. {
  470. return(GetEffectivePath(HKEY_LOCAL_MACHINE,
  471. s_szWinlogonKeyName,
  472. s_szSystemPolicyKeyName,
  473. TEXT("UIHost"),
  474. pszPath));
  475. }
  476. // --------------------------------------------------------------------------
  477. // CSystemSettings::IsUIHostStatic
  478. //
  479. // Arguments: <none>
  480. //
  481. // Returns: bool
  482. //
  483. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  484. // CurrentVersion\Winlogon\UIHostStatic and returns the
  485. // value.
  486. //
  487. // History: 2000-04-12 vtan created
  488. // --------------------------------------------------------------------------
  489. bool CSystemSettings::IsUIHostStatic (void)
  490. {
  491. int iResult;
  492. return((ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  493. s_szWinlogonKeyName,
  494. s_szSystemPolicyKeyName,
  495. TEXT("UIHostStatic"),
  496. iResult)) &&
  497. (iResult != 0));
  498. }
  499. // --------------------------------------------------------------------------
  500. // CSystemSettings::EnableFriendlyUI
  501. //
  502. // Arguments: fEnable = Enable friendly UI.
  503. //
  504. // Returns: bool
  505. //
  506. // Purpose: Enable friendly UI. This should only be allowed on workgroup
  507. // machines. Check the machine status to enforce this.
  508. //
  509. // ERROR_NOT_SUPPORTED is returned when the machine is joined to
  510. // a domain.
  511. //
  512. // History: 2000-08-01 vtan created
  513. // --------------------------------------------------------------------------
  514. bool CSystemSettings::EnableFriendlyUI (bool fEnable)
  515. {
  516. LONG lErrorCode;
  517. if (!IsDomainMember() || !fEnable)
  518. {
  519. CRegKey regKey;
  520. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  521. s_szWinlogonKeyName,
  522. KEY_SET_VALUE);
  523. if (ERROR_SUCCESS == lErrorCode)
  524. {
  525. lErrorCode = regKey.SetDWORD(s_szLogonTypeValueName,
  526. fEnable);
  527. if (fEnable)
  528. {
  529. lErrorCode = regKey.SetString(s_szBackgroundValueName,
  530. TEXT("0 0 0"));
  531. }
  532. else
  533. {
  534. (LONG)regKey.DeleteValue(s_szBackgroundValueName);
  535. }
  536. }
  537. }
  538. else
  539. {
  540. lErrorCode = ERROR_NOT_SUPPORTED;
  541. }
  542. SetLastError(static_cast<DWORD>(lErrorCode));
  543. return(ERROR_SUCCESS == lErrorCode);
  544. }
  545. // --------------------------------------------------------------------------
  546. // CSystemSettings::EnableMultipleUsers
  547. //
  548. // Arguments: fEnable = Enable multiple users.
  549. //
  550. // Returns: bool
  551. //
  552. // Purpose: Enable the multiple users feature. This sets
  553. // AllowMultipleTSSessions to 1 but only does so if remote
  554. // connections are disabled. This allows multiple console
  555. // sessions but no remote sessions. If there is a remote
  556. // connection active this call is rejected.
  557. //
  558. // ERROR_ACCESS_DENIED is returned when there are more than one
  559. // users active and being disabled.
  560. //
  561. // ERROR_CTX_NOT_CONSOLE is returned when being disabled from
  562. // a remote session (disabling only allowed from the console).
  563. //
  564. // ERROR_NOT_SUPPORTED is returned when being disabled from
  565. // the console, remote connections are enabled, and the current
  566. // session is not session 0.
  567. //
  568. // History: 2000-07-28 vtan created
  569. // --------------------------------------------------------------------------
  570. bool CSystemSettings::EnableMultipleUsers (bool fEnable)
  571. {
  572. LONG lErrorCode;
  573. // If disabling multiple users with more than one users active
  574. // reject the call. Return ERROR_ACCESS_DENIED.
  575. if (!fEnable && (GetLoggedOnUserCount() > 1))
  576. {
  577. lErrorCode = ERROR_ACCESS_DENIED;
  578. }
  579. // If disabling and not on the console, reject the call.
  580. // Return ERROR_CTX_NOT_CONSOLE.
  581. else if (!fEnable && !IsActiveConsoleSession())
  582. {
  583. lErrorCode = ERROR_CTX_NOT_CONSOLE;
  584. }
  585. // If disabling from the console and remote connections are enabled and
  586. // the current session is not session 0, reject the call. Otherwise, a
  587. // a remote connection with FUS disabled causes strange results because
  588. // it expects to connect to session 0.
  589. // Return ERROR_NOT_SUPPORTED.
  590. else if (!fEnable && IsRemoteConnectionsEnabled() && NtCurrentPeb()->SessionId != 0)
  591. {
  592. lErrorCode = ERROR_NOT_SUPPORTED;
  593. }
  594. else
  595. {
  596. CRegKey regKey;
  597. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  598. s_szWinlogonKeyName,
  599. KEY_SET_VALUE);
  600. if (ERROR_SUCCESS == lErrorCode)
  601. {
  602. lErrorCode = regKey.SetDWORD(s_szMultipleUsersValueName,
  603. fEnable);
  604. if (ERROR_SUCCESS == lErrorCode)
  605. {
  606. (DWORD)AdjustFUSCompatibilityServiceState(NULL);
  607. }
  608. }
  609. }
  610. SetLastError(static_cast<DWORD>(lErrorCode));
  611. return(ERROR_SUCCESS == lErrorCode);
  612. }
  613. // --------------------------------------------------------------------------
  614. // CSystemSettings::EnableRemoteConnections
  615. //
  616. // Arguments: fEnable = Enable remote connections.
  617. //
  618. // Returns: bool
  619. //
  620. // Purpose: Enable the remote connections feature. This sets
  621. // fDenyTSConnections to 0 but only does so if there is a one
  622. // user logged onto the system. This allows the single
  623. // connection to be remotely connected but not allow multiple
  624. // console sessions. This conforms to the single user per CPU
  625. // license of the workstation product. To get multiple users
  626. // you need the server product.
  627. //
  628. // ERROR_NOT_SUPPORTED is returned when enabling remote
  629. // connections with FUS disabled and the current session != 0.
  630. //
  631. // History: 2000-07-28 vtan created
  632. // --------------------------------------------------------------------------
  633. bool CSystemSettings::EnableRemoteConnections (bool fEnable)
  634. {
  635. LONG lErrorCode;
  636. // If enabling remote connections, FUS is disabled, and we are not on
  637. // session 0 (can happen immediately after disabling FUS), then a remote
  638. // connection will fail. With FUS disabled, the connection must go to
  639. // session 0. This is a fringe case, but disallow enabling remote
  640. // connections if it happens.
  641. if (fEnable && !IsMultipleUsersEnabled() && NtCurrentPeb()->SessionId != 0)
  642. {
  643. lErrorCode = ERROR_NOT_SUPPORTED;
  644. }
  645. else
  646. {
  647. CRegKey regKey;
  648. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  649. s_szTerminalServerKeyName,
  650. KEY_SET_VALUE);
  651. if (ERROR_SUCCESS == lErrorCode)
  652. {
  653. lErrorCode = regKey.SetDWORD(s_szDenyRemoteConnectionsValueName,
  654. !fEnable);
  655. }
  656. }
  657. SetLastError(static_cast<DWORD>(lErrorCode));
  658. return(ERROR_SUCCESS == lErrorCode);
  659. }
  660. // --------------------------------------------------------------------------
  661. // CSystemSettings::GetLoggedOnUserCount
  662. //
  663. // Arguments: <none>
  664. //
  665. // Returns: int
  666. //
  667. // Purpose: Returns the count of logged on users on this machine. Ripped
  668. // straight out of shtdndlg.c in msgina.
  669. //
  670. // History: 2000-03-29 vtan created
  671. // 2000-04-21 vtan copied from taskmgr
  672. // 2000-07-28 vtan moved from userlist.cpp
  673. // --------------------------------------------------------------------------
  674. int CSystemSettings::GetLoggedOnUserCount (void)
  675. {
  676. int iCount;
  677. HANDLE hServer;
  678. iCount = 0;
  679. // Open a connection to terminal services and get the number of sessions.
  680. hServer = WinStationOpenServerW(reinterpret_cast<WCHAR*>(SERVERNAME_CURRENT));
  681. if (hServer != NULL)
  682. {
  683. TS_COUNTER tsCounters[2] = {0};
  684. tsCounters[0].counterHead.dwCounterID = TERMSRV_CURRENT_DISC_SESSIONS;
  685. tsCounters[1].counterHead.dwCounterID = TERMSRV_CURRENT_ACTIVE_SESSIONS;
  686. if (WinStationGetTermSrvCountersValue(hServer, ARRAYSIZE(tsCounters), tsCounters))
  687. {
  688. int i;
  689. for (i = 0; i < ARRAYSIZE(tsCounters); i++)
  690. {
  691. if (tsCounters[i].counterHead.bResult)
  692. {
  693. iCount += tsCounters[i].dwValue;
  694. }
  695. }
  696. }
  697. (BOOLEAN)WinStationCloseServer(hServer);
  698. }
  699. // Return result.
  700. return(iCount);
  701. }
  702. // --------------------------------------------------------------------------
  703. // CSystemSettings::CheckDomainMembership
  704. //
  705. // Arguments: <none>
  706. //
  707. // Returns: NTSTATUS
  708. //
  709. // Purpose: Checks the consistency of domain membership and allowing
  710. // multiple TS sessions. The check is only for domain membership
  711. // true not false.
  712. //
  713. // History: 2000-04-12 vtan created
  714. // --------------------------------------------------------------------------
  715. NTSTATUS CSystemSettings::CheckDomainMembership (void)
  716. {
  717. if (IsDomainMember() && !IsForceFriendlyUI() && IsProfessionalTerminalServer())
  718. {
  719. TBOOL(EnableFriendlyUI(false));
  720. (BOOL)EnableMultipleUsers(false);
  721. }
  722. return(STATUS_SUCCESS);
  723. }
  724. // --------------------------------------------------------------------------
  725. // CSystemSettings::AdjustFUSCompatibilityServiceState
  726. //
  727. // Arguments: <none>
  728. //
  729. // Returns: <none>
  730. //
  731. // Purpose: Turns on or off the FUS compatbility service based on the
  732. // FUS configuration.
  733. //
  734. // History: 2001-02-12 vtan created
  735. // --------------------------------------------------------------------------
  736. DWORD WINAPI CSystemSettings::AdjustFUSCompatibilityServiceState (void *pV)
  737. {
  738. UNREFERENCED_PARAMETER(pV);
  739. #ifdef _X86_
  740. if (IsWorkStationProduct())
  741. {
  742. bool fMultipleUsersEnabled;
  743. SC_HANDLE hSCManager;
  744. fMultipleUsersEnabled = IsMultipleUsersEnabled();
  745. // Connect to the service control manager.
  746. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  747. if (hSCManager != NULL)
  748. {
  749. SC_HANDLE hSCService;
  750. // Open the "FastUserSwitchingCompatibility" service.
  751. hSCService = OpenService(hSCManager,
  752. TEXT("FastUserSwitchingCompatibility"),
  753. SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS);
  754. if (hSCService != NULL)
  755. {
  756. SERVICE_STATUS serviceStatus;
  757. // Find out the status of the service.
  758. if (QueryServiceStatus(hSCService, &serviceStatus) != FALSE)
  759. {
  760. if (fMultipleUsersEnabled && (serviceStatus.dwCurrentState == SERVICE_STOPPED))
  761. {
  762. // If it's supposed to be started and it is not
  763. // running then start the service. This can fail
  764. // because the service is set to disabled. Ignore it.
  765. (BOOL)StartService(hSCService, 0, NULL);
  766. }
  767. else if (!fMultipleUsersEnabled && (serviceStatus.dwCurrentState == SERVICE_RUNNING))
  768. {
  769. // If it's supposed to be stopped and it is
  770. // running then stop the service.
  771. TBOOL(ControlService(hSCService, SERVICE_CONTROL_STOP, &serviceStatus));
  772. }
  773. }
  774. TBOOL(CloseServiceHandle(hSCService));
  775. }
  776. TBOOL(CloseServiceHandle(hSCManager));
  777. }
  778. }
  779. #endif /* _X86_ */
  780. return(0);
  781. }
  782. // --------------------------------------------------------------------------
  783. // CSystemSettings::GetEffectiveInteger
  784. //
  785. // Arguments: hKey = HKEY to read.
  786. // pszKeyName = Subkey name to read.
  787. // pszPolicyKeyName = Policy subkey name to read.
  788. // pszValueName = Value name in subkey to read.
  789. // iResult = int result.
  790. //
  791. // Returns: LONG
  792. //
  793. // Purpose: Reads the effective setting from the registry. The effective
  794. // setting is whatever the user chooses as the regular setting
  795. // overriden by policy. The policy setting is always returned if
  796. // present.
  797. //
  798. // History: 2000-04-12 vtan created
  799. // --------------------------------------------------------------------------
  800. LONG CSystemSettings::GetEffectiveInteger (HKEY hKey, const TCHAR *pszKeyName, const TCHAR *pszPolicyKeyName, const TCHAR *pszValueName, int& iResult)
  801. {
  802. CRegKey regKey;
  803. // Start with a typical initialized value.
  804. iResult = 0;
  805. // First check the regular location.
  806. if (ERROR_SUCCESS == regKey.Open(hKey,
  807. pszKeyName,
  808. KEY_QUERY_VALUE))
  809. {
  810. (LONG)regKey.GetInteger(pszValueName, iResult);
  811. }
  812. // Then check the policy.
  813. if (ERROR_SUCCESS == regKey.Open(hKey,
  814. pszPolicyKeyName,
  815. KEY_QUERY_VALUE))
  816. {
  817. (LONG)regKey.GetInteger(pszValueName, iResult);
  818. }
  819. // Always return ERROR_SUCCESS.
  820. return(ERROR_SUCCESS);
  821. }
  822. // --------------------------------------------------------------------------
  823. // CSystemSettings::GetEffectivePath
  824. //
  825. // Arguments: hKey = HKEY to read.
  826. // pszKeyName = Subkey name to read.
  827. // pszPolicyKeyName = Policy subkey name to read.
  828. // pszValueName = Value name in subkey to read.
  829. // pszPath = TCHAR array to receive effect path.
  830. //
  831. // Returns: LONG
  832. //
  833. // Purpose: Reads the effective setting from the registry. The effective
  834. // setting is whatever the user chooses as the regular setting
  835. // overriden by policy. The policy setting is always returned if
  836. // present. The buffer must be at least MAX_PATH characters.
  837. //
  838. // History: 2000-04-12 vtan created
  839. // --------------------------------------------------------------------------
  840. LONG CSystemSettings::GetEffectivePath (HKEY hKey, const TCHAR *pszKeyName, const TCHAR *pszPolicyKeyName, const TCHAR *pszValueName, TCHAR *pszPath)
  841. {
  842. LONG lErrorCode;
  843. if (IsBadWritePtr(pszPath, MAX_PATH * sizeof(TCHAR)))
  844. {
  845. lErrorCode = ERROR_INVALID_PARAMETER;
  846. }
  847. else
  848. {
  849. LONG lPolicyErrorCode;
  850. CRegKey regKey;
  851. // Start with a typical initialized value.
  852. *pszPath = TEXT('\0');
  853. // First check the regular location.
  854. lErrorCode = regKey.Open(hKey,
  855. pszKeyName,
  856. KEY_QUERY_VALUE);
  857. if (ERROR_SUCCESS == lErrorCode)
  858. {
  859. lErrorCode = regKey.GetPath(pszValueName,
  860. pszPath);
  861. }
  862. // Then check the policy.
  863. lPolicyErrorCode = regKey.Open(hKey,
  864. pszPolicyKeyName,
  865. KEY_QUERY_VALUE);
  866. if (ERROR_SUCCESS == lPolicyErrorCode)
  867. {
  868. lPolicyErrorCode = regKey.GetPath(pszValueName,
  869. pszPath);
  870. }
  871. // If either error code is ERROR_SUCCESS then return that
  872. // error code. Otherwise return the non policy error code.
  873. if ((ERROR_SUCCESS == lErrorCode) || (ERROR_SUCCESS == lPolicyErrorCode))
  874. {
  875. lErrorCode = ERROR_SUCCESS;
  876. }
  877. }
  878. return(lErrorCode);
  879. }
  880. // --------------------------------------------------------------------------
  881. // CSystemSettings::IsProfessionalTerminalServer
  882. //
  883. // Arguments: <none>
  884. //
  885. // Returns: bool
  886. //
  887. // Purpose: Returns whether this machine is a personal terminal server.
  888. // That is workstation with single user TS.
  889. //
  890. // History: 2000-08-09 vtan created
  891. // --------------------------------------------------------------------------
  892. bool CSystemSettings::IsProfessionalTerminalServer (void)
  893. {
  894. OSVERSIONINFOEX osVersion;
  895. ZeroMemory(&osVersion, sizeof(osVersion));
  896. osVersion.dwOSVersionInfoSize = sizeof(osVersion);
  897. return((GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osVersion)) != FALSE) &&
  898. (osVersion.wProductType == VER_NT_WORKSTATION) &&
  899. ((osVersion.wSuiteMask & VER_SUITE_PERSONAL) == 0) &&
  900. ((osVersion.wSuiteMask & VER_SUITE_SINGLEUSERTS) != 0));
  901. }
  902. // --------------------------------------------------------------------------
  903. // CSystemSettings::IsMicrosoftGINA
  904. //
  905. // Arguments: <none>
  906. //
  907. // Returns: bool
  908. //
  909. // Purpose: Returns whether the current GINA is the Microsoft GINA.
  910. //
  911. // History: 2001-01-05 vtan created
  912. // --------------------------------------------------------------------------
  913. bool CSystemSettings::IsMicrosoftGINA (void)
  914. {
  915. bool fResult;
  916. LONG lErrorCode;
  917. TCHAR szGinaDLL[MAX_PATH];
  918. CRegKey regKey;
  919. fResult = true;
  920. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  921. s_szWinlogonKeyName,
  922. KEY_QUERY_VALUE);
  923. if (ERROR_SUCCESS == lErrorCode)
  924. {
  925. fResult = (regKey.GetString(TEXT("GinaDLL"), szGinaDLL, ARRAYSIZE(szGinaDLL)) != ERROR_SUCCESS);
  926. }
  927. return(fResult);
  928. }
  929. // --------------------------------------------------------------------------
  930. // CSystemSettings::IsSCMTerminalServicesDisabled
  931. //
  932. // Arguments: <none>
  933. //
  934. // Returns: bool
  935. //
  936. // Purpose: Returns whether terminal services is disabled via the service
  937. // control manager.
  938. //
  939. // History: 2001-04-13 vtan created
  940. // --------------------------------------------------------------------------
  941. bool CSystemSettings::IsSCMTerminalServicesDisabled (void)
  942. {
  943. bool fResult;
  944. SC_HANDLE hSCManager;
  945. fResult = false;
  946. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  947. if (hSCManager != NULL)
  948. {
  949. SC_HANDLE hSCService;
  950. hSCService = OpenService(hSCManager,
  951. TEXT("TermService"),
  952. SERVICE_QUERY_CONFIG);
  953. if (hSCService != NULL)
  954. {
  955. DWORD dwBytesNeeded;
  956. QUERY_SERVICE_CONFIG *pQueryServiceConfig;
  957. (BOOL)QueryServiceConfig(hSCService, NULL, 0, &dwBytesNeeded);
  958. pQueryServiceConfig = static_cast<QUERY_SERVICE_CONFIG*>(LocalAlloc(LMEM_FIXED, dwBytesNeeded));
  959. if (pQueryServiceConfig != NULL)
  960. {
  961. fResult = ((QueryServiceConfig(hSCService,
  962. pQueryServiceConfig,
  963. dwBytesNeeded,
  964. &dwBytesNeeded) != FALSE) &&
  965. (pQueryServiceConfig->dwStartType == SERVICE_DISABLED));
  966. (HLOCAL)LocalFree(pQueryServiceConfig);
  967. }
  968. TBOOL(CloseServiceHandle(hSCService));
  969. }
  970. TBOOL(CloseServiceHandle(hSCManager));
  971. }
  972. return(fResult);
  973. }