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.

526 lines
19 KiB

  1. /*************************************************************************
  2. *
  3. * registry.c
  4. *
  5. * WinStation Registry Routines
  6. *
  7. * Copyright Microsoft Corporation, 1998
  8. *
  9. *
  10. *************************************************************************/
  11. /*
  12. * Includes
  13. */
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. /*=============================================================================
  17. == Public functions
  18. =============================================================================*/
  19. NTSTATUS WinStationReadRegistryWorker( VOID );
  20. /*=============================================================================
  21. == Functions Used
  22. =============================================================================*/
  23. NTSTATUS IcaRegWinStationEnumerate( PULONG, PWINSTATIONNAME, PULONG );
  24. NTSTATUS QueueWinStationCreate( PWINSTATIONNAME );
  25. PWINSTATION FindWinStationByName( LPWSTR WinStationName, BOOLEAN LockList );
  26. NTSTATUS QueueWinStationReset( ULONG LogonId );
  27. NTSTATUS ReadWinStationSecurityDescriptor( PWINSTATION pWinStation );
  28. NTSTATUS WinStationRenameWorker(PWINSTATIONNAME, ULONG, PWINSTATIONNAME, ULONG);
  29. /*=============================================================================
  30. == Global data
  31. =============================================================================*/
  32. extern LIST_ENTRY WinStationListHead; // protected by WinStationListLock
  33. extern RTL_RESOURCE WinStationSecurityLock;
  34. extern POLICY_TS_MACHINE g_MachinePolicy; //defined in winsta.c
  35. extern RTL_RESOURCE WinStationSecurityLock;
  36. /*******************************************************************************
  37. *
  38. * WinStationReadRegistryWorker
  39. *
  40. * Update the listening winstations to match the registry
  41. *
  42. * This function assumes that g_MachinePolicy is up to date. This object is a global object
  43. * which is updated on TS startup, and any time there is a TS related policy change.
  44. *
  45. * ENTRY:
  46. * nothing
  47. *
  48. * EXIT:
  49. * STATUS_SUCCESS - no error
  50. *
  51. ******************************************************************************/
  52. typedef struct _RENAMEINFO {
  53. WINSTATIONNAME OldName;
  54. BOOLEAN Renamed;
  55. } RENAMEINFO, *PRENAMEINFO;
  56. #define KEEP_ALIVE_INTERVAL_DFLT 4 // in minutes
  57. NTSTATUS
  58. WinStationKeepAlive()
  59. {
  60. NTSTATUS Status;
  61. ICA_KEEP_ALIVE k;
  62. HANDLE hKeepAlive;
  63. static ICA_KEEP_ALIVE kPrev;
  64. static BOOLEAN firstTime = TRUE;
  65. k.start = FALSE;
  66. k.interval = 0;
  67. if ( g_MachinePolicy.fPolicyKeepAlive )
  68. {
  69. k.start = (BOOLEAN) g_MachinePolicy.fKeepAliveEnable;
  70. k.interval = g_MachinePolicy.KeepAliveInterval;
  71. }
  72. else
  73. {
  74. // read to see what the registry policy is set to...
  75. // Code below was cut/paste from termdd ( where Zw was replaced with Nt )
  76. UNICODE_STRING RegistryPath;
  77. UNICODE_STRING KeyName;
  78. HANDLE hKey;
  79. OBJECT_ATTRIBUTES ObjAttribs;
  80. ULONG KeyInfoBuffer[16];
  81. ULONG KeyInfoLength;
  82. PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
  83. ULONG KeepAliveEnable;
  84. ULONG KeepAliveInterval;
  85. // Open the Terminal Server subkey under \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentConttrolSet\
  86. // Control\Terminal Server
  87. RtlInitUnicodeString(&RegistryPath, REG_NTAPI_CONTROL_TSERVER);
  88. InitializeObjectAttributes(&ObjAttribs, &RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
  89. Status = NtOpenKey(&hKey, KEY_READ, &ObjAttribs);
  90. if (Status == STATUS_SUCCESS) {
  91. pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfoBuffer;
  92. // Get the value for KeepAliveEnable Key
  93. RtlInitUnicodeString(&KeyName, KEEP_ALIVE_ENABLE_KEY);
  94. Status = NtQueryValueKey(hKey, &KeyName, KeyValuePartialInformation,
  95. pKeyInfo, sizeof(KeyInfoBuffer), &KeyInfoLength);
  96. if ((Status == STATUS_SUCCESS) && (pKeyInfo->Type == REG_DWORD) &&
  97. (pKeyInfo->DataLength == sizeof(ULONG))) {
  98. KeepAliveEnable = *((PULONG) pKeyInfo->Data);
  99. }
  100. else {
  101. // By default, we don't enable keepalive
  102. KeepAliveEnable = 0;
  103. }
  104. if (KeepAliveEnable) {
  105. // Get the value for KeepAliveInterval
  106. RtlInitUnicodeString(&KeyName, KEEP_ALIVE_INTERVAL_KEY);
  107. Status = NtQueryValueKey(hKey, &KeyName, KeyValuePartialInformation,
  108. pKeyInfo, sizeof(KeyInfoBuffer), &KeyInfoLength);
  109. if (Status == STATUS_SUCCESS && (pKeyInfo->Type == REG_DWORD) &&
  110. (pKeyInfo->DataLength == sizeof(ULONG))) {
  111. KeepAliveInterval = *((PULONG) pKeyInfo->Data);
  112. }
  113. else {
  114. // The default KeepAliveInterval is 2 min
  115. KeepAliveInterval = KEEP_ALIVE_INTERVAL_DFLT;
  116. }
  117. }
  118. else {
  119. // The default KeepAliveInterval
  120. KeepAliveInterval = KEEP_ALIVE_INTERVAL_DFLT;
  121. }
  122. // Close the Key
  123. NtClose(hKey);
  124. }
  125. else {
  126. // Set the default values for KeepAlive parameters
  127. KeepAliveEnable = 0;
  128. KeepAliveInterval = KEEP_ALIVE_INTERVAL_DFLT;
  129. }
  130. k.start = (BOOLEAN )KeepAliveEnable;
  131. k.interval = KeepAliveInterval;
  132. }
  133. if ( firstTime )
  134. {
  135. kPrev = k;
  136. }
  137. else
  138. {
  139. #ifdef DBG
  140. #ifdef ARABERN_TEST
  141. #include <time.h>
  142. ULONG x;
  143. srand( (unsigned)time( NULL ) );
  144. x = rand();
  145. k.start = (BOOLEAN ) (0x00000001 & x) ;
  146. k.interval = 0x00000008 & x ;
  147. #endif
  148. #endif
  149. if ( ( kPrev.start == k.start ) && ( kPrev.interval == k.interval ) )
  150. {
  151. // no change, nothing to do, so return;
  152. return STATUS_SUCCESS;
  153. }
  154. }
  155. /*
  156. * Open TermDD.
  157. */
  158. Status = IcaOpen(&hKeepAlive);
  159. if (NT_SUCCESS(Status))
  160. {
  161. Status = IcaIoControl(hKeepAlive, IOCTL_ICA_SYSTEM_KEEP_ALIVE , &k,
  162. sizeof(k), NULL, 0, NULL);
  163. IcaClose(hKeepAlive);
  164. hKeepAlive = NULL;
  165. }
  166. firstTime = FALSE;
  167. return Status;
  168. }
  169. NTSTATUS
  170. WinStationReadRegistryWorker()
  171. {
  172. ULONG WinStationCount;
  173. ULONG ByteCount;
  174. WINSTATIONNAME * pWinStationName;
  175. PWINSTATIONCONFIG2 pWinConfig;
  176. PWINSTATION pWinStation;
  177. PRENAMEINFO pRenameInfo;
  178. PLIST_ENTRY Head, Next;
  179. NTSTATUS Status;
  180. ULONG i;
  181. if ( !gbServer )
  182. ENTERCRIT( &WinStationListenersLock );
  183. // see if keep alive is required, then IOCTL it to TermDD
  184. WinStationKeepAlive();
  185. /*
  186. * Get the number of WinStations in the registry
  187. */
  188. WinStationCount = 0;
  189. Status = IcaRegWinStationEnumerate( &WinStationCount, NULL, &ByteCount );
  190. if ( !NT_SUCCESS(Status) )
  191. goto badenum1;
  192. /*
  193. * Allocate a buffer for the WinStation names
  194. */
  195. pWinStationName = MemAlloc( ByteCount );
  196. if ( pWinStationName == NULL ) {
  197. Status = STATUS_NO_MEMORY;
  198. goto badalloc1;
  199. }
  200. /*
  201. * Get list of WinStation names from registry
  202. */
  203. WinStationCount = (ULONG) -1;
  204. Status = IcaRegWinStationEnumerate( &WinStationCount,
  205. (PWINSTATIONNAME)pWinStationName,
  206. &ByteCount );
  207. if ( !NT_SUCCESS(Status) )
  208. goto badenum2;
  209. /*
  210. * Allocate a buffer for WinStation configuration data
  211. */
  212. pWinConfig = MemAlloc( sizeof(WINSTATIONCONFIG2) * WinStationCount );
  213. if ( pWinConfig == NULL ) {
  214. Status = STATUS_NO_MEMORY;
  215. goto badalloc2;
  216. }
  217. /*
  218. * Allocate a buffer for tracking listener WinStation renames
  219. */
  220. pRenameInfo = MemAlloc( sizeof(RENAMEINFO) * WinStationCount );
  221. if ( pRenameInfo == NULL ) {
  222. Status = STATUS_NO_MEMORY;
  223. goto badalloc3;
  224. }
  225. /*
  226. * Now query the configuration data for each of the WinStation names
  227. */
  228. for ( i = 0; i < WinStationCount; i++ ) {
  229. pRenameInfo[i].Renamed = FALSE;
  230. {
  231. TRACE((hTrace,TC_ICASRV,TT_API2,"TERMSRV: WinStationReadRegistryWorker: %S\n",pWinStationName[i]));
  232. Status = RegWinStationQueryEx(
  233. SERVERNAME_CURRENT,
  234. &g_MachinePolicy,
  235. pWinStationName[i],
  236. &pWinConfig[i],
  237. sizeof(WINSTATIONCONFIG2),
  238. &ByteCount, TRUE );
  239. if ( !NT_SUCCESS(Status) ) {
  240. goto badregdata;
  241. }
  242. }
  243. }
  244. /*
  245. * Check if any existing WinStations need to be deleted
  246. */
  247. Head = &WinStationListHead;
  248. ENTERCRIT( &WinStationListLock );
  249. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  250. pWinStation = CONTAINING_RECORD( Next, WINSTATION, Links );
  251. /*
  252. * only check listening and single-instance winstations
  253. */
  254. if ( !(pWinStation->Flags & WSF_LISTEN) &&
  255. !(pWinStation->Config.Pd[0].Create.PdFlag & PD_SINGLE_INST) )
  256. continue;
  257. /* check if name still exists in the registry */
  258. for ( i = 0; i < WinStationCount; i++ ) {
  259. if ( !_wcsicmp( pWinStationName[i], pWinStation->WinStationName ) ) {
  260. break;
  261. }
  262. }
  263. if ( i == WinStationCount ) {
  264. /* The WinStation is not in the registry. If the listener was
  265. renamed, we don't want to reset it. We look for a registry
  266. entry which has the same configuration info.
  267. */
  268. for ( i = 0; i < WinStationCount; i++ ) {
  269. if ( !memcmp( &pWinStation->Config, &pWinConfig[i], sizeof(WINSTATIONCONFIG2) ) ) {
  270. pRenameInfo[i].Renamed = TRUE;
  271. wcscpy(pRenameInfo[i].OldName, pWinStation->WinStationName);
  272. DBGPRINT(("TERMSRV: Renaming %ws to %ws\n",
  273. pWinStation->WinStationName, pWinStationName[i]));
  274. break;
  275. }
  276. }
  277. }
  278. /* If no match was found in the registry, or if the matching
  279. listener is diabled, reset the listener.
  280. */
  281. if ((i == WinStationCount) ||
  282. (CheckWinStationEnable(!pRenameInfo[i].Renamed ?
  283. pWinStation->WinStationName :
  284. pWinStationName[i]) != STATUS_SUCCESS)) {
  285. TRACE((hTrace,TC_ICASRV,TT_API2,"TERMSRV: WinStationReadRegistryWorker: DELETE %u\n",
  286. pWinStation->LogonId ));
  287. QueueWinStationReset( pWinStation->LogonId );
  288. }
  289. }
  290. LEAVECRIT( &WinStationListLock );
  291. /*
  292. * Check if any WinStations need to be created or reset
  293. */
  294. for ( i = 0; i < WinStationCount; i++ ) {
  295. if ( _wcsicmp( pWinStationName[i], L"Console" ) ){
  296. /*
  297. * Ignore console WinStation
  298. */
  299. /*
  300. * If this WinStation exists, then see if the Registry data
  301. * has changed. If so, then reset the WinStation.
  302. */
  303. if ( pWinStation = FindWinStationByName( pWinStationName[i], FALSE ) ) {
  304. if ( memcmp( &pWinStation->Config, &pWinConfig[i], sizeof(WINSTATIONCONFIG2) ) ) {
  305. /*
  306. * NOTE: For network WinStations, we test to see if the Lan
  307. * Adapter setting has changed. If not, we simply
  308. * refresh the configuration data since resetting the
  309. * WinStation would reset ALL connections on the same
  310. * Transport/Lan adapter combination.
  311. */
  312. if ( pWinConfig[i].Pd[0].Create.SdClass == SdNetwork &&
  313. pWinConfig[i].Pd[0].Params.Network.LanAdapter ==
  314. pWinStation->Config.Pd[0].Params.Network.LanAdapter ) {
  315. memcpy( &pWinStation->Config, &pWinConfig[i], sizeof(WINSTATIONCONFIG2) );
  316. /*
  317. * Listening network winstations should update their security
  318. * descriptors.
  319. */
  320. RtlAcquireResourceExclusive(&WinStationSecurityLock, TRUE);
  321. ReadWinStationSecurityDescriptor( pWinStation );
  322. RtlReleaseResource(&WinStationSecurityLock);
  323. /*
  324. * NOTE: For async WinStations, if the WinStation is NOT in
  325. * in the listen state and the Device name and Modem
  326. * name have not changed, then we do nothing. The
  327. * new config data will be read when the WinStation
  328. * is next re-created.
  329. */
  330. } else if ( pWinConfig[i].Pd[0].Create.SdClass == SdAsync &&
  331. pWinStation->State != State_Listen &&
  332. !memcmp ( pWinConfig[i].Pd[0].Params.Async.DeviceName,
  333. pWinStation->Config.Pd[0].Params.Async.DeviceName,
  334. sizeof( pWinConfig[i].Pd[0].Params.Async.DeviceName ) ) &&
  335. !memcmp ( pWinConfig[i].Pd[0].Params.Async.ModemName,
  336. pWinStation->Config.Pd[0].Params.Async.ModemName,
  337. sizeof( pWinConfig[i].Pd[0].Params.Async.ModemName ) ) ) {
  338. // Nothing to do
  339. /*
  340. * NOTE: For OEM WinStations, if the WinStation is NOT in
  341. * in the listen state and the Pd[0] params have not
  342. * changed, then we do nothing. The new config data
  343. * will be read when the WinStation is next re-created.
  344. */
  345. } else if ( pWinConfig[i].Pd[0].Create.SdClass == SdOemTransport &&
  346. pWinStation->State != State_Listen &&
  347. !memcmp ( &pWinConfig[i].Pd[0].Params,
  348. &pWinStation->Config.Pd[0].Params,
  349. sizeof( pWinConfig[i].Pd[0].Params ) ) ) {
  350. // Nothing to do
  351. } else {
  352. BOOLEAN bRecreate = TRUE;
  353. if ( !gbServer ) {
  354. if ( g_fDenyTSConnectionsPolicy &&
  355. // Performance, we only want to check if policy enable help when connection is denied
  356. (!TSIsMachineInHelpMode() || !TSIsMachinePolicyAllowHelp()) ) {
  357. bRecreate = FALSE;
  358. }
  359. WinStationResetWorker( pWinStation->LogonId, TRUE, FALSE, bRecreate );
  360. } else {
  361. QueueWinStationReset( pWinStation->LogonId );
  362. }
  363. }
  364. }
  365. else if ( !(pWinStation->Config.Pd[0].Create.PdFlag & PD_SINGLE_INST) ||
  366. ( pWinStation->State == State_Listen ) ) {
  367. RtlAcquireResourceExclusive(&WinStationSecurityLock, TRUE);
  368. ReadWinStationSecurityDescriptor( pWinStation );
  369. RtlReleaseResource(&WinStationSecurityLock);
  370. }
  371. ReleaseWinStation( pWinStation );
  372. } else
  373. if (pRenameInfo[i].Renamed &&
  374. NT_SUCCESS(WinStationRenameWorker(pRenameInfo[i].OldName,
  375. sizeof(WINSTATIONNAMEW)/sizeof(WCHAR),
  376. pWinStationName[i],
  377. sizeof(WINSTATIONNAMEW)/sizeof(WCHAR)))) {
  378. // Rename succeeded - don't recreate listener
  379. /*
  380. * An active WinStation was not found so we will create one.
  381. */
  382. } else {
  383. if ( !gbServer &&
  384. g_fDenyTSConnectionsPolicy &&
  385. // Performance, we only want to check if policy enable help when connection is denied
  386. (!TSIsMachineInHelpMode() || !TSIsMachinePolicyAllowHelp()) ) {
  387. continue;
  388. }
  389. /*
  390. * NOTE: NEVER create TAPI modem winstations in this routine.
  391. * We only allow creation of these winstations at
  392. * system startup time due to issues with the TAPI
  393. * database potentially being locked by this and other
  394. * processes, resulting in incorrect TAPI device
  395. * enumeration.
  396. */
  397. if ( pWinConfig[i].Cd.CdClass != CdModem ) {
  398. if (!gbServer ) {
  399. WinStationCreateWorker( pWinStationName[i], NULL );
  400. } else {
  401. QueueWinStationCreate( pWinStationName[i] );
  402. }
  403. }
  404. }
  405. }
  406. else
  407. {
  408. // we are dealing with the console session, update userconfig's shadow bit, that is
  409. // the only item I know of that needs updating.
  410. if ( pWinStation = FindWinStationByName( pWinStationName[i], FALSE ) ) {
  411. pWinStation->Config.Config.User.Shadow = pWinConfig[i].Config.User.Shadow;
  412. pWinStation->Config.Config.User.fInheritShadow = pWinConfig[i].Config.User.fInheritShadow;
  413. TRACE((hTrace,TC_ICASRV,TT_API2,"TERMSRV: WinStationReadRegistryWorker: %S, Shadow value of %d copied to console session's USERCONFIG\n",pWinStationName[i],
  414. pWinConfig[i].Config.User.Shadow));
  415. ReleaseWinStation( pWinStation );
  416. }
  417. }
  418. }
  419. /*
  420. * Free buffers
  421. */
  422. MemFree( pRenameInfo );
  423. MemFree( pWinConfig );
  424. MemFree( pWinStationName );
  425. if ( !gbServer )
  426. LEAVECRIT( &WinStationListenersLock );
  427. return( STATUS_SUCCESS );
  428. /*=============================================================================
  429. == Error returns
  430. =============================================================================*/
  431. badregdata:
  432. MemFree( pRenameInfo );
  433. badalloc3:
  434. MemFree( pWinConfig );
  435. badalloc2:
  436. badenum2:
  437. MemFree( pWinStationName );
  438. badalloc1:
  439. badenum1:
  440. if ( !gbServer )
  441. LEAVECRIT( &WinStationListenersLock );
  442. return( Status );
  443. }