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.

673 lines
19 KiB

  1. /******************************************************************************
  2. *
  3. * FILE.C
  4. *
  5. * This file contains routines based off the User Profile Editor utility.
  6. *
  7. * Copyright Citrix Systems, Inc. 1997
  8. * Copyright (c) 1998-1999 Microsoft Corporation
  9. *
  10. * Author: Brad Anderson 1/20/97
  11. *
  12. * $Log: M:\nt\private\utils\citrix\cprofile\VCS\file.c $
  13. *
  14. * Rev 1.3 Jun 26 1997 18:18:38 billm
  15. * move to WF40 tree
  16. *
  17. * Rev 1.2 23 Jun 1997 16:13:20 butchd
  18. * update
  19. *
  20. * Rev 1.1 28 Jan 1997 20:06:34 BradA
  21. * Fixed up some problems related to WF 2.0 changes
  22. *
  23. * Rev 1.0 27 Jan 1997 20:03:44 BradA
  24. * Initial Version
  25. *
  26. ******************************************************************************/
  27. /****************************** Module Header ******************************\
  28. * Module Name: upesave.c
  29. *
  30. * Copyright (c) 1992, Microsoft Corporation
  31. *
  32. * Handles OPening and saving of Profiles: default, system, current and user
  33. * profiles.
  34. *
  35. \***************************************************************************/
  36. #include "precomp.h"
  37. #pragma hdrstop
  38. #ifndef RC_INVOKED
  39. #include <winstaw.h>
  40. #include <syslib.h>
  41. #include <tsappcmp.h>
  42. #include <compatfl.h>
  43. #include <utilsub.h>
  44. #endif
  45. #include "cprofile.h"
  46. HKEY hkeyCurrentUser;
  47. PSID gSystemSid; // Initialized in 'InitializeGlobalSids'
  48. PSID gAdminsLocalGroup; // Initialized in 'InitializeGlobalSids
  49. SID_IDENTIFIER_AUTHORITY gNtAuthority = SECURITY_NT_AUTHORITY;
  50. #define SYSTEM_DEFAULT_SUBKEY TEXT(".DEFAULT")
  51. #define TEMP_USER_SUBKEY TEXT("TEMP_USER")
  52. #define TEMP_USER_HIVE_PATH TEXT("%systemroot%\\system32\\config\\")
  53. #define TEMP_SAVE_HIVE TEXT("%systemroot%\\system32\\config\\HiveSave")
  54. #define CITRIX_CLASSES L"\\Registry\\Machine\\Software\\Classes"
  55. LPTSTR lpTempUserHive = NULL;
  56. LPTSTR lpTempUserHivePath = NULL;
  57. LPTSTR lpTempHiveKey;
  58. extern TCHAR szDefExt[];
  59. extern PSID gSystemSid;
  60. BOOL AllocAndExpandEnvironmentStrings(LPTSTR String, LPTSTR *lpExpandedString);
  61. VOID GetRegistryKeyFromPath(LPTSTR lpPath, LPTSTR *lpKey);
  62. NTSTATUS
  63. CtxDeleteKeyTree( HANDLE hKeyRoot,
  64. PKEY_BASIC_INFORMATION pKeyInfo,
  65. ULONG ulInfoSize );
  66. PSECURITY_DESCRIPTOR GetSecurityInfo( LPTSTR File );
  67. void FreeSecurityInfo(PSECURITY_DESCRIPTOR);
  68. /***************************************************************************\
  69. * ClearTempUserProfile
  70. *
  71. * Purpose : unloads the temp user profile loaded from a file, and deletes
  72. * the temp file
  73. *
  74. * History:
  75. * 11-20-92 JohanneC Created.
  76. \***************************************************************************/
  77. BOOL APIENTRY ClearTempUserProfile()
  78. {
  79. BOOL bRet;
  80. if (hkeyCurrentUser == HKEY_CURRENT_USER)
  81. return(TRUE);
  82. //
  83. // Close registry keys.
  84. //
  85. if (hkeyCurrentUser) {
  86. RegCloseKey(hkeyCurrentUser);
  87. }
  88. hkeyCurrentUser = HKEY_CURRENT_USER;
  89. bRet = (RegUnLoadKey(HKEY_USERS, lpTempHiveKey) == ERROR_SUCCESS);
  90. if (*lpTempUserHive) {
  91. DeleteFile(lpTempUserHive);
  92. lstrcat(lpTempUserHive, TEXT(".log"));
  93. DeleteFile(lpTempUserHive);
  94. LocalFree(lpTempUserHive);
  95. lpTempUserHive = NULL;
  96. }
  97. return(bRet);
  98. }
  99. /***************************************************************************\
  100. * OpenUserProfile
  101. *
  102. * Purpose : Load an existing profile in the registry and unload previously
  103. * loaded profile (and delete its tmp file).
  104. *
  105. * History:
  106. * 11-20-92 JohanneC Created.
  107. \***************************************************************************/
  108. BOOL APIENTRY OpenUserProfile(LPTSTR szFilePath, PSID *pUserSid)
  109. {
  110. DWORD err;
  111. //
  112. // Copy the profile to a temp hive before loading it in the registry.
  113. //
  114. if (!lpTempUserHivePath) {
  115. if (!AllocAndExpandEnvironmentStrings(TEMP_USER_HIVE_PATH, &lpTempUserHivePath))
  116. return(FALSE);
  117. }
  118. lpTempUserHive = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) *
  119. (lstrlen(lpTempUserHivePath) + 17));
  120. if (!lpTempUserHive) {
  121. return(FALSE);
  122. }
  123. if (!GetTempFileName(lpTempUserHivePath, TEXT("tmp"), 0, lpTempUserHive)) {
  124. lstrcpy(lpTempUserHive, lpTempUserHivePath);
  125. lstrcat(lpTempUserHive, TEXT("\\HiveOpen"));
  126. }
  127. if (CopyFile(szFilePath, lpTempUserHive, FALSE)) {
  128. GetRegistryKeyFromPath(lpTempUserHive, &lpTempHiveKey);
  129. if ((err = RegLoadKey(HKEY_USERS, lpTempHiveKey, lpTempUserHive)) == ERROR_SUCCESS) {
  130. if ((err = RegOpenKeyEx(HKEY_USERS, lpTempHiveKey, 0,
  131. MAXIMUM_ALLOWED,
  132. &hkeyCurrentUser)) != ERROR_SUCCESS) {
  133. //
  134. // Error, do not have access to the profile.
  135. //
  136. ErrorPrintf(IDS_ERROR_PROFILE_LOAD_ERR, err);
  137. ClearTempUserProfile();
  138. return(FALSE);
  139. }
  140. }
  141. else {
  142. DeleteFile(lpTempUserHive);
  143. lstrcat(lpTempUserHive, TEXT(".log"));
  144. DeleteFile(lpTempUserHive);
  145. LocalFree(lpTempUserHive);
  146. //
  147. // Could not load the user profile, check the error code
  148. //
  149. if (err == ERROR_BADDB) {
  150. // bad format: not a profile registry file
  151. ErrorPrintf(IDS_ERROR_BAD_PROFILE);
  152. return(FALSE);
  153. }
  154. else {
  155. // generic error message : Failed to load profile
  156. ErrorPrintf(IDS_ERROR_PROFILE_LOAD_ERR, err);
  157. return(FALSE);
  158. }
  159. }
  160. }
  161. else {
  162. //
  163. // An error occured trying to load the profile.
  164. //
  165. DeleteFile(lpTempUserHive);
  166. switch ( (err = GetLastError()) ) {
  167. case ERROR_SHARING_VIOLATION:
  168. ErrorPrintf(IDS_ERROR_PROFILE_INUSE);
  169. break;
  170. default:
  171. ErrorPrintf(IDS_ERROR_PROFILE_LOAD_ERR, err);
  172. break;
  173. }
  174. return(FALSE);
  175. }
  176. //
  177. // Get the permitted user
  178. //
  179. *pUserSid = NULL;
  180. return(TRUE);
  181. }
  182. /***************************************************************************\
  183. * SaveUserProfile
  184. *
  185. * Purpose : Save the loaded profile as a file. The registry should already
  186. * have the existing ACL's already set so nothing needs to change. The
  187. * file ACL's do need to be copied from the original and applied to the
  188. * saved file. This function assumes the orignal file exists.
  189. *
  190. \***************************************************************************/
  191. BOOL APIENTRY SaveUserProfile(PSID pUserSid, LPTSTR lpFilePath)
  192. {
  193. LPTSTR lpTmpHive = NULL;
  194. BOOL err = FALSE;
  195. //
  196. // Save the profile to a temp hive then copy it over.
  197. //
  198. if ( AllocAndExpandEnvironmentStrings(TEMP_SAVE_HIVE, &lpTmpHive) )
  199. {
  200. if( lpTmpHive != NULL )
  201. {
  202. DeleteFile(lpTmpHive);
  203. if(RegSaveKey(hkeyCurrentUser, lpTmpHive, NULL) != ERROR_SUCCESS)
  204. {
  205. LocalFree(lpTmpHive);
  206. lpTmpHive = NULL;
  207. err = TRUE;
  208. }
  209. else
  210. {
  211. PSECURITY_DESCRIPTOR pSecDesc;
  212. DWORD Attrib = GetFileAttributes(lpFilePath);
  213. pSecDesc = GetSecurityInfo(lpFilePath);
  214. SetFileAttributes(lpFilePath,FILE_ATTRIBUTE_ARCHIVE);
  215. if(CopyFile(lpTmpHive, lpFilePath, FALSE))
  216. {
  217. DeleteFile(lpTmpHive);
  218. LocalFree(lpTmpHive);
  219. lpTmpHive = NULL;
  220. if (pSecDesc)
  221. {
  222. SetFileSecurity(lpFilePath,
  223. DACL_SECURITY_INFORMATION,
  224. pSecDesc);
  225. FreeSecurityInfo(pSecDesc);
  226. }
  227. }
  228. else
  229. {
  230. if(pSecDesc)
  231. {
  232. FreeSecurityInfo(pSecDesc);
  233. }
  234. err = TRUE;
  235. }
  236. if(0xffffffff != Attrib)
  237. {
  238. SetFileAttributes(lpFilePath,Attrib);
  239. }
  240. }
  241. }
  242. }
  243. else
  244. {
  245. err = TRUE;
  246. }
  247. if( lpTmpHive != NULL )
  248. {
  249. LocalFree(lpTmpHive);
  250. }
  251. return(!err);
  252. }
  253. /***************************************************************************\
  254. * EnablePrivilege
  255. *
  256. * Enables/disabled the specified well-known privilege in the
  257. * current process context
  258. *
  259. * Returns TRUE on success, FALSE on failure
  260. *
  261. * History:
  262. * 12-05-91 Davidc Created
  263. \***************************************************************************/
  264. BOOL
  265. EnablePrivilege(
  266. DWORD Privilege,
  267. BOOL Enable
  268. )
  269. {
  270. NTSTATUS Status;
  271. #if 0
  272. BOOL WasEnabled;
  273. Status = RtlAdjustPrivilege(Privilege, Enable, TRUE, (PBOOLEAN)&WasEnabled);
  274. return(NT_SUCCESS(Status));
  275. #else
  276. HANDLE ProcessToken;
  277. LUID LuidPrivilege;
  278. PTOKEN_PRIVILEGES NewPrivileges;
  279. DWORD Length;
  280. //
  281. // Open our own token
  282. //
  283. Status = NtOpenProcessToken(
  284. NtCurrentProcess(),
  285. TOKEN_ADJUST_PRIVILEGES,
  286. &ProcessToken
  287. );
  288. if (!NT_SUCCESS(Status)) {
  289. return(FALSE);
  290. }
  291. //
  292. // Initialize the privilege adjustment structure
  293. //
  294. LuidPrivilege = RtlConvertLongToLuid(Privilege);
  295. NewPrivileges = (PTOKEN_PRIVILEGES) LocalAlloc(LPTR, sizeof(TOKEN_PRIVILEGES) +
  296. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  297. if (NewPrivileges == NULL) {
  298. NtClose(ProcessToken);
  299. return(FALSE);
  300. }
  301. NewPrivileges->PrivilegeCount = 1;
  302. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  303. //
  304. // WORKAROUND: because of a bug in NtAdjustPrivileges which
  305. // returns an error when you try to enable a privilege
  306. // that is already enabled, we first try to disable it.
  307. // to be removed when api is fixed.
  308. //
  309. NewPrivileges->Privileges[0].Attributes = 0;
  310. Status = NtAdjustPrivilegesToken(
  311. ProcessToken, // TokenHandle
  312. (BOOLEAN)FALSE, // DisableAllPrivileges
  313. NewPrivileges, // NewPrivileges
  314. 0, // BufferLength
  315. NULL, // PreviousState (OPTIONAL)
  316. &Length // ReturnLength
  317. );
  318. NewPrivileges->Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
  319. //
  320. // Enable the privilege
  321. //
  322. Status = NtAdjustPrivilegesToken(
  323. ProcessToken, // TokenHandle
  324. (BOOLEAN)FALSE, // DisableAllPrivileges
  325. NewPrivileges, // NewPrivileges
  326. 0, // BufferLength
  327. NULL, // PreviousState (OPTIONAL)
  328. &Length // ReturnLength
  329. );
  330. LocalFree(NewPrivileges);
  331. NtClose(ProcessToken);
  332. if (Status) {
  333. return(FALSE);
  334. }
  335. return(TRUE);
  336. #endif
  337. }
  338. BOOL AllocAndExpandEnvironmentStrings(LPTSTR String, LPTSTR *lpExpandedString)
  339. {
  340. LPTSTR lptmp = NULL;
  341. DWORD cchBuffer;
  342. // Get the number of characters needed.
  343. cchBuffer = ExpandEnvironmentStrings(String, lptmp, 0);
  344. if (cchBuffer) {
  345. cchBuffer++; // for NULL terminator
  346. lptmp = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * cchBuffer);
  347. if (!lptmp) {
  348. return(FALSE);
  349. }
  350. cchBuffer = ExpandEnvironmentStrings(String, lptmp, cchBuffer);
  351. }
  352. *lpExpandedString = lptmp;
  353. return(TRUE);
  354. }
  355. VOID GetRegistryKeyFromPath(LPTSTR lpPath, LPTSTR *lpKey)
  356. {
  357. LPTSTR lptmp;
  358. *lpKey = lpPath;
  359. for (lptmp = lpPath; *lptmp; lptmp++) {
  360. if (*lptmp == TEXT('\\')) {
  361. *lpKey = lptmp+1;
  362. }
  363. }
  364. }
  365. /***************************************************************************\
  366. * InitializeGlobalSids
  367. *
  368. * Initializes the various global Sids used in this module.
  369. *
  370. * History:
  371. * 04-28-93 JohanneC Created
  372. \***************************************************************************/
  373. VOID InitializeGlobalSids()
  374. {
  375. NTSTATUS Status;
  376. //
  377. // Build the admins local group SID
  378. //
  379. Status = RtlAllocateAndInitializeSid(
  380. &gNtAuthority,
  381. 2,
  382. SECURITY_BUILTIN_DOMAIN_RID,
  383. DOMAIN_ALIAS_RID_ADMINS,
  384. 0, 0, 0, 0, 0, 0,
  385. &gAdminsLocalGroup
  386. );
  387. //
  388. // create System Sid
  389. //
  390. Status = RtlAllocateAndInitializeSid(
  391. &gNtAuthority,
  392. 1,
  393. SECURITY_LOCAL_SYSTEM_RID,
  394. 0, 0, 0, 0, 0, 0, 0,
  395. &gSystemSid
  396. );
  397. }
  398. /*****************************************************************************
  399. *
  400. * ClearDisabledClasses
  401. *
  402. * This routine will check the compatibility flags for the user's Classes
  403. * registry key, and remove the keys if mapping is disabled.
  404. *
  405. * ENTRY:
  406. *
  407. * EXIT:
  408. * No return value.
  409. *
  410. ****************************************************************************/
  411. void ClearDisabledClasses(void)
  412. {
  413. NTSTATUS Status = STATUS_SUCCESS;
  414. ULONG ulcnt = 0, ultemp = 0;
  415. UNICODE_STRING UniPath;
  416. OBJECT_ATTRIBUTES ObjAttr;
  417. PKEY_BASIC_INFORMATION pKeyUserInfo = NULL;
  418. HANDLE hKeyUser = NULL;
  419. NTSTATUS Status2;
  420. HANDLE hClassesKey;
  421. WCHAR wcuser[MAX_PATH];
  422. if ( ! hkeyCurrentUser) {
  423. return;
  424. }
  425. GetTermsrCompatFlags(CITRIX_CLASSES, &ultemp, CompatibilityRegEntry);
  426. if ( (ultemp & (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) !=
  427. (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) {
  428. return;
  429. }
  430. // Get a buffer for the key info
  431. ulcnt = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH*sizeof(WCHAR) + sizeof(WCHAR);
  432. pKeyUserInfo = RtlAllocateHeap(RtlProcessHeap(),
  433. 0,
  434. ulcnt);
  435. if (!pKeyUserInfo) {
  436. Status = STATUS_NO_MEMORY;
  437. }
  438. // We have the necessary buffers, start checking the keys
  439. if (NT_SUCCESS(Status)) {
  440. // Build up a string for this user's software section
  441. wcscpy(wcuser, L"Software");
  442. // Create a unicode string for the user key path
  443. RtlInitUnicodeString(&UniPath, wcuser);
  444. InitializeObjectAttributes(&ObjAttr,
  445. &UniPath,
  446. OBJ_CASE_INSENSITIVE,
  447. hkeyCurrentUser,
  448. NULL);
  449. Status = NtOpenKey(&hKeyUser,
  450. KEY_READ | DELETE,
  451. &ObjAttr);
  452. RtlInitUnicodeString(&UniPath, L"Classes");
  453. InitializeObjectAttributes(&ObjAttr,
  454. &UniPath,
  455. OBJ_CASE_INSENSITIVE,
  456. hKeyUser,
  457. NULL);
  458. Status2 = NtOpenKey(&hClassesKey, KEY_READ | DELETE, &ObjAttr);
  459. if ( NT_SUCCESS(Status2) ) {
  460. Status2 = CtxDeleteKeyTree(hClassesKey, pKeyUserInfo, ulcnt);
  461. if ( !NT_SUCCESS(Status2)) {
  462. }
  463. NtClose(hClassesKey);
  464. }
  465. // If we allocated the system key, close it
  466. if (hKeyUser) {
  467. NtClose(hKeyUser);
  468. }
  469. }
  470. // Free up any memory we allocated
  471. if (pKeyUserInfo) {
  472. RtlFreeHeap( RtlProcessHeap(), 0, pKeyUserInfo);
  473. }
  474. }
  475. /*****************************************************************************
  476. *
  477. * CtxDeleteKeyTree
  478. *
  479. * Delete a subtree of registry keys
  480. *
  481. * ENTRY:
  482. * hKeyRoot is a handle to the root key that will be deleted along with
  483. * its children
  484. * pKeyInfo is a pointer to a KEY_BASIC_INFORMATION buffer that is
  485. * large enough to hold a MAX_PATH WCHAR string. It is
  486. * reused and destroyed by each recursive call.
  487. * ulInfoSize is the size of the pKeyInfo buffer
  488. *
  489. * EXIT:
  490. * Status
  491. *
  492. ****************************************************************************/
  493. NTSTATUS
  494. CtxDeleteKeyTree( HANDLE hKeyRoot,
  495. PKEY_BASIC_INFORMATION pKeyInfo,
  496. ULONG ulInfoSize )
  497. {
  498. NTSTATUS Status = STATUS_SUCCESS, Status2;
  499. UNICODE_STRING UniPath;
  500. OBJECT_ATTRIBUTES ObjAttr;
  501. ULONG ulcnt = 0;
  502. ULONG ultemp;
  503. HANDLE hKey;
  504. // Go through each of the subkeys
  505. while (NT_SUCCESS(Status)) {
  506. Status = NtEnumerateKey(hKeyRoot,
  507. ulcnt,
  508. KeyBasicInformation,
  509. pKeyInfo,
  510. ulInfoSize,
  511. &ultemp);
  512. // Delete sub keys
  513. if (NT_SUCCESS(Status)) {
  514. // Null terminate the key name
  515. pKeyInfo->Name[pKeyInfo->NameLength/sizeof(WCHAR)] = L'\0';
  516. // Create a unicode string for the key name
  517. RtlInitUnicodeString(&UniPath, pKeyInfo->Name);
  518. InitializeObjectAttributes(&ObjAttr,
  519. &UniPath,
  520. OBJ_CASE_INSENSITIVE,
  521. hKeyRoot,
  522. NULL);
  523. // Open up the child key
  524. Status2 = NtOpenKey(&hKey,
  525. MAXIMUM_ALLOWED,
  526. &ObjAttr);
  527. if ( NT_SUCCESS(Status2) ) {
  528. Status2 = CtxDeleteKeyTree ( hKey, pKeyInfo, ulInfoSize );
  529. NtClose(hKey);
  530. // If the key was not successfully deleted, we need
  531. // to increment the enumerate index to guarantee
  532. // that the alogorithm will complete.
  533. if ( !NT_SUCCESS(Status2) ) {
  534. ++ulcnt;
  535. }
  536. }
  537. }
  538. }
  539. // If we deleted all the sub-keys delete the curent key
  540. if ( !ulcnt ) {
  541. Status = NtDeleteKey(hKeyRoot);
  542. }
  543. else {
  544. Status = STATUS_CANNOT_DELETE;
  545. }
  546. return ( Status );
  547. }
  548. PSECURITY_DESCRIPTOR
  549. GetSecurityInfo(LPTSTR lpFilePath)
  550. {
  551. int SizeReq = 0;
  552. PSECURITY_DESCRIPTOR pSecDesc = NULL;
  553. GetFileSecurity(lpFilePath, DACL_SECURITY_INFORMATION, pSecDesc, 0,
  554. &SizeReq);
  555. if ( !SizeReq ) {
  556. return (NULL);
  557. }
  558. pSecDesc = LocalAlloc(LPTR, SizeReq);
  559. if ( pSecDesc ) {
  560. if ( !GetFileSecurity(lpFilePath, DACL_SECURITY_INFORMATION, pSecDesc,
  561. SizeReq, &SizeReq) ) {
  562. LocalFree(pSecDesc);
  563. pSecDesc = NULL;
  564. }
  565. }
  566. return (pSecDesc);
  567. }
  568. void
  569. FreeSecurityInfo(PSECURITY_DESCRIPTOR pSecDesc)
  570. {
  571. LocalFree(pSecDesc);
  572. }