//************************************************************* // // Userdiff.c // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1995 // All rights reserved // //************************************************************* #include "uenv.h" #include "strsafe.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; DWORD cchNeeded; BOOL bUserDifrExist = FALSE; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Entering."))); // // Test if the hive exists, first look for USERDIFR // cchNeeded = ExpandUserEnvironmentStrings(pEnv, USERDIFR_LOCATION, szUserDiff, MAX_PATH); if (cchNeeded > 0 && cchNeeded <= MAX_PATH) { hFile = FindFirstFile (szUserDiff, &fd); if (hFile != INVALID_HANDLE_VALUE) { bUserDifrExist = TRUE; FindClose(hFile); } } if (!bUserDifrExist) { BOOL bUserDiffExist = FALSE; DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: userdifr hive doesn't exist. Trying userdiff."))); cchNeeded = ExpandUserEnvironmentStrings(pEnv, USERDIFF_LOCATION, szUserDiff, MAX_PATH); if (cchNeeded > 0 && cchNeeded <= MAX_PATH) { hFile = FindFirstFile (szUserDiff, &fd); if (hFile != INVALID_HANDLE_VALUE) { bUserDiffExist = TRUE; FindClose(hFile); } } if (!bUserDiffExist) { DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: userdiff hive doesn't exist. Leaving."))); return TRUE; } } // // 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; } StringCchCopy (lpNewItem->szBuildNumber, MAX_BUILD_NUMBER, 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 // StringCchPrintf(szSubKey, ARRAYSIZE(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 // StringCchPrintf(szSubKey, ARRAYSIZE(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 // StringCchPrintf(szSubKey, ARRAYSIZE(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 // StringCchPrintf(szSubKey, ARRAYSIZE(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++; StringCchPrintf(szSubKey, ARRAYSIZE(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; DWORD cchEnd; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Entering."))); // // Process the entry // StringCchPrintf(szSubKey, ARRAYSIZE(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 // if (GetSpecialFolderPath (CSIDL_PROGRAMS, szDest)) { lpEnd = CheckSlashEx(szDest, ARRAYSIZE(szDest), &cchEnd); if (lpEnd) { StringCchCopy (lpEnd, cchEnd, 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 // if (GetSpecialFolderPath (CSIDL_PROGRAMS, szDest)) { lpEnd = CheckSlashEx(szDest, ARRAYSIZE(szDest), &cchEnd); if (lpEnd) { StringCchCopy (lpEnd, cchEnd, szItem); Delnode(szDest); DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted group (%s)."), szDest)); } } break; case 3: { TCHAR szStartMenu [MAX_FOLDER_SIZE]; // // 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 = CheckSlashEx(szSrc, ARRAYSIZE(szSrc), &cchEnd); if (lpEnd) { if (LoadString (g_hDllInstance, IDS_SH_PROGRAMS, szStartMenu, MAX_FOLDER_SIZE)) { StringCchCopy (lpEnd, cchEnd, szStartMenu); lpEnd = CheckSlashEx(szSrc, ARRAYSIZE(szSrc), &cchEnd); if (lpEnd) { StringCchCopy (lpEnd, cchEnd, szItem); if (GetSpecialFolderPath (CSIDL_PROGRAMS, szDest)) { lpEnd = CheckSlashEx(szDest, ARRAYSIZE(szDest), &cchEnd); if (lpEnd) { StringCchCopy (lpEnd, cchEnd, 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 // if (GetSpecialFolderPath (CSIDL_PROGRAMS, szDest)) { lpEnd = CheckSlashEx(szDest, ARRAYSIZE(szDest), &cchEnd); if (lpEnd) { StringCchCopy (lpEnd, cchEnd, 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++; StringCchPrintf(szSubKey, ARRAYSIZE(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; DWORD dwTokenSessionId; DWORD dwProcessSessionId; HANDLE hPrimaryToken = NULL; BOOL bTokenCreated = FALSE; DWORD cchExpanded; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Entering."))); // // Process the entry // StringCchPrintf(szSubKey, ARRAYSIZE(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; } // // Get the session id info for user token. In TS?FUS case we can't // create process across the session as it not yet received // WL_NOTIFY_LOGON notification from winlogon // dwProcessSessionId = NtCurrentPeb()->SessionId; if (GetTokenInformation(lpProfile->hTokenUser, TokenSessionId, (LPVOID) &dwTokenSessionId, sizeof(dwTokenSessionId), &dwSize) && dwTokenSessionId != dwProcessSessionId) { // // We are loading profile for a remote session // So first create a primary token and change // the session id in it for CreateProcessAsUser // to work // if (!DuplicateTokenEx(lpProfile->hTokenUser, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken)) { DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Failed to create primary token. Error %d"), GetLastError())); goto Exit; } bTokenCreated = TRUE; // Set the session id in new primary token if (!SetTokenInformation(hPrimaryToken, TokenSessionId, (LPVOID) &dwProcessSessionId, sizeof(dwProcessSessionId))) { DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Failed to set session id in primary token. Error %d"), GetLastError())); goto Exit; } } else { hPrimaryToken = lpProfile->hTokenUser; } 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; } /* // // If the command line is not begin with %SystemRoot%, skip it. // if (CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, szCmdLine, lstrlen(TEXT("%SystemRoot%")), TEXT("%SystemRoot%"), -1) != CSTR_EQUAL) { DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Skipping %s, since it is not from %SystemRoot%."), szCmdLine)); goto LoopAgain; } */ // // Expand the command line // cchExpanded = ExpandUserEnvironmentStrings(pEnv, szCmdLine, szFullPath, MAX_PATH); if (cchExpanded > 0 && cchExpanded < 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(hPrimaryToken, 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++; StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey), TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index); lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry); } while (lResult == ERROR_SUCCESS); Exit: if (bTokenCreated) { CloseHandle(hPrimaryToken); } 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; }