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.

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