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.

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