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.

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