Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1143 lines
38 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((!IsDomainMember() || IsForceFriendlyUI()) &&
  285. IsMicrosoftGINA() &&
  286. !IsNetwareActive() &&
  287. (ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  288. s_szWinlogonKeyName,
  289. s_szSystemPolicyKeyName,
  290. s_szLogonTypeValueName,
  291. iResult)) &&
  292. (iResult != 0));
  293. }
  294. // --------------------------------------------------------------------------
  295. // CSystemSettings::IsMultipleUsersEnabled
  296. //
  297. // Arguments: <none>
  298. //
  299. // Returns: bool
  300. //
  301. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  302. // CurrentVersion\Winlogon\AllowMultipleTSSessions and if the
  303. // value is 0x01 *AND* terminal services is installed on this
  304. // machine then the conditions are satisfied.
  305. //
  306. // History: 2000-03-02 vtan created
  307. // --------------------------------------------------------------------------
  308. bool CSystemSettings::IsMultipleUsersEnabled (void)
  309. {
  310. int iResult;
  311. return(IsTerminalServicesEnabled() &&
  312. !IsSafeMode() &&
  313. (ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  314. s_szWinlogonKeyName,
  315. s_szSystemPolicyKeyName,
  316. s_szMultipleUsersValueName,
  317. iResult)) &&
  318. (iResult != 0));
  319. }
  320. // --------------------------------------------------------------------------
  321. // CSystemSettings::IsRemoteConnectionsEnabled
  322. //
  323. // Arguments: <none>
  324. //
  325. // Returns: bool
  326. //
  327. // Purpose: Read the registry HKLM\System\CurrentControlSet\Control\
  328. // Terminal Server\fDenyTSConnections and returns the
  329. // value back to the caller.
  330. //
  331. // History: 2000-07-28 vtan created
  332. // --------------------------------------------------------------------------
  333. bool CSystemSettings::IsRemoteConnectionsEnabled (void)
  334. {
  335. int iResult;
  336. CRegKey regKey;
  337. return(IsTerminalServicesEnabled() &&
  338. (ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  339. s_szTerminalServerKeyName,
  340. s_szTerminalServerPolicyKeyName,
  341. s_szDenyRemoteConnectionsValueName,
  342. iResult)) &&
  343. (iResult == 0));
  344. }
  345. // --------------------------------------------------------------------------
  346. // CSystemSettings::IsRemoteConnectionPresent
  347. //
  348. // Arguments: <none>
  349. //
  350. // Returns: bool
  351. //
  352. // Purpose: Returns whether there is a remote connection active on the
  353. // current system.
  354. //
  355. // History: 2000-07-28 vtan created
  356. // --------------------------------------------------------------------------
  357. bool CSystemSettings::IsRemoteConnectionPresent (void)
  358. {
  359. bool fRemoteConnectionPresent;
  360. HANDLE hServer;
  361. PLOGONID pLogonID, pLogonIDs;
  362. ULONG ul, ulEntries;
  363. fRemoteConnectionPresent = false;
  364. // Open a connection to terminal services and get the number of sessions.
  365. hServer = WinStationOpenServerW(reinterpret_cast<WCHAR*>(SERVERNAME_CURRENT));
  366. if (hServer != NULL)
  367. {
  368. if (WinStationEnumerate(hServer, &pLogonIDs, &ulEntries) != FALSE)
  369. {
  370. // Iterate the sessions looking for active and shadow sessions only.
  371. for (ul = 0, pLogonID = pLogonIDs; !fRemoteConnectionPresent && (ul < ulEntries); ++ul, ++pLogonID)
  372. {
  373. if ((pLogonID->State == State_Active) || (pLogonID->State == State_Shadow))
  374. {
  375. fRemoteConnectionPresent = (lstrcmpi(pLogonID->WinStationName, TEXT("console")) != 0);
  376. }
  377. }
  378. // Free any resources used.
  379. (BOOLEAN)WinStationFreeMemory(pLogonIDs);
  380. }
  381. (BOOLEAN)WinStationCloseServer(hServer);
  382. }
  383. // Return result.
  384. return(fRemoteConnectionPresent);
  385. }
  386. // --------------------------------------------------------------------------
  387. // CSystemSettings::IsShutdownWithoutLogonAllowed
  388. //
  389. // Arguments: <none>
  390. //
  391. // Returns: bool
  392. //
  393. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  394. // CurrentVersion\Winlogon\ShutdownWithoutLogon and returns the
  395. // value back to the caller.
  396. //
  397. // History: 2000-04-27 vtan created
  398. // --------------------------------------------------------------------------
  399. bool CSystemSettings::IsShutdownWithoutLogonAllowed (void)
  400. {
  401. int iResult;
  402. return((ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  403. s_szWinlogonKeyName,
  404. s_szSystemPolicyKeyName,
  405. TEXT("ShutdownWithoutLogon"),
  406. iResult)) &&
  407. (iResult != 0));
  408. }
  409. // --------------------------------------------------------------------------
  410. // CSystemSettings::IsUndockWithoutLogonAllowed
  411. //
  412. // Arguments: <none>
  413. //
  414. // Returns: bool
  415. //
  416. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  417. // CurrentVersion\Winlogon\UndockWithoutLogon and returns the
  418. // value back to the caller.
  419. //
  420. // History: 2001-03-17 vtan created
  421. // --------------------------------------------------------------------------
  422. bool CSystemSettings::IsUndockWithoutLogonAllowed (void)
  423. {
  424. int iResult;
  425. return((ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  426. s_szWinlogonKeyName,
  427. s_szSystemPolicyKeyName,
  428. REGSTR_VAL_UNDOCK_WITHOUT_LOGON,
  429. iResult)) &&
  430. (iResult != 0));
  431. }
  432. // --------------------------------------------------------------------------
  433. // CSystemSettings::IsForceFriendlyUI
  434. //
  435. // Arguments: <none>
  436. //
  437. // Returns: bool
  438. //
  439. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  440. // CurrentVersion\Winlogon\ForceFriendlyUI and returns the
  441. // value back to the caller.
  442. //
  443. // History: 2000-04-27 vtan created
  444. // --------------------------------------------------------------------------
  445. bool CSystemSettings::IsForceFriendlyUI (void)
  446. {
  447. int iResult;
  448. return((ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  449. s_szWinlogonKeyName,
  450. s_szSystemPolicyKeyName,
  451. TEXT("ForceFriendlyUI"),
  452. iResult)) &&
  453. (iResult != 0));
  454. }
  455. // --------------------------------------------------------------------------
  456. // CSystemSettings::GetUIHost
  457. //
  458. // Arguments: pszPath = TCHAR array to receive UI host path.
  459. //
  460. // Returns: LONG
  461. //
  462. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  463. // CurrentVersion\Winlogon\UIHost and returns the value.
  464. //
  465. // History: 2000-04-12 vtan created
  466. // --------------------------------------------------------------------------
  467. LONG CSystemSettings::GetUIHost (TCHAR *pszPath)
  468. {
  469. return(GetEffectivePath(HKEY_LOCAL_MACHINE,
  470. s_szWinlogonKeyName,
  471. s_szSystemPolicyKeyName,
  472. TEXT("UIHost"),
  473. pszPath));
  474. }
  475. // --------------------------------------------------------------------------
  476. // CSystemSettings::IsUIHostStatic
  477. //
  478. // Arguments: <none>
  479. //
  480. // Returns: bool
  481. //
  482. // Purpose: Read the registry HKLM\Software\Microsoft\Windows NT\
  483. // CurrentVersion\Winlogon\UIHostStatic and returns the
  484. // value.
  485. //
  486. // History: 2000-04-12 vtan created
  487. // --------------------------------------------------------------------------
  488. bool CSystemSettings::IsUIHostStatic (void)
  489. {
  490. int iResult;
  491. return((ERROR_SUCCESS == GetEffectiveInteger(HKEY_LOCAL_MACHINE,
  492. s_szWinlogonKeyName,
  493. s_szSystemPolicyKeyName,
  494. TEXT("UIHostStatic"),
  495. iResult)) &&
  496. (iResult != 0));
  497. }
  498. // --------------------------------------------------------------------------
  499. // CSystemSettings::EnableFriendlyUI
  500. //
  501. // Arguments: fEnable = Enable friendly UI.
  502. //
  503. // Returns: bool
  504. //
  505. // Purpose: Enable friendly UI. This should only be allowed on workgroup
  506. // machines. Check the machine status to enforce this.
  507. //
  508. // ERROR_NOT_SUPPORTED is returned when the machine is joined to
  509. // a domain.
  510. //
  511. // History: 2000-08-01 vtan created
  512. // --------------------------------------------------------------------------
  513. bool CSystemSettings::EnableFriendlyUI (bool fEnable)
  514. {
  515. LONG lErrorCode;
  516. if (!IsDomainMember() || !fEnable)
  517. {
  518. CRegKey regKey;
  519. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  520. s_szWinlogonKeyName,
  521. KEY_SET_VALUE);
  522. if (ERROR_SUCCESS == lErrorCode)
  523. {
  524. lErrorCode = regKey.SetDWORD(s_szLogonTypeValueName,
  525. fEnable);
  526. if (fEnable)
  527. {
  528. lErrorCode = regKey.SetString(s_szBackgroundValueName,
  529. TEXT("0 0 0"));
  530. }
  531. else
  532. {
  533. (LONG)regKey.DeleteValue(s_szBackgroundValueName);
  534. }
  535. }
  536. }
  537. else
  538. {
  539. lErrorCode = ERROR_NOT_SUPPORTED;
  540. }
  541. SetLastError(static_cast<DWORD>(lErrorCode));
  542. return(ERROR_SUCCESS == lErrorCode);
  543. }
  544. // --------------------------------------------------------------------------
  545. // CSystemSettings::EnableMultipleUsers
  546. //
  547. // Arguments: fEnable = Enable multiple users.
  548. //
  549. // Returns: bool
  550. //
  551. // Purpose: Enable the multiple users feature. This sets
  552. // AllowMultipleTSSessions to 1 but only does so if remote
  553. // connections are disabled. This allows multiple console
  554. // sessions but no remote sessions. If there is a remote
  555. // connection active this call is rejected.
  556. //
  557. // ERROR_ACCESS_DENIED is returned when there are more than one
  558. // users active and being disabled.
  559. //
  560. // ERROR_CTX_NOT_CONSOLE is returned when being disabled from
  561. // a remote session (disabling only allowed from the console).
  562. //
  563. // ERROR_NOT_SUPPORTED is returned when being disabled from
  564. // the console, remote connections are enabled, and the current
  565. // session is not session 0.
  566. //
  567. // History: 2000-07-28 vtan created
  568. // --------------------------------------------------------------------------
  569. bool CSystemSettings::EnableMultipleUsers (bool fEnable)
  570. {
  571. LONG lErrorCode;
  572. // If disabling multiple users with more than one users active
  573. // reject the call. Return ERROR_ACCESS_DENIED.
  574. if (!fEnable && (GetLoggedOnUserCount() > 1))
  575. {
  576. lErrorCode = ERROR_ACCESS_DENIED;
  577. }
  578. // If disabling and not on the console, reject the call.
  579. // Return ERROR_CTX_NOT_CONSOLE.
  580. else if (!fEnable && !IsActiveConsoleSession())
  581. {
  582. lErrorCode = ERROR_CTX_NOT_CONSOLE;
  583. }
  584. // If disabling from the console and remote connections are enabled and
  585. // the current session is not session 0, reject the call. Otherwise, a
  586. // a remote connection with FUS disabled causes strange results because
  587. // it expects to connect to session 0.
  588. // Return ERROR_NOT_SUPPORTED.
  589. else if (!fEnable && IsRemoteConnectionsEnabled() && NtCurrentPeb()->SessionId != 0)
  590. {
  591. lErrorCode = ERROR_NOT_SUPPORTED;
  592. }
  593. else
  594. {
  595. CRegKey regKey;
  596. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  597. s_szWinlogonKeyName,
  598. KEY_SET_VALUE);
  599. if (ERROR_SUCCESS == lErrorCode)
  600. {
  601. lErrorCode = regKey.SetDWORD(s_szMultipleUsersValueName,
  602. fEnable);
  603. if (ERROR_SUCCESS == lErrorCode)
  604. {
  605. (DWORD)AdjustFUSCompatibilityServiceState(NULL);
  606. }
  607. }
  608. }
  609. SetLastError(static_cast<DWORD>(lErrorCode));
  610. return(ERROR_SUCCESS == lErrorCode);
  611. }
  612. // --------------------------------------------------------------------------
  613. // CSystemSettings::EnableRemoteConnections
  614. //
  615. // Arguments: fEnable = Enable remote connections.
  616. //
  617. // Returns: bool
  618. //
  619. // Purpose: Enable the remote connections feature. This sets
  620. // fDenyTSConnections to 0 but only does so if there is a one
  621. // user logged onto the system. This allows the single
  622. // connection to be remotely connected but not allow multiple
  623. // console sessions. This conforms to the single user per CPU
  624. // license of the workstation product. To get multiple users
  625. // you need the server product.
  626. //
  627. // ERROR_NOT_SUPPORTED is returned when enabling remote
  628. // connections with FUS disabled and the current session != 0.
  629. //
  630. // History: 2000-07-28 vtan created
  631. // --------------------------------------------------------------------------
  632. bool CSystemSettings::EnableRemoteConnections (bool fEnable)
  633. {
  634. LONG lErrorCode;
  635. // If enabling remote connections, FUS is disabled, and we are not on
  636. // session 0 (can happen immediately after disabling FUS), then a remote
  637. // connection will fail. With FUS disabled, the connection must go to
  638. // session 0. This is a fringe case, but disallow enabling remote
  639. // connections if it happens.
  640. if (fEnable && !IsMultipleUsersEnabled() && NtCurrentPeb()->SessionId != 0)
  641. {
  642. lErrorCode = ERROR_NOT_SUPPORTED;
  643. }
  644. else
  645. {
  646. CRegKey regKey;
  647. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  648. s_szTerminalServerKeyName,
  649. KEY_SET_VALUE);
  650. if (ERROR_SUCCESS == lErrorCode)
  651. {
  652. lErrorCode = regKey.SetDWORD(s_szDenyRemoteConnectionsValueName,
  653. !fEnable);
  654. }
  655. }
  656. SetLastError(static_cast<DWORD>(lErrorCode));
  657. return(ERROR_SUCCESS == lErrorCode);
  658. }
  659. // --------------------------------------------------------------------------
  660. // CSystemSettings::GetLoggedOnUserCount
  661. //
  662. // Arguments: <none>
  663. //
  664. // Returns: int
  665. //
  666. // Purpose: Returns the count of logged on users on this machine. Ripped
  667. // straight out of shtdndlg.c in msgina.
  668. //
  669. // History: 2000-03-29 vtan created
  670. // 2000-04-21 vtan copied from taskmgr
  671. // 2000-07-28 vtan moved from userlist.cpp
  672. // --------------------------------------------------------------------------
  673. int CSystemSettings::GetLoggedOnUserCount (void)
  674. {
  675. int iCount;
  676. HANDLE hServer;
  677. iCount = 0;
  678. // Open a connection to terminal services and get the number of sessions.
  679. hServer = WinStationOpenServerW(reinterpret_cast<WCHAR*>(SERVERNAME_CURRENT));
  680. if (hServer != NULL)
  681. {
  682. TS_COUNTER tsCounters[2] = {0};
  683. tsCounters[0].counterHead.dwCounterID = TERMSRV_CURRENT_DISC_SESSIONS;
  684. tsCounters[1].counterHead.dwCounterID = TERMSRV_CURRENT_ACTIVE_SESSIONS;
  685. if (WinStationGetTermSrvCountersValue(hServer, ARRAYSIZE(tsCounters), tsCounters))
  686. {
  687. int i;
  688. for (i = 0; i < ARRAYSIZE(tsCounters); i++)
  689. {
  690. if (tsCounters[i].counterHead.bResult)
  691. {
  692. iCount += tsCounters[i].dwValue;
  693. }
  694. }
  695. }
  696. (BOOLEAN)WinStationCloseServer(hServer);
  697. }
  698. // Return result.
  699. return(iCount);
  700. }
  701. // --------------------------------------------------------------------------
  702. // CSystemSettings::CheckDomainMembership
  703. //
  704. // Arguments: <none>
  705. //
  706. // Returns: NTSTATUS
  707. //
  708. // Purpose: Checks the consistency of domain membership and allowing
  709. // multiple TS sessions. The check is only for domain membership
  710. // true not false.
  711. //
  712. // History: 2000-04-12 vtan created
  713. // --------------------------------------------------------------------------
  714. NTSTATUS CSystemSettings::CheckDomainMembership (void)
  715. {
  716. if (IsDomainMember() && !IsForceFriendlyUI() && IsProfessionalTerminalServer())
  717. {
  718. TBOOL(EnableFriendlyUI(false));
  719. (BOOL)EnableMultipleUsers(false);
  720. }
  721. return(STATUS_SUCCESS);
  722. }
  723. // --------------------------------------------------------------------------
  724. // CSystemSettings::AdjustFUSCompatibilityServiceState
  725. //
  726. // Arguments: <none>
  727. //
  728. // Returns: <none>
  729. //
  730. // Purpose: Turns on or off the FUS compatbility service based on the
  731. // FUS configuration.
  732. //
  733. // History: 2001-02-12 vtan created
  734. // --------------------------------------------------------------------------
  735. DWORD WINAPI CSystemSettings::AdjustFUSCompatibilityServiceState (void *pV)
  736. {
  737. UNREFERENCED_PARAMETER(pV);
  738. #ifdef _X86_
  739. if (IsWorkStationProduct())
  740. {
  741. bool fMultipleUsersEnabled;
  742. SC_HANDLE hSCManager;
  743. fMultipleUsersEnabled = IsMultipleUsersEnabled();
  744. // Connect to the service control manager.
  745. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  746. if (hSCManager != NULL)
  747. {
  748. SC_HANDLE hSCService;
  749. // Open the "FastUserSwitchingCompatibility" service.
  750. hSCService = OpenService(hSCManager,
  751. TEXT("FastUserSwitchingCompatibility"),
  752. SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS);
  753. if (hSCService != NULL)
  754. {
  755. SERVICE_STATUS serviceStatus;
  756. // Find out the status of the service.
  757. if (QueryServiceStatus(hSCService, &serviceStatus) != FALSE)
  758. {
  759. if (fMultipleUsersEnabled && (serviceStatus.dwCurrentState == SERVICE_STOPPED))
  760. {
  761. // If it's supposed to be started and it is not
  762. // running then start the service. This can fail
  763. // because the service is set to disabled. Ignore it.
  764. (BOOL)StartService(hSCService, 0, NULL);
  765. }
  766. else if (!fMultipleUsersEnabled && (serviceStatus.dwCurrentState == SERVICE_RUNNING))
  767. {
  768. // If it's supposed to be stopped and it is
  769. // running then stop the service.
  770. TBOOL(ControlService(hSCService, SERVICE_CONTROL_STOP, &serviceStatus));
  771. }
  772. }
  773. TBOOL(CloseServiceHandle(hSCService));
  774. }
  775. TBOOL(CloseServiceHandle(hSCManager));
  776. }
  777. }
  778. #endif /* _X86_ */
  779. return(0);
  780. }
  781. // --------------------------------------------------------------------------
  782. // CSystemSettings::GetEffectiveInteger
  783. //
  784. // Arguments: hKey = HKEY to read.
  785. // pszKeyName = Subkey name to read.
  786. // pszPolicyKeyName = Policy subkey name to read.
  787. // pszValueName = Value name in subkey to read.
  788. // iResult = int result.
  789. //
  790. // Returns: LONG
  791. //
  792. // Purpose: Reads the effective setting from the registry. The effective
  793. // setting is whatever the user chooses as the regular setting
  794. // overriden by policy. The policy setting is always returned if
  795. // present.
  796. //
  797. // History: 2000-04-12 vtan created
  798. // --------------------------------------------------------------------------
  799. LONG CSystemSettings::GetEffectiveInteger (HKEY hKey, const TCHAR *pszKeyName, const TCHAR *pszPolicyKeyName, const TCHAR *pszValueName, int& iResult)
  800. {
  801. CRegKey regKey;
  802. // Start with a typical initialized value.
  803. iResult = 0;
  804. // First check the regular location.
  805. if (ERROR_SUCCESS == regKey.Open(hKey,
  806. pszKeyName,
  807. KEY_QUERY_VALUE))
  808. {
  809. (LONG)regKey.GetInteger(pszValueName, iResult);
  810. }
  811. // Then check the policy.
  812. if (ERROR_SUCCESS == regKey.Open(hKey,
  813. pszPolicyKeyName,
  814. KEY_QUERY_VALUE))
  815. {
  816. (LONG)regKey.GetInteger(pszValueName, iResult);
  817. }
  818. // Always return ERROR_SUCCESS.
  819. return(ERROR_SUCCESS);
  820. }
  821. // --------------------------------------------------------------------------
  822. // CSystemSettings::GetEffectivePath
  823. //
  824. // Arguments: hKey = HKEY to read.
  825. // pszKeyName = Subkey name to read.
  826. // pszPolicyKeyName = Policy subkey name to read.
  827. // pszValueName = Value name in subkey to read.
  828. // pszPath = TCHAR array to receive effect path.
  829. //
  830. // Returns: LONG
  831. //
  832. // Purpose: Reads the effective setting from the registry. The effective
  833. // setting is whatever the user chooses as the regular setting
  834. // overriden by policy. The policy setting is always returned if
  835. // present. The buffer must be at least MAX_PATH characters.
  836. //
  837. // History: 2000-04-12 vtan created
  838. // --------------------------------------------------------------------------
  839. LONG CSystemSettings::GetEffectivePath (HKEY hKey, const TCHAR *pszKeyName, const TCHAR *pszPolicyKeyName, const TCHAR *pszValueName, TCHAR *pszPath)
  840. {
  841. LONG lErrorCode;
  842. if (IsBadWritePtr(pszPath, MAX_PATH * sizeof(TCHAR)))
  843. {
  844. lErrorCode = ERROR_INVALID_PARAMETER;
  845. }
  846. else
  847. {
  848. LONG lPolicyErrorCode;
  849. CRegKey regKey;
  850. // Start with a typical initialized value.
  851. *pszPath = TEXT('\0');
  852. // First check the regular location.
  853. lErrorCode = regKey.Open(hKey,
  854. pszKeyName,
  855. KEY_QUERY_VALUE);
  856. if (ERROR_SUCCESS == lErrorCode)
  857. {
  858. lErrorCode = regKey.GetPath(pszValueName,
  859. pszPath);
  860. }
  861. // Then check the policy.
  862. lPolicyErrorCode = regKey.Open(hKey,
  863. pszPolicyKeyName,
  864. KEY_QUERY_VALUE);
  865. if (ERROR_SUCCESS == lPolicyErrorCode)
  866. {
  867. lPolicyErrorCode = regKey.GetPath(pszValueName,
  868. pszPath);
  869. }
  870. // If either error code is ERROR_SUCCESS then return that
  871. // error code. Otherwise return the non policy error code.
  872. if ((ERROR_SUCCESS == lErrorCode) || (ERROR_SUCCESS == lPolicyErrorCode))
  873. {
  874. lErrorCode = ERROR_SUCCESS;
  875. }
  876. }
  877. return(lErrorCode);
  878. }
  879. // --------------------------------------------------------------------------
  880. // CSystemSettings::IsProfessionalTerminalServer
  881. //
  882. // Arguments: <none>
  883. //
  884. // Returns: bool
  885. //
  886. // Purpose: Returns whether this machine is a personal terminal server.
  887. // That is workstation with single user TS.
  888. //
  889. // History: 2000-08-09 vtan created
  890. // --------------------------------------------------------------------------
  891. bool CSystemSettings::IsProfessionalTerminalServer (void)
  892. {
  893. OSVERSIONINFOEX osVersion;
  894. ZeroMemory(&osVersion, sizeof(osVersion));
  895. osVersion.dwOSVersionInfoSize = sizeof(osVersion);
  896. return((GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osVersion)) != FALSE) &&
  897. (osVersion.wProductType == VER_NT_WORKSTATION) &&
  898. ((osVersion.wSuiteMask & VER_SUITE_PERSONAL) == 0) &&
  899. ((osVersion.wSuiteMask & VER_SUITE_SINGLEUSERTS) != 0));
  900. }
  901. // --------------------------------------------------------------------------
  902. // CSystemSettings::IsMicrosoftGINA
  903. //
  904. // Arguments: <none>
  905. //
  906. // Returns: bool
  907. //
  908. // Purpose: Returns whether the current GINA is the Microsoft GINA.
  909. //
  910. // History: 2001-01-05 vtan created
  911. // --------------------------------------------------------------------------
  912. bool CSystemSettings::IsMicrosoftGINA (void)
  913. {
  914. bool fResult;
  915. LONG lErrorCode;
  916. TCHAR szGinaDLL[MAX_PATH];
  917. CRegKey regKey;
  918. fResult = true;
  919. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  920. s_szWinlogonKeyName,
  921. KEY_QUERY_VALUE);
  922. if (ERROR_SUCCESS == lErrorCode)
  923. {
  924. fResult = (regKey.GetString(TEXT("GinaDLL"), szGinaDLL, ARRAYSIZE(szGinaDLL)) != ERROR_SUCCESS);
  925. }
  926. return(fResult);
  927. }
  928. // --------------------------------------------------------------------------
  929. // CSystemSettings::IsSCMTerminalServicesDisabled
  930. //
  931. // Arguments: <none>
  932. //
  933. // Returns: bool
  934. //
  935. // Purpose: Returns whether terminal services is disabled via the service
  936. // control manager.
  937. //
  938. // History: 2001-04-13 vtan created
  939. // --------------------------------------------------------------------------
  940. bool CSystemSettings::IsSCMTerminalServicesDisabled (void)
  941. {
  942. bool fResult;
  943. SC_HANDLE hSCManager;
  944. fResult = false;
  945. hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  946. if (hSCManager != NULL)
  947. {
  948. SC_HANDLE hSCService;
  949. hSCService = OpenService(hSCManager,
  950. TEXT("TermService"),
  951. SERVICE_QUERY_CONFIG);
  952. if (hSCService != NULL)
  953. {
  954. DWORD dwBytesNeeded;
  955. QUERY_SERVICE_CONFIG *pQueryServiceConfig;
  956. (BOOL)QueryServiceConfig(hSCService, NULL, 0, &dwBytesNeeded);
  957. pQueryServiceConfig = static_cast<QUERY_SERVICE_CONFIG*>(LocalAlloc(LMEM_FIXED, dwBytesNeeded));
  958. if (pQueryServiceConfig != NULL)
  959. {
  960. fResult = ((QueryServiceConfig(hSCService,
  961. pQueryServiceConfig,
  962. dwBytesNeeded,
  963. &dwBytesNeeded) != FALSE) &&
  964. (pQueryServiceConfig->dwStartType == SERVICE_DISABLED));
  965. (HLOCAL)LocalFree(pQueryServiceConfig);
  966. }
  967. TBOOL(CloseServiceHandle(hSCService));
  968. }
  969. TBOOL(CloseServiceHandle(hSCManager));
  970. }
  971. return(fResult);
  972. }