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.

1503 lines
43 KiB

  1. //*************************************************************
  2. //
  3. // Userdiff.c
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1995
  7. // All rights reserved
  8. //
  9. //*************************************************************
  10. #include "uenv.h"
  11. #include "strsafe.h"
  12. #define MAX_KEY_NAME MAX_PATH
  13. BOOL AddUDNode (LPUDNODE *lpList, LPTSTR lpBuildNumber);
  14. BOOL FreeUDList (LPUDNODE lpList);
  15. BOOL ProcessBuild(LPPROFILE lpProfile, LPUDNODE lpItem, LPVOID pEnv);
  16. BOOL ProcessHive(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey);
  17. BOOL ProcessFiles(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey);
  18. BOOL ProcessPrograms(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey, LPVOID pEnv);
  19. BOOL OkToProcessItem(DWORD dwProductType);
  20. //*************************************************************
  21. //
  22. // ProcessUserDiff()
  23. //
  24. // Purpose: Processes the userdiff hive
  25. //
  26. // Parameters: lpProfile - Profile information
  27. // dwBuildNumber - profile build #
  28. // pEnv - Environment block
  29. //
  30. // Return: TRUE if successful
  31. // FALSE if an error occurs
  32. //
  33. // Comments:
  34. //
  35. // History: Date Author Comment
  36. // 10/2/95 ericflo Created
  37. //
  38. //*************************************************************
  39. BOOL ProcessUserDiff (LPPROFILE lpProfile, DWORD dwBuildNumber, LPVOID pEnv)
  40. {
  41. TCHAR szUserDiff[MAX_PATH] = {0};
  42. TCHAR szName[MAX_KEY_NAME];
  43. HANDLE hFile;
  44. WIN32_FIND_DATA fd;
  45. LPUDNODE lpList = NULL, lpItem;
  46. LONG lResult;
  47. HKEY hKeyUserDiff;
  48. UINT Index = 0;
  49. DWORD dwSize;
  50. FILETIME ftWrite;
  51. DWORD cchNeeded;
  52. BOOL bUserDifrExist = FALSE;
  53. //
  54. // Verbose output
  55. //
  56. DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Entering.")));
  57. //
  58. // Test if the hive exists, first look for USERDIFR
  59. //
  60. cchNeeded = ExpandUserEnvironmentStrings(pEnv, USERDIFR_LOCATION, szUserDiff, MAX_PATH);
  61. if (cchNeeded > 0 && cchNeeded <= MAX_PATH)
  62. {
  63. hFile = FindFirstFile (szUserDiff, &fd);
  64. if (hFile != INVALID_HANDLE_VALUE)
  65. {
  66. bUserDifrExist = TRUE;
  67. FindClose(hFile);
  68. }
  69. }
  70. if (!bUserDifrExist)
  71. {
  72. BOOL bUserDiffExist = FALSE;
  73. DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: userdifr hive doesn't exist. Trying userdiff.")));
  74. cchNeeded = ExpandUserEnvironmentStrings(pEnv, USERDIFF_LOCATION, szUserDiff, MAX_PATH);
  75. if (cchNeeded > 0 && cchNeeded <= MAX_PATH)
  76. {
  77. hFile = FindFirstFile (szUserDiff, &fd);
  78. if (hFile != INVALID_HANDLE_VALUE)
  79. {
  80. bUserDiffExist = TRUE;
  81. FindClose(hFile);
  82. }
  83. }
  84. if (!bUserDiffExist)
  85. {
  86. DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: userdiff hive doesn't exist. Leaving.")));
  87. return TRUE;
  88. }
  89. }
  90. //
  91. // Load the hive
  92. //
  93. if (MyRegLoadKey(HKEY_USERS, USERDIFF, szUserDiff) != ERROR_SUCCESS) {
  94. DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: Failed to load userdiff.")));
  95. return FALSE;
  96. }
  97. //
  98. // Open the key
  99. //
  100. lResult = RegOpenKeyEx(HKEY_USERS, USERDIFF, 0, KEY_READ, &hKeyUserDiff);
  101. if (lResult != ERROR_SUCCESS) {
  102. MyRegUnLoadKey(HKEY_USERS, USERDIFF);
  103. DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: failed to open registry root (%d)"), lResult));
  104. return FALSE;
  105. }
  106. //
  107. // Enumerate the build numbers
  108. //
  109. dwSize = MAX_KEY_NAME;
  110. lResult = RegEnumKeyEx(hKeyUserDiff, Index, szName, &dwSize, NULL,
  111. NULL, NULL, &ftWrite);
  112. if (lResult == ERROR_SUCCESS) {
  113. do {
  114. //
  115. // Add the node
  116. //
  117. if (!AddUDNode (&lpList, szName)) {
  118. break;
  119. }
  120. Index++;
  121. dwSize = MAX_KEY_NAME;
  122. lResult = RegEnumKeyEx(hKeyUserDiff, Index, szName, &dwSize, NULL,
  123. NULL, NULL, &ftWrite);
  124. } while (lResult == ERROR_SUCCESS);
  125. }
  126. //
  127. // Close the open key
  128. //
  129. RegCloseKey(hKeyUserDiff);
  130. //
  131. // Process the builds
  132. //
  133. lpItem = lpList;
  134. while (lpItem) {
  135. //
  136. // Only want to apply changes that occurred in
  137. // builds after the one the user is running.
  138. //
  139. if ( (lpItem->dwBuildNumber > dwBuildNumber) &&
  140. (lpItem->dwBuildNumber <= g_dwBuildNumber) ) {
  141. ProcessBuild(lpProfile, lpItem, pEnv);
  142. }
  143. lpItem = lpItem->pNext;
  144. }
  145. //
  146. // Free the link list
  147. //
  148. FreeUDList (lpList);
  149. //
  150. // Unload the hive
  151. //
  152. MyRegUnLoadKey(HKEY_USERS, USERDIFF);
  153. //
  154. // Success
  155. //
  156. DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Leaving successfully.")));
  157. return TRUE;
  158. }
  159. //*************************************************************
  160. //
  161. // AddUDNode()
  162. //
  163. // Purpose: Adds a build node to the link listed
  164. // sorted by build number
  165. //
  166. // Parameters: lpList - Link list of nodes
  167. // lpBuildNumber - New node name
  168. //
  169. //
  170. // Return: TRUE if successful
  171. // FALSE if an error occurs
  172. //
  173. // Comments:
  174. //
  175. // History: Date Author Comment
  176. // 10/3/95 ericflo Created
  177. //
  178. //*************************************************************
  179. BOOL AddUDNode (LPUDNODE *lpList, LPTSTR lpBuildNumber)
  180. {
  181. LPUDNODE lpNewItem;
  182. LPUDNODE lpHead, lpPrev;
  183. if (!lpBuildNumber || !*lpBuildNumber) {
  184. return TRUE;
  185. }
  186. //
  187. // Setup the new node
  188. //
  189. lpNewItem = (LPUDNODE) LocalAlloc(LPTR, sizeof(UDNODE));
  190. if (!lpNewItem) {
  191. return FALSE;
  192. }
  193. StringCchCopy (lpNewItem->szBuildNumber, MAX_BUILD_NUMBER, lpBuildNumber);
  194. lpNewItem->dwBuildNumber = StringToInt(lpBuildNumber);
  195. lpNewItem->pNext = NULL;
  196. //
  197. // Now add it to the list sorted
  198. //
  199. lpHead = *lpList;
  200. lpPrev = NULL;
  201. if (!lpHead) {
  202. //
  203. // First item in the list
  204. //
  205. *lpList = lpNewItem;
  206. return TRUE;
  207. }
  208. //
  209. // If we made it here, there is one or more items in the list
  210. //
  211. while (lpHead) {
  212. if (lpNewItem->dwBuildNumber <= lpHead->dwBuildNumber) {
  213. if (lpPrev) {
  214. //
  215. // Insert the item
  216. //
  217. lpPrev->pNext = lpNewItem;
  218. lpNewItem->pNext = lpHead;
  219. return TRUE;
  220. } else {
  221. //
  222. // Head of the list
  223. //
  224. lpNewItem->pNext = lpHead;
  225. *lpList = lpNewItem;
  226. return TRUE;
  227. }
  228. }
  229. lpPrev = lpHead;
  230. lpHead = lpHead->pNext;
  231. }
  232. //
  233. // Add node to the end of the list
  234. //
  235. lpPrev->pNext = lpNewItem;
  236. return TRUE;
  237. }
  238. //*************************************************************
  239. //
  240. // FreeUDList()
  241. //
  242. // Purpose: Free's a UDNODE link list
  243. //
  244. // Parameters: lpList - List to be freed
  245. //
  246. // Return: TRUE if successful
  247. // FALSE if an error occurs
  248. //
  249. // Comments:
  250. //
  251. // History: Date Author Comment
  252. // 10/3/95 ericflo Created
  253. //
  254. //*************************************************************
  255. BOOL FreeUDList (LPUDNODE lpList)
  256. {
  257. LPUDNODE lpNext;
  258. if (!lpList) {
  259. return TRUE;
  260. }
  261. lpNext = lpList->pNext;
  262. while (lpList) {
  263. LocalFree (lpList);
  264. lpList = lpNext;
  265. if (lpList) {
  266. lpNext = lpList->pNext;
  267. }
  268. }
  269. return TRUE;
  270. }
  271. //*************************************************************
  272. //
  273. // ProcessBuild()
  274. //
  275. // Purpose: Processes the changes for a specific build
  276. //
  277. // Parameters: lpProfile - Profile information
  278. // lpItem - Build item to process
  279. // pEnv - Environment block
  280. //
  281. // Return: TRUE if successful
  282. // FALSE if an error occurs
  283. //
  284. // Comments:
  285. //
  286. // History: Date Author Comment
  287. // 10/3/95 ericflo Created
  288. //
  289. //*************************************************************
  290. BOOL ProcessBuild(LPPROFILE lpProfile, LPUDNODE lpItem, LPVOID pEnv)
  291. {
  292. TCHAR szSubKey[MAX_PATH];
  293. LONG lResult;
  294. HKEY hKey;
  295. //
  296. // Verbose output
  297. //
  298. DebugMsg((DM_VERBOSE, TEXT("ProcessBuild: Entering with build <%s>."),
  299. lpItem->szBuildNumber));
  300. //
  301. // Open "Hive" subkey
  302. //
  303. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Hive"), USERDIFF, lpItem->szBuildNumber);
  304. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
  305. if (lResult == ERROR_SUCCESS) {
  306. ProcessHive(lpProfile, lpItem, hKey);
  307. RegCloseKey (hKey);
  308. }
  309. //
  310. // Open "Files" subkey
  311. //
  312. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Files"), USERDIFF, lpItem->szBuildNumber);
  313. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
  314. if (lResult == ERROR_SUCCESS) {
  315. ProcessFiles(lpProfile, lpItem, hKey);
  316. RegCloseKey (hKey);
  317. }
  318. //
  319. // Open "Execute" subkey
  320. //
  321. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Execute"), USERDIFF, lpItem->szBuildNumber);
  322. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
  323. if (lResult == ERROR_SUCCESS) {
  324. ProcessPrograms(lpProfile, lpItem, hKey, pEnv);
  325. RegCloseKey (hKey);
  326. }
  327. //
  328. // Success
  329. //
  330. DebugMsg((DM_VERBOSE, TEXT("ProcessBuild: Leaving successfully.")));
  331. return TRUE;
  332. }
  333. //*************************************************************
  334. //
  335. // ProcessHive()
  336. //
  337. // Purpose: Processes the Hive entry for a build
  338. //
  339. // Parameters: lpProfile - Profile information
  340. // lpItem - Build item
  341. // hKey - Registry key to enumerate
  342. //
  343. // Return: TRUE if successful
  344. // FALSE if an error occurs
  345. //
  346. // Comments:
  347. //
  348. // History: Date Author Comment
  349. // 10/3/95 ericflo Created
  350. //
  351. //*************************************************************
  352. BOOL ProcessHive(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey)
  353. {
  354. TCHAR szSubKey[MAX_PATH];
  355. TCHAR szValueName[MAX_KEY_NAME];
  356. DWORD dwSize, dwType, dwAction, dwDisp, dwFlags, dwProductType;
  357. LPBYTE lpValueData;
  358. LONG lResult;
  359. UINT Index = 1;
  360. FILETIME ftWrite;
  361. HKEY hKeyEntry, hKeyTemp;
  362. LPTSTR lpName;
  363. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Entering.")));
  364. //
  365. // Process the entry
  366. //
  367. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Hive\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
  368. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
  369. if (lResult != ERROR_SUCCESS) {
  370. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: No hive entries.")));
  371. goto Exit;
  372. }
  373. do {
  374. //
  375. // Query for the product type
  376. //
  377. dwSize = sizeof(dwProductType);
  378. lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
  379. (LPBYTE)&dwProductType, &dwSize);
  380. //
  381. // It's ok to not have a product type listed in userdiff.ini.
  382. // In this case, we always apply the change regardless of the
  383. // platform.
  384. //
  385. if (lResult == ERROR_SUCCESS) {
  386. //
  387. // A specific product was listed. Check if
  388. // we can process this entry.
  389. //
  390. if (!OkToProcessItem(dwProductType)) {
  391. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Skipping Item %d due to product type mismatch."), Index));
  392. goto LoopAgain;
  393. }
  394. }
  395. //
  396. // Query for the action type
  397. //
  398. dwSize = sizeof(dwAction);
  399. lResult = RegQueryValueEx(hKeyEntry, UD_ACTION, NULL, &dwType,
  400. (LPBYTE)&dwAction, &dwSize);
  401. if (lResult == ERROR_SUCCESS) {
  402. switch (dwAction) {
  403. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Item %d has an action of %d."),
  404. Index, dwAction));
  405. case 1: {
  406. //
  407. // Add New Key
  408. //
  409. // Get the key name
  410. //
  411. dwSize = MAX_PATH * sizeof(TCHAR);
  412. lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
  413. (LPBYTE)szSubKey, &dwSize);
  414. if (lResult == ERROR_SUCCESS) {
  415. lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
  416. szSubKey, 0, NULL,
  417. REG_OPTION_NON_VOLATILE,
  418. KEY_ALL_ACCESS, NULL,
  419. &hKeyTemp, &dwDisp);
  420. if (lResult == ERROR_SUCCESS) {
  421. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Created subkey <%s>."),
  422. szSubKey));
  423. RegCloseKey(hKeyTemp);
  424. } else {
  425. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create subkey <%s> with error %d."),
  426. szSubKey, lResult));
  427. }
  428. }
  429. }
  430. break;
  431. case 2: {
  432. //
  433. // Delete a key and all it's subkeys
  434. //
  435. // Get the key name
  436. //
  437. dwSize = MAX_PATH * sizeof(TCHAR);
  438. lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
  439. (LPBYTE)szSubKey, &dwSize);
  440. if (lResult == ERROR_SUCCESS) {
  441. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Calling RegDelnode on <%s>."),
  442. szSubKey));
  443. RegDelnode (lpProfile->hKeyCurrentUser, szSubKey);
  444. }
  445. }
  446. break;
  447. case 3: {
  448. //
  449. // Add a new value
  450. //
  451. // Get the key name
  452. //
  453. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Adding a new value.")));
  454. dwSize = MAX_PATH * sizeof(TCHAR);
  455. lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
  456. (LPBYTE)szSubKey, &dwSize);
  457. if (lResult != ERROR_SUCCESS) {
  458. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to get UD_KEYNAME with error %d."), lResult));
  459. goto LoopAgain;
  460. }
  461. lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
  462. szSubKey, 0, NULL,
  463. REG_OPTION_NON_VOLATILE,
  464. KEY_ALL_ACCESS, NULL,
  465. &hKeyTemp, &dwDisp);
  466. if (lResult != ERROR_SUCCESS) {
  467. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create UD_KEYNAME with error %d."), lResult));
  468. goto LoopAgain;
  469. }
  470. //
  471. // Query for the value name
  472. //
  473. dwSize = MAX_KEY_NAME * sizeof(TCHAR);
  474. lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAME, NULL, &dwType,
  475. (LPBYTE)szValueName, &dwSize);
  476. if (lResult != ERROR_SUCCESS) {
  477. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query UD_VALUENAME with error %d."), lResult));
  478. RegCloseKey(hKeyTemp);
  479. goto LoopAgain;
  480. }
  481. //
  482. // Query for the value data size
  483. //
  484. dwSize = 0;
  485. lResult = RegQueryValueEx(hKeyEntry, UD_VALUE, NULL, &dwType,
  486. NULL, &dwSize);
  487. if (lResult != ERROR_SUCCESS) {
  488. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query UD_VALUE with error %d."), lResult));
  489. RegCloseKey(hKeyTemp);
  490. goto LoopAgain;
  491. }
  492. //
  493. // Allocate space for the data
  494. //
  495. lpValueData = LocalAlloc (LPTR, dwSize);
  496. if (!lpValueData) {
  497. DebugMsg((DM_WARNING, TEXT("ProcessHive: LocalAlloc failed (%d)."), GetLastError()));
  498. RegCloseKey(hKeyTemp);
  499. goto LoopAgain;
  500. }
  501. //
  502. // Query for the value data
  503. //
  504. lResult = RegQueryValueEx(hKeyEntry, UD_VALUE, NULL, &dwType,
  505. lpValueData, &dwSize);
  506. if (lResult != ERROR_SUCCESS) {
  507. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query value data with error %d."), lResult));
  508. LocalFree (lpValueData);
  509. RegCloseKey(hKeyTemp);
  510. goto LoopAgain;
  511. }
  512. //
  513. // Set the new value
  514. //
  515. RegSetValueEx(hKeyTemp, szValueName, 0, dwType,
  516. lpValueData, dwSize);
  517. //
  518. // Clean up
  519. //
  520. LocalFree (lpValueData);
  521. RegCloseKey(hKeyTemp);
  522. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Finished adding value <%s>."), szValueName));
  523. }
  524. break;
  525. case 4: {
  526. //
  527. // Delete value(s)
  528. //
  529. // Get the key name
  530. //
  531. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Entering delete a value.")));
  532. dwSize = ARRAYSIZE(szSubKey);
  533. lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
  534. (LPBYTE)szSubKey, &dwSize);
  535. if (lResult != ERROR_SUCCESS) {
  536. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value to delete (%d)."), lResult));
  537. goto LoopAgain;
  538. }
  539. lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
  540. szSubKey, 0, NULL,
  541. REG_OPTION_NON_VOLATILE,
  542. KEY_ALL_ACCESS, NULL,
  543. &hKeyTemp, &dwDisp);
  544. if (lResult != ERROR_SUCCESS) {
  545. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create key (%s) for value to delete (%d)."), szSubKey, lResult));
  546. goto LoopAgain;
  547. }
  548. //
  549. // Query for the flags
  550. //
  551. dwSize = sizeof(dwFlags);
  552. lResult = RegQueryValueEx(hKeyEntry, UD_FLAGS, NULL, &dwType,
  553. (LPBYTE)&dwFlags, &dwSize);
  554. if (lResult != ERROR_SUCCESS) {
  555. dwFlags = 0;
  556. }
  557. //
  558. // Process the flags
  559. //
  560. if (dwFlags == 2) {
  561. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Calling DeleteAllValues.")));
  562. DeleteAllValues (hKeyTemp);
  563. RegCloseKey(hKeyTemp);
  564. goto LoopAgain;
  565. }
  566. //
  567. // Query for the value names size
  568. //
  569. dwSize = 0;
  570. lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAMES, NULL, &dwType,
  571. NULL, &dwSize);
  572. if (lResult != ERROR_SUCCESS) {
  573. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value names to delete (%d)."), lResult));
  574. RegCloseKey(hKeyTemp);
  575. goto LoopAgain;
  576. }
  577. //
  578. // Allocate space for the data
  579. //
  580. lpValueData = LocalAlloc (LPTR, dwSize);
  581. if (!lpValueData) {
  582. DebugMsg((DM_WARNING, TEXT("ProcessHive: LocalAlloc failed (%d)."), GetLastError()));
  583. RegCloseKey(hKeyTemp);
  584. goto LoopAgain;
  585. }
  586. //
  587. // Query for the value data
  588. //
  589. lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAMES, NULL, &dwType,
  590. lpValueData, &dwSize);
  591. if (lResult != ERROR_SUCCESS) {
  592. DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value data to delete (%d)."), lResult));
  593. LocalFree (lpValueData);
  594. RegCloseKey(hKeyTemp);
  595. goto LoopAgain;
  596. }
  597. //
  598. // Delete the values
  599. //
  600. lpName = (LPTSTR) lpValueData;
  601. while (*lpName) {
  602. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Deleting (%s)."), lpName));
  603. RegDeleteValue (hKeyTemp, lpName);
  604. lpName += lstrlen(lpName) + 1;
  605. }
  606. //
  607. // Delete the no-name value if appropriate
  608. //
  609. if (dwFlags == 1) {
  610. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Deleting no name value.")));
  611. RegDeleteValue (hKeyTemp, NULL);
  612. }
  613. //
  614. // Clean up
  615. //
  616. LocalFree (lpValueData);
  617. RegCloseKey(hKeyTemp);
  618. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Leaving deletion code.")));
  619. }
  620. break;
  621. }
  622. }
  623. LoopAgain:
  624. //
  625. // Close the registry key
  626. //
  627. RegCloseKey(hKeyEntry);
  628. //
  629. // Enumerate again
  630. //
  631. Index++;
  632. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Hive\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
  633. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
  634. } while (lResult == ERROR_SUCCESS);
  635. Exit:
  636. DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Leaving.")));
  637. return TRUE;
  638. }
  639. //*************************************************************
  640. //
  641. // ProcessFiles()
  642. //
  643. // Purpose: Processes the Files entry for a build
  644. //
  645. // Parameters: lpProfile - Profile information
  646. // lpItem - Build item
  647. // hKey - Registry key to enumerate
  648. //
  649. // Return: TRUE if successful
  650. // FALSE if an error occurs
  651. //
  652. // Comments:
  653. //
  654. // History: Date Author Comment
  655. // 10/3/95 ericflo Created
  656. //
  657. //*************************************************************
  658. BOOL ProcessFiles(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey)
  659. {
  660. TCHAR szSubKey[MAX_PATH];
  661. TCHAR szSrc[MAX_PATH];
  662. TCHAR szDest[MAX_PATH];
  663. TCHAR szItem[MAX_PATH];
  664. LPTSTR lpEnd, lpTemp;
  665. DWORD dwSize, dwType, dwAction, dwProductType;
  666. LONG lResult;
  667. UINT Index = 1;
  668. FILETIME ftWrite;
  669. HKEY hKeyEntry;
  670. HANDLE hOldToken;
  671. BOOL bImpersonateUser = FALSE;
  672. DWORD cchEnd;
  673. //
  674. // Verbose Output
  675. //
  676. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Entering.")));
  677. //
  678. // Process the entry
  679. //
  680. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Files\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
  681. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
  682. if (lResult != ERROR_SUCCESS) {
  683. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: No Files entries.")));
  684. goto Exit;
  685. }
  686. do {
  687. //
  688. // Query for the product type
  689. //
  690. dwSize = sizeof(dwProductType);
  691. lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
  692. (LPBYTE)&dwProductType, &dwSize);
  693. //
  694. // It's ok to not have a product type listed in userdiff.ini.
  695. // In this case, we always apply the change regardless of the
  696. // platform.
  697. //
  698. if (lResult == ERROR_SUCCESS) {
  699. //
  700. // A specific product was listed. Check if
  701. // we can process this entry.
  702. //
  703. if (!OkToProcessItem(dwProductType)) {
  704. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Skipping Item %d due to product type mismatch."), Index));
  705. goto LoopAgain;
  706. }
  707. }
  708. //
  709. // Query for the action type
  710. //
  711. dwSize = sizeof(dwAction);
  712. lResult = RegQueryValueEx(hKeyEntry, UD_ACTION, NULL, &dwType,
  713. (LPBYTE)&dwAction, &dwSize);
  714. if (lResult != ERROR_SUCCESS) {
  715. DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to query action type (%d)."), lResult));
  716. goto LoopAgain;
  717. }
  718. //
  719. // Query for the item
  720. //
  721. dwSize = ARRAYSIZE(szItem);
  722. lResult = RegQueryValueEx(hKeyEntry, UD_ITEM, NULL, &dwType,
  723. (LPBYTE)szItem, &dwSize);
  724. if (lResult != ERROR_SUCCESS) {
  725. DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to query UD_ITEM type (%d)."), lResult));
  726. goto LoopAgain;
  727. }
  728. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Item %d has an action of %d."),
  729. Index, dwAction));
  730. //
  731. // Impersonate the user
  732. //
  733. if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) {
  734. DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to impersonate user")));
  735. RegCloseKey(hKeyEntry);
  736. goto Exit;
  737. }
  738. bImpersonateUser = TRUE;
  739. switch (dwAction) {
  740. case 1:
  741. //
  742. // Create new program group
  743. //
  744. if (GetSpecialFolderPath (CSIDL_PROGRAMS, szDest))
  745. {
  746. lpEnd = CheckSlashEx(szDest, ARRAYSIZE(szDest), &cchEnd);
  747. if (lpEnd)
  748. {
  749. StringCchCopy (lpEnd, cchEnd, szItem);
  750. if (CreateNestedDirectory(szDest, NULL)) {
  751. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Created new group (%s)."), szDest));
  752. } else {
  753. DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to created new group (%s) with (%d)."),
  754. szDest, GetLastError()));
  755. }
  756. }
  757. }
  758. break;
  759. case 2:
  760. //
  761. // Delete a program group
  762. //
  763. if (GetSpecialFolderPath (CSIDL_PROGRAMS, szDest))
  764. {
  765. lpEnd = CheckSlashEx(szDest, ARRAYSIZE(szDest), &cchEnd);
  766. if (lpEnd)
  767. {
  768. StringCchCopy (lpEnd, cchEnd, szItem);
  769. Delnode(szDest);
  770. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted group (%s)."), szDest));
  771. }
  772. }
  773. break;
  774. case 3:
  775. {
  776. TCHAR szStartMenu [MAX_FOLDER_SIZE];
  777. //
  778. // Add a new item
  779. //
  780. dwSize = ARRAYSIZE(szSrc);
  781. if (!GetDefaultUserProfileDirectory(szSrc, &dwSize)) {
  782. DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to get default user profile.")));
  783. goto LoopAgain;
  784. }
  785. lpEnd = CheckSlashEx(szSrc, ARRAYSIZE(szSrc), &cchEnd);
  786. if (lpEnd)
  787. {
  788. if (LoadString (g_hDllInstance, IDS_SH_PROGRAMS, szStartMenu,
  789. MAX_FOLDER_SIZE)) {
  790. StringCchCopy (lpEnd, cchEnd, szStartMenu);
  791. lpEnd = CheckSlashEx(szSrc, ARRAYSIZE(szSrc), &cchEnd);
  792. if (lpEnd)
  793. {
  794. StringCchCopy (lpEnd, cchEnd, szItem);
  795. if (GetSpecialFolderPath (CSIDL_PROGRAMS, szDest))
  796. {
  797. lpEnd = CheckSlashEx(szDest, ARRAYSIZE(szDest), &cchEnd);
  798. if (lpEnd)
  799. {
  800. StringCchCopy (lpEnd, cchEnd, szItem);
  801. if (CopyFile (szSrc, szDest, FALSE)) {
  802. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: <%s> ==> <%s> [OK]."),
  803. szSrc, szDest));
  804. } else {
  805. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: <%s> ==> <%s> [FAILED %d]."),
  806. szSrc, szDest, GetLastError()));
  807. }
  808. }
  809. }
  810. }
  811. }
  812. }
  813. }
  814. break;
  815. case 4:
  816. //
  817. // Delete a program item
  818. //
  819. if (GetSpecialFolderPath (CSIDL_PROGRAMS, szDest))
  820. {
  821. lpEnd = CheckSlashEx(szDest, ARRAYSIZE(szDest), &cchEnd);
  822. if (lpEnd)
  823. {
  824. StringCchCopy (lpEnd, cchEnd, szItem);
  825. if (DeleteFile(szDest)) {
  826. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted <%s>"), szDest));
  827. } else {
  828. DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to deleted <%s> with %d"), szDest, GetLastError()));
  829. }
  830. //
  831. // Attempt to delete the directory
  832. //
  833. lpTemp = szDest + lstrlen(szDest) - 1;
  834. lpEnd--;
  835. while ((*lpTemp != TEXT('\\')) && lpTemp > lpEnd) {
  836. lpTemp--;
  837. }
  838. if (lpTemp == lpEnd) {
  839. break;
  840. }
  841. *lpTemp = TEXT('\0');
  842. if (RemoveDirectory(szDest)) {
  843. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted directory <%s>"), szDest));
  844. } else {
  845. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Failed to delete directory <%s> with %d"), szDest, GetLastError()));
  846. }
  847. }
  848. }
  849. break;
  850. }
  851. LoopAgain:
  852. if (bImpersonateUser) {
  853. //
  854. // Revert to being 'ourself'
  855. //
  856. if (!RevertToUser(&hOldToken)) {
  857. DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to revert to self")));
  858. }
  859. bImpersonateUser = FALSE;
  860. }
  861. //
  862. // Close the registry key
  863. //
  864. RegCloseKey(hKeyEntry);
  865. //
  866. // Enumerate again
  867. //
  868. Index++;
  869. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Files\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
  870. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
  871. } while (lResult == ERROR_SUCCESS);
  872. Exit:
  873. DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Leaving.")));
  874. return TRUE;
  875. }
  876. //*************************************************************
  877. //
  878. // ProcessPrograms()
  879. //
  880. // Purpose: Processes the Execute entry for a build
  881. //
  882. // Parameters: lpProfile - Profile information
  883. // lpItem - Build item
  884. // hKey - Registry key to enumerate
  885. // pEnv - Environment block
  886. //
  887. // Return: TRUE if successful
  888. // FALSE if an error occurs
  889. //
  890. // Comments:
  891. //
  892. // History: Date Author Comment
  893. // 11/16/95 ericflo Created
  894. //
  895. //*************************************************************
  896. BOOL ProcessPrograms (LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey, LPVOID pEnv)
  897. {
  898. TCHAR szSubKey[MAX_PATH];
  899. TCHAR szCmdLine[MAX_PATH];
  900. TCHAR szFullPath[MAX_PATH];
  901. DWORD dwSize, dwType, dwProductType;
  902. LONG lResult;
  903. UINT Index = 1;
  904. HKEY hKeyEntry;
  905. STARTUPINFO si;
  906. PROCESS_INFORMATION ProcessInformation;
  907. BOOL Result;
  908. DWORD dwTokenSessionId;
  909. DWORD dwProcessSessionId;
  910. HANDLE hPrimaryToken = NULL;
  911. BOOL bTokenCreated = FALSE;
  912. DWORD cchExpanded;
  913. //
  914. // Verbose output
  915. //
  916. DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Entering.")));
  917. //
  918. // Process the entry
  919. //
  920. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
  921. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
  922. if (lResult != ERROR_SUCCESS) {
  923. DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: No execute entries.")));
  924. goto Exit;
  925. }
  926. //
  927. // Get the session id info for user token. In TS?FUS case we can't
  928. // create process across the session as it not yet received
  929. // WL_NOTIFY_LOGON notification from winlogon
  930. //
  931. dwProcessSessionId = NtCurrentPeb()->SessionId;
  932. if (GetTokenInformation(lpProfile->hTokenUser,
  933. TokenSessionId,
  934. (LPVOID) &dwTokenSessionId,
  935. sizeof(dwTokenSessionId),
  936. &dwSize) &&
  937. dwTokenSessionId != dwProcessSessionId) {
  938. //
  939. // We are loading profile for a remote session
  940. // So first create a primary token and change
  941. // the session id in it for CreateProcessAsUser
  942. // to work
  943. //
  944. if (!DuplicateTokenEx(lpProfile->hTokenUser,
  945. TOKEN_ALL_ACCESS,
  946. NULL, SecurityImpersonation,
  947. TokenPrimary,
  948. &hPrimaryToken)) {
  949. DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Failed to create primary token. Error %d"), GetLastError()));
  950. goto Exit;
  951. }
  952. bTokenCreated = TRUE;
  953. // Set the session id in new primary token
  954. if (!SetTokenInformation(hPrimaryToken,
  955. TokenSessionId,
  956. (LPVOID) &dwProcessSessionId,
  957. sizeof(dwProcessSessionId))) {
  958. DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Failed to set session id in primary token. Error %d"), GetLastError()));
  959. goto Exit;
  960. }
  961. }
  962. else {
  963. hPrimaryToken = lpProfile->hTokenUser;
  964. }
  965. do {
  966. //
  967. // Query for the product type
  968. //
  969. dwSize = sizeof(dwProductType);
  970. lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
  971. (LPBYTE)&dwProductType, &dwSize);
  972. //
  973. // It's ok to not have a product type listed in userdiff.ini.
  974. // In this case, we always apply the change regardless of the
  975. // platform.
  976. //
  977. if (lResult == ERROR_SUCCESS) {
  978. //
  979. // A specific product was listed. Check if
  980. // we can process this entry.
  981. //
  982. if (!OkToProcessItem(dwProductType)) {
  983. DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Skipping Item %d due to product type mismatch."), Index));
  984. goto LoopAgain;
  985. }
  986. }
  987. //
  988. // Query for the command line
  989. //
  990. dwSize = MAX_PATH * sizeof(TCHAR);
  991. lResult = RegQueryValueEx(hKeyEntry, UD_COMMANDLINE, NULL, &dwType,
  992. (LPBYTE)szCmdLine, &dwSize);
  993. if (lResult != ERROR_SUCCESS) {
  994. goto LoopAgain;
  995. }
  996. //
  997. // If we have a NULL path, loop again.
  998. //
  999. if (szCmdLine[0] == TEXT('\0')) {
  1000. goto LoopAgain;
  1001. }
  1002. /*
  1003. //
  1004. // If the command line is not begin with %SystemRoot%, skip it.
  1005. //
  1006. if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE,
  1007. szCmdLine, lstrlen(TEXT("%SystemRoot%")), TEXT("%SystemRoot%"), -1) != CSTR_EQUAL)
  1008. {
  1009. DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Skipping %s, since it is not from %SystemRoot%."), szCmdLine));
  1010. goto LoopAgain;
  1011. }
  1012. */
  1013. //
  1014. // Expand the command line
  1015. //
  1016. cchExpanded = ExpandUserEnvironmentStrings(pEnv, szCmdLine, szFullPath, MAX_PATH);
  1017. if (cchExpanded > 0 && cchExpanded < MAX_PATH)
  1018. {
  1019. //
  1020. // Initialize process startup info
  1021. //
  1022. si.cb = sizeof(STARTUPINFO);
  1023. si.lpReserved = NULL;
  1024. si.lpTitle = NULL;
  1025. si.lpDesktop = NULL;
  1026. si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
  1027. si.dwFlags = STARTF_USESHOWWINDOW;
  1028. si.wShowWindow = SW_SHOWNORMAL;
  1029. si.lpReserved2 = NULL;
  1030. si.cbReserved2 = 0;
  1031. //
  1032. // Start the app
  1033. //
  1034. Result = CreateProcessAsUser(hPrimaryToken, NULL, szFullPath,
  1035. NULL, NULL, FALSE,
  1036. NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
  1037. pEnv, NULL, &si, &ProcessInformation);
  1038. if (Result) {
  1039. DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Spawned <%s>. Waiting for it to complete."),
  1040. szFullPath));
  1041. //
  1042. // Wait for the app to complete (3 minutes max)
  1043. //
  1044. WaitForSingleObject(ProcessInformation.hProcess, 180000);
  1045. DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Finished waiting for <%s>."),
  1046. szFullPath));
  1047. //
  1048. // Close our handles to the process and thread
  1049. //
  1050. CloseHandle(ProcessInformation.hProcess);
  1051. CloseHandle(ProcessInformation.hThread);
  1052. } else {
  1053. DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Failed to execute <%s>, error = %d"),
  1054. szFullPath, GetLastError()));
  1055. }
  1056. }
  1057. LoopAgain:
  1058. //
  1059. // Close the registry key
  1060. //
  1061. RegCloseKey(hKeyEntry);
  1062. //
  1063. // Enumerate again
  1064. //
  1065. Index++;
  1066. StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
  1067. lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
  1068. } while (lResult == ERROR_SUCCESS);
  1069. Exit:
  1070. if (bTokenCreated) {
  1071. CloseHandle(hPrimaryToken);
  1072. }
  1073. DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Leaving.")));
  1074. return TRUE;
  1075. }
  1076. //*************************************************************
  1077. //
  1078. // OkToProcessItem()
  1079. //
  1080. // Purpose: Determines if the platform currently running
  1081. // on should have the change in userdiff.ini applied.
  1082. //
  1083. // Parameters: dwProductType - ProductType for a specific entry
  1084. // in userdiff.ini
  1085. //
  1086. // Return: TRUE if change should be applied
  1087. // FALSE if not
  1088. //
  1089. // Comments: dwProductType can be one of these values:
  1090. //
  1091. // 0 = All platforms
  1092. // 1 = All server platforms
  1093. // 2 = Workstation
  1094. // 3 = Server
  1095. // 4 = Domain Controller
  1096. //
  1097. // History: Date Author Comment
  1098. // 4/08/96 ericflo Created
  1099. //
  1100. //*************************************************************
  1101. BOOL OkToProcessItem(DWORD dwProductType)
  1102. {
  1103. BOOL bRetVal = FALSE;
  1104. switch (g_ProductType) {
  1105. case PT_WORKSTATION:
  1106. if ( (dwProductType == 0) ||
  1107. (dwProductType == 2) ) {
  1108. bRetVal = TRUE;
  1109. }
  1110. break;
  1111. case PT_SERVER:
  1112. if ( (dwProductType == 0) ||
  1113. (dwProductType == 1) ||
  1114. (dwProductType == 3) ) {
  1115. bRetVal = TRUE;
  1116. }
  1117. break;
  1118. case PT_DC:
  1119. if ( (dwProductType == 0) ||
  1120. (dwProductType == 1) ||
  1121. (dwProductType == 4) ) {
  1122. bRetVal = TRUE;
  1123. }
  1124. break;
  1125. }
  1126. return bRetVal;
  1127. }