mirror of https://github.com/tongzx/nt5src
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
1399 lines
36 KiB
//*************************************************************
|
|
//
|
|
// Userdiff.c
|
|
//
|
|
// Microsoft Confidential
|
|
// Copyright (c) Microsoft Corporation 1995
|
|
// All rights reserved
|
|
//
|
|
//*************************************************************
|
|
|
|
#include "uenv.h"
|
|
|
|
#define MAX_KEY_NAME MAX_PATH
|
|
|
|
BOOL AddUDNode (LPUDNODE *lpList, LPTSTR lpBuildNumber);
|
|
BOOL FreeUDList (LPUDNODE lpList);
|
|
BOOL ProcessBuild(LPPROFILE lpProfile, LPUDNODE lpItem, LPVOID pEnv);
|
|
BOOL ProcessHive(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey);
|
|
BOOL ProcessFiles(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey);
|
|
BOOL ProcessPrograms(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey, LPVOID pEnv);
|
|
BOOL OkToProcessItem(DWORD dwProductType);
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessUserDiff()
|
|
//
|
|
// Purpose: Processes the userdiff hive
|
|
//
|
|
// Parameters: lpProfile - Profile information
|
|
// dwBuildNumber - profile build #
|
|
// pEnv - Environment block
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 10/2/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ProcessUserDiff (LPPROFILE lpProfile, DWORD dwBuildNumber, LPVOID pEnv)
|
|
{
|
|
TCHAR szUserDiff[MAX_PATH] = {0};
|
|
TCHAR szName[MAX_KEY_NAME];
|
|
HANDLE hFile;
|
|
WIN32_FIND_DATA fd;
|
|
LPUDNODE lpList = NULL, lpItem;
|
|
LONG lResult;
|
|
HKEY hKeyUserDiff;
|
|
UINT Index = 0;
|
|
DWORD dwSize;
|
|
FILETIME ftWrite;
|
|
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Entering.")));
|
|
|
|
|
|
//
|
|
// Test if the hive exists, first look for USERDIFR
|
|
//
|
|
|
|
ExpandUserEnvironmentStrings(pEnv, USERDIFR_LOCATION, szUserDiff, MAX_PATH);
|
|
hFile = FindFirstFile (szUserDiff, &fd);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: userdifr hive doesn't exist. Trying userdiff.")));
|
|
|
|
ExpandUserEnvironmentStrings(pEnv, USERDIFF_LOCATION, szUserDiff, MAX_PATH);
|
|
hFile = FindFirstFile (szUserDiff, &fd);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: userdiff hive doesn't exist. Leaving.")));
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
FindClose (hFile);
|
|
|
|
|
|
//
|
|
// Load the hive
|
|
//
|
|
|
|
if (MyRegLoadKey(HKEY_USERS, USERDIFF, szUserDiff) != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: Failed to load userdiff.")));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Open the key
|
|
//
|
|
|
|
lResult = RegOpenKeyEx(HKEY_USERS, USERDIFF, 0, KEY_READ, &hKeyUserDiff);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
MyRegUnLoadKey(HKEY_USERS, USERDIFF);
|
|
DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: failed to open registry root (%d)"), lResult));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Enumerate the build numbers
|
|
//
|
|
|
|
dwSize = MAX_KEY_NAME;
|
|
lResult = RegEnumKeyEx(hKeyUserDiff, Index, szName, &dwSize, NULL,
|
|
NULL, NULL, &ftWrite);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
do {
|
|
|
|
//
|
|
// Add the node
|
|
//
|
|
|
|
if (!AddUDNode (&lpList, szName)) {
|
|
break;
|
|
}
|
|
|
|
Index++;
|
|
dwSize = MAX_KEY_NAME;
|
|
|
|
lResult = RegEnumKeyEx(hKeyUserDiff, Index, szName, &dwSize, NULL,
|
|
NULL, NULL, &ftWrite);
|
|
|
|
|
|
} while (lResult == ERROR_SUCCESS);
|
|
}
|
|
|
|
|
|
//
|
|
// Close the open key
|
|
//
|
|
|
|
RegCloseKey(hKeyUserDiff);
|
|
|
|
|
|
//
|
|
// Process the builds
|
|
//
|
|
|
|
lpItem = lpList;
|
|
|
|
while (lpItem) {
|
|
|
|
//
|
|
// Only want to apply changes that occurred in
|
|
// builds after the one the user is running.
|
|
//
|
|
|
|
if ( (lpItem->dwBuildNumber > dwBuildNumber) &&
|
|
(lpItem->dwBuildNumber <= g_dwBuildNumber) ) {
|
|
ProcessBuild(lpProfile, lpItem, pEnv);
|
|
}
|
|
|
|
lpItem = lpItem->pNext;
|
|
}
|
|
|
|
|
|
//
|
|
// Free the link list
|
|
//
|
|
|
|
FreeUDList (lpList);
|
|
|
|
|
|
//
|
|
// Unload the hive
|
|
//
|
|
|
|
MyRegUnLoadKey(HKEY_USERS, USERDIFF);
|
|
|
|
|
|
//
|
|
// Success
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Leaving successfully.")));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// AddUDNode()
|
|
//
|
|
// Purpose: Adds a build node to the link listed
|
|
// sorted by build number
|
|
//
|
|
// Parameters: lpList - Link list of nodes
|
|
// lpBuildNumber - New node name
|
|
//
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 10/3/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL AddUDNode (LPUDNODE *lpList, LPTSTR lpBuildNumber)
|
|
{
|
|
LPUDNODE lpNewItem;
|
|
LPUDNODE lpHead, lpPrev;
|
|
|
|
if (!lpBuildNumber || !*lpBuildNumber) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Setup the new node
|
|
//
|
|
|
|
lpNewItem = (LPUDNODE) LocalAlloc(LPTR, sizeof(UDNODE));
|
|
|
|
if (!lpNewItem) {
|
|
return FALSE;
|
|
}
|
|
|
|
lstrcpy (lpNewItem->szBuildNumber, lpBuildNumber);
|
|
lpNewItem->dwBuildNumber = StringToInt(lpBuildNumber);
|
|
lpNewItem->pNext = NULL;
|
|
|
|
|
|
//
|
|
// Now add it to the list sorted
|
|
//
|
|
|
|
lpHead = *lpList;
|
|
lpPrev = NULL;
|
|
|
|
|
|
if (!lpHead) {
|
|
|
|
//
|
|
// First item in the list
|
|
//
|
|
|
|
*lpList = lpNewItem;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// If we made it here, there is one or more items in the list
|
|
//
|
|
|
|
|
|
while (lpHead) {
|
|
|
|
if (lpNewItem->dwBuildNumber <= lpHead->dwBuildNumber) {
|
|
|
|
if (lpPrev) {
|
|
|
|
//
|
|
// Insert the item
|
|
//
|
|
|
|
lpPrev->pNext = lpNewItem;
|
|
lpNewItem->pNext = lpHead;
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Head of the list
|
|
//
|
|
|
|
lpNewItem->pNext = lpHead;
|
|
*lpList = lpNewItem;
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lpPrev = lpHead;
|
|
lpHead = lpHead->pNext;
|
|
}
|
|
|
|
|
|
//
|
|
// Add node to the end of the list
|
|
//
|
|
|
|
lpPrev->pNext = lpNewItem;
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// FreeUDList()
|
|
//
|
|
// Purpose: Free's a UDNODE link list
|
|
//
|
|
// Parameters: lpList - List to be freed
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 10/3/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL FreeUDList (LPUDNODE lpList)
|
|
{
|
|
LPUDNODE lpNext;
|
|
|
|
|
|
if (!lpList) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
lpNext = lpList->pNext;
|
|
|
|
while (lpList) {
|
|
LocalFree (lpList);
|
|
lpList = lpNext;
|
|
|
|
if (lpList) {
|
|
lpNext = lpList->pNext;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessBuild()
|
|
//
|
|
// Purpose: Processes the changes for a specific build
|
|
//
|
|
// Parameters: lpProfile - Profile information
|
|
// lpItem - Build item to process
|
|
// pEnv - Environment block
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 10/3/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ProcessBuild(LPPROFILE lpProfile, LPUDNODE lpItem, LPVOID pEnv)
|
|
{
|
|
TCHAR szSubKey[MAX_PATH];
|
|
LONG lResult;
|
|
HKEY hKey;
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessBuild: Entering with build <%s>."),
|
|
lpItem->szBuildNumber));
|
|
|
|
|
|
//
|
|
// Open "Hive" subkey
|
|
//
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Hive"), USERDIFF, lpItem->szBuildNumber);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
ProcessHive(lpProfile, lpItem, hKey);
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Open "Files" subkey
|
|
//
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Files"), USERDIFF, lpItem->szBuildNumber);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
ProcessFiles(lpProfile, lpItem, hKey);
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Open "Execute" subkey
|
|
//
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Execute"), USERDIFF, lpItem->szBuildNumber);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
ProcessPrograms(lpProfile, lpItem, hKey, pEnv);
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
//
|
|
// Success
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessBuild: Leaving successfully.")));
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessHive()
|
|
//
|
|
// Purpose: Processes the Hive entry for a build
|
|
//
|
|
// Parameters: lpProfile - Profile information
|
|
// lpItem - Build item
|
|
// hKey - Registry key to enumerate
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 10/3/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ProcessHive(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey)
|
|
{
|
|
TCHAR szSubKey[MAX_PATH];
|
|
TCHAR szValueName[MAX_KEY_NAME];
|
|
DWORD dwSize, dwType, dwAction, dwDisp, dwFlags, dwProductType;
|
|
LPBYTE lpValueData;
|
|
LONG lResult;
|
|
UINT Index = 1;
|
|
FILETIME ftWrite;
|
|
HKEY hKeyEntry, hKeyTemp;
|
|
LPTSTR lpName;
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Entering.")));
|
|
|
|
//
|
|
// Process the entry
|
|
//
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Hive\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: No hive entries.")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
//
|
|
// Query for the product type
|
|
//
|
|
|
|
dwSize = sizeof(dwProductType);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
|
|
(LPBYTE)&dwProductType, &dwSize);
|
|
|
|
|
|
//
|
|
// It's ok to not have a product type listed in userdiff.ini.
|
|
// In this case, we always apply the change regardless of the
|
|
// platform.
|
|
//
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// A specific product was listed. Check if
|
|
// we can process this entry.
|
|
//
|
|
|
|
if (!OkToProcessItem(dwProductType)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Skipping Item %d due to product type mismatch."), Index));
|
|
goto LoopAgain;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the action type
|
|
//
|
|
|
|
dwSize = sizeof(dwAction);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_ACTION, NULL, &dwType,
|
|
(LPBYTE)&dwAction, &dwSize);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
switch (dwAction) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Item %d has an action of %d."),
|
|
Index, dwAction));
|
|
|
|
case 1: {
|
|
//
|
|
// Add New Key
|
|
//
|
|
// Get the key name
|
|
//
|
|
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
|
|
(LPBYTE)szSubKey, &dwSize);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
|
|
szSubKey, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS, NULL,
|
|
&hKeyTemp, &dwDisp);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Created subkey <%s>."),
|
|
szSubKey));
|
|
|
|
RegCloseKey(hKeyTemp);
|
|
} else {
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create subkey <%s> with error %d."),
|
|
szSubKey, lResult));
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case 2: {
|
|
//
|
|
// Delete a key and all it's subkeys
|
|
//
|
|
// Get the key name
|
|
//
|
|
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
|
|
(LPBYTE)szSubKey, &dwSize);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Calling RegDelnode on <%s>."),
|
|
szSubKey));
|
|
|
|
RegDelnode (lpProfile->hKeyCurrentUser, szSubKey);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case 3: {
|
|
//
|
|
// Add a new value
|
|
//
|
|
// Get the key name
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Adding a new value.")));
|
|
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
|
|
(LPBYTE)szSubKey, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to get UD_KEYNAME with error %d."), lResult));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
|
|
szSubKey, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS, NULL,
|
|
&hKeyTemp, &dwDisp);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create UD_KEYNAME with error %d."), lResult));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the value name
|
|
//
|
|
|
|
dwSize = MAX_KEY_NAME * sizeof(TCHAR);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAME, NULL, &dwType,
|
|
(LPBYTE)szValueName, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query UD_VALUENAME with error %d."), lResult));
|
|
RegCloseKey(hKeyTemp);
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the value data size
|
|
//
|
|
|
|
dwSize = 0;
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_VALUE, NULL, &dwType,
|
|
NULL, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query UD_VALUE with error %d."), lResult));
|
|
RegCloseKey(hKeyTemp);
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate space for the data
|
|
//
|
|
|
|
lpValueData = LocalAlloc (LPTR, dwSize);
|
|
|
|
if (!lpValueData) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: LocalAlloc failed (%d)."), GetLastError()));
|
|
RegCloseKey(hKeyTemp);
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the value data
|
|
//
|
|
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_VALUE, NULL, &dwType,
|
|
lpValueData, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query value data with error %d."), lResult));
|
|
LocalFree (lpValueData);
|
|
RegCloseKey(hKeyTemp);
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the new value
|
|
//
|
|
|
|
RegSetValueEx(hKeyTemp, szValueName, 0, dwType,
|
|
lpValueData, dwSize);
|
|
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
LocalFree (lpValueData);
|
|
|
|
RegCloseKey(hKeyTemp);
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Finished adding value <%s>."), szValueName));
|
|
}
|
|
break;
|
|
|
|
case 4: {
|
|
//
|
|
// Delete value(s)
|
|
//
|
|
// Get the key name
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Entering delete a value.")));
|
|
|
|
dwSize = ARRAYSIZE(szSubKey);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
|
|
(LPBYTE)szSubKey, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value to delete (%d)."), lResult));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
|
|
szSubKey, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS, NULL,
|
|
&hKeyTemp, &dwDisp);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create key (%s) for value to delete (%d)."), szSubKey, lResult));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the flags
|
|
//
|
|
|
|
dwSize = sizeof(dwFlags);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_FLAGS, NULL, &dwType,
|
|
(LPBYTE)&dwFlags, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
dwFlags = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Process the flags
|
|
//
|
|
|
|
if (dwFlags == 2) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Calling DeleteAllValues.")));
|
|
DeleteAllValues (hKeyTemp);
|
|
RegCloseKey(hKeyTemp);
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the value names size
|
|
//
|
|
|
|
dwSize = 0;
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAMES, NULL, &dwType,
|
|
NULL, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value names to delete (%d)."), lResult));
|
|
RegCloseKey(hKeyTemp);
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Allocate space for the data
|
|
//
|
|
|
|
lpValueData = LocalAlloc (LPTR, dwSize);
|
|
|
|
if (!lpValueData) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: LocalAlloc failed (%d)."), GetLastError()));
|
|
RegCloseKey(hKeyTemp);
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the value data
|
|
//
|
|
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAMES, NULL, &dwType,
|
|
lpValueData, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value data to delete (%d)."), lResult));
|
|
LocalFree (lpValueData);
|
|
RegCloseKey(hKeyTemp);
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Delete the values
|
|
//
|
|
|
|
lpName = (LPTSTR) lpValueData;
|
|
|
|
while (*lpName) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Deleting (%s)."), lpName));
|
|
RegDeleteValue (hKeyTemp, lpName);
|
|
lpName += lstrlen(lpName) + 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Delete the no-name value if appropriate
|
|
//
|
|
|
|
if (dwFlags == 1) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Deleting no name value.")));
|
|
RegDeleteValue (hKeyTemp, NULL);
|
|
}
|
|
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
|
|
LocalFree (lpValueData);
|
|
RegCloseKey(hKeyTemp);
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Leaving deletion code.")));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
LoopAgain:
|
|
|
|
//
|
|
// Close the registry key
|
|
//
|
|
|
|
RegCloseKey(hKeyEntry);
|
|
|
|
|
|
//
|
|
// Enumerate again
|
|
//
|
|
|
|
Index++;
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Hive\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
|
|
|
|
} while (lResult == ERROR_SUCCESS);
|
|
|
|
Exit:
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Leaving.")));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessFiles()
|
|
//
|
|
// Purpose: Processes the Files entry for a build
|
|
//
|
|
// Parameters: lpProfile - Profile information
|
|
// lpItem - Build item
|
|
// hKey - Registry key to enumerate
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 10/3/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ProcessFiles(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey)
|
|
{
|
|
TCHAR szSubKey[MAX_PATH];
|
|
TCHAR szSrc[MAX_PATH];
|
|
TCHAR szDest[MAX_PATH];
|
|
TCHAR szItem[MAX_PATH];
|
|
LPTSTR lpEnd, lpTemp;
|
|
DWORD dwSize, dwType, dwAction, dwProductType;
|
|
LONG lResult;
|
|
UINT Index = 1;
|
|
FILETIME ftWrite;
|
|
HKEY hKeyEntry;
|
|
HANDLE hOldToken;
|
|
BOOL bImpersonateUser = FALSE;
|
|
|
|
|
|
//
|
|
// Verbose Output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Entering.")));
|
|
|
|
|
|
//
|
|
// Process the entry
|
|
//
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Files\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: No Files entries.")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
do {
|
|
//
|
|
// Query for the product type
|
|
//
|
|
|
|
dwSize = sizeof(dwProductType);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
|
|
(LPBYTE)&dwProductType, &dwSize);
|
|
|
|
|
|
//
|
|
// It's ok to not have a product type listed in userdiff.ini.
|
|
// In this case, we always apply the change regardless of the
|
|
// platform.
|
|
//
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// A specific product was listed. Check if
|
|
// we can process this entry.
|
|
//
|
|
|
|
if (!OkToProcessItem(dwProductType)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Skipping Item %d due to product type mismatch."), Index));
|
|
goto LoopAgain;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the action type
|
|
//
|
|
|
|
dwSize = sizeof(dwAction);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_ACTION, NULL, &dwType,
|
|
(LPBYTE)&dwAction, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to query action type (%d)."), lResult));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the item
|
|
//
|
|
|
|
dwSize = ARRAYSIZE(szItem);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_ITEM, NULL, &dwType,
|
|
(LPBYTE)szItem, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to query UD_ITEM type (%d)."), lResult));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Item %d has an action of %d."),
|
|
Index, dwAction));
|
|
|
|
//
|
|
// Impersonate the user
|
|
//
|
|
|
|
if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to impersonate user")));
|
|
RegCloseKey(hKeyEntry);
|
|
goto Exit;
|
|
}
|
|
bImpersonateUser = TRUE;
|
|
|
|
switch (dwAction) {
|
|
|
|
case 1:
|
|
|
|
//
|
|
// Create new program group
|
|
//
|
|
|
|
GetSpecialFolderPath (CSIDL_PROGRAMS, szDest);
|
|
lpEnd = CheckSlash(szDest);
|
|
lstrcpy (lpEnd, szItem);
|
|
|
|
if (CreateNestedDirectory(szDest, NULL)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Created new group (%s)."), szDest));
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to created new group (%s) with (%d)."),
|
|
szDest, GetLastError()));
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
//
|
|
// Delete a program group
|
|
//
|
|
|
|
GetSpecialFolderPath (CSIDL_PROGRAMS, szDest);
|
|
lpEnd = CheckSlash(szDest);
|
|
lstrcpy (lpEnd, szItem);
|
|
|
|
Delnode(szDest);
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted group (%s)."), szDest));
|
|
|
|
break;
|
|
|
|
case 3:
|
|
{
|
|
TCHAR szStartMenu [MAX_FOLDER_SIZE];
|
|
DWORD dwSize;
|
|
|
|
//
|
|
// Add a new item
|
|
//
|
|
|
|
dwSize = ARRAYSIZE(szSrc);
|
|
if (!GetDefaultUserProfileDirectory(szSrc, &dwSize)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to get default user profile.")));
|
|
goto LoopAgain;
|
|
}
|
|
|
|
lpEnd = CheckSlash(szSrc);
|
|
|
|
if (LoadString (g_hDllInstance, IDS_SH_PROGRAMS, szStartMenu,
|
|
MAX_FOLDER_SIZE)) {
|
|
|
|
lstrcpy (lpEnd, szStartMenu);
|
|
lpEnd = CheckSlash(szSrc);
|
|
lstrcpy (lpEnd, szItem);
|
|
|
|
|
|
GetSpecialFolderPath (CSIDL_PROGRAMS, szDest);
|
|
lpEnd = CheckSlash(szDest);
|
|
lstrcpy (lpEnd, szItem);
|
|
|
|
if (CopyFile (szSrc, szDest, FALSE)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: <%s> ==> <%s> [OK]."),
|
|
szSrc, szDest));
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: <%s> ==> <%s> [FAILED %d]."),
|
|
szSrc, szDest, GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
|
//
|
|
// Delete a program item
|
|
//
|
|
|
|
GetSpecialFolderPath (CSIDL_PROGRAMS, szDest);
|
|
lpEnd = CheckSlash(szDest);
|
|
lstrcpy (lpEnd, szItem);
|
|
|
|
if (DeleteFile(szDest)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted <%s>"), szDest));
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to deleted <%s> with %d"), szDest, GetLastError()));
|
|
}
|
|
|
|
|
|
//
|
|
// Attempt to delete the directory
|
|
//
|
|
|
|
lpTemp = szDest + lstrlen(szDest) - 1;
|
|
lpEnd--;
|
|
|
|
while ((*lpTemp != TEXT('\\')) && lpTemp > lpEnd) {
|
|
lpTemp--;
|
|
}
|
|
|
|
if (lpTemp == lpEnd) {
|
|
break;
|
|
}
|
|
|
|
*lpTemp = TEXT('\0');
|
|
|
|
if (RemoveDirectory(szDest)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted directory <%s>"), szDest));
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Failed to delete directory <%s> with %d"), szDest, GetLastError()));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
LoopAgain:
|
|
|
|
if (bImpersonateUser) {
|
|
//
|
|
// Revert to being 'ourself'
|
|
//
|
|
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to revert to self")));
|
|
}
|
|
bImpersonateUser = FALSE;
|
|
}
|
|
|
|
//
|
|
// Close the registry key
|
|
//
|
|
|
|
RegCloseKey(hKeyEntry);
|
|
|
|
|
|
//
|
|
// Enumerate again
|
|
//
|
|
|
|
Index++;
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Files\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
|
|
|
|
} while (lResult == ERROR_SUCCESS);
|
|
|
|
Exit:
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Leaving.")));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessPrograms()
|
|
//
|
|
// Purpose: Processes the Execute entry for a build
|
|
//
|
|
// Parameters: lpProfile - Profile information
|
|
// lpItem - Build item
|
|
// hKey - Registry key to enumerate
|
|
// pEnv - Environment block
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 11/16/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ProcessPrograms (LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey, LPVOID pEnv)
|
|
{
|
|
TCHAR szSubKey[MAX_PATH];
|
|
TCHAR szCmdLine[MAX_PATH];
|
|
TCHAR szFullPath[MAX_PATH];
|
|
DWORD dwSize, dwType, dwProductType;
|
|
LONG lResult;
|
|
UINT Index = 1;
|
|
HKEY hKeyEntry;
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION ProcessInformation;
|
|
BOOL Result;
|
|
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Entering.")));
|
|
|
|
|
|
//
|
|
// Process the entry
|
|
//
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: No execute entries.")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
//
|
|
// Query for the product type
|
|
//
|
|
|
|
dwSize = sizeof(dwProductType);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
|
|
(LPBYTE)&dwProductType, &dwSize);
|
|
|
|
|
|
//
|
|
// It's ok to not have a product type listed in userdiff.ini.
|
|
// In this case, we always apply the change regardless of the
|
|
// platform.
|
|
//
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// A specific product was listed. Check if
|
|
// we can process this entry.
|
|
//
|
|
|
|
if (!OkToProcessItem(dwProductType)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Skipping Item %d due to product type mismatch."), Index));
|
|
goto LoopAgain;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the command line
|
|
//
|
|
|
|
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
lResult = RegQueryValueEx(hKeyEntry, UD_COMMANDLINE, NULL, &dwType,
|
|
(LPBYTE)szCmdLine, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// If we have a NULL path, loop again.
|
|
//
|
|
|
|
if (szCmdLine[0] == TEXT('\0')) {
|
|
goto LoopAgain;
|
|
}
|
|
|
|
|
|
//
|
|
// Expand the command line
|
|
//
|
|
|
|
ExpandUserEnvironmentStrings(pEnv, szCmdLine, szFullPath, MAX_PATH);
|
|
|
|
|
|
//
|
|
// Initialize process startup info
|
|
//
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.lpReserved = NULL;
|
|
si.lpTitle = NULL;
|
|
si.lpDesktop = NULL;
|
|
si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
|
|
si.dwFlags = STARTF_USESHOWWINDOW;
|
|
si.wShowWindow = SW_SHOWNORMAL;
|
|
si.lpReserved2 = NULL;
|
|
si.cbReserved2 = 0;
|
|
|
|
|
|
//
|
|
// Start the app
|
|
//
|
|
|
|
Result = CreateProcessAsUser(lpProfile->hTokenUser, NULL, szFullPath,
|
|
NULL, NULL, FALSE,
|
|
NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
|
|
pEnv, NULL, &si, &ProcessInformation);
|
|
|
|
if (Result) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Spawned <%s>. Waiting for it to complete."),
|
|
szFullPath));
|
|
|
|
//
|
|
// Wait for the app to complete (3 minutes max)
|
|
//
|
|
|
|
WaitForSingleObject(ProcessInformation.hProcess, 180000);
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Finished waiting for <%s>."),
|
|
szFullPath));
|
|
|
|
|
|
//
|
|
// Close our handles to the process and thread
|
|
//
|
|
|
|
CloseHandle(ProcessInformation.hProcess);
|
|
CloseHandle(ProcessInformation.hThread);
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Failed to execute <%s>, error = %d"),
|
|
szFullPath, GetLastError()));
|
|
}
|
|
|
|
LoopAgain:
|
|
|
|
//
|
|
// Close the registry key
|
|
//
|
|
|
|
RegCloseKey(hKeyEntry);
|
|
|
|
|
|
//
|
|
// Enumerate again
|
|
//
|
|
|
|
Index++;
|
|
|
|
wsprintf (szSubKey, TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
|
|
lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
|
|
|
|
} while (lResult == ERROR_SUCCESS);
|
|
|
|
Exit:
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Leaving.")));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// OkToProcessItem()
|
|
//
|
|
// Purpose: Determines if the platform currently running
|
|
// on should have the change in userdiff.ini applied.
|
|
//
|
|
// Parameters: dwProductType - ProductType for a specific entry
|
|
// in userdiff.ini
|
|
//
|
|
// Return: TRUE if change should be applied
|
|
// FALSE if not
|
|
//
|
|
// Comments: dwProductType can be one of these values:
|
|
//
|
|
// 0 = All platforms
|
|
// 1 = All server platforms
|
|
// 2 = Workstation
|
|
// 3 = Server
|
|
// 4 = Domain Controller
|
|
//
|
|
// History: Date Author Comment
|
|
// 4/08/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL OkToProcessItem(DWORD dwProductType)
|
|
{
|
|
BOOL bRetVal = FALSE;
|
|
|
|
|
|
switch (g_ProductType) {
|
|
|
|
case PT_WORKSTATION:
|
|
|
|
if ( (dwProductType == 0) ||
|
|
(dwProductType == 2) ) {
|
|
|
|
bRetVal = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case PT_SERVER:
|
|
|
|
if ( (dwProductType == 0) ||
|
|
(dwProductType == 1) ||
|
|
(dwProductType == 3) ) {
|
|
|
|
bRetVal = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case PT_DC:
|
|
if ( (dwProductType == 0) ||
|
|
(dwProductType == 1) ||
|
|
(dwProductType == 4) ) {
|
|
|
|
bRetVal = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return bRetVal;
|
|
}
|