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.

2403 lines
80 KiB

  1. /*************************************************************************
  2. *
  3. * regmap.c
  4. *
  5. * Handle Copy-On-Reference Registry Entry Mapping
  6. *
  7. * copyright notice: Copyright 1996-1997, Citrix Systems Inc.
  8. * Copyright (C) 1997-1999 Microsoft Corp.
  9. *
  10. * Author: Bill Madden
  11. *
  12. * NOTE for Hydra (butchd 9/26/97): In comments below, substitute
  13. *
  14. * SOFTWARE\Citrix
  15. *
  16. * with
  17. *
  18. * SOFTWARE\Microsoft\Windows NT\CurrentVersion\Terminal Server
  19. *
  20. * Here's a brief(?) summary of how the registry mapping works. The goal is
  21. * that an administrator can install an application, and then all users can
  22. * use it, without any per-user configuration. The current design is that
  23. * the administrator puts the system into installation mode (change user
  24. * /install), installs the application, and then returns the system to
  25. * execute mode (change user /execute). There are hooks in the API's used to
  26. * create keys and values in the registry (BaseRegCreateKey, BaseRegSetValue,
  27. * BaseRegRestoreKey, etc), and the hooks create a copy of the registry keys
  28. * created under \HKEY_LOCAL_MACHINE\SOFTWARE\Citrix\Install (both for the
  29. * user specific keys and the local machine keys). The local machine keys
  30. * are added so that if sometime in the future we need to know all of the
  31. * registry values created by an application, there is a copy of them
  32. * available.
  33. *
  34. * When a user starts a Win32 app for the first time, the app will open the
  35. * keys it needs to query. If the key doesn't exist underneath
  36. * HKEY_CURRENT_USER, there are hooks in the base registry API's to catch the
  37. * error and then search underneath the Citrix/Install section to see if the
  38. * key exists there. If the key exists in the install section, we copy the
  39. * key, its values, and its subkeys to the current user's registry. This
  40. * way we only have to hook opens, and not every registry API. This helps
  41. * reduce the overhead associated with this registry mapping.
  42. *
  43. * Some apps (such as the office short cut bar) delete entries and need to
  44. * recreate the entries themselves. When an app deletes a key and the
  45. * system is in execute mode, we will set a value under the key indicating
  46. * that we should only copy the key to the user once. What this currently
  47. * means, is that if this is the only key being created, we won't create it
  48. * when that flag is set. However, if we are creating this key because we
  49. * created its parent, we will still create the key.
  50. *
  51. * The other part of the registry mapping support is that when a user logs
  52. * in, userinit calls a routine (CtxCheckNewRegEntries) which checks if any
  53. * of the system keys are newer than any of the corresponding user keys. If
  54. * they are, the user keys are deleted (we're assuming that if the system
  55. * key is newer, than the admin has installed a newer version of an
  56. * application). This deleting can be disabled by setting a value under
  57. * HKEY_LOCAL_MACHINE\Software\Citrix\Compatibility\IniFiles\xxx where xxx
  58. * is the key name, and the value should be 0x48.
  59. *
  60. *************************************************************************/
  61. #include "precomp.h"
  62. #pragma hdrstop
  63. #include <rpc.h>
  64. #include <regmap.h>
  65. #include <aclapi.h>
  66. #include <shlwapi.h>
  67. /* External Functions */
  68. ULONG GetCtxAppCompatFlags(LPDWORD, LPDWORD);
  69. /* Internal Functions */
  70. PWCHAR GetUserSWKey(PWCHAR pPath, PBOOL fUserReg, PBOOL bClassesKey);
  71. PWCHAR Ctxwcsistr(PWCHAR pstring1, PWCHAR pstring2);
  72. NTSTATUS TermsrvGetRegPath(IN HANDLE hKey,
  73. IN POBJECT_ATTRIBUTES pObjectAttr,
  74. IN PWCHAR pInstPath,
  75. IN ULONG ulbuflen);
  76. NTSTATUS TermsrvGetInstallPath(IN PWCHAR pUserPath,
  77. IN PWCHAR *ppInstPath);
  78. NTSTATUS TermsrvCreateKey(IN PWCHAR pSrcPath,
  79. IN PWCHAR pDstPath,
  80. IN BOOL fCloneValues,
  81. IN BOOL fCloneSubKeys,
  82. OUT PHANDLE phKey);
  83. NTSTATUS TermsrvCloneKey(HANDLE hSrcKey,
  84. HANDLE hDstKey,
  85. PKEY_FULL_INFORMATION pDefKeyInfo,
  86. BOOL fCreateSubKeys);
  87. void TermsrvLogRegInstallTime(void);
  88. BOOL ExistsInOmissionList(PWCHAR pwch);
  89. BOOL ExistsInEnumeratedKeys(HKEY hOmissionKey, PKEY_FULL_INFORMATION pDefKeyInfo, PWCHAR pwch);
  90. /*****************************************************************************
  91. *
  92. * TermsrvCreateRegEntry
  93. *
  94. * If in installation mode, create the registry entry in the citrix
  95. * install user section of the registry. If the system is in execution
  96. * mode, verify that the key values and subkeys have been created.
  97. *
  98. * ENTRY:
  99. * IN HANDLE hKey: Handle of new key just created
  100. * IN ULONG TitleIndex: Title Index
  101. * IN PUNICODE_STRING pUniClass: Ptr to unicode string of class
  102. * IN ULONG ulCreateOpt: Creation options
  103. *
  104. *
  105. * EXIT:
  106. * TRUE: Entry created in install section or cloned from install section
  107. * FALSE: Entry not created or cloned
  108. *
  109. ****************************************************************************/
  110. BOOL TermsrvCreateRegEntry(IN HANDLE hKey,
  111. IN POBJECT_ATTRIBUTES pObjAttr,
  112. IN ULONG TitleIndex,
  113. IN PUNICODE_STRING pUniClass OPTIONAL,
  114. IN ULONG ulCreateOpt)
  115. {
  116. NTSTATUS Status;
  117. ULONG ultemp;
  118. OBJECT_ATTRIBUTES InstObjectAttr;
  119. UNICODE_STRING UniString;
  120. HKEY hNewKey = NULL;
  121. PWCHAR wcbuff = NULL;
  122. PWCHAR pUserPath;
  123. BOOL fMapping;
  124. BOOL fUserReg;
  125. PKEY_FULL_INFORMATION pDefKeyInfo = NULL;
  126. // Get the current state of ini file mapping
  127. fMapping = !TermsrvAppInstallMode();
  128. // Get a buffer to hold the path of the key
  129. ultemp = sizeof(WCHAR)*MAX_PATH*2;
  130. pUserPath = RtlAllocateHeap(RtlProcessHeap(),
  131. 0,
  132. ultemp);
  133. // Get the full path associated with this key
  134. if (pUserPath) {
  135. Status = TermsrvGetRegPath(hKey,
  136. NULL,
  137. pUserPath,
  138. ultemp);
  139. } else {
  140. Status = STATUS_NO_MEMORY;
  141. }
  142. if (NT_SUCCESS(Status)) {
  143. // Get the corresponding path in the install section
  144. Status = TermsrvGetInstallPath(pUserPath,
  145. &wcbuff);
  146. if (NT_SUCCESS(Status)) {
  147. // Set up an object attribute structure to point to the
  148. // path of the key in the install section
  149. RtlInitUnicodeString(&UniString, wcbuff);
  150. InitializeObjectAttributes(&InstObjectAttr,
  151. &UniString,
  152. OBJ_CASE_INSENSITIVE,
  153. NULL,
  154. pObjAttr->SecurityDescriptor);
  155. // If we're in install mode, create the key in the default
  156. // install section
  157. if (!fMapping) {
  158. // Inherit the default security for the install section
  159. InstObjectAttr.SecurityDescriptor = NULL;
  160. Status = NtCreateKey(&hNewKey,
  161. KEY_WRITE,
  162. &InstObjectAttr,
  163. TitleIndex,
  164. pUniClass,
  165. ulCreateOpt,
  166. &ultemp);
  167. if (!NT_SUCCESS(Status)) {
  168. // Need to build up the path to the registry key
  169. Status = TermsrvCreateKey(pUserPath,
  170. wcbuff,
  171. FALSE,
  172. FALSE,
  173. &hNewKey);
  174. }
  175. // Update the registry entry for the last time a registry
  176. // entry was added
  177. if (NT_SUCCESS(Status)) {
  178. TermsrvLogRegInstallTime();
  179. }
  180. // The system is in execute mode, try to copy the key from the
  181. // installation section
  182. } else {
  183. HANDLE hUserKey = NULL;
  184. ULONG ulAppType = TERMSRV_COMPAT_WIN32;
  185. // First verify that this is in the user software section
  186. if (!GetUserSWKey(pUserPath, &fUserReg, NULL)) {
  187. Status = STATUS_NO_MORE_FILES;
  188. }
  189. // If mapping is on, but disabled for this app, return
  190. GetCtxAppCompatFlags(&ultemp, &ulAppType);
  191. if ((ultemp & (TERMSRV_COMPAT_NOREGMAP | TERMSRV_COMPAT_WIN32)) ==
  192. (TERMSRV_COMPAT_NOREGMAP | TERMSRV_COMPAT_WIN32)) {
  193. Status = STATUS_NO_MORE_FILES;
  194. }
  195. // Check if registry mapping is disabled for this key path
  196. GetTermsrCompatFlags(pUserPath, &ultemp, CompatibilityRegEntry);
  197. if ((ultemp & (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) ==
  198. (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) {
  199. Status = STATUS_NO_MORE_FILES;
  200. }
  201. if (NT_SUCCESS(Status)) {
  202. // Open up a key for the install section
  203. Status = NtOpenKey(&hNewKey,
  204. KEY_READ,
  205. &InstObjectAttr);
  206. }
  207. if (NT_SUCCESS(Status)) {
  208. // Set an attribute structure to point at the user path
  209. RtlInitUnicodeString(&UniString, pUserPath);
  210. InitializeObjectAttributes(&InstObjectAttr,
  211. &UniString,
  212. OBJ_CASE_INSENSITIVE,
  213. NULL,
  214. pObjAttr->SecurityDescriptor);
  215. // Open the user path so we can write to it
  216. Status = NtOpenKey(&hUserKey,
  217. KEY_WRITE,
  218. &InstObjectAttr);
  219. }
  220. // Get the key info
  221. if (NT_SUCCESS(Status)) {
  222. // Get a buffer for the key info
  223. ultemp = sizeof(KEY_FULL_INFORMATION) +
  224. MAX_PATH*sizeof(WCHAR);
  225. pDefKeyInfo = RtlAllocateHeap(RtlProcessHeap(),
  226. 0,
  227. ultemp);
  228. if (pDefKeyInfo) {
  229. Status = NtQueryKey(hNewKey,
  230. KeyFullInformation,
  231. pDefKeyInfo,
  232. ultemp,
  233. &ultemp);
  234. } else {
  235. Status = STATUS_NO_MEMORY;
  236. }
  237. }
  238. // Copy all of the values and subkeys for this key from the
  239. // install section to the user section
  240. if (NT_SUCCESS(Status)) {
  241. Status = TermsrvCloneKey(hNewKey,
  242. hUserKey,
  243. pDefKeyInfo,
  244. TRUE);
  245. if (pDefKeyInfo) {
  246. RtlFreeHeap(RtlProcessHeap(), 0, pDefKeyInfo);
  247. }
  248. }
  249. if (hUserKey) {
  250. NtClose(hUserKey);
  251. }
  252. }
  253. if (hNewKey) {
  254. NtClose(hNewKey);
  255. }
  256. }
  257. }
  258. if (pUserPath) {
  259. RtlFreeHeap(RtlProcessHeap(), 0, pUserPath);
  260. }
  261. if (wcbuff) {
  262. RtlFreeHeap(RtlProcessHeap(), 0, wcbuff);
  263. }
  264. if (NT_SUCCESS(Status)) {
  265. return(TRUE);
  266. } else {
  267. return(FALSE);
  268. }
  269. }
  270. /*****************************************************************************
  271. *
  272. * TermsrvOpenRegEntry
  273. *
  274. * If the system is in execute mode, copy application registry entries
  275. * from the default user to the current user.
  276. *
  277. * ENTRY:
  278. * OUT PHANDLE pUserKey:
  279. * Pointer to return key handle if opened
  280. * IN ACCESS_MASK DesiredAccess:
  281. * Desired access to the key
  282. * IN POBJECT_ATTRIBUTES ObjectAttributes:
  283. * Object attribute structure for key to open
  284. *
  285. * EXIT:
  286. * TRUE: Entry moved from install to current user
  287. * FALSE: Entry not moved
  288. *
  289. ****************************************************************************/
  290. BOOL TermsrvOpenRegEntry(OUT PHANDLE pUserhKey,
  291. IN ACCESS_MASK DesiredAccess,
  292. IN POBJECT_ATTRIBUTES pUserObjectAttr)
  293. {
  294. NTSTATUS Status;
  295. ULONG ultemp=0;
  296. ULONG ulAppType = TERMSRV_COMPAT_WIN32;
  297. HKEY hNewKey;
  298. WCHAR wcbuff[MAX_PATH*2];
  299. PWCHAR pwch, pUserPath;
  300. BOOL fUserReg;
  301. // If running in install mode, return
  302. if (TermsrvAppInstallMode() ) {
  303. return(FALSE);
  304. }
  305. // If mapping is on, but disabled for this app, return
  306. GetCtxAppCompatFlags(&ultemp, &ulAppType);
  307. if ((ultemp & (TERMSRV_COMPAT_NOREGMAP | TERMSRV_COMPAT_WIN32)) ==
  308. (TERMSRV_COMPAT_NOREGMAP | TERMSRV_COMPAT_WIN32)) {
  309. return(FALSE);
  310. }
  311. // Get a buffer to hold the user's path in the registry
  312. ultemp = sizeof(WCHAR)*MAX_PATH*2;
  313. pUserPath = RtlAllocateHeap(RtlProcessHeap(),
  314. 0,
  315. ultemp);
  316. if (pUserPath) {
  317. // Get the full path associated with this object attribute structure
  318. Status = TermsrvGetRegPath(NULL,
  319. pUserObjectAttr,
  320. pUserPath,
  321. ultemp);
  322. } else {
  323. Status = STATUS_NO_MEMORY;
  324. }
  325. // Create the key for this user
  326. if (NT_SUCCESS(Status)) {
  327. Status = STATUS_NO_SUCH_FILE;
  328. //DbgPrint("Attempting to open key %ws\n",pUserPath);
  329. // Check if they are trying to open the key under HKEY_CURRENT_USER
  330. pwch = GetUserSWKey(pUserPath, &fUserReg, NULL);
  331. if (pwch) {
  332. // Check if registry mapping is disabled for this key
  333. GetTermsrCompatFlags(pUserPath, &ultemp, CompatibilityRegEntry);
  334. if ((ultemp & (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) !=
  335. (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) {
  336. wcscpy(wcbuff, TERMSRV_INSTALL);
  337. wcscat(wcbuff, pwch);
  338. Status = TermsrvCreateKey(wcbuff,
  339. pUserPath,
  340. TRUE,
  341. TRUE,
  342. &hNewKey);
  343. if (NT_SUCCESS(Status)) {
  344. NtClose(hNewKey);
  345. }
  346. } else {
  347. Status = STATUS_NO_MORE_FILES;
  348. }
  349. // App is trying to open the key under HKEY_LOCAL_MACHINE, mask off
  350. // the access bits they don't have by default
  351. } else if (!_wcsnicmp(pUserPath,
  352. TERMSRV_MACHINEREGISTRY,
  353. wcslen(TERMSRV_MACHINEREGISTRY)) &&
  354. (DesiredAccess &
  355. (WRITE_DAC | WRITE_OWNER | KEY_CREATE_LINK))) {
  356. DesiredAccess &= ~(WRITE_DAC | WRITE_OWNER | KEY_CREATE_LINK);
  357. Status = STATUS_SUCCESS;
  358. }
  359. } else {
  360. Status = STATUS_NO_SUCH_FILE;
  361. }
  362. if (pUserPath) {
  363. RtlFreeHeap(RtlProcessHeap(), 0, pUserPath);
  364. }
  365. // We successfully copied the key, so actually do the open
  366. if (NT_SUCCESS(Status)) {
  367. Status = NtOpenKey(pUserhKey,
  368. DesiredAccess,
  369. pUserObjectAttr);
  370. }
  371. if (NT_SUCCESS(Status)) {
  372. return(TRUE);
  373. } else {
  374. return(FALSE);
  375. }
  376. }
  377. /*****************************************************************************
  378. *
  379. * TermsrvSetValueKey
  380. *
  381. * If the system is in install (ini mapping off) mode, set the entry in
  382. * the citrix install user section of the registry. If the system is in
  383. * execute (ini mapping on) mode, do nothing.
  384. *
  385. * ENTRY:
  386. * HANDLE hKey: Open key to query value from
  387. * PUNICODE_STRING ValueName: Ptr to unicode value name to set
  388. * ULONG TitleIndex: Title Index
  389. * ULONG Type: Type of data
  390. * PVOID Data: Ptr to data
  391. * ULONG DataSize: Data length
  392. *
  393. * EXIT:
  394. * TRUE: Entry created in install section
  395. * FALSE: Entry not created
  396. *
  397. ****************************************************************************/
  398. BOOL TermsrvSetValueKey(HANDLE hKey,
  399. PUNICODE_STRING ValueName,
  400. ULONG TitleIndex,
  401. ULONG Type,
  402. PVOID Data,
  403. ULONG DataSize)
  404. {
  405. NTSTATUS Status;
  406. ULONG ultemp;
  407. PWCHAR pwch, pUserPath;
  408. PWCHAR wcbuff = NULL;
  409. UNICODE_STRING UniString;
  410. OBJECT_ATTRIBUTES InstObjectAttr;
  411. HKEY hNewKey;
  412. // If not in install mode, return
  413. if ( !TermsrvAppInstallMode() ) {
  414. return(FALSE);
  415. }
  416. // Allocate a buffer to hold the path to the key in the registry
  417. ultemp = sizeof(WCHAR)*MAX_PATH*2;
  418. pUserPath = RtlAllocateHeap(RtlProcessHeap(),
  419. 0,
  420. ultemp);
  421. // Get the path of this key
  422. if (pUserPath) {
  423. Status = TermsrvGetRegPath(hKey,
  424. NULL,
  425. pUserPath,
  426. ultemp);
  427. } else {
  428. Status = STATUS_NO_MEMORY;
  429. }
  430. if (NT_SUCCESS(Status)) {
  431. // Get the path to the entry in the install section of the registry
  432. Status = TermsrvGetInstallPath(pUserPath,
  433. &wcbuff);
  434. if (NT_SUCCESS(Status)) {
  435. RtlInitUnicodeString(&UniString, wcbuff);
  436. InitializeObjectAttributes(&InstObjectAttr,
  437. &UniString,
  438. OBJ_CASE_INSENSITIVE,
  439. NULL,
  440. NULL);
  441. // Open the key in under the install section
  442. Status = NtOpenKey(&hNewKey,
  443. KEY_WRITE,
  444. &InstObjectAttr);
  445. // If we couldn't open it, try creating the key
  446. if (!NT_SUCCESS(Status)) {
  447. Status = TermsrvCreateKey(pUserPath,
  448. wcbuff,
  449. TRUE,
  450. FALSE,
  451. &hNewKey);
  452. }
  453. // If the key was opened, set the value in the install section
  454. if (NT_SUCCESS(Status)) {
  455. Status = NtSetValueKey(hNewKey,
  456. ValueName,
  457. TitleIndex,
  458. Type,
  459. Data,
  460. DataSize);
  461. NtClose(hNewKey);
  462. // Update the registry entry for the last time a registry
  463. // entry was added
  464. if (NT_SUCCESS(Status)) {
  465. TermsrvLogRegInstallTime();
  466. }
  467. }
  468. }
  469. }
  470. if (pUserPath) {
  471. RtlFreeHeap(RtlProcessHeap(), 0, pUserPath);
  472. }
  473. if (wcbuff) {
  474. RtlFreeHeap(RtlProcessHeap(), 0, wcbuff);
  475. }
  476. if (NT_SUCCESS(Status)) {
  477. return(TRUE);
  478. } else {
  479. return(FALSE);
  480. }
  481. }
  482. /*****************************************************************************
  483. *
  484. * TermsrvDeleteKey
  485. *
  486. * If the system is in install mode, delete the registry entry in the citrix
  487. * install section of the registry. If the system is in execution mode,
  488. * mark the entry in the install section as being deleted.
  489. *
  490. * ENTRY:
  491. * HANDLE hKey: Handle of key in user section to delete
  492. *
  493. * EXIT:
  494. * TRUE: Entry deleted in install section
  495. * FALSE: Entry not created
  496. *
  497. ****************************************************************************/
  498. BOOL TermsrvDeleteKey(HANDLE hKey)
  499. {
  500. NTSTATUS Status;
  501. ULONG ultemp=0;
  502. ULONG ulAppType = TERMSRV_COMPAT_WIN32;
  503. OBJECT_ATTRIBUTES ObjectAttr;
  504. PKEY_BASIC_INFORMATION pKeyInfo;
  505. UNICODE_STRING UniString;
  506. HKEY hNewKey;
  507. PWCHAR wcbuff = NULL;
  508. PWCHAR pwch, pUserPath;
  509. BOOL fMapping;
  510. // Get the current state of ini file/registry mapping, default to execute
  511. fMapping = !TermsrvAppInstallMode();
  512. // If mapping is on, but disabled for this app, return
  513. if (fMapping) {
  514. GetCtxAppCompatFlags(&ultemp, &ulAppType);
  515. if ((ultemp & (TERMSRV_COMPAT_NOREGMAP | TERMSRV_COMPAT_WIN32)) ==
  516. (TERMSRV_COMPAT_NOREGMAP | TERMSRV_COMPAT_WIN32)) {
  517. return(FALSE);
  518. }
  519. }
  520. // Allocate a buffer to hold the path of the key
  521. ultemp = sizeof(WCHAR)*MAX_PATH*2;
  522. pUserPath = RtlAllocateHeap(RtlProcessHeap(),
  523. 0,
  524. ultemp);
  525. // Get the path to the user's key
  526. if (pUserPath) {
  527. Status = TermsrvGetRegPath(hKey,
  528. NULL,
  529. pUserPath,
  530. ultemp);
  531. } else {
  532. Status = STATUS_NO_MEMORY;
  533. }
  534. if (NT_SUCCESS(Status)) {
  535. // Get the corresponding path in the install section
  536. Status = TermsrvGetInstallPath(pUserPath,
  537. &wcbuff);
  538. if (NT_SUCCESS(Status)) {
  539. RtlInitUnicodeString(&UniString, wcbuff);
  540. InitializeObjectAttributes(&ObjectAttr,
  541. &UniString,
  542. OBJ_CASE_INSENSITIVE,
  543. NULL,
  544. NULL);
  545. // Open the key in the install section to mark it or delete it
  546. if (fMapping) {
  547. Status = NtOpenKey(&hNewKey,
  548. KEY_READ | KEY_WRITE,
  549. &ObjectAttr);
  550. } else {
  551. Status = NtOpenKey(&hNewKey,
  552. KEY_READ | KEY_WRITE | DELETE,
  553. &ObjectAttr);
  554. }
  555. }
  556. if (NT_SUCCESS(Status)) {
  557. // If in execute mode, set the copy once flag, but preserve the
  558. // last write time of this key
  559. if (fMapping) {
  560. PKEY_VALUE_PARTIAL_INFORMATION pValKeyInfo;
  561. PKEY_BASIC_INFORMATION pKeyInfo;
  562. NTSTATUS SubStatus;
  563. ULONG ulcbuf;
  564. // Get a buffer
  565. ulcbuf = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH*sizeof(WCHAR);
  566. pKeyInfo = RtlAllocateHeap(RtlProcessHeap(),
  567. 0,
  568. ultemp);
  569. // If we got the buffer, see if the copy once flag exists
  570. if (pKeyInfo) {
  571. RtlInitUnicodeString(&UniString, TERMSRV_COPYONCEFLAG);
  572. pValKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)pKeyInfo;
  573. SubStatus = NtQueryValueKey(hNewKey,
  574. &UniString,
  575. KeyValuePartialInformation,
  576. pValKeyInfo,
  577. ulcbuf,
  578. &ultemp);
  579. // If we couldn't get the value of the key, or it's not
  580. // what it should be, reset it
  581. if (!NT_SUCCESS(SubStatus) ||
  582. (pValKeyInfo->Type != REG_DWORD) ||
  583. (*pValKeyInfo->Data != 1)) {
  584. // Get the last update time of the key
  585. SubStatus = NtQueryKey(hNewKey,
  586. KeyBasicInformation,
  587. pKeyInfo,
  588. ultemp,
  589. &ultemp);
  590. // Set the copy once flag
  591. ultemp = 1;
  592. Status = NtSetValueKey(hNewKey,
  593. &UniString,
  594. 0,
  595. REG_DWORD,
  596. &ultemp,
  597. sizeof(ultemp));
  598. // Restore the lastwritetime of the key
  599. if (NT_SUCCESS(SubStatus)) {
  600. NtSetInformationKey(hNewKey,
  601. KeyWriteTimeInformation,
  602. &pKeyInfo->LastWriteTime,
  603. sizeof(pKeyInfo->LastWriteTime));
  604. }
  605. }
  606. // Free up our buffer
  607. RtlFreeHeap(RtlProcessHeap(), 0, pKeyInfo);
  608. }
  609. // For install mode, delete our copy of the key
  610. } else {
  611. Status = NtDeleteKey( hNewKey );
  612. }
  613. NtClose( hNewKey );
  614. }
  615. }
  616. if (pUserPath) {
  617. RtlFreeHeap(RtlProcessHeap(), 0, pUserPath);
  618. }
  619. if (wcbuff) {
  620. RtlFreeHeap(RtlProcessHeap(), 0, wcbuff);
  621. }
  622. if (NT_SUCCESS(Status)) {
  623. return(TRUE);
  624. } else {
  625. return(FALSE);
  626. }
  627. }
  628. /*****************************************************************************
  629. *
  630. * TermsrvDeleteValue
  631. *
  632. * Delete the registry value in the citrix install user section of the
  633. * registry.
  634. *
  635. * ENTRY:
  636. * HANDLE hKey: Handle of key in install section
  637. * PUNICODE_STRING pUniValue: Ptr to unicode value name to delete
  638. *
  639. * EXIT:
  640. * TRUE: Entry deleted in install section
  641. * FALSE: Entry not created
  642. *
  643. ****************************************************************************/
  644. BOOL TermsrvDeleteValue(HANDLE hKey,
  645. PUNICODE_STRING pUniValue)
  646. {
  647. NTSTATUS Status;
  648. OBJECT_ATTRIBUTES ObjectAttr;
  649. WCHAR wcUserPath[MAX_PATH*2];
  650. PWCHAR wcInstPath = NULL;
  651. UNICODE_STRING UniString;
  652. HANDLE hInstKey;
  653. // If not in install mode, return
  654. if ( !TermsrvAppInstallMode() ) {
  655. return(FALSE);
  656. }
  657. // Get the path to the key in the user section
  658. Status = TermsrvGetRegPath(hKey,
  659. NULL,
  660. wcUserPath,
  661. sizeof(wcUserPath)/sizeof(WCHAR));
  662. if (NT_SUCCESS(Status)) {
  663. // Get the corresponding path in the install section
  664. Status = TermsrvGetInstallPath(wcUserPath,
  665. &wcInstPath);
  666. if (NT_SUCCESS(Status)) {
  667. RtlInitUnicodeString(&UniString, wcInstPath);
  668. InitializeObjectAttributes(&ObjectAttr,
  669. &UniString,
  670. OBJ_CASE_INSENSITIVE,
  671. NULL,
  672. NULL);
  673. // Open the install path key to delete the value
  674. Status = NtOpenKey(&hInstKey,
  675. MAXIMUM_ALLOWED,
  676. &ObjectAttr);
  677. // Delete the value
  678. if (NT_SUCCESS(Status)) {
  679. Status = NtDeleteValueKey(hInstKey,
  680. pUniValue);
  681. NtClose( hInstKey );
  682. }
  683. }
  684. }
  685. if (wcInstPath) {
  686. RtlFreeHeap(RtlProcessHeap(), 0, wcInstPath);
  687. }
  688. if (NT_SUCCESS(Status)) {
  689. return(TRUE);
  690. } else {
  691. return(FALSE);
  692. }
  693. }
  694. /*****************************************************************************
  695. *
  696. * TermsrvRestoreKey
  697. *
  698. * If the system is in installation mode and the application is trying to
  699. * restore a key into the user or machine section of the registry, also
  700. * restore the key into our install section.
  701. *
  702. * ENTRY:
  703. * HANDLE hKey: Handle of key in user section
  704. * HANDLE hFile: Handle of file to load in
  705. * ULONG Flags: Restore key flags
  706. *
  707. * EXIT:
  708. * TRUE: Entry created in install section
  709. * FALSE: Entry not created
  710. *
  711. ****************************************************************************/
  712. BOOL TermsrvRestoreKey(IN HANDLE hKey,
  713. IN HANDLE hFile,
  714. IN ULONG Flags)
  715. {
  716. NTSTATUS Status;
  717. OBJECT_ATTRIBUTES ObjectAttr;
  718. WCHAR wcUserPath[MAX_PATH*2];
  719. PWCHAR wcInstPath = NULL;
  720. UNICODE_STRING UniString;
  721. HANDLE hInstKey;
  722. // If not in install mode or it's
  723. // a memory only restore, return
  724. if ( !TermsrvAppInstallMode() ||
  725. (Flags & REG_WHOLE_HIVE_VOLATILE)) {
  726. return(FALSE);
  727. }
  728. // Get the path to the key in the user section
  729. Status = TermsrvGetRegPath(hKey,
  730. NULL,
  731. wcUserPath,
  732. sizeof(wcUserPath)/sizeof(WCHAR));
  733. if (NT_SUCCESS(Status)) {
  734. // Get the corresponding path in the install section
  735. Status = TermsrvGetInstallPath(wcUserPath,
  736. &wcInstPath);
  737. if (NT_SUCCESS(Status)) {
  738. RtlInitUnicodeString(&UniString, wcInstPath);
  739. InitializeObjectAttributes(&ObjectAttr,
  740. &UniString,
  741. OBJ_CASE_INSENSITIVE,
  742. NULL,
  743. NULL);
  744. // Open the install path key to load the key into
  745. Status = NtOpenKey(&hInstKey,
  746. KEY_WRITE,
  747. &ObjectAttr);
  748. // If we couldn't open it, try creating the key
  749. if (!NT_SUCCESS(Status)) {
  750. Status = TermsrvCreateKey(wcUserPath,
  751. wcInstPath,
  752. TRUE,
  753. FALSE,
  754. &hInstKey);
  755. }
  756. // Restore the key into the user section
  757. if (NT_SUCCESS(Status)) {
  758. Status = NtRestoreKey(hInstKey,
  759. hFile,
  760. Flags);
  761. NtClose( hInstKey );
  762. // Update the registry entry for the last time a registry
  763. // entry was added
  764. if (NT_SUCCESS(Status)) {
  765. TermsrvLogRegInstallTime();
  766. }
  767. }
  768. }
  769. }
  770. if (wcInstPath) {
  771. RtlFreeHeap(RtlProcessHeap(), 0, wcInstPath);
  772. }
  773. if (NT_SUCCESS(Status)) {
  774. return(TRUE);
  775. } else {
  776. return(FALSE);
  777. }
  778. }
  779. /*****************************************************************************
  780. *
  781. * TermsrvSetKeySecurity
  782. *
  783. * If the system is in installation mode and the application is trying to
  784. * set the security of an entry in the the user or machine section of the
  785. * registry, also set the security of the key in the install section.
  786. *
  787. * ENTRY:
  788. * HANDLE hKey: Handle in user section to set security
  789. * SECURITY_INFORMATION SecInfo: Security info struct
  790. * PSECURITY_DESCRIPTOR pSecDesc: Ptr to security descriptor
  791. *
  792. * EXIT:
  793. * TRUE: Security set in install section
  794. * FALSE: Error
  795. *
  796. ****************************************************************************/
  797. BOOL TermsrvSetKeySecurity(IN HANDLE hKey,
  798. IN SECURITY_INFORMATION SecInfo,
  799. IN PSECURITY_DESCRIPTOR pSecDesc)
  800. {
  801. NTSTATUS Status;
  802. OBJECT_ATTRIBUTES ObjectAttr;
  803. WCHAR wcUserPath[MAX_PATH*2];
  804. PWCHAR wcInstPath = NULL;
  805. UNICODE_STRING UniString;
  806. HANDLE hInstKey;
  807. // If not in install mode, return
  808. if ( !TermsrvAppInstallMode() ) {
  809. return(FALSE);
  810. }
  811. // Get the path to the key in the user section
  812. Status = TermsrvGetRegPath(hKey,
  813. NULL,
  814. wcUserPath,
  815. sizeof(wcUserPath)/sizeof(WCHAR));
  816. if (NT_SUCCESS(Status)) {
  817. // Get the corresponding path in the install section
  818. Status = TermsrvGetInstallPath(wcUserPath,
  819. &wcInstPath);
  820. if (NT_SUCCESS(Status)) {
  821. RtlInitUnicodeString(&UniString, wcInstPath);
  822. InitializeObjectAttributes(&ObjectAttr,
  823. &UniString,
  824. OBJ_CASE_INSENSITIVE,
  825. NULL,
  826. NULL);
  827. // Open the install path key to load the key into
  828. Status = NtOpenKey(&hInstKey,
  829. KEY_WRITE | WRITE_OWNER | WRITE_DAC,
  830. &ObjectAttr);
  831. // Set the security
  832. if (NT_SUCCESS(Status)) {
  833. Status = NtSetSecurityObject(hKey,
  834. SecInfo,
  835. pSecDesc);
  836. NtClose( hInstKey );
  837. }
  838. }
  839. }
  840. if (wcInstPath) {
  841. RtlFreeHeap(RtlProcessHeap(), 0, wcInstPath);
  842. }
  843. if (NT_SUCCESS(Status)) {
  844. return(TRUE);
  845. } else {
  846. return(FALSE);
  847. }
  848. }
  849. /*****************************************************************************
  850. *
  851. * TermsrvGetRegPath
  852. *
  853. * From the handle or a pointer to the object attributes, return the
  854. * object's path in the registry.
  855. *
  856. * ENTRY:
  857. * HANDLE hKey: Handle of an open key to get the path of
  858. * POBJECT_ATTRIBUTES Ptr to open attribute structure to get the path of
  859. * PWCHAR pInstPath Ptr to return buffer
  860. * ULONG ulbuflen Length of return buffer
  861. *
  862. * NOTES:
  863. * Either hKey or pObjectAttr must be specified, but not both.
  864. *
  865. * EXIT:
  866. * NTSTATUS return code
  867. *
  868. ****************************************************************************/
  869. NTSTATUS TermsrvGetRegPath(IN HANDLE hKey,
  870. IN POBJECT_ATTRIBUTES pObjectAttr,
  871. IN PWCHAR pUserPath,
  872. IN ULONG ulbuflen)
  873. {
  874. NTSTATUS Status = STATUS_SUCCESS;
  875. ULONG ultemp;
  876. ULONG ulWcharLength; //Keep track of the WCHAR string length
  877. PWCHAR pwch;
  878. PVOID pBuffer = NULL;
  879. // Make sure only one of hKey or pObjectAttr was specified
  880. if ((hKey && pObjectAttr) || (!hKey && !pObjectAttr)) {
  881. return(STATUS_INVALID_PARAMETER);
  882. }
  883. // A key handle or root directory was specified, so get its path
  884. if (hKey || (pObjectAttr && pObjectAttr->RootDirectory)) {
  885. ultemp = sizeof(UNICODE_STRING) + sizeof(WCHAR)*MAX_PATH*2;
  886. pBuffer = RtlAllocateHeap(RtlProcessHeap(),
  887. 0,
  888. ultemp);
  889. // Got the buffer OK, query the path
  890. if (pBuffer) {
  891. // Get the path for key or root directory
  892. Status = NtQueryObject(hKey ? hKey : pObjectAttr->RootDirectory,
  893. ObjectNameInformation,
  894. (PVOID)pBuffer,
  895. ultemp,
  896. NULL);
  897. if (!NT_SUCCESS(Status)) {
  898. RtlFreeHeap(RtlProcessHeap(), 0, pBuffer);
  899. return(Status);
  900. }
  901. } else {
  902. return(STATUS_NO_MEMORY);
  903. }
  904. // Build the full path to the key to be created
  905. pwch = ((PUNICODE_STRING)pBuffer)->Buffer;
  906. // BBUG 417564. Bad apps close HKLM, but we might need it here.
  907. if (!pwch) {
  908. RtlFreeHeap(RtlProcessHeap(), 0, pBuffer);
  909. return(STATUS_INVALID_HANDLE);
  910. }
  911. // Make sure the string is zero terminated
  912. ulWcharLength = ((PUNICODE_STRING)pBuffer)->Length / sizeof(WCHAR);
  913. pwch[ulWcharLength] = 0;
  914. // If using Object Attributes and there's room, tack on the object name
  915. if (pObjectAttr) {
  916. if ((((PUNICODE_STRING)pBuffer)->Length +
  917. pObjectAttr->ObjectName->Length + sizeof(WCHAR)) < ultemp) {
  918. wcscat(pwch, L"\\");
  919. //Increment the length of the string
  920. ulWcharLength += 1;
  921. //Append the relative path to the root path (Don't use wcscat. The string may not
  922. // be zero terminated
  923. wcsncpy(&pwch[ulWcharLength], pObjectAttr->ObjectName->Buffer, pObjectAttr->ObjectName->Length / sizeof (WCHAR));
  924. // Make sure the string is zero terminated
  925. ulWcharLength += (pObjectAttr->ObjectName->Length / sizeof(WCHAR));
  926. pwch[ulWcharLength] = 0;
  927. } else {
  928. Status = STATUS_BUFFER_TOO_SMALL;
  929. }
  930. }
  931. } else {
  932. // No root directory, they specified the entire path
  933. pwch = pObjectAttr->ObjectName->Buffer;
  934. //Make sure it is zero terminated
  935. pwch[pObjectAttr->ObjectName->Length / sizeof(WCHAR)] = 0;
  936. }
  937. // Make sure the path will fit in the buffer
  938. if ((Status == STATUS_SUCCESS) &&
  939. (wcslen(pwch)*sizeof(WCHAR) < ulbuflen)) {
  940. wcscpy(pUserPath, pwch);
  941. } else {
  942. Status = STATUS_BUFFER_TOO_SMALL;
  943. }
  944. if (pBuffer) {
  945. RtlFreeHeap(RtlProcessHeap(), 0, pBuffer);
  946. }
  947. return(Status);
  948. }
  949. /*****************************************************************************
  950. *
  951. * TermsrvGetInstallPath
  952. *
  953. * From the path to the user entry in the registry, get the path to the
  954. * entry in the default install section.
  955. *
  956. * ENTRY:
  957. * IN PWCHAR pUserPath: Ptr to path of key in user section
  958. * IN PWCHAR *ppInstPath: Ptr to ptr to return path of key in install section
  959. *
  960. * NOTES:
  961. * Caller must use RtlFreeHeap to free memory allocated for ppInstPath!
  962. *
  963. * EXIT:
  964. * NTSTATUS return code
  965. *
  966. ****************************************************************************/
  967. NTSTATUS TermsrvGetInstallPath(IN PWCHAR pUserPath,
  968. IN PWCHAR *ppInstPath)
  969. {
  970. NTSTATUS Status = STATUS_NO_SUCH_FILE;
  971. PWCHAR pwch = NULL;
  972. BOOL fUserReg;
  973. BOOL bClassesKey = FALSE;
  974. *ppInstPath = NULL;
  975. // Check if the app is accessing the user or local machine section
  976. pwch = GetUserSWKey(pUserPath, &fUserReg, &bClassesKey);
  977. // Copy the path to the user's buffer
  978. if (pwch || bClassesKey)
  979. {
  980. ULONG ulInstBufLen = ( wcslen(TERMSRV_INSTALL) + wcslen(SOFTWARE_PATH) + wcslen(CLASSES_PATH) + 1 )*sizeof(WCHAR);
  981. if (pwch)
  982. ulInstBufLen += wcslen(pwch) * sizeof(WCHAR);
  983. *ppInstPath = RtlAllocateHeap(RtlProcessHeap(),
  984. 0,
  985. ulInstBufLen);
  986. if(*ppInstPath) {
  987. wcscpy(*ppInstPath, TERMSRV_INSTALL);
  988. if (bClassesKey)
  989. {
  990. wcscat(*ppInstPath, SOFTWARE_PATH);
  991. wcscat(*ppInstPath, CLASSES_PATH);
  992. }
  993. if (pwch)
  994. wcscat(*ppInstPath, pwch);
  995. Status = STATUS_SUCCESS;
  996. } else {
  997. Status = STATUS_NO_MEMORY;
  998. }
  999. }
  1000. return(Status);
  1001. }
  1002. /*****************************************************************************
  1003. *
  1004. * TermsrvCreateKey
  1005. *
  1006. * This routine will create (or open) the specified path in the registry.
  1007. * If the path doesn't exist in the registry, it will be created.
  1008. *
  1009. * ENTRY:
  1010. * PWCHAR pSrcPath: Source path to copy keys from (optional)
  1011. * PWCHAR pDstPath: Destination path to create
  1012. * BOOL fCloneValues: TRUE means to clone all values under this key
  1013. * BOOL fCloneSubKeys: TRUE means to create all subkeys under this key
  1014. * PHANDLE phKey: Pointer for key created
  1015. *
  1016. * EXIT:
  1017. * NTSTATUS return code
  1018. *
  1019. ****************************************************************************/
  1020. NTSTATUS TermsrvCreateKey(IN PWCHAR pSrcPath,
  1021. IN PWCHAR pDstPath,
  1022. BOOL fCloneValues,
  1023. BOOL fCloneSubKeys,
  1024. OUT PHANDLE phKey)
  1025. {
  1026. NTSTATUS Status;
  1027. PWCHAR pSource = NULL, pDest = NULL;
  1028. HANDLE hDstKey, hDstRoot, hSrcKey, hSrcRoot;
  1029. ULONG ultemp, NumSubKeys, ulcnt, ulbufsize, ulkey;
  1030. UNICODE_STRING UniString, UniClass;
  1031. OBJECT_ATTRIBUTES ObjectAttr;
  1032. PKEY_FULL_INFORMATION pDefKeyInfo = NULL;
  1033. ULONG aulbuf[4];
  1034. PKEY_VALUE_PARTIAL_INFORMATION pValKeyInfo =
  1035. (PKEY_VALUE_PARTIAL_INFORMATION)aulbuf;
  1036. BOOL fClassesKey = FALSE, fUserReg;
  1037. // Check if we are trying to copy values into the user's registry
  1038. pDest = GetUserSWKey(pDstPath, &fUserReg, NULL);
  1039. if (fUserReg) {
  1040. if (fCloneValues || fCloneSubKeys) {
  1041. // Skip to software section of the default install user
  1042. pSource = pSrcPath + wcslen(TERMSRV_INSTALL);
  1043. // If copying CLASSES, set Clone to FALSE so don't clone
  1044. // until we're at the CLASSES key
  1045. // Actually, this func is not called for copying classes, I belive that feature is/was
  1046. // turned off in W2K, which means that any time this func is called, we for sure are
  1047. // dealing with either HKCU\SW or HKLM, but never HKCU\SW\Clasess.
  1048. // Nov 30, 2000
  1049. //
  1050. if (pDest)
  1051. {
  1052. if (!_wcsnicmp(pDest,
  1053. TERMSRV_SOFTWARECLASSES,
  1054. wcslen(TERMSRV_SOFTWARECLASSES))) {
  1055. fClassesKey = TRUE;
  1056. fCloneValues = fCloneSubKeys = FALSE;
  1057. }
  1058. }
  1059. }
  1060. // Trying to copy to citrix install section?
  1061. } else if (!_wcsnicmp(pDstPath,
  1062. TERMSRV_INSTALL,
  1063. wcslen(TERMSRV_INSTALL))) {
  1064. // Skip to software section of the default install user
  1065. pDest = pDstPath + wcslen(TERMSRV_INSTALL);
  1066. // If copying from MACHINE\..\CLASSES, set Clone values to FALSE
  1067. // so we don't clone until we're at the CLASSES key.
  1068. if (pSrcPath && !_wcsnicmp(pSrcPath,
  1069. TERMSRV_CLASSES,
  1070. wcslen(TERMSRV_CLASSES))) {
  1071. fClassesKey = TRUE;
  1072. pSource = Ctxwcsistr(pSrcPath, SOFTWARE_PATH);
  1073. fCloneValues = fCloneSubKeys = FALSE;
  1074. }
  1075. // If we're cloning, set up the source path
  1076. else if (fCloneValues || fCloneSubKeys) {
  1077. // Is this from the user section?
  1078. pSource = GetUserSWKey(pSrcPath, &fUserReg, NULL);
  1079. // Must be from the local machine section
  1080. if (!fUserReg) {
  1081. pSource = Ctxwcsistr(pSrcPath, L"\\machine");
  1082. }
  1083. }
  1084. }
  1085. // Make sure the paths are valid
  1086. if (!pDest || ((fCloneValues || fCloneSubKeys) && !pSource)) {
  1087. return(STATUS_NO_SUCH_FILE);
  1088. }
  1089. // Initialize the number of subkeys to be created
  1090. NumSubKeys = 1;
  1091. while ((pDest = wcschr(pDest, L'\\')) != NULL) {
  1092. *pDest = L'\0';
  1093. pDest++;
  1094. NumSubKeys++;
  1095. }
  1096. // If we need to clone values or keys from the source path, get the
  1097. // buffers we'll need, and tokenize the source path
  1098. if (fCloneValues || fCloneSubKeys || fClassesKey) {
  1099. // Allocate a buffer for the class of the source key
  1100. ulbufsize = sizeof(KEY_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR);
  1101. pDefKeyInfo = RtlAllocateHeap(RtlProcessHeap(),
  1102. 0,
  1103. ulbufsize);
  1104. if (pDefKeyInfo) {
  1105. while ((pSource = wcschr(pSource, L'\\')) != NULL) {
  1106. *pSource = L'\0';
  1107. pSource++;
  1108. }
  1109. pSource = pSrcPath;
  1110. } else {
  1111. fCloneValues = fCloneSubKeys = fClassesKey = FALSE;
  1112. }
  1113. }
  1114. hSrcRoot = hDstRoot = NULL;
  1115. pDest = pDstPath;
  1116. // Go through each key in the path, creating it if it doesn't exist
  1117. for (ulcnt = 0; ulcnt < NumSubKeys; ulcnt++) {
  1118. if ((*pDest == L'\0') &&
  1119. (ulcnt != NumSubKeys - 1)) {
  1120. pDest++;
  1121. pSource++;
  1122. continue;
  1123. }
  1124. // If we're at CLASSES key, we need to clone the whole key
  1125. else if (fClassesKey && !_wcsicmp(pDest, L"classes")) {
  1126. fCloneValues = fCloneSubKeys = TRUE;
  1127. }
  1128. // If we're copying values from the source, open up the source so we
  1129. // can get the values and subkeys
  1130. // Also need to check for ClassesKey cause we'll be cloning later and
  1131. // we need some setup done
  1132. if (fCloneValues || fCloneSubKeys || fClassesKey) {
  1133. // Set up the attribute structure for the source path
  1134. RtlInitUnicodeString(&UniString, pSource);
  1135. InitializeObjectAttributes(&ObjectAttr,
  1136. &UniString,
  1137. OBJ_CASE_INSENSITIVE,
  1138. hSrcRoot,
  1139. NULL);
  1140. // Open the source key
  1141. Status = NtOpenKey(&hSrcKey,
  1142. KEY_READ,
  1143. &ObjectAttr);
  1144. // Get the source key info and value
  1145. if (NT_SUCCESS(Status)) {
  1146. // Close the source root, if necessary
  1147. if (hSrcRoot) {
  1148. NtClose(hSrcRoot);
  1149. }
  1150. hSrcRoot = hSrcKey;
  1151. Status = NtQueryKey(hSrcKey,
  1152. KeyFullInformation,
  1153. pDefKeyInfo,
  1154. ulbufsize,
  1155. &ultemp);
  1156. if (NT_SUCCESS(Status)) {
  1157. RtlInitUnicodeString(&UniString, TERMSRV_COPYONCEFLAG);
  1158. Status = NtQueryValueKey(hSrcKey,
  1159. &UniString,
  1160. KeyValuePartialInformation,
  1161. pValKeyInfo,
  1162. sizeof(aulbuf),
  1163. &ultemp);
  1164. if (NT_SUCCESS(Status) && (pValKeyInfo->Data)) {
  1165. break;
  1166. }
  1167. }
  1168. } else {
  1169. break;
  1170. }
  1171. // Setup the unicode string for the class
  1172. if ( pDefKeyInfo->ClassLength ) {
  1173. pDefKeyInfo->Class[pDefKeyInfo->ClassLength/sizeof(WCHAR)] = UNICODE_NULL;
  1174. RtlInitUnicodeString(&UniClass, pDefKeyInfo->Class );
  1175. } else
  1176. RtlInitUnicodeString(&UniClass, NULL);
  1177. // Advance to the next key
  1178. pSource += wcslen( pSource ) + 1;
  1179. } else {
  1180. // Set the class to NULL
  1181. RtlInitUnicodeString(&UniClass, NULL);
  1182. }
  1183. // Set up the attribute structure for the destination
  1184. RtlInitUnicodeString(&UniString, pDest);
  1185. InitializeObjectAttributes(&ObjectAttr,
  1186. &UniString,
  1187. OBJ_CASE_INSENSITIVE,
  1188. hDstRoot,
  1189. NULL);
  1190. // Open/Create the destination key
  1191. Status = NtCreateKey(&hDstKey,
  1192. MAXIMUM_ALLOWED,
  1193. &ObjectAttr,
  1194. 0,
  1195. &UniClass,
  1196. REG_OPTION_NON_VOLATILE,
  1197. &ultemp);
  1198. // If the key was created (NOT opened) copy the values and subkeys
  1199. if (NT_SUCCESS(Status) &&
  1200. ((ultemp == REG_CREATED_NEW_KEY) &&
  1201. (fCloneSubKeys || fCloneValues))) {
  1202. Status = TermsrvCloneKey(hSrcKey,
  1203. hDstKey,
  1204. pDefKeyInfo,
  1205. fCloneSubKeys);
  1206. }
  1207. // Close the intermediate key.
  1208. if( hDstRoot != NULL ) {
  1209. NtClose( hDstRoot );
  1210. }
  1211. // Initialize the next object directory (i.e. parent key)
  1212. hDstRoot = hDstKey;
  1213. // If creating the key failed, break out of the loop
  1214. if( !NT_SUCCESS( Status )) {
  1215. break;
  1216. }
  1217. pDest += wcslen( pDest ) + 1;
  1218. }
  1219. // Close the source root, if necessary
  1220. if (hSrcRoot) {
  1221. NtClose(hSrcRoot);
  1222. }
  1223. if ( !NT_SUCCESS( Status ) && hDstRoot) {
  1224. NtClose(hDstRoot);
  1225. hDstKey = NULL;
  1226. }
  1227. if (pDefKeyInfo) {
  1228. RtlFreeHeap(RtlProcessHeap(), 0, pDefKeyInfo);
  1229. }
  1230. *phKey = hDstKey;
  1231. return(Status);
  1232. }
  1233. /*****************************************************************************
  1234. *
  1235. * TermsrvCloneKey
  1236. *
  1237. * This routine will recursively create (or open) the specified path in the
  1238. * registry. If the path doesn't exist in the registry, it will be created.
  1239. *
  1240. * ENTRY:
  1241. * HANDLE hSrcKey: Handle for source key
  1242. * HANDLE hDstKey: Handle for destination key
  1243. * PKEY_FULL_INFORMATION pDefKeyInfo: Ptr to key info structure of source
  1244. * BOOL fCreateSubKeys: TRUE means to recursively clone subkeys
  1245. *
  1246. * EXIT:
  1247. * NTSTATUS return code
  1248. *
  1249. ****************************************************************************/
  1250. NTSTATUS TermsrvCloneKey(HANDLE hSrcKey,
  1251. HANDLE hDstKey,
  1252. PKEY_FULL_INFORMATION pDefKeyInfo,
  1253. BOOL fCreateSubKeys)
  1254. {
  1255. NTSTATUS Status = STATUS_SUCCESS;
  1256. ULONG ulbufsize, ultemp, ulkey, ulcursize;
  1257. UNICODE_STRING UniString, UniClass;
  1258. OBJECT_ATTRIBUTES ObjectAttr;
  1259. PKEY_NODE_INFORMATION pKeyNodeInfo;
  1260. PKEY_VALUE_FULL_INFORMATION pKeyValInfo;
  1261. PKEY_VALUE_BASIC_INFORMATION pKeyCurInfo;
  1262. PKEY_FULL_INFORMATION pKeyNewInfo;
  1263. HANDLE hNewDst, hNewSrc;
  1264. SECURITY_DESCRIPTOR SecDesc;
  1265. #ifdef CLONE_SECURITY
  1266. // Get the security access for the source key
  1267. Status = NtQuerySecurityObject(hSrcKey,
  1268. OWNER_SECURITY_INFORMATION |
  1269. GROUP_SECURITY_INFORMATION |
  1270. DACL_SECURITY_INFORMATION |
  1271. SACL_SECURITY_INFORMATION,
  1272. &SecDesc,
  1273. sizeof(SecDesc),
  1274. &ultemp);
  1275. // Set the security access for the destination key
  1276. if (NT_SUCCESS(Status)) {
  1277. Status = NtSetSecurityObject(hDstKey,
  1278. OWNER_SECURITY_INFORMATION |
  1279. GROUP_SECURITY_INFORMATION |
  1280. DACL_SECURITY_INFORMATION |
  1281. SACL_SECURITY_INFORMATION,
  1282. &SecDesc);
  1283. }
  1284. #endif
  1285. // Create the values for this key
  1286. if (pDefKeyInfo->Values) {
  1287. ulbufsize = sizeof(KEY_VALUE_FULL_INFORMATION) +
  1288. (pDefKeyInfo->MaxValueNameLen + 1)*sizeof(WCHAR) +
  1289. pDefKeyInfo->MaxValueDataLen;
  1290. pKeyValInfo = RtlAllocateHeap(RtlProcessHeap(),
  1291. 0,
  1292. ulbufsize);
  1293. // Get a buffer to hold current value of the key (for existance check)
  1294. ulcursize = sizeof(KEY_VALUE_BASIC_INFORMATION) +
  1295. (pDefKeyInfo->MaxNameLen + 1)*sizeof(WCHAR);
  1296. pKeyCurInfo = RtlAllocateHeap(RtlProcessHeap(),
  1297. 0,
  1298. ulcursize);
  1299. if (pKeyValInfo && pKeyCurInfo) {
  1300. for (ulkey = 0; ulkey < pDefKeyInfo->Values; ulkey++) {
  1301. Status = NtEnumerateValueKey(hSrcKey,
  1302. ulkey,
  1303. KeyValueFullInformation,
  1304. pKeyValInfo,
  1305. ulbufsize,
  1306. &ultemp);
  1307. // If successful and this isn't our "copy once" flag, copy
  1308. // the value to the user's keys
  1309. if (NT_SUCCESS(Status) &&
  1310. (wcsncmp(pKeyValInfo->Name, TERMSRV_COPYONCEFLAG,
  1311. sizeof(TERMSRV_COPYONCEFLAG)/sizeof(WCHAR)-1))) {
  1312. UniString.Buffer = pKeyValInfo->Name;
  1313. UniString.Length = (USHORT)pKeyValInfo->NameLength;
  1314. UniString.MaximumLength = UniString.Length + 2;
  1315. // Check if the value exists
  1316. Status = NtQueryValueKey(hDstKey,
  1317. &UniString,
  1318. KeyValueBasicInformation,
  1319. pKeyCurInfo,
  1320. ulcursize,
  1321. &ultemp);
  1322. // Value doesn't exist, go ahead and create it
  1323. if (!NT_SUCCESS(Status)) {
  1324. Status = NtSetValueKey(hDstKey,
  1325. &UniString,
  1326. 0,
  1327. pKeyValInfo->Type,
  1328. (PCHAR)pKeyValInfo +
  1329. pKeyValInfo->DataOffset,
  1330. pKeyValInfo->DataLength);
  1331. }
  1332. }
  1333. }
  1334. RtlFreeHeap(RtlProcessHeap(), 0, pKeyValInfo);
  1335. RtlFreeHeap(RtlProcessHeap(), 0, pKeyCurInfo);
  1336. } else {
  1337. if (pKeyValInfo) {
  1338. RtlFreeHeap(RtlProcessHeap(), 0, pKeyValInfo);
  1339. }
  1340. Status = STATUS_NO_MEMORY;
  1341. }
  1342. }
  1343. // If requested, create all of the child keys
  1344. if (fCreateSubKeys && pDefKeyInfo->SubKeys) {
  1345. // Allocate a buffer to get name and class of key to create
  1346. ulbufsize = sizeof(KEY_NODE_INFORMATION) + 2*MAX_PATH*sizeof(WCHAR);
  1347. pKeyNodeInfo = RtlAllocateHeap(RtlProcessHeap(),
  1348. 0,
  1349. ulbufsize);
  1350. // Allocate a buffer for subkey info
  1351. ulbufsize = sizeof(KEY_FULL_INFORMATION) + MAX_PATH*sizeof(WCHAR);
  1352. pKeyNewInfo = RtlAllocateHeap(RtlProcessHeap(),
  1353. 0,
  1354. ulbufsize);
  1355. if (pKeyNodeInfo && pKeyNewInfo) {
  1356. for (ulkey = 0; ulkey < pDefKeyInfo->SubKeys; ulkey++) {
  1357. Status = NtEnumerateKey(hSrcKey,
  1358. ulkey,
  1359. KeyNodeInformation,
  1360. pKeyNodeInfo,
  1361. ulbufsize,
  1362. &ultemp);
  1363. if (NT_SUCCESS(Status)) {
  1364. // Init the unicode string for the class
  1365. UniClass.Buffer = (PWCHAR)((PCHAR)pKeyNodeInfo +
  1366. pKeyNodeInfo->ClassOffset);
  1367. UniClass.Length = (USHORT)pKeyNodeInfo->ClassLength;
  1368. UniClass.MaximumLength = UniString.Length + 2;
  1369. // Init the unicode string for the name
  1370. UniString.Buffer = pKeyNodeInfo->Name;
  1371. UniString.Length = (USHORT)pKeyNodeInfo->NameLength;
  1372. UniString.MaximumLength = UniString.Length + 2;
  1373. InitializeObjectAttributes(&ObjectAttr,
  1374. &UniString,
  1375. OBJ_CASE_INSENSITIVE,
  1376. hDstKey,
  1377. NULL);
  1378. Status = NtCreateKey(&hNewDst,
  1379. MAXIMUM_ALLOWED,
  1380. &ObjectAttr,
  1381. 0,
  1382. &UniClass,
  1383. REG_OPTION_NON_VOLATILE,
  1384. &ultemp);
  1385. if (NT_SUCCESS(Status)) {
  1386. InitializeObjectAttributes(&ObjectAttr,
  1387. &UniString,
  1388. OBJ_CASE_INSENSITIVE,
  1389. hSrcKey,
  1390. NULL);
  1391. Status = NtOpenKey(&hNewSrc,
  1392. KEY_READ,
  1393. &ObjectAttr);
  1394. // Get the key info
  1395. if (NT_SUCCESS(Status)) {
  1396. Status = NtQueryKey(hNewSrc,
  1397. KeyFullInformation,
  1398. pKeyNewInfo,
  1399. ulbufsize,
  1400. &ultemp);
  1401. if (NT_SUCCESS(Status) &&
  1402. (pKeyNewInfo->SubKeys ||
  1403. pKeyNewInfo->Values)) {
  1404. Status = TermsrvCloneKey(hNewSrc,
  1405. hNewDst,
  1406. pKeyNewInfo,
  1407. TRUE);
  1408. }
  1409. NtClose(hNewSrc);
  1410. }
  1411. NtClose(hNewDst);
  1412. }
  1413. }
  1414. }
  1415. RtlFreeHeap(RtlProcessHeap(), 0, pKeyNodeInfo);
  1416. RtlFreeHeap(RtlProcessHeap(), 0, pKeyNewInfo);
  1417. } else {
  1418. if (pKeyNodeInfo) {
  1419. RtlFreeHeap(RtlProcessHeap(), 0, pKeyNodeInfo);
  1420. }
  1421. Status = STATUS_NO_MEMORY;
  1422. }
  1423. }
  1424. return(Status);
  1425. }
  1426. /*****************************************************************************
  1427. *
  1428. * Ctxwcsistr
  1429. *
  1430. * This is a case insensitive version of wcsstr.
  1431. *
  1432. * ENTRY:
  1433. * PWCHAR pstring1 (In) - String to search in
  1434. * PWCHAR pstring2 (In) - String to search for
  1435. *
  1436. * EXIT:
  1437. * Success:
  1438. * pointer to substring
  1439. * Failure:
  1440. * NULL
  1441. *
  1442. ****************************************************************************/
  1443. PWCHAR
  1444. Ctxwcsistr(PWCHAR pstring1,
  1445. PWCHAR pstring2)
  1446. {
  1447. PWCHAR pch, ps1, ps2;
  1448. pch = pstring1;
  1449. while (*pch)
  1450. {
  1451. ps1 = pch;
  1452. ps2 = pstring2;
  1453. while (*ps1 && *ps2 && !(towupper(*ps1) - towupper(*ps2))) {
  1454. ps1++;
  1455. ps2++;
  1456. }
  1457. if (!*ps2) {
  1458. return(pch);
  1459. }
  1460. pch++;
  1461. }
  1462. return(NULL);
  1463. }
  1464. /*****************************************************************************
  1465. *
  1466. * IsSystemLUID
  1467. *
  1468. * This routines checks if we are running under the system context, and if
  1469. * so returns false. We want all of the registry mapping support disable
  1470. * for system services.
  1471. *
  1472. * Note we don't check the thread's token, so impersonation doesn't work.
  1473. *
  1474. * ENTRY:
  1475. *
  1476. * EXIT:
  1477. * TRUE:
  1478. * Called from within system context
  1479. * FALSE:
  1480. * Regular context
  1481. *
  1482. ****************************************************************************/
  1483. #define SIZE_OF_STATISTICS_TOKEN_INFORMATION \
  1484. sizeof( TOKEN_STATISTICS )
  1485. BOOL IsSystemLUID(VOID)
  1486. {
  1487. HANDLE TokenHandle;
  1488. UCHAR TokenInformation[ SIZE_OF_STATISTICS_TOKEN_INFORMATION ];
  1489. ULONG ReturnLength;
  1490. static LUID CurrentLUID = { 0, 0 };
  1491. LUID SystemLUID = SYSTEM_LUID;
  1492. if ( CurrentLUID.LowPart == 0 && CurrentLUID.HighPart == 0 ) {
  1493. if ( !OpenProcessToken( GetCurrentProcess(),
  1494. TOKEN_READ,
  1495. &TokenHandle ))
  1496. {
  1497. return(TRUE);
  1498. }
  1499. if ( !GetTokenInformation( TokenHandle,
  1500. TokenStatistics,
  1501. TokenInformation,
  1502. sizeof( TokenInformation ),
  1503. &ReturnLength ))
  1504. {
  1505. return(TRUE);
  1506. }
  1507. CloseHandle( TokenHandle );
  1508. RtlCopyLuid(&CurrentLUID,
  1509. &(((PTOKEN_STATISTICS)TokenInformation)->AuthenticationId));
  1510. }
  1511. if (RtlEqualLuid(&CurrentLUID, &SystemLUID)) {
  1512. return(TRUE);
  1513. } else {
  1514. return(FALSE );
  1515. }
  1516. }
  1517. /*****************************************************************************
  1518. *
  1519. * TermsrvLogRegInstallTime
  1520. *
  1521. * This routines updates the LatestRegistryKey value in the registry to
  1522. * contain the current time.
  1523. *
  1524. * ENTRY:
  1525. *
  1526. * EXIT:
  1527. * No return value
  1528. *
  1529. ****************************************************************************/
  1530. void TermsrvLogRegInstallTime()
  1531. {
  1532. UNICODE_STRING UniString;
  1533. HANDLE hKey;
  1534. FILETIME FileTime;
  1535. ULONG ultmp;
  1536. NTSTATUS Status;
  1537. WCHAR wcbuff[MAX_PATH];
  1538. // Open up the registry key to store the last write time of the file
  1539. wcscpy(wcbuff, TERMSRV_INIFILE_TIMES);
  1540. // Create or open the path to the IniFile Times key
  1541. Status = TermsrvCreateKey(NULL,
  1542. wcbuff,
  1543. FALSE,
  1544. FALSE,
  1545. &hKey);
  1546. // Opened up the registry key, now set the value to the current time
  1547. if (NT_SUCCESS(Status)) {
  1548. GetSystemTimeAsFileTime(&FileTime);
  1549. RtlTimeToSecondsSince1970((PLARGE_INTEGER)&FileTime,
  1550. &ultmp);
  1551. RtlInitUnicodeString(&UniString,
  1552. INIFILE_TIMES_LATESTREGISTRYKEY);
  1553. // Now store it under the citrix key in the registry
  1554. Status = NtSetValueKey(hKey,
  1555. &UniString,
  1556. 0,
  1557. REG_DWORD,
  1558. &ultmp,
  1559. sizeof(ultmp));
  1560. // Close the registry key
  1561. NtClose(hKey);
  1562. }
  1563. }
  1564. /*****************************************************************************
  1565. *
  1566. * TermsrvOpenUserClasses
  1567. *
  1568. * If the system is in execute mode, open \SOFTWARE\CLASSES key under
  1569. * HKEY_CURRENT_USER. If CLASSES doesen't exist under TERMSRV\INSTALL
  1570. * or HKEY_CURRENT_USER, copy it from \MACHINE\SOFTWARE\CLASSES.
  1571. *
  1572. * ENTRY:
  1573. * IN ACCESS_MASK DesiredAccess:
  1574. * Desired access to the key
  1575. * OUT PHANDLE phKey:
  1576. * Pointer to return key handle if opened
  1577. *
  1578. * EXIT:
  1579. * NT_STATUS return code
  1580. *
  1581. ****************************************************************************/
  1582. BOOL TermsrvOpenUserClasses(IN ACCESS_MASK DesiredAccess,
  1583. OUT PHANDLE pUserhKey)
  1584. {
  1585. NTSTATUS Status;
  1586. ULONG ultemp;
  1587. ULONG ulAppType = TERMSRV_COMPAT_WIN32;
  1588. HKEY hDstKey;
  1589. WCHAR wcbuff[MAX_PATH],wcClassbuff[TERMSRV_CLASSES_SIZE];
  1590. PWCHAR pUserPath;
  1591. OBJECT_ATTRIBUTES Obja;
  1592. UNICODE_STRING UniString;
  1593. // set return handle to 0 cause OpenClassesRoot checks it
  1594. *pUserhKey = 0;
  1595. //Disable it for now
  1596. return(STATUS_NO_SUCH_FILE);
  1597. // If called under a system service or in install mode, return
  1598. if ( IsSystemLUID() || TermsrvAppInstallMode() ) {
  1599. return(STATUS_NO_SUCH_FILE);
  1600. }
  1601. // If mapping is on, but disabled for CLASSES, return
  1602. GetTermsrCompatFlags(TERMSRV_CLASSES, &ultemp, CompatibilityRegEntry);
  1603. if ((ultemp & (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) ==
  1604. (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) {
  1605. return(STATUS_NO_SUCH_FILE);
  1606. }
  1607. // Open MACHINE\SOFTWARE\CLASSES key
  1608. RtlInitUnicodeString(&UniString, TERMSRV_CLASSES);
  1609. InitializeObjectAttributes(
  1610. &Obja,
  1611. &UniString,
  1612. OBJ_CASE_INSENSITIVE,
  1613. NULL,
  1614. NULL
  1615. );
  1616. Status = NtOpenKey(&hDstKey,
  1617. KEY_READ,
  1618. &Obja);
  1619. if (!NT_SUCCESS(Status)) {
  1620. return(STATUS_NO_SUCH_FILE);
  1621. }
  1622. NtClose(hDstKey);
  1623. // Need to put this in buffer cause CtxCreateKey modifies the string.
  1624. wcscpy(wcClassbuff, TERMSRV_CLASSES);
  1625. // Try to open TERMSRV\INSTALL\SOFTWARE\CLASSES; if it doesn't exist,
  1626. // clone it from MACHINE\SOFTWARE\CLASSES.
  1627. wcscpy(wcbuff, TERMSRV_INSTALLCLASSES);
  1628. Status = TermsrvCreateKey(wcClassbuff,
  1629. wcbuff,
  1630. TRUE,
  1631. TRUE,
  1632. &hDstKey);
  1633. if (NT_SUCCESS(Status)) {
  1634. NtClose(hDstKey);
  1635. }
  1636. // Try to open HKEY_CURRENT_USER\SOFTWARE\CLASSES; if it doesn't exist,
  1637. // clone it from TERMSRV\INSTALL\SOFTWARE\CLASSES.
  1638. Status = RtlOpenCurrentUser( DesiredAccess, pUserhKey );
  1639. if (NT_SUCCESS(Status)) {
  1640. ultemp = sizeof(WCHAR)*MAX_PATH;
  1641. Status = TermsrvGetRegPath(*pUserhKey,
  1642. NULL,
  1643. (PWCHAR)&wcbuff,
  1644. ultemp);
  1645. NtClose(*pUserhKey);
  1646. if (NT_SUCCESS(Status)) {
  1647. wcscat(wcbuff, TERMSRV_SOFTWARECLASSES);
  1648. wcscpy(wcClassbuff, TERMSRV_INSTALLCLASSES);
  1649. Status = TermsrvCreateKey(wcClassbuff,
  1650. wcbuff,
  1651. TRUE,
  1652. TRUE,
  1653. pUserhKey);
  1654. }
  1655. }
  1656. return(Status);
  1657. }
  1658. /*****************************************************************************
  1659. *
  1660. * TermsrvGetPreSetValue
  1661. *
  1662. * Get any preset value during install.
  1663. *
  1664. * ENTRY:
  1665. *
  1666. * IN HANDLE hKey: Key user wants to set
  1667. * IN PUNICODE_STRING pValueName: Value name user wants to set
  1668. * IN ULONG Type: Type of value
  1669. * OUT PVOID *Data: Pre-set data
  1670. * OUT PULONG DataSize: Size of preset data
  1671. *
  1672. * NOTES:
  1673. *
  1674. * EXIT:
  1675. * NTSTATUS return code
  1676. *
  1677. ****************************************************************************/
  1678. NTSTATUS TermsrvGetPreSetValue( IN HANDLE hKey,
  1679. IN PUNICODE_STRING pValueName,
  1680. IN ULONG Type,
  1681. OUT PVOID *Data
  1682. )
  1683. {
  1684. #define DEFAULT_VALUE_SIZE 128
  1685. NTSTATUS Status = STATUS_NO_SUCH_FILE;
  1686. PWCHAR pwch = NULL;
  1687. WCHAR pUserPath[MAX_PATH];
  1688. WCHAR ValuePath[2 * MAX_PATH];
  1689. ULONG ultemp;
  1690. UNICODE_STRING UniString;
  1691. OBJECT_ATTRIBUTES Obja;
  1692. ULONG BufferLength;
  1693. PVOID KeyValueInformation;
  1694. ULONG ResultLength;
  1695. HANDLE hValueKey;
  1696. BOOL fUserReg;
  1697. // If running in execute mode, return
  1698. if ( !TermsrvAppInstallMode() ) {
  1699. return(STATUS_NO_SUCH_FILE);
  1700. }
  1701. ultemp = sizeof(WCHAR)*MAX_PATH;
  1702. // Get the path of this key
  1703. Status = TermsrvGetRegPath(hKey,
  1704. NULL,
  1705. pUserPath,
  1706. ultemp);
  1707. if (!NT_SUCCESS(Status))
  1708. return Status;
  1709. // Check if the app is accessing the local machine section
  1710. // or the user section.
  1711. pwch = GetUserSWKey(pUserPath, &fUserReg, NULL);
  1712. if (!fUserReg) {
  1713. if (!_wcsnicmp(pUserPath,
  1714. TERMSRV_VALUE,
  1715. wcslen(TERMSRV_VALUE))) {
  1716. Status = STATUS_NO_SUCH_FILE;
  1717. return Status;
  1718. } else if (!_wcsnicmp(pUserPath,
  1719. TERMSRV_MACHINEREGISTRY,
  1720. wcslen(TERMSRV_MACHINEREGISTRY))) {
  1721. pwch = Ctxwcsistr(pUserPath, L"\\machine");
  1722. } else {
  1723. Status = STATUS_NO_SUCH_FILE;
  1724. return Status;
  1725. }
  1726. }
  1727. if ( pwch == NULL )
  1728. {
  1729. Status = STATUS_NO_SUCH_FILE;
  1730. return Status;
  1731. }
  1732. // Get the path to the preset value section
  1733. wcscpy(ValuePath, TERMSRV_VALUE);
  1734. wcscat(ValuePath, pwch);
  1735. // Open Value key
  1736. RtlInitUnicodeString(&UniString, ValuePath);
  1737. InitializeObjectAttributes(
  1738. &Obja,
  1739. &UniString,
  1740. OBJ_CASE_INSENSITIVE,
  1741. NULL,
  1742. NULL
  1743. );
  1744. Status = NtOpenKey(&hValueKey,
  1745. KEY_READ,
  1746. &Obja);
  1747. if (!NT_SUCCESS(Status)) {
  1748. return(STATUS_NO_SUCH_FILE);
  1749. }
  1750. // Allocate space for the "new" value
  1751. BufferLength = DEFAULT_VALUE_SIZE + sizeof( KEY_VALUE_PARTIAL_INFORMATION );
  1752. KeyValueInformation = RtlAllocateHeap( RtlProcessHeap( ), 0, BufferLength );
  1753. if ( !KeyValueInformation ) {
  1754. NtClose(hValueKey);
  1755. return STATUS_NO_MEMORY;
  1756. }
  1757. Status = NtQueryValueKey( hValueKey,
  1758. pValueName,
  1759. KeyValuePartialInformation,
  1760. KeyValueInformation,
  1761. BufferLength,
  1762. &ResultLength
  1763. );
  1764. // If we didn't allocate enough space, try again
  1765. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  1766. RtlFreeHeap(RtlProcessHeap(), 0, KeyValueInformation);
  1767. BufferLength = ResultLength;
  1768. KeyValueInformation = RtlAllocateHeap( RtlProcessHeap( ), 0,
  1769. BufferLength
  1770. );
  1771. if ( !KeyValueInformation ) {
  1772. NtClose(hValueKey);
  1773. return STATUS_NO_MEMORY;
  1774. }
  1775. //
  1776. // This one should succeed
  1777. //
  1778. Status = NtQueryValueKey( hValueKey,
  1779. pValueName,
  1780. KeyValuePartialInformation,
  1781. KeyValueInformation,
  1782. BufferLength,
  1783. &ResultLength
  1784. );
  1785. }
  1786. NtClose(hValueKey);
  1787. if (!NT_SUCCESS(Status)) {
  1788. Status = STATUS_NO_SUCH_FILE;
  1789. }
  1790. else
  1791. {
  1792. //
  1793. // Make sure the types match.
  1794. // If they do, return the new value.
  1795. //
  1796. if ( Type == (( PKEY_VALUE_PARTIAL_INFORMATION )
  1797. KeyValueInformation )->Type )
  1798. *Data = KeyValueInformation;
  1799. else
  1800. Status = STATUS_NO_SUCH_FILE;
  1801. }
  1802. return(Status);
  1803. }
  1804. /*****************************************************************************
  1805. *
  1806. * IsUserSWPath
  1807. *
  1808. * Determine if user is accessing registry key user \registry\user\xxx\software
  1809. *
  1810. * ENTRY:
  1811. *
  1812. * IN PWCHAR pPath: Registry path to check
  1813. * OUT PBOOL pUserReg: If this key is under registry\user
  1814. *
  1815. * NOTES:
  1816. *
  1817. * EXIT:
  1818. * Returns: pointer to \software key of user registry (or NULL if not
  1819. * user software key)
  1820. * pUserReg: TRUE if registry path is HKCU (\registry\user)
  1821. *
  1822. ****************************************************************************/
  1823. PWCHAR GetUserSWKey(PWCHAR pPath, PBOOL pUserReg, PBOOL bClassesKey)
  1824. {
  1825. PWCHAR pwch = NULL;
  1826. PWCHAR pwchClassesTest = NULL;
  1827. PWCHAR pwClassesKey = NULL;
  1828. ULONG ultemp = 0;
  1829. if (pUserReg)
  1830. *pUserReg = FALSE;
  1831. if (bClassesKey)
  1832. *bClassesKey = FALSE;
  1833. if (!pPath)
  1834. return NULL;
  1835. if (!_wcsnicmp(pPath,
  1836. TERMSRV_USERREGISTRY,
  1837. sizeof(TERMSRV_USERREGISTRY)/sizeof(WCHAR) - 1))
  1838. {
  1839. if (pUserReg)
  1840. *pUserReg = TRUE;
  1841. // Skip over first part of path + backslash
  1842. pwch = pPath + (sizeof(TERMSRV_USERREGISTRY)/sizeof(WCHAR));
  1843. if (pwch)
  1844. {
  1845. //First test for classes
  1846. if (wcschr(pwch, L'\\'))
  1847. pwchClassesTest = wcschr(pwch, L'\\') - sizeof(CLASSES_SUBSTRING)/sizeof(WCHAR) + 1;
  1848. else
  1849. pwchClassesTest = pwch + wcslen(pwch) - sizeof(CLASSES_SUBSTRING)/sizeof(WCHAR) + 1;
  1850. if (pwchClassesTest)
  1851. {
  1852. if (!_wcsnicmp(pwchClassesTest, CLASSES_SUBSTRING, sizeof(CLASSES_SUBSTRING)/sizeof(WCHAR) - 1))
  1853. {
  1854. ultemp = (sizeof(SOFTWARE_PATH) + sizeof(CLASSES_PATH) + wcslen(pwch) + 1) * sizeof(WCHAR);
  1855. pwClassesKey = RtlAllocateHeap(RtlProcessHeap(), 0, ultemp);
  1856. wcscpy(pwClassesKey, SOFTWARE_PATH);
  1857. wcscat(pwClassesKey, CLASSES_PATH);
  1858. // Skip over user sid
  1859. pwch = wcschr(pwch, L'\\');
  1860. if (pwch)
  1861. wcscat(pwClassesKey, pwch);
  1862. if (ExistsInOmissionList(pwClassesKey))
  1863. pwch = NULL;
  1864. else
  1865. {
  1866. if (bClassesKey)
  1867. *bClassesKey = TRUE;
  1868. }
  1869. if (pwClassesKey)
  1870. RtlFreeHeap(RtlProcessHeap(), 0, pwClassesKey);
  1871. return (pwch);
  1872. }
  1873. }
  1874. // Skip over user sid
  1875. pwch = wcschr(pwch, L'\\');
  1876. if (pwch)
  1877. {
  1878. if (_wcsnicmp(pwch, SOFTWARE_PATH, sizeof(SOFTWARE_PATH)/sizeof(WCHAR) - 1))
  1879. return NULL;
  1880. if (ExistsInOmissionList(pwch))
  1881. return NULL;
  1882. }
  1883. }
  1884. }
  1885. return(pwch);
  1886. }
  1887. /*****************************************************************************
  1888. *
  1889. * ExistsInOmissionList
  1890. *
  1891. * Determine whether the registry key exists in the list of registry values
  1892. * that should not be copied
  1893. *
  1894. * ENTRY:
  1895. *
  1896. * IN PWCHAR pPath: Registry path to check
  1897. *
  1898. *
  1899. * EXIT:
  1900. * Returns: True if the key matches one of those in the list
  1901. *
  1902. ****************************************************************************/
  1903. BOOL ExistsInOmissionList(PWCHAR pwch)
  1904. {
  1905. BOOL bExists = FALSE;
  1906. NTSTATUS Status;
  1907. HKEY hOmissionKey = NULL;
  1908. PKEY_FULL_INFORMATION pDefKeyInfo = NULL;
  1909. ULONG ultemp = 0;
  1910. // Get the key info
  1911. RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_ENTRIES, 0, KEY_READ, &hOmissionKey);
  1912. // Get a buffer for the key info
  1913. ultemp = sizeof(KEY_FULL_INFORMATION) + MAX_PATH * sizeof(WCHAR);
  1914. pDefKeyInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ultemp);
  1915. if (pDefKeyInfo)
  1916. {
  1917. Status = NtQueryKey(hOmissionKey,
  1918. KeyFullInformation,
  1919. pDefKeyInfo,
  1920. ultemp,
  1921. &ultemp);
  1922. }
  1923. else
  1924. Status = STATUS_NO_MEMORY;
  1925. if (NT_SUCCESS(Status))
  1926. bExists = ExistsInEnumeratedKeys(hOmissionKey, pDefKeyInfo, pwch);
  1927. if (pDefKeyInfo)
  1928. RtlFreeHeap(RtlProcessHeap(), 0, pDefKeyInfo);
  1929. return bExists;
  1930. }
  1931. /*****************************************************************************
  1932. *
  1933. * ExistsInEnumeratedKeys
  1934. *
  1935. * Determine whether the registry key exists in the list of registry
  1936. * values passed in thru the pDefKeyInfo structure
  1937. *
  1938. * ENTRY:
  1939. *
  1940. * IN HKEY hOmissionKey: Key containing the values against which to compare pwch
  1941. * IN PKEY_FULL_INFORMATION pDefKeyInfo: Structure containing information about
  1942. * the list of values against which
  1943. * to compare pwch
  1944. *
  1945. * IN PWCHAR pwch: Key to check against the list
  1946. *
  1947. *
  1948. * EXIT:
  1949. * Returns: True if the key matches one of those in the list
  1950. *
  1951. ****************************************************************************/
  1952. BOOL ExistsInEnumeratedKeys(HKEY hOmissionKey, PKEY_FULL_INFORMATION pDefKeyInfo, PWCHAR pwch)
  1953. {
  1954. BOOL bExists = FALSE;
  1955. PKEY_VALUE_BASIC_INFORMATION pKeyValInfo = NULL;
  1956. ULONG ulbufsize = 0;
  1957. ULONG ulkey = 0;
  1958. ULONG ultemp = 0;
  1959. if (!hOmissionKey || !pDefKeyInfo || !pwch)
  1960. return FALSE;
  1961. // Traverse the values for this key
  1962. if (pDefKeyInfo->Values)
  1963. {
  1964. ulbufsize = sizeof(KEY_VALUE_BASIC_INFORMATION) +
  1965. (pDefKeyInfo->MaxValueNameLen + 1) * sizeof(WCHAR) +
  1966. pDefKeyInfo->MaxValueDataLen;
  1967. pKeyValInfo = RtlAllocateHeap(RtlProcessHeap(), 0, ulbufsize);
  1968. // Get a buffer to hold current value of the key (for existence check)
  1969. if (pKeyValInfo)
  1970. {
  1971. for (ulkey = 0; ulkey < pDefKeyInfo->Values; ulkey++)
  1972. {
  1973. NtEnumerateValueKey(hOmissionKey,
  1974. ulkey,
  1975. KeyValueBasicInformation,
  1976. pKeyValInfo,
  1977. ulbufsize,
  1978. &ultemp);
  1979. if ((pwch + (sizeof(SOFTWARE_PATH)/sizeof(WCHAR))) && (pKeyValInfo->Name))
  1980. {
  1981. if (!_wcsnicmp(pwch + (sizeof(SOFTWARE_PATH)/sizeof(WCHAR)), pKeyValInfo->Name,
  1982. (pKeyValInfo->NameLength/sizeof(WCHAR))))
  1983. {
  1984. bExists = TRUE;
  1985. }
  1986. }
  1987. }
  1988. }
  1989. if (pKeyValInfo)
  1990. RtlFreeHeap(RtlProcessHeap(), 0, pKeyValInfo);
  1991. }
  1992. return bExists;
  1993. }
  1994. /*****************************************************************************
  1995. *
  1996. * TermsrvRemoveClassesKey
  1997. *
  1998. * Delete the classes key for the current user and then set a
  1999. * registry flag indicating that this has been done (we only
  2000. * want this to be done the first time the user logs in).
  2001. *
  2002. * ENTRY: None
  2003. *
  2004. *
  2005. *
  2006. * EXIT: True if the classes key was deleted (even if it was empty
  2007. * or didn't exist) and false otherwise
  2008. *
  2009. *
  2010. ****************************************************************************/
  2011. BOOL TermsrvRemoveClassesKey(LPTSTR sSid)
  2012. {
  2013. BOOL bDeletionPerformed = FALSE;
  2014. HKEY hPerformed;
  2015. HKEY hDeletionFlag;
  2016. ULONG ulFlagPathLen = 0;
  2017. PWCHAR pFlagPath = NULL;
  2018. ULONG ulClassesPathLen = 0;
  2019. PWCHAR pClassesPath = NULL;
  2020. if (!sSid)
  2021. return FALSE;
  2022. ulFlagPathLen = (wcslen(sSid) + wcslen(TERMSRV_APP_PATH) + wcslen(CLASSES_DELETED) + 1) * sizeof(WCHAR);
  2023. pFlagPath = RtlAllocateHeap(RtlProcessHeap(), 0, ulFlagPathLen);
  2024. if (pFlagPath)
  2025. {
  2026. wcscpy(pFlagPath, sSid);
  2027. wcscat(pFlagPath, TERMSRV_APP_PATH);
  2028. wcscat(pFlagPath, CLASSES_DELETED);
  2029. //Make sure the operation hasn't already been performed for this user
  2030. if (RegOpenKeyEx(HKEY_USERS, pFlagPath, 0, KEY_READ, &hPerformed) == ERROR_FILE_NOT_FOUND)
  2031. {
  2032. //It hasn't, so delete the software\classes key
  2033. ulClassesPathLen = (wcslen(TERMSRV_APP_PATH) + wcslen(SOFTWARE_PATH) + wcslen(CLASSES_PATH) + 1) * sizeof(WCHAR);
  2034. pClassesPath = RtlAllocateHeap(RtlProcessHeap(), 0, ulClassesPathLen);
  2035. if (pClassesPath)
  2036. {
  2037. wcscpy(pClassesPath, sSid);
  2038. wcscat(pClassesPath, SOFTWARE_PATH);
  2039. wcscat(pClassesPath, CLASSES_PATH);
  2040. SHDeleteKey(HKEY_USERS, pClassesPath);
  2041. RegCreateKeyEx(HKEY_USERS, pFlagPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hDeletionFlag, NULL);
  2042. RegCloseKey(hDeletionFlag);
  2043. bDeletionPerformed = TRUE;
  2044. }
  2045. if (pClassesPath)
  2046. RtlFreeHeap(RtlProcessHeap(), 0, pClassesPath);
  2047. }
  2048. else
  2049. RegCloseKey(hPerformed);
  2050. }
  2051. if (pFlagPath)
  2052. RtlFreeHeap(RtlProcessHeap(), 0, pFlagPath);
  2053. return bDeletionPerformed;
  2054. }