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.

802 lines
18 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. policy.cpp
  5. Abstract:
  6. RDS Policy related function
  7. Author:
  8. HueiWang 5/2/2000
  9. --*/
  10. #include "stdafx.h"
  11. #include "policy.h"
  12. #ifndef __WIN9XBUILD__
  13. extern "C" BOOLEAN RegDenyTSConnectionsPolicy();
  14. typedef struct __RDSLevelShadowMap {
  15. SHADOWCLASS shadowClass;
  16. REMOTE_DESKTOP_SHARING_CLASS rdsLevel;
  17. } RDSLevelShadowMap;
  18. static const RDSLevelShadowMap ShadowMap[] = {
  19. { Shadow_Disable, NO_DESKTOP_SHARING }, // No RDS sharing
  20. { Shadow_EnableInputNotify, CONTROLDESKTOP_PERMISSION_REQUIRE }, // Interact with user permission
  21. { Shadow_EnableInputNoNotify, CONTROLDESKTOP_PERMISSION_NOT_REQUIRE }, // Interact without user permission
  22. { Shadow_EnableNoInputNotify, VIEWDESKTOP_PERMISSION_REQUIRE}, // View with user permission
  23. { Shadow_EnableNoInputNoNotify, VIEWDESKTOP_PERMISSION_NOT_REQUIRE } // View without user permission
  24. };
  25. DWORD
  26. GetPolicyAllowGetHelpSetting(
  27. HKEY hKey,
  28. LPCTSTR pszKeyName,
  29. LPCTSTR pszValueName,
  30. IN DWORD* value
  31. )
  32. /*++
  33. Routine Description:
  34. Routine to query policy registry value.
  35. Parameters:
  36. hKey : Currently open registry key.
  37. pszKeyName : Pointer to a null-terminated string containing
  38. the name of the subkey to open.
  39. pszValueName : Pointer to a null-terminated string containing
  40. the name of the value to query
  41. value : Pointer to DWORD to receive GetHelp policy setting.
  42. Returns:
  43. ERROR_SUCCESS or error code from RegOpenKeyEx().
  44. --*/
  45. {
  46. DWORD dwStatus;
  47. HKEY hPolicyKey = NULL;
  48. DWORD dwType;
  49. DWORD cbData;
  50. //
  51. // Open registry key for system policy
  52. //
  53. dwStatus = RegOpenKeyEx(
  54. hKey,
  55. pszKeyName,
  56. 0,
  57. KEY_READ,
  58. &hPolicyKey
  59. );
  60. if( ERROR_SUCCESS == dwStatus )
  61. {
  62. // query value
  63. cbData = 0;
  64. dwType = 0;
  65. dwStatus = RegQueryValueEx(
  66. hPolicyKey,
  67. pszValueName,
  68. NULL,
  69. &dwType,
  70. NULL,
  71. &cbData
  72. );
  73. if( ERROR_SUCCESS == dwStatus )
  74. {
  75. if( REG_DWORD == dwType )
  76. {
  77. cbData = sizeof(DWORD);
  78. // our registry value is REG_DWORD, if different type,
  79. // assume not exist.
  80. dwStatus = RegQueryValueEx(
  81. hPolicyKey,
  82. pszValueName,
  83. NULL,
  84. &dwType,
  85. (LPBYTE)value,
  86. &cbData
  87. );
  88. ASSERT( ERROR_SUCCESS == dwStatus );
  89. }
  90. else
  91. {
  92. // bad registry key type, assume
  93. // key does not exist.
  94. dwStatus = ERROR_FILE_NOT_FOUND;
  95. }
  96. }
  97. RegCloseKey( hPolicyKey );
  98. }
  99. return dwStatus;
  100. }
  101. SHADOWCLASS
  102. MapRDSLevelToTSShadowSetting(
  103. IN REMOTE_DESKTOP_SHARING_CLASS RDSLevel
  104. )
  105. /*++
  106. Routine Description:
  107. Convert TS Shadow settings to our RDS sharing level.
  108. Parameter:
  109. TSShadowClass : TS Shadow setting.
  110. Returns:
  111. REMOTE_DESKTOP_SHARING_CLASS
  112. --*/
  113. {
  114. SHADOWCLASS shadowClass;
  115. for( int i=0; i < sizeof(ShadowMap)/sizeof(ShadowMap[0]); i++)
  116. {
  117. if( ShadowMap[i].rdsLevel == RDSLevel )
  118. {
  119. break;
  120. }
  121. }
  122. if( i < sizeof(ShadowMap)/sizeof(ShadowMap[0]) )
  123. {
  124. shadowClass = ShadowMap[i].shadowClass;
  125. }
  126. else
  127. {
  128. MYASSERT(FALSE);
  129. shadowClass = Shadow_Disable;
  130. }
  131. return shadowClass;
  132. }
  133. REMOTE_DESKTOP_SHARING_CLASS
  134. MapTSShadowSettingToRDSLevel(
  135. SHADOWCLASS TSShadowClass
  136. )
  137. /*++
  138. Routine Description:
  139. Convert TS Shadow settings to our RDS sharing level.
  140. Parameter:
  141. TSShadowClass : TS Shadow setting.
  142. Returns:
  143. REMOTE_DESKTOP_SHARING_CLASS
  144. --*/
  145. {
  146. REMOTE_DESKTOP_SHARING_CLASS level;
  147. for( int i=0; i < sizeof(ShadowMap)/sizeof(ShadowMap[0]); i++)
  148. {
  149. if( ShadowMap[i].shadowClass == TSShadowClass )
  150. {
  151. break;
  152. }
  153. }
  154. if( i < sizeof(ShadowMap)/sizeof(ShadowMap[0]) )
  155. {
  156. level = ShadowMap[i].rdsLevel;
  157. }
  158. else
  159. {
  160. MYASSERT(FALSE);
  161. level = NO_DESKTOP_SHARING;
  162. }
  163. return level;
  164. }
  165. DWORD
  166. MapSessionIdToWinStationName(
  167. IN ULONG ulSessionID,
  168. OUT PWINSTATIONNAME pWinstationName
  169. )
  170. /*++
  171. Routine Description:
  172. Find out TS winstation name for the session specified.
  173. Parameters:
  174. ulSessionID : TS Session ID to query.
  175. pWinstationName : Pointer to WINSTATIONNAME to receive
  176. name of WinStation for Session ID specified.
  177. Returns:
  178. ERROR_SUCCESS or Error code.
  179. -*/
  180. {
  181. BOOL bSuccess;
  182. DWORD dwStatus;
  183. LPTSTR pBuffer = NULL;
  184. DWORD bytesReturned;
  185. bSuccess = WTSQuerySessionInformation(
  186. WTS_CURRENT_SERVER,
  187. ulSessionID,
  188. WTSWinStationName,
  189. &pBuffer,
  190. &bytesReturned
  191. );
  192. if( TRUE == bSuccess )
  193. {
  194. LPTSTR pszChr;
  195. //
  196. // WINSTATIONNAME returned from WTSQuerySessionInformation
  197. // has '#...' appended to it, we can't use it to query
  198. // WINSTATION configuration as RegApi look for exact WINSTATION
  199. // name in registry and so it will return default value.
  200. //
  201. pszChr = _tcschr( pBuffer, _TEXT('#') );
  202. if( NULL != pszChr )
  203. {
  204. *pszChr = _TEXT('\0');
  205. }
  206. ZeroMemory( pWinstationName, sizeof( WINSTATIONNAME ) );
  207. CopyMemory( pWinstationName, pBuffer, bytesReturned );
  208. dwStatus = ERROR_SUCCESS;
  209. }
  210. else
  211. {
  212. dwStatus = GetLastError();
  213. }
  214. if( NULL != pBuffer )
  215. {
  216. WTSFreeMemory( pBuffer );
  217. }
  218. return dwStatus;
  219. }
  220. DWORD
  221. GetWinStationConfig(
  222. IN ULONG ulSessionId,
  223. OUT WINSTATIONCONFIG2* pConfig
  224. )
  225. /*++
  226. Routine Description:
  227. Retrieve WINSTATIONCONFIG2 for session specified.
  228. Parameters:
  229. ulSessionId : TS Session to query.
  230. pConfig : Pointer to WINSTATIONCONIF2 to receive result.
  231. Returns:
  232. ERROR_SUCCESS or error code.
  233. --*/
  234. {
  235. WINSTATIONNAME WinStationName;
  236. DWORD dwStatus;
  237. ULONG length = 0;
  238. dwStatus = MapSessionIdToWinStationName(
  239. ulSessionId,
  240. WinStationName
  241. );
  242. if( ERROR_SUCCESS == dwStatus )
  243. {
  244. dwStatus = RegWinStationQuery(
  245. NULL,
  246. WinStationName,
  247. pConfig,
  248. sizeof(WINSTATIONCONFIG2),
  249. &length
  250. );
  251. }
  252. return dwStatus;
  253. }
  254. #endif
  255. BOOL
  256. IsUserAllowToGetHelp(
  257. IN ULONG ulSessionId,
  258. IN LPCTSTR pszUserSid
  259. )
  260. /*++
  261. Routine Description:
  262. Determine if caller can 'GetHelp'
  263. Parameters:
  264. ulSessionId : User's TS logon ID.
  265. pszUserSid : User's SID in textual form.
  266. Returns:
  267. TRUE/FALSE
  268. Note:
  269. Must have impersonate user first.
  270. --*/
  271. {
  272. BOOL bAllow;
  273. DWORD dwStatus;
  274. DWORD dwAllow;
  275. LPTSTR pszUserHive = NULL;
  276. MYASSERT( NULL != pszUserSid );
  277. //
  278. // Must be able to GetHelp from machine
  279. //
  280. bAllow = TSIsMachinePolicyAllowHelp();
  281. if( TRUE == bAllow )
  282. {
  283. pszUserHive = (LPTSTR)LocalAlloc(
  284. LPTR,
  285. sizeof(TCHAR) * (lstrlen(pszUserSid) + lstrlen(RDS_GROUPPOLICY_SUBTREE) + 2 )
  286. );
  287. lstrcpy( pszUserHive, pszUserSid );
  288. lstrcat( pszUserHive, _TEXT("\\") );
  289. lstrcat( pszUserHive, RDS_GROUPPOLICY_SUBTREE );
  290. //
  291. // Query user level AllowGetHelp setting.
  292. dwStatus = GetPolicyAllowGetHelpSetting(
  293. HKEY_USERS,
  294. pszUserHive,
  295. RDS_ALLOWGETHELP_VALUENAME,
  296. &dwAllow
  297. );
  298. if( ERROR_SUCCESS == dwStatus )
  299. {
  300. bAllow = (POLICY_ENABLE == dwAllow);
  301. }
  302. else
  303. {
  304. // no configuration for this user, assume GetHelp
  305. // is enabled.
  306. bAllow = TRUE;
  307. }
  308. }
  309. if( NULL != pszUserHive )
  310. {
  311. LocalFree( pszUserHive );
  312. }
  313. return bAllow;
  314. }
  315. DWORD
  316. GetSystemRDSLevel(
  317. IN ULONG ulSessionId,
  318. OUT REMOTE_DESKTOP_SHARING_CLASS* pSharingLevel
  319. )
  320. /*++
  321. Routine Description:
  322. Retrieve policy setting for remote desktop sharing level.
  323. Parameters:
  324. ulSessionId : TS session ID, unuse if TS group policy is set.
  325. pSharingLever : Pointer to REMOTE_DESKTOP_SHARING_CLASS to receive
  326. machine RDS level.
  327. Returns:
  328. REMOTE_DESKTOP_SHARING_CLASS
  329. --*/
  330. {
  331. DWORD dwStatus;
  332. #ifndef __WIN9XBUILD__
  333. WINSTATIONCONFIG2 WSConfig;
  334. ULONG length = 0;
  335. //
  336. // TS Group Policy does not have machine level shadow
  337. // setting, only TSCC has this setting, and TSCC setting
  338. // is based on WINSTATION not entire machine.
  339. //
  340. // We can't query TS since TS already merger all policy
  341. // setting into USERCONFIG which might not be correct
  342. //
  343. dwStatus = GetWinStationConfig(
  344. ulSessionId,
  345. &WSConfig
  346. );
  347. if( ERROR_SUCCESS == dwStatus )
  348. {
  349. if( TRUE == WSConfig.Config.User.fInheritShadow )
  350. {
  351. // Shadow config is inherite from user properies
  352. // so we query user level setting.
  353. dwStatus = GetUserRDSLevel( ulSessionId, pSharingLevel );
  354. }
  355. else
  356. {
  357. *pSharingLevel = MapTSShadowSettingToRDSLevel( WSConfig.Config.User.Shadow );
  358. }
  359. }
  360. #else
  361. // TODO - revisit this for Win9x Build
  362. MYASSERT(FALSE);
  363. *pSharingLevel = CONTROLDESKTOP_PERMISSION_REQUIRE;
  364. dwStatus = ERROR_SUCCESS;
  365. #endif
  366. return dwStatus;
  367. }
  368. DWORD
  369. GetUserRDSLevel(
  370. IN ULONG ulSessionId,
  371. OUT REMOTE_DESKTOP_SHARING_CLASS* pLevel
  372. )
  373. /*++
  374. same as GetSystemRDSLevel() except it retrieve currently logon user's
  375. RDS level.
  376. --*/
  377. {
  378. DWORD dwStatus;
  379. #ifndef __WIN9XBUILD__
  380. BOOL bSuccess;
  381. WINSTATIONCONFIG WSConfig;
  382. DWORD dwByteReturned;
  383. memset( &WSConfig, 0, sizeof(WSConfig) );
  384. // Here we call WInStationQueryInformation() since WTSAPI require
  385. // few calls to get the same result
  386. bSuccess = WinStationQueryInformation(
  387. WTS_CURRENT_SERVER,
  388. ulSessionId,
  389. WinStationConfiguration,
  390. &WSConfig,
  391. sizeof( WSConfig ),
  392. &dwByteReturned
  393. );
  394. if( TRUE == bSuccess )
  395. {
  396. dwStatus = ERROR_SUCCESS;
  397. *pLevel = MapTSShadowSettingToRDSLevel( WSConfig.User.Shadow );
  398. }
  399. else
  400. {
  401. dwStatus = GetLastError();
  402. }
  403. #else
  404. // TODO - revisit this for Win9x Build
  405. MYASSERT(FALSE);
  406. *pLevel = CONTROLDESKTOP_PERMISSION_REQUIRE;
  407. dwStatus = ERROR_SUCCESS;
  408. #endif
  409. return dwStatus;
  410. }
  411. DWORD
  412. ConfigSystemGetHelp(
  413. BOOL bEnable
  414. )
  415. /*++
  416. Routine Description:
  417. Enable/disable 'GetHelp' on local machine.
  418. Parameters:
  419. bEnable : TRUE to enable, FALSE otherwise.
  420. Returns:
  421. ERROR_SUCCESS or error code.
  422. --*/
  423. {
  424. DWORD dwStatus = ERROR_SUCCESS;
  425. BOOL bMember;
  426. HKEY hKey = NULL;
  427. DWORD dwValue;
  428. BOOL bAllowHelp;
  429. #ifndef __WIN9XBUILD__
  430. dwStatus = IsUserAdmin( &bMember );
  431. if( ERROR_SUCCESS != dwStatus )
  432. {
  433. goto CLEANUPANDEXIT;
  434. }
  435. if( FALSE == bMember )
  436. {
  437. dwStatus = ERROR_ACCESS_DENIED;
  438. goto CLEANUPANDEXIT;
  439. }
  440. #endif
  441. // We only check if Group Policy has this setting and no
  442. // checking on TSCC deny connection setting since
  443. // TSCC set WINSTATION deny connection not entire machine
  444. // and we can't be sure which connection that connection
  445. // is denied, so it is still possible that GetHelp is enabled
  446. // but WINSTATION's deny connection is still set to TRUE
  447. // in this case, no help is available even this funtion
  448. // return SUCCEEDED.
  449. // verify no group policy on this
  450. dwStatus = GetPolicyAllowGetHelpSetting(
  451. HKEY_LOCAL_MACHINE,
  452. RDS_GROUPPOLICY_SUBTREE,
  453. RDS_ALLOWGETHELP_VALUENAME,
  454. &dwValue
  455. );
  456. if( ERROR_SUCCESS == dwStatus )
  457. {
  458. dwStatus = ERROR_ACCESS_DENIED;
  459. }
  460. else
  461. {
  462. //
  463. // Write to registry
  464. //
  465. dwStatus = RegCreateKeyEx(
  466. HKEY_LOCAL_MACHINE,
  467. RDS_MACHINEPOLICY_SUBTREE,
  468. 0,
  469. NULL,
  470. REG_OPTION_NON_VOLATILE,
  471. KEY_ALL_ACCESS,
  472. NULL,
  473. &hKey,
  474. NULL
  475. );
  476. if( ERROR_SUCCESS == dwStatus )
  477. {
  478. dwValue = (bEnable) ? POLICY_ENABLE : POLICY_DISABLE;
  479. dwStatus = RegSetValueEx(
  480. hKey,
  481. RDS_ALLOWGETHELP_VALUENAME,
  482. 0,
  483. REG_DWORD,
  484. (LPBYTE) &dwValue,
  485. sizeof(DWORD)
  486. );
  487. }
  488. MYASSERT( ERROR_SUCCESS == dwStatus );
  489. }
  490. #ifndef __WIN9XBUILD__
  491. CLEANUPANDEXIT:
  492. #endif
  493. if( NULL != hKey )
  494. {
  495. RegCloseKey(hKey);
  496. }
  497. return dwStatus;
  498. }
  499. DWORD
  500. ConfigSystemRDSLevel(
  501. IN REMOTE_DESKTOP_SHARING_CLASS level
  502. )
  503. /*++
  504. Routine Description:
  505. This routine set machine wide RDS level.
  506. Parameters:
  507. level : new RDS level.
  508. Returns:
  509. ERROR_SUCCESS or error code.
  510. --*/
  511. {
  512. //
  513. // TODO - revisit this, on Win2K and Whilster,
  514. // group policy override this setting via User Properties
  515. // or if group policy is not set, TSCC can override this.
  516. // and since a user account always has some default value
  517. // for this, so we have no way to determine whether this is
  518. // a default or else, so we simple return ERROR for Win2K
  519. // and Whilster platform.
  520. //
  521. //
  522. // TODO : For legacy platform, Win9x/NT40/TS40, we need to figure
  523. // out how/where poledit put this setting, for now,
  524. // just return error.
  525. //
  526. DWORD dwStatus = ERROR_INVALID_FUNCTION;
  527. return dwStatus;
  528. }
  529. DWORD
  530. ConfigUserSessionRDSLevel(
  531. IN ULONG ulSessionId,
  532. IN REMOTE_DESKTOP_SHARING_CLASS level
  533. )
  534. /*++
  535. --*/
  536. {
  537. #ifndef __WIN9XBUILD__
  538. WINSTATIONCONFIG winstationConfig;
  539. SHADOWCLASS shadowClass = MapRDSLevelToTSShadowSetting( level );
  540. BOOL bSuccess;
  541. DWORD dwLength;
  542. DWORD dwStatus;
  543. memset( &winstationConfig, 0, sizeof(winstationConfig) );
  544. bSuccess = WinStationQueryInformation(
  545. WTS_CURRENT_SERVER,
  546. ulSessionId,
  547. WinStationConfiguration,
  548. &winstationConfig,
  549. sizeof(winstationConfig),
  550. &dwLength
  551. );
  552. if( TRUE == bSuccess )
  553. {
  554. winstationConfig.User.Shadow = shadowClass;
  555. bSuccess = WinStationSetInformation(
  556. WTS_CURRENT_SERVER,
  557. ulSessionId,
  558. WinStationConfiguration,
  559. &winstationConfig,
  560. sizeof(winstationConfig)
  561. );
  562. }
  563. if( TRUE == bSuccess )
  564. {
  565. dwStatus = ERROR_SUCCESS;
  566. }
  567. else
  568. {
  569. dwStatus = GetLastError();
  570. }
  571. return dwStatus;
  572. #else
  573. return ERROR_SUCCESS;
  574. #endif
  575. }
  576. #if 0
  577. HRESULT
  578. PolicyGetAllowUnSolicitedHelp(
  579. BOOL* bAllow
  580. )
  581. /*++
  582. --*/
  583. {
  584. HRESULT hRes;
  585. CComPtr<IRARegSetting> IRegSetting;
  586. hRes = IRegSetting.CoCreateInstance( CLSID_RARegSetting );
  587. if( SUCCEEDED(hRes) )
  588. {
  589. hRes = IRegSetting->get_AllowUnSolicited(bAllow);
  590. }
  591. MYASSERT( SUCCEEDED(hRes) );
  592. return hRes;
  593. }
  594. #endif
  595. HRESULT
  596. PolicyGetMaxTicketExpiry(
  597. LONG* value
  598. )
  599. /*++
  600. --*/
  601. {
  602. HRESULT hRes;
  603. CComPtr<IRARegSetting> IRegSetting;
  604. hRes = IRegSetting.CoCreateInstance( CLSID_RARegSetting );
  605. if( SUCCEEDED(hRes) )
  606. {
  607. hRes = IRegSetting->get_MaxTicketExpiry(value);
  608. }
  609. MYASSERT( SUCCEEDED(hRes) );
  610. return hRes;
  611. }