//************************************************************* // // Profile management routines. Implements IUserProfile. // The organization of this file is as follows: // Implementation of CUserProfile object // Implementation of CUserProfile2 object // LoadUserProfile // UnloadUserProfile // All other global functions // Implementation of various other objects and data structures // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1995 // All rights reserved // //************************************************************* #include "uenv.h" #include #include #include #include #include #include #include "profmgr.hxx" // // XPSP1 specific // #include "xpsp1res.h" // // Length of const strings. // DWORD USER_KEY_PREFIX_LEN = lstrlen(USER_KEY_PREFIX); DWORD USER_CLASSES_HIVE_SUFFIX_LEN = lstrlen(USER_CLASSES_HIVE_SUFFIX); // // Tells us if we are loaded by winlogon or not. // extern "C" DWORD g_dwLoadFlags = 0; // // The user profile manager. There's only one instance of this object, // it resides in console winlogon. // CUserProfile cUserProfileManager; // // Local function proto-types // LPTSTR AllocAndExpandProfilePath(LPPROFILEINFO lpProfileInfo); DWORD ApplySecurityToRegistryTree(HKEY RootKey, PSECURITY_DESCRIPTOR pSD); BOOL CheckForSlowLink(LPPROFILE lpProfile, DWORD dwTime, LPTSTR lpPath, BOOL bDlgLogin); BOOL CheckNetDefaultProfile(LPPROFILE lpProfile); BOOL APIENTRY ChooseProfileDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL CompareProfileInfo(LPPROFILEINFO pProfileInfo1, LPPROFILEINFO pProfileInfo2); LPPROFILEINFO CopyProfileInfo(LPPROFILEINFO pProfileInfo); BOOL CreateLocalProfileImage(LPPROFILE lpProfile, LPTSTR lpBaseName); BOOL CreateLocalProfileKey(LPPROFILE lpProfile, PHKEY phKey, BOOL *bKeyExists); DWORD DecrementProfileRefCount(LPPROFILE lpProfile); DWORD DeletePolicyState(LPCWSTR szSid ); void DeleteProfileInfo(LPPROFILEINFO pProfileInfo); void DumpOpenRegistryHandle(LPTSTR lpkeyName); BOOL GetExistingLocalProfileImage(LPPROFILE lpProfile); void ReleaseClientContext_s(PPCONTEXT_HANDLE pphContext); BOOL GetUserDomainName(LPPROFILE lpProfile, LPTSTR lpDomainName, LPDWORD lpDomainNameSize); DWORD GetUserPreferenceValue(HANDLE hToken); DWORD IncrementProfileRefCount(LPPROFILE lpProfile, BOOL bInitialize); BOOL IsCacheDeleted(); BOOL IsCentralProfileReachable(LPPROFILE lpProfile, BOOL *bCreateCentralProfile, BOOL *bMandatory, BOOL* bOwnerOK); BOOL IssueDefaultProfile(LPPROFILE lpProfile, LPTSTR lpDefaultProfile, LPTSTR lpLocalProfile, LPTSTR lpSidString, BOOL bMandatory); BOOL IsTempProfileAllowed(); LPPROFILE LoadProfileInfo(HANDLE hTokenClient, HANDLE hTokenUser, HKEY hKeyCurrentUser); BOOL ParseProfilePath(LPPROFILE lpProfile, LPTSTR lpProfilePath, BOOL *bpCSCBypassed, TCHAR *cpDrive); BOOL PatchNewProfileIfRequired(HANDLE hToken); BOOL IsGuiSetupInProgress(); BOOL PrepareProfileForUse(LPPROFILE lpProfile, LPVOID pEnv); BOOL RestoreUserProfile(LPPROFILE lpProfile); BOOL SaveProfileInfo(LPPROFILE lpProfile); BOOL SetNtUserIniAttributes(LPTSTR szDir); BOOL SetProfileTime(LPPROFILE lpProfile); BOOL TestIfUserProfileLoaded(HANDLE hUserToken, LPPROFILEINFO lpProfileInfo); DWORD ThreadMain(PMAP pThreadMap); BOOL UpgradeCentralProfile(LPPROFILE lpProfile, LPTSTR lpOldProfile); BOOL UpgradeProfile(LPPROFILE lpProfile, LPVOID pEnv); BOOL IsProfileInUse (LPCTSTR szComputer, LPCTSTR lpSid); BOOL IsUIRequired(HANDLE hToken); void CheckRUPShare(LPTSTR lpProfilePath); INT_PTR APIENTRY LoginSlowLinkDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR APIENTRY LogoffSlowLinkDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL RegisterDialogInterface(LPTSTR szRPCEndPoint); BOOL UnRegisterDialogInterface(void); BOOL IsPartialRoamingProfile(LPPROFILE lpProfile); void TouchLocalHive(LPPROFILE lpProfile); HRESULT CheckRoamingShareOwnership(LPTSTR lpDir, HANDLE hTokenUser); #define USERNAME_VARIABLE TEXT("USERNAME") //************************************************************* // // LoadUserProfile() // // Purpose: Loads the user's profile, if unable to load // use the cached profile or issue the default profile. // // Parameters: hToken - User's token // lpProfileInfo - Profile Information // // Return: TRUE if successful // FALSE if an error occurs // // Comments: This is a wrapper around IUserProfile::LoadUserProfile // and LoadUserProfileP. // // History: Date Author Comment // 6/6/95 ericflo Created // 6/14/00 weiruc changed to be a wrapper for // IUserProfile->LoadUserProfileP. // //************************************************************* BOOL WINAPI LoadUserProfile(HANDLE hToken, LPPROFILEINFO lpProfileInfo) { BOOL bResult = FALSE; // Return value HANDLE hOldToken = NULL; NTSTATUS status; BOOLEAN bRestoreWasEnabled; BOOLEAN bBackupWasEnabled; BOOL bRestoreEnabled = FALSE; BOOL bBackupEnabled = FALSE; TCHAR ProfileDir[MAX_PATH]; DWORD dwProfileDirSize = MAX_PATH; BOOL bCoInitialized = FALSE; long lResult; LPTSTR pSid = NULL; DWORD dwErr = ERROR_SUCCESS; PCONTEXT_HANDLE phContext = NULL; handle_t hIfUserProfile; BOOL bBindInterface = FALSE; TCHAR szRPCEndPoint[MAX_PATH]; LPTSTR lpRPCEndPoint = NULL; // // Initialize the debug flags. // InitDebugSupport( FALSE ); // // Check Parameters // if (!lpProfileInfo) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: NULL lpProfileInfo"))); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } if (lpProfileInfo->dwSize != sizeof(PROFILEINFO)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: lpProfileInfo->dwSize != sizeof(PROFILEINFO)"))); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } if (!lpProfileInfo->lpUserName || !(*lpProfileInfo->lpUserName)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: received a NULL pointer for lpUserName."))); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } // // Make sure we can impersonate the user // if (!ImpersonateUser(hToken, &hOldToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to impersonate user with %d."), dwErr)); goto Exit; } // // Revert to ourselves. // RevertToUser(&hOldToken); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Yes, we can impersonate the user. Running as self"))); // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("========================================================="))); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Entering, hToken = <0x%x>, lpProfileInfo = 0x%x"), hToken, lpProfileInfo)); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->dwFlags = <0x%x>"), lpProfileInfo->dwFlags)); if (lpProfileInfo->lpUserName) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpUserName = <%s>"), lpProfileInfo->lpUserName)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL user name!"))); } if (lpProfileInfo->lpProfilePath) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpProfilePath = <%s>"), lpProfileInfo->lpProfilePath)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL central profile path"))); } if (lpProfileInfo->lpDefaultPath) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpDefaultPath = <%s>"), lpProfileInfo->lpDefaultPath)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL default profile path"))); } if (lpProfileInfo->lpServerName) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpServerName = <%s>"), lpProfileInfo->lpServerName)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL server name"))); } if (lpProfileInfo->dwFlags & PI_APPLYPOLICY) { if (lpProfileInfo->lpPolicyPath) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpPolicyPath = <%s>"), lpProfileInfo->lpPolicyPath)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL policy path"))); } } // // If we are in console winlogon process, call // IUserProfile::LoadUserProfileP directly. Otherwise get the COM interface // if(cUserProfileManager.IsConsoleWinlogon()) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: In console winlogon process"))); // // Call the private load user profile function. // if (!cUserProfileManager.LoadUserProfileP(NULL, hToken, lpProfileInfo, NULL)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: LoadUserProfileP failed with error %d"), dwErr)); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: LoadUserProfileP succeeded"))); } else { // // Enable restore and backup privilege (LoadUserClasses requires both). // Winlogon won't be able to enable the privilege for us. // status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &bRestoreWasEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to enable the restore privilege. error = %08x"), status)); dwErr = RtlNtStatusToDosError(status); goto Exit; } bRestoreEnabled = TRUE; status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &bBackupWasEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to enable the backup privilege. error = %08x"), status)); dwErr = RtlNtStatusToDosError(status); goto Exit; } bBackupEnabled = TRUE; // // Get the IUserProfile interface. // if (!GetInterface(&hIfUserProfile, cszRPCEndPoint)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: GetInterface failed with error %d"), dwErr)); goto Exit; } bBindInterface = TRUE; // // Call IUserProfile->DropClientToken, this will let us drop off our // client token and give us back the context. // RpcTryExcept { dwErr = cliDropClientContext(hIfUserProfile, lpProfileInfo, &phContext); } RpcExcept(1) { dwErr = RpcExceptionCode(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Calling DropClientContext took exception. err = %d"), dwErr)); } RpcEndExcept if (dwErr != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Calling DropClientContext failed. err = %d"), dwErr)); goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Calling DropClientToken (as self) succeeded"))); } // // Register the dialog interface // if (!(lpProfileInfo->dwFlags & (PI_NOUI | PI_LITELOAD))) { _snwprintf(szRPCEndPoint, MAX_PATH, L"IProfileDialog_%d", GetCurrentProcessId()); if (!RegisterDialogInterface(szRPCEndPoint)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: RegisterDialogInterface fails."))); lpRPCEndPoint = NULL; } else { lpRPCEndPoint = szRPCEndPoint; } } // // Impersonate the user and call IUserProfile->LoadUserProfileI(). // if(!ImpersonateUser(hToken, &hOldToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ImpersonateUser failed. err = %d"), dwErr)); goto Exit; } RpcTryExcept { dwErr = cliLoadUserProfileI(hIfUserProfile, lpProfileInfo, phContext, lpRPCEndPoint); } RpcExcept(1) { dwErr = RpcExceptionCode(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Calling LoadUserProfileI took exception. err = %d"), dwErr)); } RpcEndExcept RevertToUser(&hOldToken); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Running as self"))); if (dwErr != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Calling LoadUserProfileI failed. err = %d"), dwErr)); goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Calling LoadUserProfileI (as user) succeeded"))); } // // Open the user's hive. // pSid = GetSidString(hToken); if(pSid == NULL) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: GetSidString failed, err = %d"), dwErr)); goto Exit; } lResult = RegOpenKeyEx(HKEY_USERS, pSid, 0, KEY_ALL_ACCESS, (PHKEY)&lpProfileInfo->hProfile); if(lResult != ERROR_SUCCESS) { dwErr = lResult; DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to open current user <%s> key. Error = %d"), pSid, lResult)); DeleteSidString(pSid); goto Exit; } DeleteSidString(pSid); } // Is console winlogon? // // Set the USERPROFILE environment variable just so that there's no change // of behavior with the old in process LoadUserProfile API. Callers // expecting this env to be set is under the risk that while // SetEnvironmentVariable is per process but LoadUserProfile can be called // on multiple threads. // if(!GetUserProfileDirectory(hToken, ProfileDir, &dwProfileDirSize)) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: GetUserProfileDirectory failed with %08x"), GetLastError())); } else { SetEnvironmentVariable (TEXT("USERPROFILE"), ProfileDir); } bResult = TRUE; DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Returning success. Final Information follows:"))); DebugMsg((DM_VERBOSE, TEXT("lpProfileInfo->UserName = <%s>"), lpProfileInfo->lpUserName)); DebugMsg((DM_VERBOSE, TEXT("lpProfileInfo->lpProfilePath = <%s>"), lpProfileInfo->lpProfilePath)); DebugMsg((DM_VERBOSE, TEXT("lpProfileInfo->dwFlags = 0x%x"), lpProfileInfo->dwFlags)); Exit: // // Restore the previous privileges. // if(bRestoreEnabled && !bRestoreWasEnabled) { status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, bRestoreWasEnabled, FALSE, &bRestoreWasEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Failed to restore the original restore privilege setting. error = %08x"), status)); } } if(bBackupEnabled && !bBackupWasEnabled) { status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, bBackupWasEnabled, FALSE, &bBackupWasEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Failed to restore the original backup privilege setting. error = %08x"), status)); } } // // Unregister the Dialog interface // if (lpRPCEndPoint && !UnRegisterDialogInterface()) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: UnRegisterDialogInterface fails."))); } // // Release the context handle // if (phContext) { RpcTryExcept { cliReleaseClientContext(hIfUserProfile, &phContext); } RpcExcept(1) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ReleaseClientContext took exception."), RpcExceptionCode())); } RpcEndExcept } // // Release the interface // if (bBindInterface) { if (!ReleaseInterface(&hIfUserProfile)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ReleaseInterface failed."))); } } // // Release the tokens. // if(hOldToken) { CloseHandle(hOldToken); } if(bResult) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Returning TRUE. hProfile = <0x%x>"), lpProfileInfo->hProfile)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Returning FALSE. Error = %d"), dwErr)); } // // Set the last error to win32 error code. // SetLastError(dwErr); // // Return. // return bResult; } //************************************************************* // // UnloadUserProfile() // // Purpose: Unloads the user's profile. // // Parameters: hToken - User's token // hProfile - Profile handle created in LoadUserProfile // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/7/95 ericflo Created // 6/15/00 weiruc Modified to wrap // IUserProfile->UnloadUserProfileP. // //************************************************************* BOOL WINAPI UnloadUserProfile(HANDLE hToken, HANDLE hProfile) { HANDLE hOldToken = NULL; BOOL bResult = FALSE; NTSTATUS status; BOOLEAN bWasBackupEnabled, bWasRestoreEnabled; BOOL bBackupEnabled = FALSE, bRestoreEnabled = FALSE; BOOL bCoInitialized = FALSE; DWORD dwErr = ERROR_SUCCESS; PCONTEXT_HANDLE phContext = NULL; handle_t hIfUserProfile; BOOL bBindInterface = FALSE; TCHAR szRPCEndPoint[MAX_PATH]; LPTSTR lpRPCEndPoint = NULL; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Entering, hProfile = <0x%x>"), hProfile)); // // Check Parameters // if (!hProfile || hProfile == INVALID_HANDLE_VALUE) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: received a NULL hProfile."))); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } if(!hToken || hToken == INVALID_HANDLE_VALUE) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: received a NULL hToken."))); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } // // Make sure we can impersonate the user // if (!ImpersonateUser(hToken, &hOldToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to impersonate user with %d."), dwErr)); goto Exit; } // // Revert to ourselves. // RevertToUser(&hOldToken); // // If we are in console winlogon process, call // IUserProfile::UnloadUserProfileP directly. Otherwise get the COM interface // if(cUserProfileManager.IsConsoleWinlogon()) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: In console winlogon process"))); // // Call the private UnloadUserProfile function. // if(!cUserProfileManager.UnloadUserProfileP(NULL, hToken, (HKEY)hProfile, NULL)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: UnloadUserProfileP failed with %d"), dwErr)); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: UnloadUserProfileP succeeded"))); } else { // // Close the hProfile key user passed in. // RegCloseKey((HKEY)hProfile); // // Enable the restore & backup privilege before calling over to winlogon. // Winlogon won't be able to enable the privilege for us. // status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &bWasRestoreEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to enable the restore privilege. error = %08x"), status)); dwErr = RtlNtStatusToDosError(status); goto Exit; } bRestoreEnabled = TRUE; status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &bWasBackupEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to enable the backup privilege. error = %08x"), status)); dwErr = RtlNtStatusToDosError(status); goto Exit; } bBackupEnabled = TRUE; // // Get the IUserProfile interface. // if(!GetInterface(&hIfUserProfile, cszRPCEndPoint)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: GetInterface failed with error %d"), dwErr)); goto Exit; } bBindInterface = TRUE; // // Call IUserProfile->DropClientToken, this will let us drop off our // client token and give us back the context. // RpcTryExcept { dwErr = cliDropClientContext(hIfUserProfile, NULL, &phContext); } RpcExcept(1) { dwErr = RpcExceptionCode(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfile: Calling DropClientToken took exception. error %d"), dwErr)); } RpcEndExcept if (dwErr != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnLoadUserProfile: Calling DropClientContext failed. err = %d"), dwErr)); goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("UnLoadUserProfile: Calling DropClientToken (as self) succeeded"))); } // // Register the dialog interface if req // if (IsUIRequired(hToken)) { _snwprintf(szRPCEndPoint, MAX_PATH, L"IProfileDialog_%d", GetCurrentProcessId()); if (!RegisterDialogInterface(szRPCEndPoint)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: RegisterDialogInterface fails."))); lpRPCEndPoint = NULL; } else { lpRPCEndPoint = szRPCEndPoint; } } // // Impersonate the user and call IUserProfile->UnloadUserProfileI(). // if (!ImpersonateUser(hToken, &hOldToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: ImpersonateUser failed. err = %d"), dwErr)); goto Exit; } RpcTryExcept { dwErr = cliUnloadUserProfileI(hIfUserProfile, phContext, lpRPCEndPoint); } RpcExcept(1) { dwErr = RpcExceptionCode(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfile: Calling UnLoadUserProfileI took exception. err = %d"), dwErr)); } RpcEndExcept // // Revert back. // RevertToUser(&hOldToken); if (dwErr != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnLoadUserProfile: Calling UnLoadUserProfileI failed. err = %d"), dwErr)); goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Calling UnloadUserProfileI succeeded"))); } } // Is console winlogon? bResult = TRUE; Exit: // // Restore the previous privilege. // if(bRestoreEnabled && !bWasRestoreEnabled) { status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, bWasRestoreEnabled, FALSE, &bWasRestoreEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Failed to restore the original restore privilege setting. error = %08x"), status)); } } if(bBackupEnabled && !bWasBackupEnabled) { status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, bWasBackupEnabled, FALSE, &bWasBackupEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Failed to restore the original backup privilege setting. error = %08x"), status)); } } // // Unregister the Dialog interface // if (lpRPCEndPoint && !UnRegisterDialogInterface()) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: UnRegisterDialogInterface fails."))); } // // Release the context handle // if (phContext) { RpcTryExcept { cliReleaseClientContext(hIfUserProfile, &phContext); } RpcExcept(1) { DebugMsg((DM_WARNING, TEXT("UnLoadUserProfile: ReleaseClientContext took exception."), RpcExceptionCode())); } RpcEndExcept } // // Release the interface // if (bBindInterface) { if (!ReleaseInterface(&hIfUserProfile)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ReleaseInterface failed."))); } } // // Release the tokens. // if(hOldToken) { CloseHandle(hOldToken); } // // Set the last error to win32 error code. // SetLastError(dwErr); // // Return. // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: returning %d"), bResult)); return bResult; } //************************************************************* // // CUserProfile::Initialize() // // Initializes the class. Called by and only by console winlogon. // // Return value: // // This function does not return a value. // // History: // // Created weiruc 2/29/2000 // //************************************************************* void CUserProfile::Initialize() { LONG lResult; HKEY hkProfileList = NULL; DWORD i = 0; TCHAR tszSubKeyName[MAX_PATH]; DWORD dwcSubKeyName = MAX_PATH; FILETIME ftLWT; // last write time. HRESULT hres; BOOL bCSInitialized = FALSE; RPC_STATUS status; DebugMsg((DM_VERBOSE, TEXT("Entering CUserProfile::Initialize ..."))); // // If the caller is not winlogon, do nothing and return. // if(g_dwLoadFlags != WINLOGON_LOAD) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize called by non-winlogon process, %d"), g_dwLoadFlags)); goto Exit; } bConsoleWinlogon = TRUE; DebugMsg((DM_VERBOSE, TEXT("CUserProfile::Initialize called by winlogon"))); // // If this function is already called, do nothing but return. // if(bInitialized) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize already called"))); goto Exit; } // // Initialize the critical section that protects the map. // __try { if(!InitializeCriticalSectionAndSpinCount(&csMap, 0x80000000)) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize: InitializeCriticalSectionAndSpinCount failed with %08x"), GetLastError())); goto Exit; } bCSInitialized = TRUE; } __except(EXCEPTION_EXECUTE_HANDLER) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize: InitializeCriticalSection failed"))); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("CUserProfile::Initialize: critical section initialized"))); // // Initialize the whrc data // pMap = NULL; cTable.Initialize(); // // Initialize the sync manager. // if(!cSyncMgr.Initialize()) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize: Initialize sync manager failed"))); goto Exit; } // // Clean up the unloaded hives and undeleted profiles that we didn't handle // before last shutdown. // // // Open the profile list key. // lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, PROFILE_LIST_PATH, 0, KEY_READ, &hkProfileList); if(lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize: Failed to open profile list key with error %d"), lResult)); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("CUserProfile::Initialize: registry key %s opened"), PROFILE_LIST_PATH)); // // Enumerate users. // i = 0; while((lResult = RegEnumKeyEx(hkProfileList, i, tszSubKeyName, &dwcSubKeyName, NULL, NULL, NULL, &ftLWT)) == ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("CUserProfile::Initialize: Proccessing %s"), tszSubKeyName)); CleanupUserProfile(tszSubKeyName, &hkProfileList); dwcSubKeyName = MAX_PATH; i++; } if(lResult != ERROR_SUCCESS && lResult != ERROR_NO_MORE_ITEMS) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize: RegEnumKeyEx returned %08x"), lResult)); } // // Specify to use the local rpc protocol sequence // status = RpcServerUseProtseqEp(cszRPCProtocol, // ncalrpc prot seq cdwMaxRpcCalls, // max concurrent calls cszRPCEndPoint, NULL); // Security descriptor if (status != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize: RpcServerUseProtseqEp fails with error %ld"), status)); goto Exit; } // // Register the IUserProfile interface // status = RpcServerRegisterIfEx(IUserProfile_v1_0_s_ifspec, // interface to register NULL, // MgrTypeUuid NULL, // MgrEpv; null means use default RPC_IF_AUTOLISTEN, // auto-listen interface cdwMaxRpcCalls, // max concurrent calls NULL); // no callback if (status != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("CUserProfile::Initialize: RpcServerRegisterIfEx fails with error %ld"), status)); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("CUserProfile::Initialize: RpcServerRegisterIfEx successful"))); bInitialized = TRUE; Exit: if(bInitialized == FALSE && bCSInitialized == TRUE) { DeleteCriticalSection(&csMap); } if(hkProfileList != NULL) { RegCloseKey(hkProfileList); } if(bInitialized == TRUE) { DebugMsg((DM_VERBOSE, TEXT("Exiting CUserProfile::Initialize, successful"))); } else { DebugMsg((DM_VERBOSE, TEXT("Exiting CUserProfile::Initialize, unsuccessful"))); } } //************************************************************* // // CUserProfile::LoadUserProfileP() // // Purpose: Loads the user's profile, if unable to load // use the cached profile or issue the default profile. // // Parameters: hTokenClient - the client who's trying to load the // user's profile. A NULL value indicate // that this is a in-proccess call. // hTokenUser - the user who's profile is being loaded. // lpProfileInfo - Profile Information // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/6/95 ericflo Created // 6/27/00 weiruc Made a private function called // by the win32 API LoadUserProfile to do // the actual work. // //************************************************************* BOOL CUserProfile::LoadUserProfileP(HANDLE hTokenClient, HANDLE hTokenUser, LPPROFILEINFO lpProfileInfo, LPTSTR lpRPCEndPoint) { LPPROFILE lpProfile = NULL; BOOL bResult = FALSE, bNewProfileLoaded = FALSE; HANDLE hOldToken = NULL; HANDLE hTmpToken = NULL; DWORD dwRef, dwErr = ERROR_SUCCESS; LPTSTR SidString = NULL; LPVOID pEnv = NULL; NTSTATUS status; BOOL bInCS = FALSE; BOOL bCSCBypassed = FALSE; TCHAR cDrive; // // Initialize the debug flags. // InitDebugSupport( FALSE ); DebugMsg((DM_VERBOSE, TEXT("In LoadUserProfileP"))); if(hTokenClient && hTokenClient != INVALID_HANDLE_VALUE) { // // Check the client's identity // if (!IsUserAnAdminMember(hTokenClient) && !IsUserALocalSystemMember(hTokenClient)) { dwErr = ERROR_ACCESS_DENIED; DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Unable to load profile for client %08x. Not enough permission. Error %d."), hTokenClient, dwErr)); goto Exit; } // // Run under the client's identity rather than winlogon's. // if(!ImpersonateUser(hTokenClient, &hTmpToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ImpersonateUser <%08x> failed with %08x"), hTokenClient, dwErr)); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Running as client"))); } // // Check Parameters // if (!lpProfileInfo) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: NULL lpProfileInfo"))); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } if (!lpProfileInfo->lpUserName || !(*lpProfileInfo->lpUserName)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: received a NULL pointer for lpUserName."))); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } // // if the profile path or default path is greater than MAX_PATH, ignore them. // if ((lpProfileInfo->lpProfilePath) && (lstrlen(lpProfileInfo->lpProfilePath) >= MAX_PATH)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: long profile path name %s. ignoring"), lpProfileInfo->lpProfilePath)); ReportError(hTokenUser, PI_NOUI, 1, EVENT_PROFILE_PATH_TOOLONG, lpProfileInfo->lpProfilePath); (lpProfileInfo->lpProfilePath)[0] = TEXT('\0'); } if ((lpProfileInfo->lpDefaultPath) && (lstrlen(lpProfileInfo->lpDefaultPath) >= MAX_PATH)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: long default profile path name %s. ignoring"), lpProfileInfo->lpDefaultPath)); (lpProfileInfo->lpDefaultPath)[0] = TEXT('\0'); } // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("========================================================="))); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Entering, hToken = <0x%x>, lpProfileInfo = 0x%x"), hTokenUser, lpProfileInfo)); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->dwFlags = <0x%x>"), lpProfileInfo->dwFlags)); if (lpProfileInfo->lpUserName) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpUserName = <%s>"), lpProfileInfo->lpUserName)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL user name!"))); } if (lpProfileInfo->lpProfilePath) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpProfilePath = <%s>"), lpProfileInfo->lpProfilePath)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL central profile path"))); } if (lpProfileInfo->lpDefaultPath) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpDefaultPath = <%s>"), lpProfileInfo->lpDefaultPath)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL default profile path"))); } if (lpProfileInfo->lpServerName) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpServerName = <%s>"), lpProfileInfo->lpServerName)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL server name"))); } if (lpProfileInfo->dwFlags & PI_APPLYPOLICY) { if (lpProfileInfo->lpPolicyPath) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: lpProfileInfo->lpPolicyPath = <%s>"), lpProfileInfo->lpPolicyPath)); } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: NULL policy path"))); } } // // Make sure someone isn't loading a profile during // GUI mode setup (eg: mapi) // if (IsGuiSetupInProgress()) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: LoadUserProfile can not be called during GUI mode setup."))); dwErr = ERROR_NOT_READY; goto Exit; } // // Wait for the profile setup event to be signalled // if (g_hProfileSetup) { if ((WaitForSingleObject (g_hProfileSetup, 600000) != WAIT_OBJECT_0)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to wait on the profile setup event. Error = %d."), GetLastError())); dwErr = GetLastError(); goto Exit; } } // // Get the user's sid in string form // SidString = GetSidString(hTokenUser); if (!SidString) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to get sid string for user"))); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: User sid: %s"), SidString)); // // Enter the critical section. // if(!cSyncMgr.EnterLock(SidString, lpRPCEndPoint)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile:: Failed to get the user profile lock"))); goto Exit; } bInCS = TRUE; DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Wait succeeded. In critical section."))); //------------------- BEGIN CRITICAL SECTION ------------------------ // // We are in the critical section at this point, no doddling now... // // // Check if the profile is loaded already. // if (TestIfUserProfileLoaded(hTokenUser, lpProfileInfo)) { DWORD dwFlags = lpProfileInfo->dwFlags; // // This profile is already loaded. Grab the info from the registry // and add the missing chunks. // lpProfile = LoadProfileInfo(hTokenClient, hTokenUser, (HKEY)lpProfileInfo->hProfile); if (!lpProfile) { RegCloseKey ((HKEY)lpProfileInfo->hProfile); lpProfileInfo->hProfile = NULL; dwErr = GetLastError(); goto Exit; } // // LoadProfileInfo will overwrite the dwFlags field with the // value from the previous profile loading. Restore the flags. // lpProfile->dwFlags = dwFlags; if (lpProfile->dwFlags & PI_LITELOAD) { lpProfile->dwFlags |= PI_NOUI; } // // LoadProfileInfo doesn't restore username, servername, policypath so // special case these. // lpProfile->lpUserName = (LPTSTR)LocalAlloc (LPTR, (lstrlen(lpProfileInfo->lpUserName) + 1) * sizeof(TCHAR)); if (!lpProfile->lpUserName) { RegCloseKey ((HKEY)lpProfileInfo->hProfile); dwErr = GetLastError(); goto Exit; } lstrcpy (lpProfile->lpUserName, lpProfileInfo->lpUserName); if (lpProfileInfo->lpServerName) { lpProfile->lpServerName = (LPTSTR)LocalAlloc (LPTR, (lstrlen(lpProfileInfo->lpServerName) + 1) * sizeof(TCHAR)); if (lpProfile->lpServerName) { lstrcpy (lpProfile->lpServerName, lpProfileInfo->lpServerName); } } if (lpProfileInfo->dwFlags & PI_APPLYPOLICY) { if (lpProfileInfo->lpPolicyPath) { lpProfile->lpPolicyPath = (LPTSTR)LocalAlloc (LPTR, (lstrlen(lpProfileInfo->lpPolicyPath) + 1) * sizeof(TCHAR)); if (lpProfile->lpPolicyPath) { lstrcpy (lpProfile->lpPolicyPath, lpProfileInfo->lpPolicyPath); } } } // // If the profile is already loaded because it was leaked, // then the classes root may not be loaded. Insure that it // is loaded. // if (!(lpProfile->dwFlags & PI_LITELOAD)) { dwErr = LoadUserClasses( lpProfile, SidString, FALSE ); if (dwErr != ERROR_SUCCESS) { LPTSTR szErr = NULL; szErr = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szErr) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfileP: Out of memory"))); goto Exit; } // // If the user is an Admin, then let him/her log on with // either the .default profile, or an empty profile. // if (IsUserAnAdminMember(lpProfile->hTokenUser)) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_ADMIN_OVERRIDE, GetErrString(dwErr, szErr)); dwErr = ERROR_SUCCESS; LocalFree(szErr); } else { DebugMsg((DM_WARNING, TEXT("LoadUserProfileP: Could not load the user class hive. Error = %d"), dwErr)); ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_FAILED_LOAD_PROFILE, GetErrString(dwErr, szErr)); RegCloseKey ((HKEY)lpProfileInfo->hProfile); lpProfileInfo->hProfile = NULL; LocalFree(szErr); goto Exit; } } } // // Jump to the end of the profile loading code. // goto ProfileLoaded; } // // If we are here, the profile isn't loaded yet, so we are // starting from scratch. // // // Clone the process's environment block. This is passed to CreateProcess // by userdiff and system policy because they rely on the USERPROFILE // environment variable, but setting USERPROFILE for the whole process // is not thread safe. // status = RtlCreateEnvironment(TRUE, &pEnv); if(!NT_SUCCESS(status)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: RtlCreateEnvironment returned %08x"), status)); dwErr = status; goto Exit; } // // Allocate an internal Profile structure to work with. // lpProfile = (LPPROFILE) LocalAlloc (LPTR, sizeof(USERPROFILE)); if (!lpProfile) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to allocate memory"))); dwErr = GetLastError(); goto Exit; } // // Save the data passed in. // lpProfile->dwFlags = lpProfileInfo->dwFlags; // // No UI in case of Lite_Load // if (lpProfile->dwFlags & PI_LITELOAD) { lpProfile->dwFlags |= PI_NOUI; } lpProfile->dwUserPreference = GetUserPreferenceValue(hTokenUser); lpProfile->hTokenUser = hTokenUser; lpProfile->hTokenClient = hTokenClient; lpProfile->lpUserName = (LPTSTR)LocalAlloc (LPTR, (lstrlen(lpProfileInfo->lpUserName) + 1) * sizeof(TCHAR)); if (!lpProfile->lpUserName) { dwErr = GetLastError(); goto Exit; } lstrcpy (lpProfile->lpUserName, lpProfileInfo->lpUserName); if (lpProfileInfo->lpDefaultPath) { lpProfile->lpDefaultProfile = (LPTSTR)LocalAlloc (LPTR, (lstrlen(lpProfileInfo->lpDefaultPath) + 1) * sizeof(TCHAR)); if (lpProfile->lpDefaultProfile) { lstrcpy (lpProfile->lpDefaultProfile, lpProfileInfo->lpDefaultPath); } } if (lpProfileInfo->lpProfilePath) { lpProfile->lpProfilePath = AllocAndExpandProfilePath (lpProfileInfo); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Expanded profile path is %s"), lpProfile->lpProfilePath?lpProfile->lpProfilePath:TEXT("NULL"))); } if (lpProfileInfo->lpServerName) { lpProfile->lpServerName = (LPTSTR)LocalAlloc (LPTR, (lstrlen(lpProfileInfo->lpServerName) + 1) * sizeof(TCHAR)); if (lpProfile->lpServerName) { lstrcpy (lpProfile->lpServerName, lpProfileInfo->lpServerName); } } if (lpProfileInfo->dwFlags & PI_APPLYPOLICY) { if (lpProfileInfo->lpPolicyPath) { lpProfile->lpPolicyPath = (LPTSTR)LocalAlloc (LPTR, (lstrlen(lpProfileInfo->lpPolicyPath) + 1) * sizeof(TCHAR)); if (lpProfile->lpPolicyPath) { lstrcpy (lpProfile->lpPolicyPath, lpProfileInfo->lpPolicyPath); } } } lpProfile->lpLocalProfile = (LPTSTR)LocalAlloc (LPTR, MAX_PATH * sizeof(TCHAR)); if (!lpProfile->lpLocalProfile) { dwErr = GetLastError(); goto Exit; } lpProfile->lpRoamingProfile = (LPTSTR)LocalAlloc (LPTR, MAX_PATH * sizeof(TCHAR)); if (!lpProfile->lpRoamingProfile) { dwErr = GetLastError(); goto Exit; } // // If there is a central profile, check for 3.x or 4.0 format. // if (lpProfileInfo->lpProfilePath && (*lpProfileInfo->lpProfilePath)) { // // Call ParseProfilePath to work some magic on it // if (!ParseProfilePath(lpProfile, lpProfile->lpProfilePath, &bCSCBypassed, &cDrive)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ParseProfilePath returned FALSE"))); goto Exit; } // // The real central profile directory is... // DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: ParseProfilePath returned a directory of <%s>"), lpProfile->lpRoamingProfile)); } // // Load the user's profile // if (!RestoreUserProfile(lpProfile)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: RestoreUserProfile returned FALSE"))); dwErr = GetLastError(); goto Exit; } GetSystemTimeAsFileTime (&lpProfile->ftProfileLoad); // // Save the profile information in the registry // SaveProfileInfo (lpProfile); // // Set the USERPROFILE environment variable into the block. // This allows ExpandEnvironmentStrings to be used // in the userdiff processing. // if(pEnv) { SetEnvironmentVariableInBlock(&pEnv, TEXT("USERPROFILE"), lpProfile->lpLocalProfile, TRUE); } // // Flush the special folder pidls stored in shell32.dll // FlushSpecialFolderCache(); // // Set attributes on ntuser.ini // SetNtUserIniAttributes(lpProfile->lpLocalProfile); // // Upgrade the profile if appropriate. // if (!(lpProfileInfo->dwFlags & PI_LITELOAD)) { if(pEnv) { if (!UpgradeProfile(lpProfile, pEnv)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: UpgradeProfile returned FALSE"))); } } else { if (!UpgradeProfile(lpProfile, GetEnvironmentStrings())) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: UpgradeProfile returned FALSE"))); } } } // // Prepare the profile for use on this machine // PrepareProfileForUse (lpProfile, pEnv); bNewProfileLoaded = TRUE; ProfileLoaded: // // Increment the profile Ref count // dwRef = IncrementProfileRefCount(lpProfile, bNewProfileLoaded); if (!bNewProfileLoaded && (dwRef <= 1)) { DebugMsg((DM_WARNING, TEXT("Profile was loaded but the Ref Count is %d !!!"), dwRef)); } else { DebugMsg((DM_VERBOSE, TEXT("Profile Ref Count is %d"), dwRef)); } // // This will leave the critical section so other threads/process can // continue. // DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Leaving critical Section."))); if(cSyncMgr.LeaveLock(SidString)) { bInCS = FALSE; } else { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: User profile lock not released %08x"), GetLastError())); } // // Notify LSA that the profile has loaded // if (!ImpersonateUser(hTokenUser, &hOldToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to impersonate user with %d."), dwErr )); goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Impersonated user: %08x, %08x"), hTokenUser, hOldToken)); } if (!CredProfileLoaded()) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to notify LSA that profile loaded %d."), dwErr )); RevertToUser(&hOldToken); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Reverted to user: %08x"), hOldToken)); goto Exit; } RevertToUser(&hOldToken); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Reverted to user: %08x"), hOldToken)); // // The critical section is now released so we can do slower things like // apply policy... // //------------------- END MUTEX SECTION ------------------------ // // Apply Policy // if (lpProfile->dwFlags & PI_APPLYPOLICY) { // // Group Policy does not run on personal // OSVERSIONINFOEXW version; version.dwOSVersionInfoSize = sizeof(version); if ( !GetVersionEx( (LPOSVERSIONINFO) &version ) ) { return ERROR_SUCCESS; } else { if ( ( version.wSuiteMask & VER_SUITE_PERSONAL ) != 0 ) { return ERROR_SUCCESS; } } if (!ApplySystemPolicy((SP_FLAG_APPLY_MACHINE_POLICY | SP_FLAG_APPLY_USER_POLICY), lpProfile->hTokenUser, lpProfile->hKeyCurrentUser, lpProfile->lpUserName, lpProfile->lpPolicyPath, lpProfile->lpServerName)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ApplySystemPolicy returned FALSE"))); } } // // Save the outgoing parameters // lpProfileInfo->hProfile = (HANDLE) lpProfile->hKeyCurrentUser; // // Success! // bResult = TRUE; Exit: if (bCSCBypassed) { CancelCSCBypassedConnection(lpProfile->hTokenUser, cDrive); } if(bInCS) { cSyncMgr.LeaveLock(SidString); } if(SidString) { DeleteSidString(SidString); } // // Free the structure // if (lpProfile) { if (lpProfile->lpUserName) { LocalFree (lpProfile->lpUserName); } if (lpProfile->lpDefaultProfile) { LocalFree (lpProfile->lpDefaultProfile); } if (lpProfile->lpProfilePath) { LocalFree (lpProfile->lpProfilePath); } if (lpProfile->lpServerName) { LocalFree (lpProfile->lpServerName); } if (lpProfile->lpPolicyPath) { LocalFree (lpProfile->lpPolicyPath); } if (lpProfile->lpLocalProfile) { LocalFree (lpProfile->lpLocalProfile); } if (lpProfile->lpRoamingProfile) { LocalFree (lpProfile->lpRoamingProfile); } if (lpProfile->lpExclusionList) { LocalFree (lpProfile->lpExclusionList); } // // Caller will release these handles. // lpProfile->hTokenClient = NULL; lpProfile->hTokenUser = NULL; LocalFree (lpProfile); } // // Free the cloned environment block. // if (pEnv) { RtlDestroyEnvironment(pEnv); } // // Revert to ourselves // if(hTokenClient && hTokenClient != INVALID_HANDLE_VALUE) { RevertToUser(&hTmpToken); DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Reverted back to user <%08x>"), hTmpToken)); } // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Leaving with a value of %d."), bResult)); DebugMsg((DM_VERBOSE, TEXT("========================================================="))); SetLastError(dwErr); return bResult; } //************************************************************* // // CUserProfile::UnloadUserProfileP() // // Purpose: Unloads the user's profile. // // Parameters: hTokenClient - The client who's trying to load // the user's profile. // hTokenUser - User's token // hProfile - Profile handle // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/7/95 ericflo Created // 6/27/00 weiruc Modified to be a private function // called by UnloadUserProfile to do // the actual work. // //************************************************************* BOOL CUserProfile::UnloadUserProfileP(HANDLE hTokenClient, HANDLE hTokenUser, HKEY hProfile, LPTSTR lpRPCEndPoint) { LPPROFILE lpProfile=NULL; LPTSTR lpSidString = NULL, lpEnd, SidStringTemp = NULL; LONG err, IgnoreError, lResult; BOOL bProfileCopied = FALSE, bRetVal = FALSE, bDeleteCache, bRoaming = FALSE; HKEY hKey; DWORD dwSize, dwType, dwDisp; LPTSTR szExcludeList1 = NULL; LPTSTR szExcludeList2 = NULL; LPTSTR szExcludeList = NULL; LPTSTR szBuffer = NULL; DWORD dwFlags, dwRef = 0; HANDLE hOldToken = NULL; HANDLE hTmpToken = NULL; DWORD dwErr=0, dwErr1 = ERROR_SUCCESS, dwCSCErr; // dwErr1 is what gets set in SetLastError() LPTSTR szErr = NULL; LPTSTR szKeyName = NULL; DWORD dwCopyTmpHive = 0; DWORD dwWatchHiveFlags = 0; LPTSTR tszTmpHiveFile = NULL; BOOL bUnloadHiveSucceeded = TRUE; BOOL bInCS = FALSE; BOOL bCSCBypassed = FALSE; LPTSTR lpCscBypassedPath = NULL; TCHAR cDrive; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Entering, hProfile = <0x%x>"), hProfile)); // // Run under the client's identity rather than winlogon's. // if(hTokenClient && hTokenClient != INVALID_HANDLE_VALUE) { if(!ImpersonateUser(hTokenClient, &hTmpToken)) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: ImpersonateUser <%08x> failed with %08x"), hTokenClient, dwErr1)); RegCloseKey((HKEY)hProfile); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: ImpersonateUser <%08x>, old token is <%08x>"), hTokenClient, hTmpToken)); } // // Get the Sid string for the current user // lpSidString = GetProfileSidString(hTokenUser); if (!lpSidString) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to get sid string for user %08x"), dwErr1)); RegCloseKey((HKEY)hProfile); goto Exit; } // // Load profile information // lpProfile = LoadProfileInfo(hTokenClient, hTokenUser, (HKEY)hProfile); if (!lpProfile) { dwErr1 = GetLastError(); RegCloseKey((HKEY)hProfile); goto Exit; } // // Get the user's sid in string form // SidStringTemp = GetSidString(hTokenUser); if (!SidStringTemp) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to get sid string for user"))); RegCloseKey(lpProfile->hKeyCurrentUser); goto Exit; } // // Allocate memory for Local variables to avoid stack overflow // szKeyName = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szKeyName) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfileP: Out of memory"))); goto Exit; } szErr = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szErr) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfileP: Out of memory"))); goto Exit; } szBuffer = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szBuffer) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfileP: Out of memory"))); goto Exit; } // Store the actual roaming profile path before mapping it to drive lpProfile->lpProfilePath = lpProfile->lpRoamingProfile; // // Try to bypass CSC to avoid conflicts in syncing files between roaming share & local profile // if (IsUNCPath(lpProfile->lpRoamingProfile)) { if ((dwCSCErr = AbleToBypassCSC(hTokenUser, lpProfile->lpRoamingProfile, &lpCscBypassedPath, &cDrive)) == ERROR_SUCCESS) { bCSCBypassed = TRUE; lpProfile->lpRoamingProfile = lpCscBypassedPath; DebugMsg((DM_VERBOSE, TEXT("UnLoadUserProfileP: CSC bypassed."))); } else { if (dwCSCErr == WN_BAD_LOCALNAME || dwCSCErr == WN_ALREADY_CONNECTED || dwCSCErr == ERROR_BAD_PROVIDER) { DebugMsg((DM_VERBOSE, TEXT("UnLoadUserProfileP: CSC bypassed failed. Profile path %s"), lpProfile->lpRoamingProfile)); } else { // Share is not up. So we do not need to do any further check lpProfile->lpRoamingProfile = NULL; DebugMsg((DM_VERBOSE, TEXT("UnLoadUserProfileP: CSC bypassed failed. Ignoring Roaming profile path"))); } } } // // Check for a list of directories to exclude both user preferences // and user policy // szExcludeList1 = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szExcludeList1) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfileP: Out of memory"))); goto Exit; } szExcludeList2 = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szExcludeList2) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfileP: Out of memory"))); goto Exit; } szExcludeList = (LPTSTR)LocalAlloc(LPTR, 2*MAX_PATH*sizeof(TCHAR)); if (!szExcludeList) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfileP: Out of memory"))); goto Exit; } szExcludeList1[0] = TEXT('\0'); if (RegOpenKeyEx (lpProfile->hKeyCurrentUser, WINLOGON_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = MAX_PATH*sizeof(TCHAR); RegQueryValueEx (hKey, TEXT("ExcludeProfileDirs"), NULL, &dwType, (LPBYTE) szExcludeList1, &dwSize); RegCloseKey (hKey); } szExcludeList2[0] = TEXT('\0'); if (RegOpenKeyEx (lpProfile->hKeyCurrentUser, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = MAX_PATH*sizeof(TCHAR); RegQueryValueEx (hKey, TEXT("ExcludeProfileDirs"), NULL, &dwType, (LPBYTE) szExcludeList2, &dwSize); RegCloseKey (hKey); } // // Merge the user preferences and policy together // szExcludeList[0] = TEXT('\0'); if (szExcludeList1[0] != TEXT('\0')) { CheckSemicolon(szExcludeList1); lstrcpy (szExcludeList, szExcludeList1); } if (szExcludeList2[0] != TEXT('\0')) { lstrcat (szExcludeList, szExcludeList2); } // // Check if the cached copy of the profile should be deleted // bDeleteCache = IsCacheDeleted(); // // Enter the critical section. // if(!cSyncMgr.EnterLock(SidStringTemp, lpRPCEndPoint)) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP:: Failed to get the user profile lock %08x"), dwErr1)); goto Exit; } bInCS = TRUE; DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Wait succeeded. In critical section."))); // // Flush out the profile which will also sync the log. // err = RegFlushKey(lpProfile->hKeyCurrentUser); if (err != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to flush the current user key, error = %d"), err)); } // // Close the current user key that was opened in LoadUserProfile. // err = RegCloseKey(lpProfile->hKeyCurrentUser); if (err != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to close the current user key, error = %d"), err)); } dwRef = DecrementProfileRefCount(lpProfile); if (dwRef != 0) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Didn't unload user profile, Ref Count is %d"), dwRef)); bRetVal = TRUE; goto Exit; } // // Unload the user profile // err = MyRegUnLoadKey(HKEY_USERS, lpSidString); if (!err) { if((dwErr1 = GetLastError()) == ERROR_ACCESS_DENIED) { // // We failed to unload the hive due to leaked reg keys. // dwWatchHiveFlags |= WHRC_UNLOAD_HIVE; if (!(lpProfile->dwFlags & PI_LITELOAD)) { // // Call Special Registry APIs to dump handles // only if it is not called through Lite_load // there are known problems with liteLoad loading because // of which eventlog can get full during stress // lstrcpy(szKeyName, TEXT("\\Registry\\User\\")); lstrcat(szKeyName, lpSidString); DumpOpenRegistryHandle(szKeyName); } } DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Didn't unload user profile "), GetLastError())); // // Only in the case of reg leak do we want to call WatchHiveRefCount. // So use this flag to tell later code the the hive failed to // unload, no matter what the reason. // bUnloadHiveSucceeded = FALSE; } else { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Succesfully unloaded profile"))); } // // Unload HKCU // if (!(lpProfile->dwFlags & PI_LITELOAD)) { err = UnloadClasses(lpSidString); if (!err) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Didn't unload user classes."))); if((dwErr1 = GetLastError()) == ERROR_ACCESS_DENIED) { // // Call Special Registry APIs to dump handles // lstrcpy(szKeyName, TEXT("\\Registry\\User\\")); lstrcat(szKeyName, lpSidString); lstrcat(szKeyName, TEXT("_Classes")); DumpOpenRegistryHandle(szKeyName); ReportError(hTokenUser, PI_NOUI | EVENT_WARNING_TYPE, 0, EVENT_FAILED_CLASS_HIVE_UNLOAD); dwWatchHiveFlags = dwWatchHiveFlags | WHRC_UNLOAD_CLASSESROOT; } bRetVal = TRUE; } else { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Successfully unloaded user classes"))); } } // // Figure out if we need to do anything special in the event of registry // key leak. // if(dwWatchHiveFlags != 0 || !bUnloadHiveSucceeded) { tszTmpHiveFile = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!tszTmpHiveFile) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnLoadUserProfileP: Out of memory"))); goto Exit; } dwErr = HandleRegKeyLeak(lpSidString, lpProfile, bUnloadHiveSucceeded, &dwWatchHiveFlags, &dwCopyTmpHive, tszTmpHiveFile); // // If registry leak is handled successfully, the last error code should // be ERROR_SUCCESS. Otherwise, it should be whatever MyRegUnLoadKey // returned, which is in dwErr1. // if(dwErr == ERROR_SUCCESS) { dwErr1 = dwErr; } } // // If this is a mandatory or a guest profile, unload it now, // Guest profiles are always deleted so one guest can't see // the profile of a previous guest. Only do this if the user's // hive had been successfully unloaded. // if ((lpProfile->dwInternalFlags & PROFILE_MANDATORY) || (lpProfile->dwInternalFlags & PROFILE_READONLY) || (lpProfile->dwInternalFlags & PROFILE_GUEST_USER)) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: flushing HKEY_USERS"))); IgnoreError = RegFlushKey(HKEY_USERS); if (IgnoreError != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to flush HKEY_USERS, error = %d"), IgnoreError)); } // Don't delete the guest account if machine is in workgroup INT iRole; if (bDeleteCache || ((lpProfile->dwInternalFlags & PROFILE_GUEST_USER) && GetMachineRole(&iRole) && (iRole != 0))) { // // Delete the profile, including all other user related stuff // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: deleting profile because it is a guest user or cache needs to be deleted"))); if (!DeleteProfile (lpSidString, NULL, NULL)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: DeleteProfileDirectory returned false. Error = %d"), GetLastError())); } DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Successfully deleted profile because it is a guest/mandatory user"))); } if (err) { bRetVal = TRUE; } if (lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED) { // // Just delete the user profile, backup should never exist for mandatory profile // if (!DeleteProfileEx (lpSidString, lpProfile->lpLocalProfile, 0, HKEY_LOCAL_MACHINE, NULL)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: DeleteProfileDirectory returned false (2). Error = %d"), GetLastError())); } } goto Exit; } // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { dwErr1 = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to impersonate user"))); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Impersonated user"))); // // Copy local profileimage to remote profilepath // if ( ((lpProfile->dwInternalFlags & PROFILE_UPDATE_CENTRAL) || (lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL)) && !(lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED) ) { if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { // // Copy to the profile path // if (lpProfile->lpRoamingProfile && *lpProfile->lpRoamingProfile) { BOOL bRoamDirectoryExist; DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Copying profile back to %s"), lpProfile->lpRoamingProfile)); bRoaming = TRUE; // // Check roaming profile directory exist or not. If not exist, try to create it with proper acl's // bRoamDirectoryExist = TRUE; if (GetFileAttributes(lpProfile->lpRoamingProfile) == -1) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Roaming profile directory does not exist."))); // // Check whether we need to give access to the admin on the RUP share // // // Check for a roaming profile security preference // BOOL bAddAdminGroup = FALSE; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(bAddAdminGroup); RegQueryValueEx(hKey, ADD_ADMIN_GROUP_TO_RUP, NULL, NULL, (LPBYTE) &bAddAdminGroup, &dwSize); RegCloseKey(hKey); } // // Check for a roaming profile security policy // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(bAddAdminGroup); RegQueryValueEx(hKey, ADD_ADMIN_GROUP_TO_RUP, NULL, NULL, (LPBYTE) &bAddAdminGroup, &dwSize); RegCloseKey(hKey); } if (!CreateSecureDirectory(lpProfile, lpProfile->lpRoamingProfile, NULL, !bAddAdminGroup) ) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: CreateSecureDirectory failed to create roaming profile directory."))); bRoamDirectoryExist = FALSE; bProfileCopied = FALSE; } lpProfile->dwInternalFlags |= PROFILE_NEW_CENTRAL; // Since we created a empty profile now } if (bRoamDirectoryExist) { DWORD dwAttributes, dwStart, dwDelta; // // We have to call GetFileAttributes twice. The // first call sets up the session so we can call it again and // get accurate timing information for slow link detection. // dwAttributes = GetFileAttributes(lpProfile->lpProfilePath); if (dwAttributes != -1) { // // if it is success, find out whether the profile is // across a slow link. // dwStart = GetTickCount(); dwAttributes = GetFileAttributes(lpProfile->lpProfilePath); dwDelta = GetTickCount() - dwStart; DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Tick Count = %d"), dwDelta)); CheckForSlowLink (lpProfile, dwDelta, lpProfile->lpProfilePath, FALSE); if (lpProfile->dwInternalFlags & PROFILE_SLOW_LINK) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Profile is across a slow link. Do not sync roaming profile"))); } } } if (!(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { if (bRoamDirectoryExist) { // // Copy the profile // dwFlags = (lpProfile->dwFlags & PI_NOUI) ? CPD_NOERRORUI : 0; dwFlags |= (lpProfile->dwFlags & (PI_LITELOAD | PI_HIDEPROFILE)) ? (CPD_SYSTEMFILES | CPD_SYSTEMDIRSONLY) : (CPD_SYNCHRONIZE | CPD_NONENCRYPTEDONLY); dwFlags |= CPD_USEDELREFTIME | CPD_USEEXCLUSIONLIST | CPD_DELDESTEXCLUSIONS; bProfileCopied = CopyProfileDirectoryEx (lpProfile->lpLocalProfile, lpProfile->lpRoamingProfile, dwFlags | dwCopyTmpHive, &lpProfile->ftProfileLoad, (szExcludeList[0] != TEXT('\0')) ? szExcludeList : NULL); } // // Save the exclusion list we used for the profile copy // if (bProfileCopied) { // save it on the roaming profile. lstrcpy (szBuffer, lpProfile->lpRoamingProfile); lpEnd = CheckSlash (szBuffer); lstrcpy (lpEnd, c_szNTUserIni); bProfileCopied = WritePrivateProfileString (PROFILE_GENERAL_SECTION, PROFILE_EXCLUSION_LIST, (szExcludeList[0] != TEXT('\0')) ? szExcludeList : NULL, szBuffer); if (lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL) { bProfileCopied = WritePrivateProfileString (PROFILE_LOAD_TYPE, PROFILE_LAST_UPLOAD_STATE, (lpProfile->dwFlags & PI_LITELOAD) ? PARTIAL_PROFILE : COMPLETE_PROFILE, szBuffer); } else if (IsPartialRoamingProfile(lpProfile)) { bProfileCopied = WritePrivateProfileString (PROFILE_LOAD_TYPE, PROFILE_LAST_UPLOAD_STATE, (lpProfile->dwFlags & PI_LITELOAD) ? PARTIAL_PROFILE : COMPLETE_PROFILE, szBuffer); } if (!bProfileCopied) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to write to ntuser.ini on profile server with error 0x%x"), GetLastError())); dwErr = GetLastError(); } else { SetFileAttributes (szBuffer, FILE_ATTRIBUTE_HIDDEN); } } else { dwErr = GetLastError(); if (dwErr == ERROR_FILE_ENCRYPTED) { ReportError(hTokenUser, lpProfile->dwFlags, 0, EVENT_PROFILEUPDATE_6002); } } // // Check return value // if (bProfileCopied) { // // The profile is copied, now we want to make sure the timestamp on // both the remote profile and the local copy are the same, so we don't // ask the user to update when it's not necessary. In the case we // save the hive to a temporary file and // upload from the tmp file rather than the actual hive file. Do not // synchronize the profile time in this case because the hive file // will still be in use and there's no point in setting time on the // tmp hive file because it will be deleted after we upload it. // if(bUnloadHiveSucceeded) { SetProfileTime(lpProfile); } } else { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: CopyProfileDirectory returned FALSE for primary profile. Error = %d"), dwErr)); ReportError(hTokenUser, lpProfile->dwFlags, 1, EVENT_CENTRAL_UPDATE_FAILED, GetErrString(dwErr, szErr)); } } } else { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Network share not available."))); ReportError(hTokenUser, lpProfile->dwFlags, 1, EVENT_CENTRAL_UPDATE_FAILED, GetErrString(dwCSCErr, szErr)); } } } // // if it is roaming, write only if copy succeeded otherwise write // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Writing local ini file"))); if (!bRoaming || bProfileCopied) { // // Mark the file with system bit before trying to write to it // SetNtUserIniAttributes(lpProfile->lpLocalProfile); // save it locally lstrcpy (szBuffer, (lpProfile->lpLocalProfile)); lpEnd = CheckSlash (szBuffer); lstrcpy (lpEnd, c_szNTUserIni); err = WritePrivateProfileString (PROFILE_GENERAL_SECTION, PROFILE_EXCLUSION_LIST, (szExcludeList[0] != TEXT('\0')) ? szExcludeList : NULL, szBuffer); if (!err) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to write to ntuser.ini on client with error 0x%x"), GetLastError())); dwErr = GetLastError(); } } if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to revert to self"))); } DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Reverting to Self"))); // // Save the profile unload time // if (bProfileCopied && !bDeleteCache && !(lpProfile->dwFlags & PI_LITELOAD) && !(lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED)) { GetSystemTimeAsFileTime (&lpProfile->ftProfileUnload); DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Got the System Time"))); lstrcpy(szBuffer, PROFILE_LIST_PATH); lpEnd = CheckSlash (szBuffer); lstrcpy(lpEnd, lpSidString); lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, 0, 0, KEY_WRITE, NULL, &hKey, &dwDisp); if (lResult == ERROR_SUCCESS) { lResult = RegSetValueEx (hKey, PROFILE_UNLOAD_TIME_LOW, 0, REG_DWORD, (LPBYTE) &lpProfile->ftProfileUnload.dwLowDateTime, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to save low profile load time with error %d"), lResult)); } lResult = RegSetValueEx (hKey, PROFILE_UNLOAD_TIME_HIGH, 0, REG_DWORD, (LPBYTE) &lpProfile->ftProfileUnload.dwHighDateTime, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: Failed to save high profile load time with error %d"), lResult)); } RegCloseKey (hKey); DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Setting the unload Time"))); } } if (lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED) { DWORD dwDeleteFlags=0; // // Just delete the user profile // if (lpProfile->dwInternalFlags & PROFILE_BACKUP_EXISTS) { dwDeleteFlags |= DP_BACKUPEXISTS; } if (!DeleteProfileEx (lpSidString, lpProfile->lpLocalProfile, dwDeleteFlags, HKEY_LOCAL_MACHINE, NULL)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: DeleteProfileDirectory returned false (2). Error = %d"), GetLastError())); } } if (bUnloadHiveSucceeded && bRoaming && bProfileCopied && bDeleteCache) { // // Delete the profile and all the related stuff // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Deleting the cached profile"))); if (!DeleteProfile (lpSidString, NULL, NULL)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileP: DeleteProfileDirectory returned false (2). Error = %d"), GetLastError())); } } if(!(dwWatchHiveFlags & WHRC_UNLOAD_HIVE)) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: exitting and cleaning up"))); bRetVal = TRUE; } else { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: exitting without cleaning up due to hive unloading failure"))); } Exit: if(hTokenClient) { // // Revert to ourselves. // RevertToUser(&hTmpToken); DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Reverted back to user <%08x>"), hTmpToken)); } // // Leave the critical section. // if(bInCS) { cSyncMgr.LeaveLock(SidStringTemp); DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Leave critical section."))); } // // Delete the tmp hive file. // if (dwCopyTmpHive & CPD_USETMPHIVEFILE) { DeleteFile(tszTmpHiveFile); } if (bCSCBypassed) { CancelCSCBypassedConnection(hTokenUser, cDrive); } if(SidStringTemp) { DeleteSidString(SidStringTemp); } if (lpSidString) { DeleteSidString(lpSidString); } if (lpProfile) { if (lpProfile->lpLocalProfile) { LocalFree (lpProfile->lpLocalProfile); } if (lpProfile->lpRoamingProfile) { if (lpProfile->lpProfilePath && (lpProfile->lpProfilePath != lpProfile->lpRoamingProfile)) { LocalFree (lpProfile->lpProfilePath); } LocalFree (lpProfile->lpRoamingProfile); lpProfile->lpProfilePath = NULL; } if (lpProfile->lpProfilePath) { LocalFree(lpProfile->lpProfilePath); } LocalFree (lpProfile); } if (szExcludeList1) { LocalFree(szExcludeList1); } if (szExcludeList2) { LocalFree(szExcludeList2); } if (szExcludeList) { LocalFree(szExcludeList); } if (tszTmpHiveFile) { LocalFree(tszTmpHiveFile); } if (szKeyName) { LocalFree(szKeyName); } if (szErr) { LocalFree(szErr); } if (szBuffer) { LocalFree(szBuffer); } // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileP: Leaving with a return value of %d"), bRetVal)); SetLastError(dwErr1); return bRetVal; } //************************************************************* // // CUserProfile::EnterUserProfileLockLocal() // // Purpose: // // Get the user profile lock (for winlogon only, other processes use // EnterUserProfileLockRemote). This is just a wrapper for // CSyncManager::EnterLock. // // Parameters: // // pSid - User's sid string // // Return: // // TRUE/FALSE // // History: Date Author Comment // 5/15/00 weiruc Created // //************************************************************* BOOL CUserProfile::EnterUserProfileLockLocal(LPTSTR pSid) { return cSyncMgr.EnterLock(pSid, NULL); } //************************************************************* // // CUserProfile::LeaveUserProfileLockLocal() // // Purpose: // // Release the user profile mutex (winlogon only. Remote processes call // LeaveUserProfileLockRemote(). // // Parameters: // // pSid - User's sid string // // Return: // // TRUE/FALSE // // Comments: // // History: Date Author Comment // 8/11/00 weiruc Created // //************************************************************* BOOL CUserProfile::LeaveUserProfileLockLocal(LPTSTR pSid) { return cSyncMgr.LeaveLock(pSid); } //************************************************************* // // CUserProfile::GetRPCEndPoint() // // Purpose: // // Returns the rpc end point associated with client registered // interface // // Parameters: // // pSid - User's sid string // // Return: // // LPTSTR // // Comments: // // History: Date Author Comment // 10/25/00 santanuc Created // //************************************************************* LPTSTR CUserProfile::GetRPCEndPoint(LPTSTR pSid) { return cSyncMgr.GetRPCEndPoint(pSid); } //************************************************************* // // DropClientContext() // // Purpose: Allows the caller to drop off it's own token. // // Parameters: hBindHandle - explicit binding handle // lpProfileInfo - Profile Information // ppfContext - server context // // // Return: DWORD // ERROR_SUCCESS - If everything ok // // Comments: // // History: Date Author Comment // 10/24/00 santanuc Created // //************************************************************* DWORD DropClientContext(IN handle_t hBindHandle, IN LPPROFILEINFO lpProfileInfo, OUT PPCONTEXT_HANDLE pphContext) { LPPROFILEINFO pProfileInfoCopy = NULL; HANDLE hClientToken = NULL; PCLIENTINFO pClientInfo = NULL; RPC_STATUS status; DWORD dwErr = ERROR_ACCESS_DENIED; // // Initialize the debug flags. // InitDebugSupport( FALSE ); if (!pphContext) { dwErr = ERROR_INVALID_PARAMETER; DebugMsg((DM_WARNING, TEXT("DropClientContext: NULL context %d"), dwErr)); goto Exit; } // // Make a copy of the PROFILEINFO structure the user passed in. // if (lpProfileInfo) { if(!(pProfileInfoCopy = CopyProfileInfo(lpProfileInfo))) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("DropClientContext: CopyProfileInfo failed with %d"), dwErr)); goto Exit; } } // // Impersonate the client to get it's token. // if((status = RpcImpersonateClient(0)) != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("DropClientContext: RpcImpersonateClient failed with %ld"), status)); dwErr = status; goto Exit; } // // Get the client's token. // if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hClientToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("DropClientContext: OpenThreadToken failed with %d"), dwErr)); RpcRevertToSelf(); goto Exit; } RpcRevertToSelf(); DebugMsg((DM_VERBOSE, TEXT("DropClientContext: Got client token"))); // // Make the user's load profile object. // pClientInfo = (PCLIENTINFO)MIDL_user_allocate(sizeof(CLIENTINFO)); if(!pClientInfo) { dwErr = ERROR_OUTOFMEMORY; DebugMsg((DM_WARNING, TEXT("DropClientContext: new failed"))); goto Exit; } pClientInfo->hClientToken = hClientToken; pClientInfo->pProfileInfo = pProfileInfoCopy; *pphContext = (PCONTEXT_HANDLE)pClientInfo; DebugMsg((DM_VERBOSE, TEXT("DropClientContext: load profile object successfully made"))); hClientToken = NULL; pProfileInfoCopy = NULL; dwErr = ERROR_SUCCESS; Exit: if(hClientToken) { CloseHandle(hClientToken); } if(pProfileInfoCopy) { DeleteProfileInfo(pProfileInfoCopy); } DebugMsg((DM_VERBOSE, TEXT("DropClientContext: Returning %d"), dwErr)); return dwErr; } //************************************************************* // // ReleaseClientContext() // // Purpose: Release the client's context handle // // Parameters: hBindHandle - explicit binding handle // ppfContext - server context // // Return: void // // Comments: // // History: Date Author Comment // 10/24/00 santanuc Created // //************************************************************* void ReleaseClientContext(IN handle_t hBindHandle, IN OUT PPCONTEXT_HANDLE pphContext) { PCLIENTINFO pClientInfo; DebugMsg((DM_VERBOSE, TEXT("ReleaseClientContext: Releasing context"))); ReleaseClientContext_s(pphContext); } // // This function also called from server rundown routine // void ReleaseClientContext_s(PPCONTEXT_HANDLE pphContext) { PCLIENTINFO pClientInfo; DebugMsg((DM_VERBOSE, TEXT("ReleaseClientContext_s: Releasing context"))); if (*pphContext) { pClientInfo = (PCLIENTINFO)*pphContext; CloseHandle(pClientInfo->hClientToken); DeleteProfileInfo(pClientInfo->pProfileInfo); MIDL_user_free(pClientInfo); *pphContext = NULL; } } //************************************************************* // // EnterUserProfileLockRemote() // // Get the lock for loading/unloading a user's profile. // // Return value: // // HRESULT // // History: // // Created weiruc 6/16/2000 // //************************************************************* DWORD EnterUserProfileLockRemote(IN handle_t hBindHandle, IN LPTSTR pSid) { DWORD dwErr = ERROR_ACCESS_DENIED; RPC_STATUS status; HANDLE hToken = NULL; // // Impersonate the client to get the user's token. // if((status = RpcImpersonateClient(0)) != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("CUserProfile::EnterUserProfileLockRemote: CoImpersonateClient failed with %ld"), status)); dwErr = status; goto Exit; } if(!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_READ, TRUE, &hToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CUserProfile::EnterUserProfileLockRemote: OpenThreadToken failed with %d"), dwErr)); RpcRevertToSelf(); goto Exit; } RpcRevertToSelf(); // // Only admin users are allowed to lock a user's profile from being loaded/unloaded. // if(!IsUserAnAdminMember(hToken)) { dwErr = ERROR_ACCESS_DENIED; DebugMsg((DM_WARNING, TEXT("CUserProfile::EnterUserProfileLockRemote: Non-admin user!!!"))); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("CUserProfile::EnterUserProfileLockRemote: Locking user %s"), pSid)); if(!cUserProfileManager.EnterUserProfileLockLocal(pSid)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CUserProfile::EnterUserProfileLockRemote: Failed with %d"), dwErr)); goto Exit; } dwErr = ERROR_SUCCESS; Exit: if(hToken) { CloseHandle(hToken); } return dwErr; } //************************************************************* // // LeaveUserProfileLockRemote() // // Release the lock for loading/unloading a user's profile. // // Return value: // // HRESULT // // History: // // Created weiruc 6/16/2000 // //************************************************************* DWORD LeaveUserProfileLockRemote(IN handle_t hBindHandle, IN LPTSTR pSid) { HANDLE hToken = NULL; DWORD dwErr = ERROR_ACCESS_DENIED; RPC_STATUS status; // // Impersonate the client to get the user's token. // if((status = RpcImpersonateClient(0)) != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("CUserProfile::LeaveUserProfileLockRemote: CoImpersonateClient failed with %ld"), status)); dwErr = status; goto Exit; } if(!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_READ, TRUE, &hToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CUserProfile::LeaveUserProfileLockRemote: OpenThreadToken failed with %d"), dwErr)); RpcRevertToSelf(); goto Exit; } RpcRevertToSelf(); // // Only admin users are allowed to lock a user's profile from being loaded/unloaded. // if(!IsUserAnAdminMember(hToken)) { dwErr = ERROR_ACCESS_DENIED; DebugMsg((DM_WARNING, TEXT("CUserProfile::LeaveUserProfileLockRemote: Non-admin user!!!"))); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("CUserProfile::LeaveUserProfileLockRemote: Unlocking user %s"), pSid)); if(!cUserProfileManager.LeaveUserProfileLockLocal(pSid)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CUserProfile::LeaveUserProfileLockRemote: Failed with %d"), dwErr)); goto Exit; } dwErr = ERROR_SUCCESS; Exit: if(hToken) { CloseHandle(hToken); } return dwErr; } //************************************************************* // // CUserProfile::WorkerThreadMain // // Main function for the worker thread // // Parameters: // // pThreadMap the work queue for this thread // // Return value: // // Always returns ERROR_SUCCESS. // // History: // // Created weiruc 3/2/2000 // //************************************************************* DWORD CUserProfile::WorkerThreadMain(PMAP pThreadMap) { DWORD index; HKEY hkProfileList = NULL; long lResult; BOOL bCleanUp; LPTSTR ptszSid, lpTmp; DebugMsg((DM_VERBOSE, TEXT("Entering CUserProfile::WorkerThreadMain"))); while(TRUE) { bCleanUp = FALSE; ptszSid = NULL; index = WaitForMultipleObjects(pThreadMap->dwItems, pThreadMap->rghEvents, FALSE, INFINITE); index = index - WAIT_OBJECT_0; EnterCriticalSection(&csMap); DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WorkerThreadMain: In critical section"))); if(index > 0 && index < pThreadMap->dwItems) { LPTSTR lpUserName; DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WorkerThreadMain: WaitForMultipleObjects successful"))); DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WorkerThreadMain: hive %s unloaded"), pThreadMap->rgSids[index])); lpUserName = GetUserNameFromSid(pThreadMap->rgSids[index]); ReportError(NULL, PI_NOUI | EVENT_INFO_TYPE, 1, EVENT_HIVE_UNLOADED, lpUserName); if (lpUserName != pThreadMap->rgSids[index]) { LocalFree(lpUserName); } // // Save the sid and Delete the work item from the map and the hash // table. // ptszSid = pThreadMap->GetSid(index); pThreadMap->Delete(index); cTable.HashDelete(ptszSid); // Convert Sid_Classes entry to Sid as CleanupUserProfile takes only Sid lpTmp = ptszSid; if (lpTmp) { while (*lpTmp && (*lpTmp != TEXT('_'))) lpTmp++; if (*lpTmp) { *lpTmp = TEXT('\0'); } } // // Set the flag to clean up here because we want to do it after // we leave the critical section. // bCleanUp = TRUE; } // if waken up because a hive is unloaded // // Check to see if the map is empty. If it is, delete the map. // if(pThreadMap->IsEmpty()) { PMAP pTmpMap = pMap; // // We always have at least 1 item left: the thread event, So now // we know we don't have any work item anymore. Delete pThreadMap. // if(pThreadMap == pMap) { // pThreadMap is at the beginning of the list. pMap = pThreadMap->pNext; } else { for(pTmpMap = pMap; pTmpMap->pNext != pThreadMap; pTmpMap = pTmpMap->pNext); pTmpMap->pNext = pThreadMap->pNext; } pThreadMap->pNext = NULL; pThreadMap->Delete(0); delete pThreadMap; // // Leave the critical section. // LeaveCriticalSection(&csMap); DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WorkerThreadMain: Leave critical section"))); if(bCleanUp) { // // Clean up user's profile. // CleanupUserProfile(ptszSid, &hkProfileList); LocalFree(ptszSid); } // // Close the profile list key. // if(hkProfileList) { RegCloseKey(hkProfileList); hkProfileList = NULL; } // // Exit the thread because we don't have any work items anymore. // DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WorkerThreadMain: No more work items, leave thread"))); return ERROR_SUCCESS; } // if thread map is empty // // Leave the critical section. // LeaveCriticalSection(&csMap); DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WorkerThreadMain: Leave critical section"))); if(bCleanUp) { // // Clean up user's profile. // CleanupUserProfile(ptszSid, &hkProfileList); LocalFree(ptszSid); } DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WorkerThreadMain: Back to waiting..."))); } // while // // Never executed. // return ERROR_SUCCESS; } //************************************************************* // // CUserProfile::WatchHiveRefCount // // Implementation of the interface IWatchHiveRefCount. // // Parameters: // // pctszSid the user's sid // dwWHRCFlags indicate which hives to unload // // Return value: // // HRESULT error code. // // History: // // Created weiruc 5/4/2000 // //************************************************************* STDMETHODIMP CUserProfile::WatchHiveRefCount(LPCTSTR pSid, DWORD dwWHRCFlags) { LPTSTR pSidCopy = NULL; NTSTATUS status; OBJECT_ATTRIBUTES oa; TCHAR tszHiveName[MAX_PATH], *pTmp; UNICODE_STRING sHiveName; BOOLEAN bWasEnabled; HRESULT hres = S_OK, hres1; HANDLE hEvent = INVALID_HANDLE_VALUE; DWORD dwSidLen = lstrlen(pSid); BOOL bInCriticalSection = FALSE; DebugMsg((DM_VERBOSE, TEXT("Entering CUserProfile::WatchHiveRefCount: %s, %d"), pSid, dwWHRCFlags)); // // Are we initialized? // if(!bInitialized) { DebugMsg((DM_WARNING, TEXT("CUserProfile::WatchHiveRefCount not initialized"))); return E_FAIL; } // // parameter validation // if(dwSidLen >= sizeof(tszHiveName) / sizeof(TCHAR) - USER_KEY_PREFIX_LEN - USER_CLASSES_HIVE_SUFFIX_LEN || dwSidLen >= sizeof(tszHiveName) / sizeof(TCHAR) - USER_KEY_PREFIX_LEN || lstrcmpi(DEFAULT_HKU, pSid) == 0) { DebugMsg((DM_WARNING, TEXT("CUserProfile::WatchHiveRefCount: Invalid parameter"))); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } // // Setup the hive name to be used by NtUnloadKeyEx. // lstrcpy(tszHiveName, USER_KEY_PREFIX); pTmp = tszHiveName + USER_KEY_PREFIX_LEN; lstrcpy(pTmp, pSid); *pTmp = (TCHAR)_totupper(*pTmp); // // Enable the restore privilege. Don't give up even if fails. In the case // of impersonation, this call will fail. But we still might still have // the privilege needed. // status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &bWasEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WatchHiveRefCount: Failed to enable the restore privilege. error = %08x"), status)); } // // Enter the critical section. // EnterCriticalSection(&csMap); bInCriticalSection = TRUE; DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WatchHiveRefCount: In critical section"))); // // Register for the hive to be unloaded. // while (dwWHRCFlags & (WHRC_UNLOAD_HIVE | WHRC_UNLOAD_CLASSESROOT)) { if(dwWHRCFlags & WHRC_UNLOAD_HIVE) { dwWHRCFlags &= ~WHRC_UNLOAD_HIVE; } else if (dwWHRCFlags & WHRC_UNLOAD_CLASSESROOT) { dwWHRCFlags &= ~WHRC_UNLOAD_CLASSESROOT; lstrcat(tszHiveName, USER_CLASSES_HIVE_SUFFIX); } // // First make sure that the item is not already in our work list. // if(cTable.IsInTable(pTmp)) { DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WatchHiveRefCount: %s already in work list"), pTmp)); } else { if((hEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { hres = HRESULT_FROM_WIN32(GetLastError()); DebugMsg((DM_WARNING, TEXT("CUserProfile::WatchHiveRefCount: CreateEvent failed. error = %08x"), hres)); goto Exit; } // // Initialize the object attributes. // RtlInitUnicodeString(&sHiveName, tszHiveName); InitializeObjectAttributes(&oa, &sHiveName, OBJ_CASE_INSENSITIVE, NULL, NULL); // // Unload the hive. // if(!NT_SUCCESS(status = NtUnloadKeyEx(&oa, hEvent))) { hres = HRESULT_FROM_WIN32(status); DebugMsg((DM_WARNING, TEXT("CUserProfile::WatchHiveRefCount: NtUnloadKeyEx failed with %08x"), status)); CloseHandle(hEvent); goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("CUserProfile::WatchHiveRefCount: NtUnloadKeyEx succeeded for %s"), tszHiveName)); } // // Add the work item to clean up the profile when the hive is unloaded. // hres = AddWorkItem(pTmp, hEvent); // // Do not return error if we fail to add the work item because // cleaning up is a best effort. The important thing is that we // unloaded the hive successfully, or at least registered // successfully to do so. // if(hres != S_OK) { DebugMsg((DM_WARNING, TEXT("CUserProfile::WatchHiveRefCount: AddWorkItem failed with %08x"), hres)); CloseHandle(hEvent); hres = S_OK; } } // Item not already in list } Exit: if(bInCriticalSection) { LeaveCriticalSection(&csMap); } // // Restore the privilege to its previous state. // status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, bWasEnabled, FALSE, &bWasEnabled); if(!bWasEnabled && !NT_SUCCESS(status)) { DebugMsg((DM_WARNING, TEXT("CUserProfile::WatchHiveRefCount: Failed to restore the privilege. error = %08x"), status)); } return hres; } //************************************************************* // // CUserProfile::AddWorkItem // // Add a new work item. // // Parameters: // // pSid the user's sid // hEvent the event registry will set when hive is unloaded. // // Return value: // // HRESULT error code. // // History: // // Created weiruc 3/2/2000 // //************************************************************* HRESULT CUserProfile::AddWorkItem(LPCTSTR pSid, HANDLE hEvent) { PMAP pThreadMap = NULL; HRESULT hres = E_FAIL; HANDLE hThreadEvent = INVALID_HANDLE_VALUE; HANDLE hThread = INVALID_HANDLE_VALUE; BOOL bHashDelete = TRUE; LPTSTR pSidCopy = NULL; DebugMsg((DM_VERBOSE, TEXT("Entering CUserProfile::AddWorkItem: %s"), pSid)); pSidCopy = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pSid) + 1) * sizeof(TCHAR)); if(!pSidCopy) { hres = HRESULT_FROM_WIN32(GetLastError()); DebugMsg((DM_WARNING, TEXT("CUserProfile::AddWorkItem: Out of memory"))); goto Exit; } lstrcpy(pSidCopy, pSid); // // Make sure the leading 's' is in uppercase. // *pSidCopy = (TCHAR)_totupper(*pSidCopy); // // Verify that this sid is not already in our work list. // if(!cTable.HashAdd(pSidCopy)) { DebugMsg((DM_VERBOSE, TEXT("CUserProfile::AddWorkItem: sid %s already in work list"), pSidCopy)); bHashDelete = FALSE; goto Exit; } // // Look through the work item thread map list to find a thread that is not // fully loaded; // for(pThreadMap = pMap; pThreadMap != NULL; pThreadMap = pThreadMap->pNext) { if(pThreadMap->dwItems < MAXIMUM_WAIT_OBJECTS) { break; } } if(!pThreadMap) { DebugMsg((DM_VERBOSE, TEXT("CUserProfile::AddWorkItem: No thread available, create a new one."))); // // Create the thread event. // pThreadMap = new MAP(); if(!pThreadMap) { hres = HRESULT_FROM_WIN32(GetLastError()); DebugMsg((DM_WARNING, TEXT("CUserProfile::AddWorkItem: new operator failed. error = %08x"), hres)); goto Exit; } if((hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { hres = HRESULT_FROM_WIN32(GetLastError()); DebugMsg((DM_WARNING, TEXT("CUserProfile::AddWorkItem: CreateEvent failed for thread event. error = %08x"), hres)); goto Exit; } pThreadMap->Insert(hThreadEvent, NULL); DebugMsg((DM_VERBOSE, TEXT("CUserProfile::AddWorkItem: Signal event item inserted"))); // // Create the thread. // if((hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadMain, pThreadMap, 0, NULL)) == NULL) { hres = HRESULT_FROM_WIN32(GetLastError()); DebugMsg((DM_WARNING, TEXT("CUserProfile::AddWorkItem: CreateThread failed. error = %08x"), hres)); // // Delete the thread signal event item. // pThreadMap->Delete(0); goto Exit; } else { CloseHandle(hThread); } DebugMsg((DM_VERBOSE, TEXT("CUserProfile::AddWorkItem: New thread created"))); // // Successful return. Insert the work item into pThreadMap. // pThreadMap->Insert(hEvent, pSidCopy); DebugMsg((DM_VERBOSE, TEXT("CUserProfile::AddWorkItem: Work Item inserted"))); // // Insert pThreadMap into the map list. // pThreadMap->pNext = pMap; pMap = pThreadMap; } else { // // Found an existing thread. Insert the work item into it's map. // pThreadMap->Insert(hEvent, pSidCopy); DebugMsg((DM_VERBOSE, TEXT("CUserProfile::AddWorkItem: Work item inserted"))); } // // Wake up the thread. If the thread can not be waken up by setting the // event here, then it'll be stuck in sleep state until one day this // SetEvent call succeeds. Leave the work item in and continue. // if(!SetEvent(pThreadMap->rghEvents[0])) { hres = HRESULT_FROM_WIN32(GetLastError()); DebugMsg((DM_WARNING, TEXT("SetEvent failed. error = %08x"), hres)); } else { DebugMsg((DM_VERBOSE, TEXT("CUserProfile::AddWorkItem: thread woken up"))); } pThreadMap = NULL; hres = S_OK; bHashDelete = FALSE; pSidCopy = NULL; Exit: if(bHashDelete && pSidCopy) { cTable.HashDelete(pSidCopy); } if(pSidCopy) { LocalFree(pSidCopy); } if(pThreadMap) { delete pThreadMap; } DebugMsg((DM_VERBOSE, TEXT("Exiting CUserProfile::AddWorkItem with %08x"), hres)); return hres; } //************************************************************* // // CUserProfile::CleanupUserProfile // // Unload the hive and delete the profile directory if necessary. // // Parameters: // // ptszSid - User's sid string // phkProfileList - in/out parameter. Handle to the profile list key. // if NULL, will fill in the handle. And this handle // has to be closed by the caller. // // Comment: // // Always ignore error and continue because this is a best effort. // //************************************************************* void CUserProfile::CleanupUserProfile(LPTSTR ptszSid, HKEY* phkProfileList) { DWORD dwInternalFlags = 0; DWORD dwRefCount; BOOL bInCS = FALSE; // // Enter the critical section. // if(!EnterUserProfileLockLocal(ptszSid)) { DebugMsg((DM_WARNING, TEXT("CUserProfile::CleanupUserProfile:: Failed to get the user profile lock for %s"), ptszSid)); goto Exit; } bInCS = TRUE; DebugMsg((DM_VERBOSE, TEXT("CUserProfile::CleanupUserProfile: Enter critical section."))); // // Get the reference count and the internal flags. // if(GetRefCountAndFlags(ptszSid, phkProfileList, &dwRefCount, &dwInternalFlags) != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CUserProfile::CleanupUserProfile: Can not get ref count and flags"))); goto Exit; } // // If the ref count is 0, clean up the user's profile. If not, give up. // if(dwRefCount != 0) { DebugMsg((DM_WARNING, TEXT("CUserProfile::CleanupUserProfile: Ref Count is not 0"))); goto Exit; } // // Delete the temporary profile if: // guest user profile or // temp profile or // mandatory profile // Profiles that are none of the above will not be cleaned up even if // Delete cache bit is set in the registry or the policy says delete // cached profiles. This is because even though now we unloaded the // hive we don't upload the profile. Deleting the local profile might // result in user's data loss. // // Don't delete the guest account if machine is in workgroup INT iRole; if(dwInternalFlags & PROFILE_MANDATORY || dwInternalFlags & PROFILE_TEMP_ASSIGNED || ((dwInternalFlags & PROFILE_GUEST_USER) && GetMachineRole(&iRole) && (iRole != 0))) { DebugMsg((DM_VERBOSE, TEXT("CUserProfile::CleanupUserProfile: DeleteProfile"))); if(!DeleteProfile(ptszSid, NULL, NULL)) { DebugMsg((DM_WARNING, TEXT("CUserProfile::CleanupUserProfile: DeleteProfile returned FALSE. error = %08x"), GetLastError())); } } Exit: if(bInCS) { LeaveUserProfileLockLocal(ptszSid); DebugMsg((DM_VERBOSE, TEXT("CUserProfile::CleanupUserProfile: Leave critical section"))); } } //************************************************************* // // CUserProfile::GetRefCountAndFlags // // Get the ref count and internal flags from the registry for a user. // // Parameters: // // ptszSid - User's sid string // phkPL - in/out parameter. Handle to the profile list key. // If NULL, will be filled with an opened key to the // profile list. The caller is responsible for // closing it. // dwRefCount - buffer for the ref count. // dwInternalFlags - buffer for the internal flags. // // History: // // Created weiruc 5/23/2000 // //************************************************************* long CUserProfile::GetRefCountAndFlags(LPCTSTR ptszSid, HKEY* phkPL, DWORD* dwRefCount, DWORD* dwInternalFlags) { HKEY hkUser = NULL; DWORD dwType, dwSize = sizeof(DWORD); long lResult = ERROR_SUCCESS; *dwRefCount = 0; *dwInternalFlags = 0; if(!*phkPL) { // // Open the profile list if it's not already opened. // lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, PROFILE_LIST_PATH, 0, KEY_READ, phkPL); if(lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CUserProfile::GetRefCountAndFlags: Failed to open profile list key with error %d"), lResult)); goto Exit; } } // // Open the user's key in the profile list. // if((lResult = RegOpenKeyEx(*phkPL, ptszSid, 0, KEY_READ, &hkUser)) != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CUserProfile::GetRefCountAndFlags: RegOpenKeyEx failed with error %08x"), lResult)); goto Exit; } // // Query for the ref count and the internal flags. // if((lResult = RegQueryValueEx(hkUser, PROFILE_REF_COUNT, 0, &dwType, (LPBYTE)dwRefCount, &dwSize)) != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CUserProfile::GetRefCountAndFlags: RegQueryValueEx failed, key = %s, error = %08x"), ptszSid, lResult)); goto Exit; } dwSize = sizeof(DWORD); if((lResult = RegQueryValueEx(hkUser, PROFILE_STATE, 0, &dwType, (LPBYTE)dwInternalFlags, &dwSize)) != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CUserProfile::GetRefCountAndFlags: RegQueryValueEx failed, key = %s, error = %08x"), ptszSid, lResult)); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("CUserProfile::GetRefCountAndFlags: Ref count is %d, state is %08x"), *dwRefCount, *dwInternalFlags)); Exit: if(hkUser) { RegCloseKey(hkUser); } return lResult; } //************************************************************* // // LoadUserProfileI() // // Purpose: Just a wrapper around CUserProfile::LoadUserProfileP // // Parameters: hBindHandle - server explicit binding handle // pProfileInfo - Profile Information // phContext - server context for client // lpRPCEndPoint - RPCEndPoint of the registered IProfileDialog interface // // Return: DWORD // ERROR_SUCCESS - if everything is ok // // Comments: // // History: Date Author Comment // 10/24/00 santanuc Created // //************************************************************* DWORD LoadUserProfileI(IN handle_t hBindHandle, IN LPPROFILEINFO lpProfileInfo, IN PCONTEXT_HANDLE phContext, IN LPTSTR lpRPCEndPoint) { HANDLE hUserToken = NULL; BOOL bImpersonatingUser = FALSE; PCLIENTINFO pClientInfo; DWORD dwErr = ERROR_ACCESS_DENIED; RPC_STATUS status; if (lpRPCEndPoint) { DebugMsg((DM_VERBOSE, TEXT("LoadUserProfileI: RPC end point %s"), lpRPCEndPoint)); } // // Get the context // if (!phContext) { dwErr = ERROR_INVALID_PARAMETER; DebugMsg((DM_WARNING, TEXT("LoadUserProfileI: NULL context"))); goto Exit; } pClientInfo = (PCLIENTINFO)phContext; // // Verify that the PROFILEINFO structure passed in is the same one. // if(!CompareProfileInfo(lpProfileInfo, pClientInfo->pProfileInfo)) { dwErr = ERROR_INVALID_PARAMETER; DebugMsg((DM_WARNING, TEXT("LoadUserProfileI: PROFILEINFO structure passed in is different"))); goto Exit; } // // Impersonate the client to get the user's token. // if((status = RpcImpersonateClient(0)) != S_OK) { DebugMsg((DM_WARNING, TEXT("LoadUserProfileI: CoImpersonateClient failed with %ld"), status)); dwErr = status; goto Exit; } bImpersonatingUser = TRUE; if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hUserToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfileI: OpenThreadToken failed with %d"), dwErr)); goto Exit; } RpcRevertToSelf(); bImpersonatingUser = FALSE; // // Now that we have both the client and the user's token, call // LoadUserProfileP to do the work. // if(!cUserProfileManager.LoadUserProfileP(pClientInfo->hClientToken, hUserToken, pClientInfo->pProfileInfo, lpRPCEndPoint)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LoadUserProfileI: LoadUserProfileP failed with %d"), dwErr)); goto Exit; } // // Close the registry handle to the user hive opened by LoadUserProfileP. // RegCloseKey((HKEY)pClientInfo->pProfileInfo->hProfile); dwErr = ERROR_SUCCESS; Exit: if(bImpersonatingUser) { RpcRevertToSelf(); } if(hUserToken) { CloseHandle(hUserToken); } DebugMsg((DM_VERBOSE, TEXT("LoadUserProfileI: returning %d"), dwErr)); return dwErr; } //************************************************************* // // UnloadUserProfileI() // // Purpose: Just a wrapper around CUserProfile::UnloadUserProfileP // // Parameters: hBindHandle - server explicit binding handle // phContext - server context for client // lpRPCEndPoint - RPCEndPoint of the registered IProfileDialog interface // // Return: DWORD // ERROR_SUCCESS - if everything is ok // // Comments: // // History: Date Author Comment // 10/24/00 santanuc Created // //************************************************************* DWORD UnloadUserProfileI(IN handle_t hBindHandle, IN PCONTEXT_HANDLE phContext, IN LPTSTR lpRPCEndPoint) { HANDLE hUserToken = NULL; HKEY hProfile = NULL; BOOL bImpersonatingUser = FALSE; PCLIENTINFO pClientInfo; LPTSTR pSid = NULL; long lResult; RPC_STATUS status; DWORD dwErr = ERROR_ACCESS_DENIED; // // Get the context // if (!phContext) { dwErr = ERROR_INVALID_PARAMETER; DebugMsg((DM_WARNING, TEXT("UnLoadUserProfileI: NULL context"))); goto Exit; } pClientInfo = (PCLIENTINFO)phContext; // // Impersonate the client to get the user's token. // if((status = RpcImpersonateClient(0)) != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfileI: CoImpersonateClient failed with %ld"), status)); dwErr = status; goto Exit; } bImpersonatingUser = TRUE; if(!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_READ, TRUE, &hUserToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfileI: OpenThreadToken failed with %d"), dwErr)); goto Exit; } RpcRevertToSelf(); bImpersonatingUser = FALSE; // // Open the user's registry hive root. // pSid = GetSidString(hUserToken); if((lResult = RegOpenKeyEx(HKEY_USERS, pSid, 0, KEY_ALL_ACCESS, &hProfile)) != ERROR_SUCCESS) { dwErr = lResult; DebugMsg((DM_WARNING, TEXT("UnloadUserProfileI: RegOpenKeyEx failed with %d"), dwErr)); goto Exit; } // // Now that we have both the client and the user's token, call // UnloadUserProfileP to do the work. hProfile gets closed in // UnloadUserProfileP so don't close it again. // if(!cUserProfileManager.UnloadUserProfileP(pClientInfo->hClientToken, hUserToken, hProfile, lpRPCEndPoint)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UnloadUserProfileI: UnloadUserProfileP failed with %d"), dwErr)); goto Exit; } dwErr = ERROR_SUCCESS; Exit: if(bImpersonatingUser) { RpcRevertToSelf(); } if(hUserToken) { CloseHandle(hUserToken); } if(pSid) { DeleteSidString(pSid); } DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfileI: returning %d"), dwErr)); SetLastError(dwErr); return dwErr; } //************************************************************* // // CompareProfileInfo() // // Purpose: Compare field by field two PROFILEINFO structures // except for the hProfile field. // // Parameters: pInfo1, pInfo2 // // Return: TRUE - Same // FALSE - Not the same // // History: Date Author Comment // 6/29/00 weiruc Created // //************************************************************* BOOL CompareProfileInfo(LPPROFILEINFO pInfo1, LPPROFILEINFO pInfo2) { BOOL bRet = TRUE; if(!pInfo1 || !pInfo2) { DebugMsg((DM_WARNING, TEXT("CompareProfileInfo: Invalid parameter"))); return FALSE; } if(pInfo1->dwSize != pInfo2->dwSize) { DebugMsg((DM_WARNING, TEXT("CompareProfileInfo: dwSize %d != %d"), pInfo1->dwSize, pInfo2->dwSize)); return FALSE; } if(pInfo1->dwFlags != pInfo2->dwFlags) { DebugMsg((DM_WARNING, TEXT("CompareProfileInfo: dwFlags %d != %d"), pInfo1->dwFlags, pInfo2->dwFlags)); return FALSE; } if(lstrcmpi(pInfo1->lpUserName, pInfo2->lpUserName)) { DebugMsg((DM_WARNING, TEXT("CompareProfileInfo: lpUserName <%s> != <%s>"), pInfo1->lpUserName, pInfo2->lpUserName)); return FALSE; } if(lstrcmpi(pInfo1->lpProfilePath, pInfo2->lpProfilePath)) { DebugMsg((DM_WARNING, TEXT("CompareProfileInfo: lpProfilePath <%s> != <%s>"), pInfo1->lpProfilePath, pInfo2->lpProfilePath)); return FALSE; } if(lstrcmpi(pInfo1->lpDefaultPath, pInfo2->lpDefaultPath)) { DebugMsg((DM_WARNING, TEXT("CompareProfileInfo: lpDefaultPath <%s> != <%s>"), pInfo1->lpDefaultPath, pInfo2->lpDefaultPath)); return FALSE; } if(lstrcmpi(pInfo1->lpServerName, pInfo2->lpServerName)) { DebugMsg((DM_WARNING, TEXT("CompareProfileInfo: lpServerName <%s> != <%s>"), pInfo1->lpServerName, pInfo2->lpServerName)); return FALSE; } if(lstrcmpi(pInfo1->lpPolicyPath, pInfo2->lpPolicyPath)) { DebugMsg((DM_WARNING, TEXT("CompareProfileInfo: lpPolicyPath <%s> != <%s>"), pInfo1->lpPolicyPath, pInfo2->lpPolicyPath)); return FALSE; } return TRUE; } //************************************************************* // // CopyProfileInfo() // // Purpose: Allocate and copy a PROFILEINFO structure. // // Parameters: pProfileInfo - To be copied // // Return: The copy // // History: Date Author Comment // 6/29/00 weiruc Created // //************************************************************* LPPROFILEINFO CopyProfileInfo(LPPROFILEINFO pProfileInfo) { LPPROFILEINFO pInfoCopy = NULL; BOOL bSuccess = FALSE; // // Allocate and initialize memory for the PROFILEINFO copy. // pInfoCopy = (LPPROFILEINFO)LocalAlloc(LPTR, sizeof(PROFILEINFO)); if(!pInfoCopy) { goto Exit; } // // Copy field by field. // pInfoCopy->dwSize = pProfileInfo->dwSize; pInfoCopy->dwFlags = pProfileInfo->dwFlags; if(pProfileInfo->lpUserName) { pInfoCopy->lpUserName = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pProfileInfo->lpUserName) + 1) * sizeof(TCHAR)); if(!pInfoCopy->lpUserName) { goto Exit; } lstrcpy(pInfoCopy->lpUserName, pProfileInfo->lpUserName); } if(pProfileInfo->lpProfilePath) { pInfoCopy->lpProfilePath = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pProfileInfo->lpProfilePath) + 1) * sizeof(TCHAR)); if(!pInfoCopy->lpProfilePath) { goto Exit; } lstrcpy(pInfoCopy->lpProfilePath, pProfileInfo->lpProfilePath); } if(pProfileInfo->lpDefaultPath) { pInfoCopy->lpDefaultPath = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pProfileInfo->lpDefaultPath) + 1) * sizeof(TCHAR)); if(!pInfoCopy->lpDefaultPath) { goto Exit; } lstrcpy(pInfoCopy->lpDefaultPath, pProfileInfo->lpDefaultPath); } if(pProfileInfo->lpServerName) { pInfoCopy->lpServerName = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pProfileInfo->lpServerName) + 1) * sizeof(TCHAR)); if(!pInfoCopy->lpServerName) { goto Exit; } lstrcpy(pInfoCopy->lpServerName, pProfileInfo->lpServerName); } if(pProfileInfo->lpPolicyPath) { pInfoCopy->lpPolicyPath = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pProfileInfo->lpPolicyPath) + 1) * sizeof(TCHAR)); if(!pInfoCopy->lpPolicyPath) { goto Exit; } lstrcpy(pInfoCopy->lpPolicyPath, pProfileInfo->lpPolicyPath); } bSuccess = TRUE; Exit: if(!bSuccess && pInfoCopy) { DeleteProfileInfo(pInfoCopy); pInfoCopy = NULL; } return pInfoCopy; } //************************************************************* // // DeleteProfileInfo() // // Purpose: Delete a PROFILEINFO structure // // Parameters: pInfo // // Return: void // // History: Date Author Comment // 6/29/00 weiruc Created // //************************************************************* void DeleteProfileInfo(LPPROFILEINFO pInfo) { if(!pInfo) { return; } if(pInfo->lpUserName) { LocalFree(pInfo->lpUserName); } if(pInfo->lpProfilePath) { LocalFree(pInfo->lpProfilePath); } if(pInfo->lpDefaultPath) { LocalFree(pInfo->lpDefaultPath); } if(pInfo->lpServerName) { LocalFree(pInfo->lpServerName); } if(pInfo->lpPolicyPath) { LocalFree(pInfo->lpPolicyPath); } LocalFree(pInfo); } //************************************************************* // // GetInterface() // // Purpose: Get the rpc binding handle // // Parameters: phIfHandle - rpc binding handle to initialize // lpRPCEndPoint - RPCEndPoint of interface // // Return: TRUE if successful. // // History: Date Author Comment // 10/24/00 santanuc Created // //************************************************************* BOOL GetInterface(handle_t * phIfHandle, LPTSTR lpRPCEndPoint) { RPC_STATUS status; LPTSTR pszStringBinding = NULL; BOOL bStringBinding = FALSE, bRetVal = FALSE; // compose string to pass to binding api status = RpcStringBindingCompose(NULL, cszRPCProtocol, NULL, lpRPCEndPoint, NULL, &pszStringBinding); if (status != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("GetInterface: RpcStringBindingCompose fails with error %ld"), status)); goto Exit; } bStringBinding = TRUE; // set the binding handle that will be used to bind to the server. status = RpcBindingFromStringBinding(pszStringBinding, phIfHandle); if (status != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("GetInterface: RpcStringBindingCompose fails with error %ld"), status)); goto Exit; } bRetVal = TRUE; DebugMsg((DM_VERBOSE, TEXT("GetInterface: Returning rpc binding handle"))); Exit: // free string if (bStringBinding) RpcStringFree(&pszStringBinding); return bRetVal; } //************************************************************* // // ReleaseInterface() // // Purpose: Release the rpc binding handle // // Parameters: phIfHandle - rpc binding handle to initialize // // Return: TRUE if successful. // // History: Date Author Comment // 10/24/00 santanuc Created // //************************************************************* BOOL ReleaseInterface(handle_t * phIfHandle) { RPC_STATUS status; // free binding handle DebugMsg((DM_VERBOSE, TEXT("ReleaseInterface: Releasing rpc binding handle"))); status = RpcBindingFree(phIfHandle); return (status == RPC_S_OK); } //************************************************************* // // Routine Description: // // This routine determines if we're doing a gui-mode setup. // // This value is retrieved from the following registry location: // // \HKLM\System\Setup\ // // SystemSetupInProgress : REG_DWORD : 0x00 (where nonzero // means we're doing a gui-setup) // // Arguments: // // None. // // Return Value: // // TRUE/FALSE // // Note: // // This function is courtesy of Andrew Ritz and the Setup API. // It's copied over from base\pnp\setupapi\dll.c. // //*************************************************************** BOOL IsGuiSetupInProgress() { HKEY hKey; DWORD Err, DataType, DataSize = sizeof(DWORD); DWORD Value; if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\Setup"), 0, KEY_READ, &hKey)) == ERROR_SUCCESS) { // // Attempt to read the the "DriverCachePath" value. // Err = RegQueryValueEx( hKey, TEXT("SystemSetupInProgress"), NULL, &DataType, (LPBYTE)&Value, &DataSize); RegCloseKey(hKey); } if(Err == NO_ERROR) { if(Value) { return(TRUE); } } return(FALSE); } //************************************************************* // // CheckNetDefaultProfile() // // Purpose: Checks if a network profile exists // // Parameters: lpProfile - Profile information // // Return: TRUE if successful // FALSE if an error occurs // // Comments: This routine assumes we are working // in the user's context. // // History: Date Author Comment // 9/21/95 ericflo Created // 4/10/99 ushaji modified to remove local caching // //************************************************************* BOOL CheckNetDefaultProfile (LPPROFILE lpProfile) { HANDLE hFile; WIN32_FIND_DATA fd; TCHAR szBuffer[MAX_PATH]; TCHAR szLocalDir[MAX_PATH]; DWORD dwSize, dwFlags, dwErr; LPTSTR lpEnd; BOOL bRetVal = FALSE; LPTSTR lpNetPath = lpProfile->lpDefaultProfile; HANDLE hOldToken; // // Get the error at the beginning of the call. // dwErr = GetLastError(); // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Entering, lpNetPath = <%s>"), (lpNetPath ? lpNetPath : TEXT("NULL")))); if (!lpNetPath || !(*lpNetPath)) { return bRetVal; } // // Impersonate the user.... // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { if (lpProfile->lpDefaultProfile) { *lpProfile->lpDefaultProfile = TEXT('\0'); } // // Last error is set // return bRetVal; } // // See if network copy exists // hFile = FindFirstFile (lpNetPath, &fd); if (hFile != INVALID_HANDLE_VALUE) { // // Close the find handle // FindClose (hFile); // // We found something. Is it a directory? // if ( !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: FindFirstFile found a file. ignoring Network Defaul profile"))); dwErr = ERROR_FILE_NOT_FOUND; goto Exit; } // // Is there a ntuser.* file in this directory? // lstrcpy (szBuffer, lpNetPath); lpEnd = CheckSlash (szBuffer); lstrcpy (lpEnd, c_szNTUserStar); hFile = FindFirstFile (szBuffer, &fd); if (hFile == INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: FindFirstFile found a directory, but no ntuser files."))); dwErr = ERROR_FILE_NOT_FOUND; goto Exit; } FindClose (hFile); DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Found a valid network profile."))); bRetVal = TRUE; } else { dwErr = ERROR_FILE_NOT_FOUND; } Exit: // // If we are leaving successfully, then // save the local profile directory. // if (bRetVal) { DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: setting default profile to <%s>"), lpNetPath)); } else { DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: setting default profile to NULL"))); // // resetting it to NULL in case we didn't see the server directory. // if (lpProfile->lpDefaultProfile) { *lpProfile->lpDefaultProfile = TEXT('\0'); } } // // Tag the internal flags so we don't do this again. // lpProfile->dwInternalFlags |= DEFAULT_NET_READY; // // Now set the last error // // // Revert before trying to delete the local default network profile // RevertToUser(&hOldToken); // // We will keep this on always so that we can delete any preexisting // default network profile, try to delete it and ignore // the failure if it happens // // Expand the local profile directory // dwSize = ARRAYSIZE(szLocalDir); if (!GetProfilesDirectoryEx(szLocalDir, &dwSize, TRUE)) { DebugMsg((DM_WARNING, TEXT("CheckNetDefaultProfile: Failed to get default user profile."))); SetLastError(dwErr); return bRetVal; } lpEnd = CheckSlash (szLocalDir); lstrcpy (lpEnd, DEFAULT_USER_NETWORK); DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Removing local copy of network default user profile."))); Delnode (szLocalDir); // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Leaving with a value of %d."), bRetVal)); SetLastError(dwErr); return bRetVal; } //************************************************************* // // ParseProfilePath() // // Purpose: Parses the profile path to determine if // it points at a directory or a filename. // In addition it determines whether a profile is // acoss a slow link and whether the user has access // to the profile. // // Parameters: lpProfile - Profile Information // lpProfilePath - Input path // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/6/95 ericflo Created // //************************************************************* BOOL ParseProfilePath(LPPROFILE lpProfile, LPTSTR lpProfilePath, BOOL *bpCSCBypassed, TCHAR *cpDrive) { DWORD dwAttributes; LPTSTR lpEnd; BOOL bRetVal = FALSE; BOOL bMandatory = FALSE; DWORD dwStart, dwDelta, dwErr = ERROR_SUCCESS; DWORD dwStrLen; HANDLE hOldToken; TCHAR szErr[MAX_PATH]; BOOL bAddAdminGroup = FALSE; BOOL bReadOnly = FALSE; HKEY hSubKey; DWORD dwSize, dwType; BOOL bImpersonated = FALSE; LPTSTR lpCscBypassedPath = NULL; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Entering, lpProfilePath = <%s>"), lpProfilePath)); if (lpProfile->dwUserPreference == USERINFO_LOCAL) { DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: User preference is local. Ignoring roaming profile path"))); goto DisableAndExit; } // // Check for .man extension // dwStrLen = lstrlen (lpProfilePath); if (dwStrLen >= 4) { lpEnd = lpProfilePath + dwStrLen - 4; if (!lstrcmpi(lpEnd, c_szMAN)) { bMandatory = TRUE; lpProfile->dwInternalFlags |= PROFILE_MANDATORY; DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Mandatory profile (.man extension)"))); } } // // Check whether we need to give access to the admin on the RUP share // // // Check for a roaming profile security/read only preference // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) { dwSize = sizeof(bAddAdminGroup); RegQueryValueEx(hSubKey, ADD_ADMIN_GROUP_TO_RUP, NULL, &dwType, (LPBYTE) &bAddAdminGroup, &dwSize); dwSize = sizeof(bReadOnly); RegQueryValueEx(hSubKey, READONLY_RUP, NULL, &dwType, (LPBYTE) &bReadOnly, &dwSize); RegCloseKey(hSubKey); } // // Check for a roaming profile security/read only policy // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) { dwSize = sizeof(bAddAdminGroup); RegQueryValueEx(hSubKey, ADD_ADMIN_GROUP_TO_RUP, NULL, &dwType, (LPBYTE) &bAddAdminGroup, &dwSize); dwSize = sizeof(bReadOnly); RegQueryValueEx(hSubKey, READONLY_RUP, NULL, &dwType, (LPBYTE) &bReadOnly, &dwSize); RegCloseKey(hSubKey); } if (bReadOnly) { lpProfile->dwInternalFlags |= PROFILE_READONLY; } // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to impersonate user"))); // last error is already set. return FALSE; } bImpersonated = TRUE; // Check whether RUP share is CSCed, if it is give a warning. CheckRUPShare(lpProfilePath); // // Try to bypass CSC to avoid conflicts in syncing files between roaming share & local profile // if (IsUNCPath(lpProfilePath)) { if ((dwErr = AbleToBypassCSC(lpProfile->hTokenUser, lpProfilePath, &lpCscBypassedPath, cpDrive)) == ERROR_SUCCESS) { *bpCSCBypassed = TRUE; lpProfilePath = lpCscBypassedPath; DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: CSC bypassed. Profile path %s"), lpProfilePath)); } else { if (dwErr == WN_BAD_LOCALNAME || dwErr == WN_ALREADY_CONNECTED || dwErr == ERROR_BAD_PROVIDER) { DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: CSC bypassed failed. Profile path %s"), lpProfilePath)); dwErr = ERROR_SUCCESS; } else { // Share is not up. So we do not need to do any further check DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: CSC bypassed failed. Ignoring Roaming profile path"))); goto Exit; } } } // // Start by calling GetFileAttributes so we have file attributes // to work with. We have to call GetFileAttributes twice. The // first call sets up the session so we can call it again and // get accurate timing information for slow link detection. // dwAttributes = GetFileAttributes(lpProfilePath); if (dwAttributes != -1) { dwStart = GetTickCount(); dwAttributes = GetFileAttributes(lpProfilePath); dwDelta = GetTickCount() - dwStart; DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Tick Count = %d"), dwDelta)); // // if it is success, find out whether the profile is // across a slow link. // // Looks like this is possible at least when a // share doesn't exist on a server across a slow link. // if this is not possible // then checkforslowlink will have to be moved down to check // after we have found a valid share // if (!bMandatory && !bReadOnly) { CheckForSlowLink (lpProfile, dwDelta, lpProfile->lpProfilePath, TRUE); if (lpProfile->dwInternalFlags & PROFILE_SLOW_LINK) { DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Profile is across a slow link. Ignoring roaming profile path"))); goto DisableAndExit; } } } else { dwErr = GetLastError(); // get the error now for later use } // // if we have got a valid handle // if (dwAttributes != -1) { // // GetFileAttributes found something. // look at the file attributes. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: GetFileAttributes found something with attributes <0x%x>"), dwAttributes)); // // If we found a directory, we have a proper profile // directory. exit. // if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) { DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a directory"))); bRetVal = TRUE; goto Exit; } else { // // We found a file. // // In 3.51, we used to have a file for the profile. // // In the migration part of the code, we used to take this file // nad migrate to a directory that ends in .pds (for normal profiles) // and .pdm for (for mandatory profiles). // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a file"))); } dwErr = ERROR_PATH_NOT_FOUND; goto Exit; } // // GetFileAttributes failed. Look at the error to determine why. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: GetFileAttributes failed with error %d"), dwErr)); if (bMandatory) { DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Couldn't access mandatory profile <%s> with error %d"), lpProfilePath, GetLastError())); goto Exit; } if (bReadOnly) { DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Couldn't access mandatory profile <%s> with error %d"), lpProfilePath, GetLastError())); goto Exit; } // // To fix bug #414176, the last error code chk has been added. // // ERROR_BAD_NET_NAME is the error code that is returned by GetFileAttributes // when the profile directory for a user actually points to the root // of the share. // CreateDirectory should succeed. // if ( (dwErr == ERROR_FILE_NOT_FOUND) || (dwErr == ERROR_PATH_NOT_FOUND) || (dwErr == ERROR_BAD_NET_NAME) ) { // // Nothing found with this name. // // In 3.51, we used to have a file for the profile. // // In the migration part of the code, we used to take this file // nad migrate to a directory that ends in .pds (for normal profiles) // and .pdm for (for mandatory profiles). // if (CreateSecureDirectory(lpProfile, lpProfilePath, NULL, !bAddAdminGroup)) { // // Successfully created the directory. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Succesfully created the sub-directory"))); bRetVal = TRUE; goto Exit; } else { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to create user sub-directory. Error = %d"), GetLastError())); goto Exit; } } goto Exit; Exit: if (!bRetVal) { // // We have failed to connect to the profile server for some reason. // Now evaluate whether we want to disable profile and log the user in // or prevent the user from logging on. // // In addition give an appropriate popup.. // if (IsUserAnAdminMember(lpProfile->hTokenUser)) { if (bMandatory) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_MANDATORY_NOT_AVAILABLE_DISABLE, GetErrString(dwErr, szErr)); } else if (bReadOnly) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_READONLY_NOT_AVAILABLE_DISABLE, GetErrString(dwErr, szErr)); } else { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_CENTRAL_NOT_AVAILABLE_DISABLE, GetErrString(dwErr, szErr)); } goto DisableAndExit; } else { if (bMandatory) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_MANDATORY_NOT_AVAILABLE_ERROR, GetErrString(dwErr, szErr)); } else if (bReadOnly) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_READONLY_NOT_AVAILABLE_DISABLE, GetErrString(dwErr, szErr)); goto DisableAndExit; // temporary profile decisions will kick in, in restoreuserprofile later on.. } else { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_CENTRAL_NOT_AVAILABLE_DISABLE, GetErrString(dwErr, szErr)); goto DisableAndExit; // temporary profile decisions will kick in, in restoreuserprofile later on.. } } } else { lstrcpy(lpProfile->lpRoamingProfile, lpProfilePath); } goto CleanupAndExit; DisableAndExit: lpProfile->lpRoamingProfile[0] = TEXT('\0'); bRetVal = TRUE; CleanupAndExit: // // Revert to being 'ourself' // if(bImpersonated) { if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to revert to self"))); } } if (lpCscBypassedPath) { LocalFree(lpCscBypassedPath); } if (!bRetVal) SetLastError(dwErr); return bRetVal; } //************************************************************* // // GetExclusionList() // // Purpose: Get's the exclusion list used at logon // // Parameters: lpProfile - Profile Information // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL GetExclusionList (LPPROFILE lpProfile) { LPTSTR szExcludeListLocal = NULL; LPTSTR szExcludeListServer = NULL; LPTSTR szNTUserIni = NULL; LPTSTR lpEnd; HANDLE hOldToken; BOOL bRetVal = FALSE; // // Allocate memory for Local variables to avoid stack overflow // szExcludeListLocal = (LPTSTR)LocalAlloc(LPTR, 2*MAX_PATH*sizeof(TCHAR)); if (!szExcludeListLocal) { DebugMsg((DM_WARNING, TEXT("GetExclusionList: Out of memory"))); goto Exit; } szExcludeListServer = (LPTSTR)LocalAlloc(LPTR, 2*MAX_PATH*sizeof(TCHAR)); if (!szExcludeListServer) { DebugMsg((DM_WARNING, TEXT("GetExclusionList: Out of memory"))); goto Exit; } szNTUserIni = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szNTUserIni) { DebugMsg((DM_WARNING, TEXT("GetExclusionList: Out of memory"))); goto Exit; } // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("GetExclusionList: Failed to impersonate user"))); // last error is set goto Exit; } // // Get the exclusion list from the server // szExcludeListServer[0] = TEXT('\0'); lstrcpy (szNTUserIni, lpProfile->lpRoamingProfile); lpEnd = CheckSlash (szNTUserIni); lstrcpy(lpEnd, c_szNTUserIni); GetPrivateProfileString (PROFILE_GENERAL_SECTION, PROFILE_EXCLUSION_LIST, TEXT(""), szExcludeListServer, 2*MAX_PATH, szNTUserIni); // // Get the exclusion list from the cache // szExcludeListLocal[0] = TEXT('\0'); lstrcpy (szNTUserIni, lpProfile->lpLocalProfile); lpEnd = CheckSlash (szNTUserIni); lstrcpy(lpEnd, c_szNTUserIni); GetPrivateProfileString (PROFILE_GENERAL_SECTION, PROFILE_EXCLUSION_LIST, TEXT(""), szExcludeListLocal, 2*MAX_PATH, szNTUserIni); // // Go back to system security context // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("GetExclusionList: Failed to revert to self"))); } // // See if the lists are the same // if (!lstrcmpi (szExcludeListServer, szExcludeListLocal)) { if (szExcludeListServer[0] != TEXT('\0')) { lpProfile->lpExclusionList = (LPTSTR)LocalAlloc (LPTR, (lstrlen (szExcludeListServer) + 1) * sizeof(TCHAR)); if (lpProfile->lpExclusionList) { lstrcpy (lpProfile->lpExclusionList, szExcludeListServer); DebugMsg((DM_VERBOSE, TEXT("GetExclusionList: The exclusion lists on both server and client are the same. The list is: <%s>"), szExcludeListServer)); } else { DebugMsg((DM_WARNING, TEXT("GetExclusionList: Failed to allocate memory for exclusion list with error %d"), GetLastError())); } } else { DebugMsg((DM_VERBOSE, TEXT("GetExclusionList: The exclusion on both server and client is empty."))); } } else { DebugMsg((DM_VERBOSE, TEXT("GetExclusionList: The exclusion lists between server and client are different. Server is <%s> and client is <%s>"), szExcludeListServer, szExcludeListLocal)); } bRetVal = TRUE; Exit: if (szExcludeListLocal) { LocalFree(szExcludeListLocal); } if (szExcludeListServer) { LocalFree(szExcludeListServer); } if (szNTUserIni) { LocalFree(szNTUserIni); } return bRetVal; } //************************************************************* // // RestoreUserProfile() // // Purpose: Downloads the user's profile if possible, // otherwise use either cached profile or // default profile. // // Parameters: lpProfile - Profile information // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/19/95 ericflo Created // //************************************************************* BOOL RestoreUserProfile(LPPROFILE lpProfile) { BOOL IsCentralReachable = FALSE; BOOL IsLocalReachable = FALSE; BOOL IsMandatory = FALSE; BOOL IsProfilePathNULL = FALSE; BOOL bCreateCentralProfile = FALSE; BOOL bDefaultUsed = FALSE; BOOL bCreateLocalProfile = TRUE; LPTSTR lpRoamingProfile = NULL; LPTSTR lpLocalProfile; BOOL bProfileLoaded = FALSE; BOOL bDefaultProfileIssued = FALSE; BOOL bNewUser = TRUE; LPTSTR SidString; LONG error = ERROR_SUCCESS; LPTSTR szProfile = NULL; LPTSTR szDefaultProfile = NULL; LPTSTR lpEnd; BOOL bRet; DWORD dwSize, dwFlags, dwErr=0, dwErr1; HANDLE hOldToken; LPTSTR szErr = NULL; BOOL bOwnerOK = TRUE; // // Get the error at the beginning of the call. // dwErr1 = GetLastError(); // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Entering"))); // // Get the Sid string for the current user // SidString = GetSidString(lpProfile->hTokenUser); if (!SidString) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to get sid string for user"))); return FALSE; } // // Allocate memory for Local variables to avoid stack overflow // szProfile = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szProfile) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Out of memory"))); goto CleanUp; } szDefaultProfile = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szDefaultProfile) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Out of memory"))); goto CleanUp; } szErr = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szErr) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Out of memory"))); goto CleanUp; } // // Test if this user is a guest. // if (IsUserAGuest(lpProfile->hTokenUser)) { lpProfile->dwInternalFlags |= PROFILE_GUEST_USER; DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: User is a Guest"))); } // // Test if this user is an admin. // if (IsUserAnAdminMember(lpProfile->hTokenUser)) { lpProfile->dwInternalFlags |= PROFILE_ADMIN_USER; lpProfile->dwInternalFlags &= ~PROFILE_GUEST_USER; DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: User is a Admin"))); } // // Decide if the central profilemage is available. // IsCentralReachable = IsCentralProfileReachable(lpProfile, &bCreateCentralProfile, &IsMandatory, &bOwnerOK); if (IsCentralReachable) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Central Profile is reachable"))); if (IsMandatory) { lpProfile->dwInternalFlags |= PROFILE_MANDATORY; DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Central Profile is mandatory"))); } else { lpProfile->dwInternalFlags |= PROFILE_UPDATE_CENTRAL; lpProfile->dwInternalFlags |= bCreateCentralProfile ? PROFILE_NEW_CENTRAL : 0; DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Central Profile is roaming"))); if ((lpProfile->dwUserPreference == USERINFO_LOCAL) || (lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Ignoring central profile due to User Preference of Local only (or slow link)."))); IsProfilePathNULL = TRUE; IsCentralReachable = FALSE; goto CheckLocal; } } } else { if (*lpProfile->lpRoamingProfile) { error = GetLastError(); DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: IsCentralProfileReachable returned FALSE. error = %d"), error)); if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { dwErr = error; ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_MANDATORY_NOT_AVAILABLE_ERROR, GetErrString(error, szErr)); goto Exit; } else if (lpProfile->dwInternalFlags & PROFILE_READONLY) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_READONLY_NOT_AVAILABLE, GetErrString(error, szErr)); *lpProfile->lpRoamingProfile = TEXT('\0'); } else if (!bOwnerOK) { ReportError(lpProfile->hTokenUser, EVENT_ERROR_TYPE, 0, EVENT_LOGON_RUP_NOT_SECURE); *lpProfile->lpRoamingProfile = TEXT('\0'); } else { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_CENTRAL_NOT_AVAILABLE, GetErrString(error, szErr)); *lpProfile->lpRoamingProfile = TEXT('\0'); } } } // // do not create a new profile locally if there is a central profile and // it is not reachable and if we do not have slow link or user preferences set // or read only profile. // if ((lpProfile->lpProfilePath) && (*lpProfile->lpProfilePath)) { if ((!IsCentralReachable) && (lpProfile->dwUserPreference != USERINFO_LOCAL) && (!(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) && (!(lpProfile->dwInternalFlags & PROFILE_READONLY))) bCreateLocalProfile = FALSE; } lpRoamingProfile = lpProfile->lpRoamingProfile; DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Profile path = <%s>"), lpRoamingProfile ? lpRoamingProfile : TEXT(""))); if (!lpRoamingProfile || !(*lpRoamingProfile)) { IsProfilePathNULL = TRUE; } CheckLocal: // // Determine if the local copy of the profilemage is available. // IsLocalReachable = GetExistingLocalProfileImage(lpProfile); if (IsLocalReachable) { DebugMsg((DM_VERBOSE, TEXT("Local Existing Profile Image is reachable"))); // // If we assign a TEMP profile from previous session due to leak // then issue a error message // if (lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_TEMPPROFILEASSIGNED); } } else { bNewUser = FALSE; if (bCreateLocalProfile) { bNewUser = CreateLocalProfileImage(lpProfile, lpProfile->lpUserName); if (!bNewUser) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: CreateLocalProfileImage failed. Unable to create a new profile!"))); } else { DebugMsg((DM_VERBOSE, TEXT("Creating Local Profile"))); IsLocalReachable = TRUE; } } if (!bNewUser) { if (lpProfile->dwFlags & PI_LITELOAD) { // // in lite load conditions we do not load a profile if it is not going to be cached on the machine. // dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Profile not loaded because server is unavailable during liteload"))); goto Exit; } // // if the user is not admin and is not allowed to create temp profile log him out. // if ((!(lpProfile->dwInternalFlags & PROFILE_ADMIN_USER)) && (!IsTempProfileAllowed())) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: User being logged off because of no temp profile policy"))); // // We have already lost the error returned from parseprofilepath. PATH_NOT_FOUND sounds quite close. // returning this. // dwErr = ERROR_PATH_NOT_FOUND; goto Exit; } if (!CreateLocalProfileImage(lpProfile, TEMP_PROFILE_NAME_BASE)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: CreateLocalProfileImage with TEMP failed with error %d. Unable to issue temporary profile!"), dwErr)); ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_TEMP_DIR_FAILED, GetErrString(dwErr, szErr)); goto Exit; } else { lpProfile->dwInternalFlags |= PROFILE_TEMP_ASSIGNED; if (!bCreateLocalProfile) ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_TEMPPROFILEASSIGNED); else { // // We have failed to create a local profile. So issue a proper error message. // ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_TEMPPROFILEASSIGNED2); } } } // clear any partly loaded flag if it exists, since this is a new profile. lpProfile->dwInternalFlags &= ~PROFILE_PARTLY_LOADED; lpProfile->dwInternalFlags |= PROFILE_NEW_LOCAL; } lpLocalProfile = lpProfile->lpLocalProfile; DebugMsg((DM_VERBOSE, TEXT("Local profile name is <%s>"), lpLocalProfile)); // // If we assign a TEMP profile from previous session due to leak // then do not reconcile RUP with TEMP profile // if ((lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED) && IsCentralReachable) { IsCentralReachable = FALSE; } // // We can do a couple of quick checks here to filter out // new users. // if (( (lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL) && (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) ) || (!IsCentralReachable && (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) )) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Working with a new user. Go straight to issuing a default profile."))); goto IssueDefault; } // // If both central and local profileimages exist, reconcile them // and load. // if (IsCentralReachable && IsLocalReachable) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Reconciling roaming profile with local profile"))); GetExclusionList (lpProfile); // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { bProfileLoaded = FALSE; dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to impersonate user"))); goto Exit; } // // Copy the profile // dwFlags = (lpProfile->dwFlags & PI_NOUI) ? CPD_NOERRORUI : 0; // // if the roaming profile is empty and the local profile is // mandatory, treat the profile as mandatory. // // Same as Win2k // if ((lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL) && (lpProfile->dwInternalFlags & PROFILE_LOCALMANDATORY)) { lpProfile->dwInternalFlags |= PROFILE_MANDATORY; } // // This can possibly be a transition from mandatory to non mandatory. // In that case, since the local profile is mandatory // we wouldn't expect any items from here to be synced with the // server yet. Go for a full sync with server but the profile will // not be marked mandatory from now on. // if ((lpProfile->dwInternalFlags & PROFILE_MANDATORY) || (lpProfile->dwInternalFlags & PROFILE_READONLY) || (lpProfile->dwInternalFlags & PROFILE_LOCALMANDATORY)) { dwFlags |= (CPD_COPYIFDIFFERENT | CPD_SYNCHRONIZE); } if (lpProfile->dwFlags & (PI_LITELOAD | PI_HIDEPROFILE)) { dwFlags |= CPD_SYSTEMFILES | CPD_SYSTEMDIRSONLY; } else dwFlags |= CPD_NONENCRYPTEDONLY; // // Profile unload time does not exist for mandatory, temp and read only profile. // But for read only profile we still want to use exclusion list without any ref time // if (lpProfile->lpExclusionList && *lpProfile->lpExclusionList) { if (lpProfile->dwInternalFlags & PROFILE_READONLY) { dwFlags |= CPD_USEEXCLUSIONLIST; } else if (lpProfile->ftProfileUnload.dwHighDateTime || lpProfile->ftProfileUnload.dwLowDateTime) { dwFlags |= (CPD_USEDELREFTIME | CPD_SYNCHRONIZE | CPD_USEEXCLUSIONLIST); } } // // If roaming copy is partial (due to LITE upload) then ignore the hive and // synchronize logic as it will end up deleting files from destination - a // massive data loss. // if (IsPartialRoamingProfile(lpProfile)) { dwFlags &= ~CPD_SYNCHRONIZE; dwFlags |= CPD_IGNOREHIVE; } // // Check whether in local machine user profile is switching from local to // roaming for first time. If yes and we have a existing hive in RUP share // then always overwrite the local hive with hive in RUP share. This is // to avoid wrong hive usage due to cached login // TouchLocalHive(lpProfile); bRet = CopyProfileDirectoryEx (lpRoamingProfile, lpLocalProfile, dwFlags, &lpProfile->ftProfileUnload, lpProfile->lpExclusionList); // // Revert to being 'ourself' // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to revert to self"))); } if (!bRet) { error = GetLastError(); if (error == ERROR_DISK_FULL) { dwErr = error; DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: CopyProfileDirectory failed because of DISK_FULL, Exitting"))); goto Exit; } if (error == ERROR_FILE_ENCRYPTED) { dwErr = error; DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: CopyProfileDirectory returned FALSE. Error = %d"), error)); ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_PROFILEUPDATE_6002); lpProfile->dwInternalFlags &= ~PROFILE_UPDATE_CENTRAL; // show the popup but exit only in the case if it is a new local profile if (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) goto IssueDefault; } else { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: CopyProfileDirectory failed. Issuing default profile"))); lpProfile->dwInternalFlags &= ~PROFILE_UPDATE_CENTRAL; lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; goto IssueDefault; } } lstrcpy (szProfile, lpLocalProfile); lpEnd = CheckSlash(szProfile); // // If the central profile is unreachable and the local profile // is manatory, treat it as mandatory. This is the same as Win2k // // We are not copying anything from the server // if (lpProfile->dwInternalFlags & PROFILE_LOCALMANDATORY) { lpProfile->dwInternalFlags |= PROFILE_MANDATORY; } if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } error = MyRegLoadKey(HKEY_USERS, SidString, szProfile); bProfileLoaded = (error == ERROR_SUCCESS); // // If we failed to load the central profile for some // reason, don't update it when we log off. // if (bProfileLoaded) { goto Exit; } else { dwErr = error; lpProfile->dwInternalFlags &= ~PROFILE_UPDATE_CENTRAL; lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; if (error == ERROR_BADDB) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_FAILED_LOAD_1009); goto IssueDefault; } else if (error == ERROR_NO_SYSTEM_RESOURCES) { goto Exit; } else { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_FAILED_LOAD_LOCAL, GetErrString(error, szErr)); goto IssueDefault; } } } // // Only a local profile exists so use it. // if (!IsCentralReachable && IsLocalReachable) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: No central profile. Attempting to load local profile."))); lstrcpy (szProfile, lpLocalProfile); lpEnd = CheckSlash(szProfile); // // If the central profile is unreachable and the local profile // is manatory, treat it as mandatory. This is the same as Win2k // // We are not copying anything from the server // if (lpProfile->dwInternalFlags & PROFILE_LOCALMANDATORY) { lpProfile->dwInternalFlags |= PROFILE_MANDATORY; } if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } error = MyRegLoadKey(HKEY_USERS, SidString, szProfile); bProfileLoaded = (error == ERROR_SUCCESS); if (!bProfileLoaded) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: MyRegLoadKey returned FALSE."))); dwErr = error; if (error == ERROR_BADDB) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_FAILED_LOAD_1009); lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; goto IssueDefault; } else if (error == ERROR_NO_SYSTEM_RESOURCES) { goto Exit; } else { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_FAILED_LOAD_LOCAL, GetErrString(error, szErr)); } } if (!bProfileLoaded && IsProfilePathNULL) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Failed to load local profile and profile path is NULL, going to overwrite local profile"))); lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; goto IssueDefault; } goto Exit; } // // Last combination. Unable to access a local profile cache, // but a central profile exists. Use the temporary profile. // if (IsCentralReachable) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Using temporary cache with central profile"))); GetExclusionList (lpProfile); // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to impersonate user"))); dwErr = GetLastError(); goto Exit; } // // Local is not reachable. So Localmandatory will not be set.. // dwFlags = (lpProfile->dwFlags & PI_NOUI) ? CPD_NOERRORUI : 0; dwFlags |= CPD_SYNCHRONIZE; if ((lpProfile->dwInternalFlags & PROFILE_MANDATORY) || (lpProfile->dwInternalFlags & PROFILE_READONLY)) { dwFlags |= CPD_COPYIFDIFFERENT; } if (lpProfile->dwFlags & (PI_LITELOAD | PI_HIDEPROFILE)) { dwFlags |= CPD_SYSTEMFILES | CPD_SYSTEMDIRSONLY; } else dwFlags |= CPD_NONENCRYPTEDONLY; // // Profile unload time does not exist for mandatory, temp and read only profile. // But for read only profile we still want to use exclusion list without any ref time // if (lpProfile->lpExclusionList && *lpProfile->lpExclusionList) { if (lpProfile->dwInternalFlags & PROFILE_READONLY) { dwFlags |= CPD_USEEXCLUSIONLIST; } else if (lpProfile->ftProfileUnload.dwHighDateTime || lpProfile->ftProfileUnload.dwLowDateTime) { dwFlags |= (CPD_USEDELREFTIME | CPD_SYNCHRONIZE | CPD_USEEXCLUSIONLIST); } } bRet = CopyProfileDirectoryEx (lpRoamingProfile, lpLocalProfile, dwFlags, &lpProfile->ftProfileUnload, lpProfile->lpExclusionList); // // Revert to being 'ourself' // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to revert to self"))); } // // Check return value // if (!bRet) { error = GetLastError(); if (error == ERROR_FILE_ENCRYPTED) { dwErr = error; DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: CopyProfileDirectory returned FALSE. Error = %d"), error)); ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_PROFILEUPDATE_6002); lpProfile->dwInternalFlags &= ~PROFILE_UPDATE_CENTRAL; // show the popup but exit only in the case if it is a new local profile if (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) goto IssueDefault; } else { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: CopyProfileDirectory returned FALSE. Error = %d"), error)); goto Exit; } } lstrcpy (szProfile, lpLocalProfile); lpEnd = CheckSlash(szProfile); if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } error = MyRegLoadKey(HKEY_USERS, SidString, szProfile); bProfileLoaded = (error == ERROR_SUCCESS); if (bProfileLoaded) { goto Exit; } SetLastError(error); dwErr = error; if (error == ERROR_BADDB) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_FAILED_LOAD_1009); // fall through } else if (error == ERROR_NO_SYSTEM_RESOURCES) { goto Exit; } // // we will delete the contents at this point // lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; } IssueDefault: DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Issuing default profile"))); // // If a cache exists, delete it, since we will // generate a new one below. // if (lpProfile->dwInternalFlags & PROFILE_DELETE_CACHE) { DWORD dwDeleteFlags=0; DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Deleting cached profile directory <%s>."), lpLocalProfile)); lpProfile->dwInternalFlags &= ~PROFILE_DELETE_CACHE; if ((!(lpProfile->dwInternalFlags & PROFILE_ADMIN_USER)) && (!IsTempProfileAllowed())) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: User being logged off because of no temp profile policy and is not an admin"))); // // We should have some error from a prev. operation. depending on that. // goto Exit; } if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: User being logged off because the profile is mandatory"))); // // We should have some error from a prev. operation. depending on that. // goto Exit; } // // backup only if we are not using a temp profile already. // if (!(lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED)) dwDeleteFlags |= DP_BACKUP | DP_BACKUPEXISTS; if ((dwDeleteFlags & DP_BACKUP) && (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL)) { dwDeleteFlags = 0; } if (!DeleteProfileEx (SidString, lpLocalProfile, dwDeleteFlags, HKEY_LOCAL_MACHINE, NULL)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: DeleteProfileDirectory returned false. Error = %d"), dwErr)); goto Exit; } else { if (dwDeleteFlags & DP_BACKUP) { lpProfile->dwInternalFlags |= PROFILE_BACKUP_EXISTS; ReportError(lpProfile->hTokenUser, PI_NOUI, 0, EVENT_PROFILE_DIR_BACKEDUP); } } if (lpProfile->dwFlags & PI_LITELOAD) { // // in lite load conditions we do not load a profile if it is not going to be cached on the machine. // // dwErr should be set before, use the same. DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Profile not loaded because server is unavailable during liteload"))); goto Exit; } // // Create a local profile to work with // if (!CreateLocalProfileImage(lpProfile, TEMP_PROFILE_NAME_BASE)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: CreateLocalProfile Image with TEMP failed."))); ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_TEMP_DIR_FAILED, GetErrString(dwErr, szErr)); goto Exit; } else { lpProfile->dwInternalFlags |= PROFILE_TEMP_ASSIGNED; lpProfile->dwInternalFlags |= PROFILE_NEW_LOCAL; // clear any partly loaded flag if it exists, since this is a new profile. lpProfile->dwInternalFlags &= ~PROFILE_PARTLY_LOADED; ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_TEMPPROFILEASSIGNED); } } // // If a default profile location was specified, try // that first. // if ( !(lpProfile->dwInternalFlags & DEFAULT_NET_READY) ) { CheckNetDefaultProfile (lpProfile); } if ( lpProfile->lpDefaultProfile && *lpProfile->lpDefaultProfile) { if (IssueDefaultProfile (lpProfile, lpProfile->lpDefaultProfile, lpLocalProfile, SidString, (lpProfile->dwInternalFlags & PROFILE_MANDATORY))) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Successfully setup the specified default."))); bProfileLoaded = TRUE; goto IssueDefaultExit; } DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: IssueDefaultProfile failed with specified default."))); } // // IssueLocalDefault // // // Issue the local default profile. // dwSize = MAX_PATH; if (!GetDefaultUserProfileDirectory(szDefaultProfile, &dwSize)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to get default user profile."))); goto Exit; } if (IssueDefaultProfile (lpProfile, szDefaultProfile, lpLocalProfile, SidString, (lpProfile->dwInternalFlags & PROFILE_MANDATORY))) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Successfully setup the local default."))); bProfileLoaded = TRUE; goto IssueDefaultExit; } DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: IssueDefaultProfile failed with local default."))); dwErr = GetLastError(); IssueDefaultExit: // // If the default profile was successfully issued, then // we need to set the security on the hive. // if (bProfileLoaded) { if (!SetupNewHive(lpProfile, SidString, NULL)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: SetupNewHive failed"))); bProfileLoaded = FALSE; } else { bDefaultProfileIssued = TRUE; } } Exit: // // If the profile was loaded, then save the profile type in the // user's hive, and setup the "User Shell Folders" section for // Explorer. // if (bProfileLoaded) { // // Open the Current User key. This will be closed in // UnloadUserProfile. // error = RegOpenKeyEx(HKEY_USERS, SidString, 0, KEY_ALL_ACCESS, &lpProfile->hKeyCurrentUser); if (error != ERROR_SUCCESS) { bProfileLoaded = FALSE; dwErr = error; DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to open current user key. Error = %d"), error)); } } if ((bProfileLoaded) && (!(lpProfile->dwFlags & PI_LITELOAD))) { // // merge the subtrees to create the HKCR tree // error = LoadUserClasses( lpProfile, SidString, bDefaultProfileIssued ); if (error != ERROR_SUCCESS) { bProfileLoaded = FALSE; dwErr = error; DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to merge classes root. Error = %d"), error)); } } if ((!bProfileLoaded) && (!(lpProfile->dwFlags & PI_LITELOAD))) { error = dwErr; // // If the user is an Admin, then let him/her log on with // either the .default profile, or an empty profile. // if (lpProfile->dwInternalFlags & PROFILE_ADMIN_USER) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_ADMIN_OVERRIDE, GetErrString(error, szErr)); bProfileLoaded = TRUE; } else { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Could not load the user profile. Error = %d"), error)); ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 1, EVENT_FAILED_LOAD_PROFILE, GetErrString(error, szErr)); if (lpProfile->hKeyCurrentUser) { RegCloseKey (lpProfile->hKeyCurrentUser); } MyRegUnLoadKey(HKEY_USERS, SidString); if ((lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL)) { if (!DeleteProfileEx (SidString, lpLocalProfile, 0, HKEY_LOCAL_MACHINE, NULL)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: DeleteProfileDirectory returned false. Error = %d"), GetLastError())); } } } } CleanUp: DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: About to Leave. Final Information follows:"))); DebugMsg((DM_VERBOSE, TEXT("Profile was %s loaded."), bProfileLoaded ? TEXT("successfully") : TEXT("NOT successfully"))); DebugMsg((DM_VERBOSE, TEXT("lpProfile->lpRoamingProfile = <%s>"), lpProfile->lpRoamingProfile)); DebugMsg((DM_VERBOSE, TEXT("lpProfile->lpLocalProfile = <%s>"), lpProfile->lpLocalProfile)); DebugMsg((DM_VERBOSE, TEXT("lpProfile->dwInternalFlags = 0x%x"), lpProfile->dwInternalFlags)); // // Free up the user's sid string // DeleteSidString(SidString); if (szProfile) { LocalFree(szProfile); } if (szDefaultProfile) { LocalFree(szDefaultProfile); } if (szErr) { LocalFree(szErr); } if (bProfileLoaded) { if (!(lpProfile->dwFlags & PI_LITELOAD)) { // clear any partly loaded flag if it exists, since this is a new profile. lpProfile->dwInternalFlags &= ~PROFILE_PARTLY_LOADED; } else { if (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) lpProfile->dwInternalFlags |= PROFILE_PARTLY_LOADED; } } if (bProfileLoaded) SetLastError(dwErr1); else { // // Make sure that at least some error is returned. // if (!dwErr) { dwErr = ERROR_BAD_ENVIRONMENT; } SetLastError(dwErr); } DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Leaving."))); return bProfileLoaded; } //*************************************************************************** // // GetProfileSidString // // Purpose: Allocates and returns a string representing the sid that we should // for the profiles // // Parameters: hToken - user's token // // Return: SidString is successful // NULL if an error occurs // // Comments: // Tries to get the old sid that we used using the profile guid. // if it doesn't exist get the sid directly from the token // // History: Date Author Comment // 11/14/95 ushaji created //*************************************************************************** LPTSTR GetProfileSidString(HANDLE hToken) { LPTSTR lpSidString; TCHAR LocalProfileKey[MAX_PATH]; LONG error; HKEY hSubKey; // // First, get the current user's sid and see if we have // profile information for them. // lpSidString = GetSidString(hToken); if (lpSidString) { lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); lstrcat(LocalProfileKey, TEXT("\\")); lstrcat(LocalProfileKey, lpSidString); error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, KEY_READ, &hSubKey); if (error == ERROR_SUCCESS) { RegCloseKey(hSubKey); return lpSidString; } lstrcat(LocalProfileKey, c_szBAK); error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, KEY_READ, &hSubKey); if (ERROR_SUCCESS == error) { RegCloseKey(hSubKey); return lpSidString; } DeleteSidString(lpSidString); } // // Check for an old sid string // lpSidString = GetOldSidString(hToken, PROFILE_GUID_PATH); if (!lpSidString) { // // Last resort, use the user's current sid // DebugMsg((DM_VERBOSE, TEXT("GetProfileSid: No Guid -> Sid Mapping available"))); lpSidString = GetSidString(hToken); } return lpSidString; } //************************************************************* // // TestIfUserProfileLoaded() // // Purpose: Test to see if this user's profile is loaded. // // Parameters: hToken - user's token // lpProfileInfo - Profile information from app // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/19/95 ericflo Ported // //************************************************************* BOOL TestIfUserProfileLoaded(HANDLE hToken, LPPROFILEINFO lpProfileInfo) { LPTSTR SidString; DWORD error; HKEY hSubKey; // // Get the Sid string for the user // SidString = GetProfileSidString(hToken); if (!SidString) { DebugMsg((DM_WARNING, TEXT("TestIfUserProfileLoaded: Failed to get sid string for user"))); return FALSE; } error = RegOpenKeyEx(HKEY_USERS, SidString, 0, KEY_ALL_ACCESS, &hSubKey); DeleteSidString(SidString); if (error == ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("TestIfUserProfileLoaded: Profile already loaded."))); // // This key will be closed in before IUserProfile->LoadUserProfile // returns. It'll be reopened on the client side. // lpProfileInfo->hProfile = hSubKey; } SetLastError(error); return(error == ERROR_SUCCESS); } //************************************************************* // // SecureUserKey() // // Purpose: Sets security on a key in the user's hive // so only admin's can change it. // // Parameters: lpProfile - Profile Information // lpKey - Key to secure // pSid - Sid (used by CreateNewUser) // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/20/95 ericflo Created // //************************************************************* BOOL SecureUserKey(LPPROFILE lpProfile, LPTSTR lpKey, PSID pSid) { DWORD Error, IgnoreError; HKEY RootKey; SECURITY_DESCRIPTOR sd; SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; PACL pAcl = NULL; PSID psidUser = NULL, psidSystem = NULL, psidAdmin = NULL, psidRestricted = NULL; DWORD cbAcl, AceIndex, dwDisp; ACE_HEADER * lpAceHeader; BOOL bRetVal = FALSE; BOOL bFreeSid = TRUE; DWORD dwFlags = 0; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Entering"))); // // Create the security descriptor // // // Give the user access by their real sid so they still have access // when they logoff and logon again // if (pSid) { psidUser = pSid; bFreeSid = FALSE; dwFlags = PI_NOUI; } else { psidUser = GetUserSid(lpProfile->hTokenUser); dwFlags = lpProfile->dwFlags; } if (!psidUser) { DebugMsg((DM_WARNING, TEXT("SecureUserKey: Failed to get user sid"))); return FALSE; } // // Get the system sid // if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to initialize system sid. Error = %d"), GetLastError())); goto Exit; } // // Get the admin sid // if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to initialize admin sid. Error = %d"), GetLastError())); goto Exit; } // // Get the restricted sid // if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_RESTRICTED_CODE_RID, 0, 0, 0, 0, 0, 0, 0, &psidRestricted)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to initialize restricted sid. Error = %d"), GetLastError())); goto Exit; } // // Allocate space for the ACL // cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) + (2 * GetLengthSid (psidAdmin)) + (2 * GetLengthSid (psidRestricted)) + sizeof(ACL) + (8 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))); pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl); if (!pAcl) { goto Exit; } if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to initialize acl. Error = %d"), GetLastError())); goto Exit; } // // Add Aces for User, System, and Admin. Non-inheritable ACEs first // AceIndex = 0; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_READ, psidUser)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to add ace for user. Error = %d"), GetLastError())); goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to add ace for system. Error = %d"), GetLastError())); goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to add ace for admin. Error = %d"), GetLastError())); goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_READ, psidRestricted)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to add ace for restricted. Error = %d"), GetLastError())); goto Exit; } // // Now the inheritable ACEs // AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ, psidUser)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to add ace for user. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to add ace for system. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to add ace for admin. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ, psidRestricted)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to add ace for restricted. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); // // Put together the security descriptor // if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to initialize security descriptor. Error = %d"), GetLastError())); goto Exit; } if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Failed to set security descriptor dacl. Error = %d"), GetLastError())); goto Exit; } // // Open the root of the user's profile // Error = RegCreateKeyEx(HKEY_USERS, lpKey, 0, NULL, REG_OPTION_NON_VOLATILE, WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL, NULL, &RootKey, &dwDisp); if (Error != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SecureUserKey: Failed to open root of user registry, error = %d"), Error)); } else { // // Set the security descriptor on the key // Error = ApplySecurityToRegistryTree(RootKey, &sd); if (Error == ERROR_SUCCESS) { bRetVal = TRUE; } else { DebugMsg((DM_WARNING, TEXT("SecureUserKey: Failed to apply security to registry key, error = %d"), Error)); SetLastError(Error); } RegCloseKey(RootKey); } Exit: // // Free the sids and acl // if (bFreeSid && psidUser) { DeleteUserSid (psidUser); } if (psidRestricted) { FreeSid(psidRestricted); } if (psidSystem) { FreeSid(psidSystem); } if (psidAdmin) { FreeSid(psidAdmin); } if (pAcl) { GlobalFree (pAcl); } // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("SecureUserKey: Leaving with a return value of %d"), bRetVal)); return(bRetVal); } //************************************************************* // // ApplySecurityToRegistryTree() // // Purpose: Applies the passed security descriptor to the passed // key and all its descendants. Only the parts of // the descriptor inddicated in the security // info value are actually applied to each registry key. // // Parameters: RootKey - Registry key // pSD - Security Descriptor // // Return: ERROR_SUCCESS if successful // // Comments: // // History: Date Author Comment // 7/19/95 ericflo Created // //************************************************************* DWORD ApplySecurityToRegistryTree(HKEY RootKey, PSECURITY_DESCRIPTOR pSD) { DWORD Error, IgnoreError; DWORD SubKeyIndex; LPTSTR SubKeyName; HKEY SubKey; DWORD cchSubKeySize = MAX_PATH + 1; // // First apply security // RegSetKeySecurity(RootKey, DACL_SECURITY_INFORMATION, pSD); // // Open each sub-key and apply security to its sub-tree // SubKeyIndex = 0; SubKeyName = (LPTSTR)GlobalAlloc (GPTR, cchSubKeySize * sizeof(TCHAR)); if (!SubKeyName) { DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryTree: Failed to allocate memory, error = %d"), GetLastError())); return GetLastError(); } while (TRUE) { // // Get the next sub-key name // Error = RegEnumKey(RootKey, SubKeyIndex, SubKeyName, cchSubKeySize); if (Error != ERROR_SUCCESS) { if (Error == ERROR_NO_MORE_ITEMS) { // // Successful end of enumeration // Error = ERROR_SUCCESS; } else { DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryTree: Registry enumeration failed with error = %d"), Error)); } break; } // // Open the sub-key // Error = RegOpenKeyEx(RootKey, SubKeyName, 0, WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL, &SubKey); if (Error == ERROR_SUCCESS) { // // Apply security to the sub-tree // ApplySecurityToRegistryTree(SubKey, pSD); // // We're finished with the sub-key // RegCloseKey(SubKey); } // // Go enumerate the next sub-key // SubKeyIndex ++; } GlobalFree (SubKeyName); return Error; } //************************************************************* // // SetDefaultUserHiveSecurity() // // Purpose: Initializes a user hive with the // appropriate acls // // Parameters: lpProfile - Profile Information // pSid - Sid (used by CreateNewUser) // RootKey - registry handle to hive root // // Return: ERROR_SUCCESS if successful // other error code if an error occurs // // Comments: // // History: Date Author Comment // 7/18/95 ericflo Created as part of // SetupNewHive // 3/29/98 adamed Moved out of SetupNewHive // to this function // //************************************************************* BOOL SetDefaultUserHiveSecurity(LPPROFILE lpProfile, PSID pSid, HKEY RootKey) { DWORD Error; SECURITY_DESCRIPTOR sd; SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; PACL pAcl = NULL; PSID psidUser = NULL, psidSystem = NULL, psidAdmin = NULL, psidRestricted = NULL; DWORD cbAcl, AceIndex; ACE_HEADER * lpAceHeader; BOOL bRetVal = FALSE; BOOL bFreeSid = TRUE; DWORD dwFlags = 0; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Entering"))); // // Create the security descriptor that will be applied to each key // // // Give the user access by their real sid so they still have access // when they logoff and logon again // if (pSid) { psidUser = pSid; bFreeSid = FALSE; dwFlags = PI_NOUI; } else { psidUser = GetUserSid(lpProfile->hTokenUser); dwFlags = lpProfile->dwFlags; } if (!psidUser) { DebugMsg((DM_WARNING, TEXT("SetDefaultUserHiveSecurity: Failed to get user sid"))); return FALSE; } // // Get the system sid // if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to initialize system sid. Error = %d"), GetLastError())); goto Exit; } // // Get the admin sid // if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to initialize admin sid. Error = %d"), GetLastError())); goto Exit; } // // Get the Restricted sid // if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_RESTRICTED_CODE_RID, 0, 0, 0, 0, 0, 0, 0, &psidRestricted)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to initialize restricted sid. Error = %d"), GetLastError())); goto Exit; } // // Allocate space for the ACL // cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) + (2 * GetLengthSid (psidAdmin)) + (2*GetLengthSid(psidRestricted)) + sizeof(ACL) + (8 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))); pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl); if (!pAcl) { goto Exit; } if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to initialize acl. Error = %d"), GetLastError())); goto Exit; } // // Add Aces for User, System, and Admin. Non-inheritable ACEs first // AceIndex = 0; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidUser)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to add ace for user. Error = %d"), GetLastError())); goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to add ace for system. Error = %d"), GetLastError())); goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to add ace for admin. Error = %d"), GetLastError())); goto Exit; } AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_READ, psidRestricted)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to add ace for Restricted. Error = %d"), GetLastError())); goto Exit; } // // Now the inheritable ACEs // AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidUser)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to add ace for user. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to add ace for system. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to add ace for admin. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ, psidRestricted)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to add ace for restricted. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to get ace (%d). Error = %d"), AceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); // // Put together the security descriptor // if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to initialize security descriptor. Error = %d"), GetLastError())); goto Exit; } if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { DebugMsg((DM_VERBOSE, TEXT("SetDefaultUserHiveSecurity: Failed to set security descriptor dacl. Error = %d"), GetLastError())); goto Exit; } // // Set the security descriptor on the entire tree // Error = ApplySecurityToRegistryTree(RootKey, &sd); if (ERROR_SUCCESS == Error) { bRetVal = TRUE; } else SetLastError(Error); Exit: // // Free the sids and acl // if (bFreeSid && psidUser) { DeleteUserSid (psidUser); } if (psidSystem) { FreeSid(psidSystem); } if (psidAdmin) { FreeSid(psidAdmin); } if (psidRestricted) { FreeSid(psidRestricted); } if (pAcl) { GlobalFree (pAcl); } return bRetVal; } //************************************************************* // // SetupNewHive() // // Purpose: Initializes the new user hive created by copying // the default hive. // // Parameters: lpProfile - Profile Information // lpSidString - Sid string // pSid - Sid (used by CreateNewUser) // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 7/18/95 ericflo Created // //************************************************************* BOOL SetupNewHive(LPPROFILE lpProfile, LPTSTR lpSidString, PSID pSid) { DWORD Error, IgnoreError; HKEY RootKey; BOOL bRetVal = FALSE; DWORD dwFlags = 0; TCHAR szErr[MAX_PATH]; // // Verbose Output // if (!lpProfile && !pSid) { DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Invalid parameter"))); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Entering"))); if (pSid) { dwFlags = PI_NOUI; } else { dwFlags = lpProfile->dwFlags; } // // Open the root of the user's profile // Error = RegOpenKeyEx(HKEY_USERS, lpSidString, 0, WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL, &RootKey); if (Error != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to open root of user registry, error = %d"), Error)); } else { // // First Secure the entire hive -- use security that // will be sufficient for most of the hive. // After this, we can add special settings to special // sections of this hive. // if (SetDefaultUserHiveSecurity(lpProfile, pSid, RootKey)) { TCHAR szSubKey[MAX_PATH]; LPTSTR lpEnd; // // Change the security on certain keys in the user's registry // so that only Admin's and the OS have write access. // lstrcpy (szSubKey, lpSidString); lpEnd = CheckSlash(szSubKey); lstrcpy (lpEnd, WINDOWS_POLICIES_KEY); if (!SecureUserKey(lpProfile, szSubKey, pSid)) { DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to secure windows policies key"))); } lstrcpy (lpEnd, ROOT_POLICIES_KEY); if (!SecureUserKey(lpProfile, szSubKey, pSid)) { DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to secure root policies key"))); } bRetVal = TRUE; } else { Error = GetLastError(); DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to apply security to user registry tree, error = %d"), Error)); ReportError(lpProfile->hTokenUser, dwFlags, 1, EVENT_SECURITY_FAILED, GetErrString(Error, szErr)); } RegFlushKey (RootKey); IgnoreError = RegCloseKey(RootKey); if (IgnoreError != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to close reg key, error = %d"), IgnoreError)); } } // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Leaving with a return value of %d"), bRetVal)); if (!bRetVal) SetLastError(Error); return(bRetVal); } //************************************************************* // // IsCentralProfileReachable() // // Purpose: Checks to see if the user can access the // central profile. // // Parameters: lpProfile - User's token // bCreateCentralProfile - Should the central profile be created // bMandatory - Is this a mandatory profile // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/20/95 ericflo Ported // //************************************************************* BOOL IsCentralProfileReachable(LPPROFILE lpProfile, BOOL *bCreateCentralProfile, BOOL *bMandatory, BOOL* bOwnerOK) { HANDLE hFile; TCHAR szProfile[MAX_PATH]; LPTSTR lpProfilePath, lpEnd; BOOL bRetVal = FALSE; DWORD dwError; HANDLE hOldToken; HRESULT hr; dwError = GetLastError(); // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Entering"))); // // Setup default values // *bMandatory = FALSE; *bCreateCentralProfile = FALSE; *bOwnerOK = TRUE; // // Check parameters // if (lpProfile->lpRoamingProfile[0] == TEXT('\0')) { DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Null path. Leaving"))); return FALSE; } lpProfilePath = lpProfile->lpRoamingProfile; // // Make sure we don't overrun our temporary buffer // if ((lstrlen(lpProfilePath) + 1 + lstrlen(c_szNTUserMan + 1)) > MAX_PATH) { DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Failed because temporary buffer is too small."))); SetLastError(ERROR_BUFFER_OVERFLOW); return FALSE; } // // Copy the profile path to a temporary buffer // we can munge it. // lstrcpy (szProfile, lpProfilePath); // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Failed to impersonate user"))); return FALSE; } // // Check ownership of the profile // hr = CheckRoamingShareOwnership(szProfile, lpProfile->hTokenUser); if (FAILED(hr)) { // // Only set the bOwnerOK to false when we encountered the invalid owner error, // this would allow us to discover other reasons for failure // if (hr == HRESULT_FROM_WIN32(ERROR_INVALID_OWNER)) *bOwnerOK = FALSE; DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Ownership check failed with %08X"), hr)); SetLastError(HRESULT_CODE(hr)); goto Exit; } // // Add the slash if appropriate and then tack on ntuser.man. // lpEnd = CheckSlash(szProfile); lstrcpy(lpEnd, c_szNTUserMan); // // See if this file exists // DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Testing <%s>"), szProfile)); hFile = CreateFile(szProfile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Found a mandatory profile."))); CloseHandle(hFile); *bMandatory = TRUE; bRetVal = TRUE; goto Exit; } dwError = GetLastError(); DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Profile is not reachable, error = %d"), dwError)); // // If we received an error other than file not // found, bail now because we won't be able to // access this location. // if (dwError != ERROR_FILE_NOT_FOUND) { DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Profile path <%s> is not reachable, error = %d"), szProfile, dwError)); goto Exit; } // // Now try ntuser.dat // lstrcpy(lpEnd, c_szNTUserDat); // // See if this file exists. // DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Testing <%s>"), szProfile)); hFile = CreateFile(szProfile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Found a user profile."))); CloseHandle(hFile); bRetVal = TRUE; goto Exit; } dwError = GetLastError(); DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Profile is not reachable, error = %d"), dwError)); // // If file not found than central profile is empty. For read // only profile ignore the empty central profile. // if ((dwError == ERROR_FILE_NOT_FOUND) && !(lpProfile->dwInternalFlags & PROFILE_READONLY)) { DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Ok to create a user profile."))); *bCreateCentralProfile = TRUE; bRetVal = TRUE; goto Exit; } DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Profile path <%s> is not reachable(2), error = %d"), szProfile, dwError)); Exit: // // Go back to system security context // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Failed to revert to self"))); } return bRetVal; } //************************************************************* // // MyRegLoadKey() // // Purpose: Loads a hive into the registry // // Parameters: hKey - Key to load the hive into // lpSubKey - Subkey name // lpFile - hive filename // // Return: ERROR_SUCCESS if successful // Error number if an error occurs // // Comments: // // History: Date Author Comment // 6/22/95 ericflo Created // //************************************************************* LONG MyRegLoadKey(HKEY hKey, LPTSTR lpSubKey, LPTSTR lpFile) { NTSTATUS Status = STATUS_SUCCESS; BOOLEAN WasEnabled; int error; TCHAR szErr[MAX_PATH]; BOOL bAdjustPriv = FALSE; HANDLE hToken = NULL; // // Check to see if we are impersonating. // if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken) || hToken == NULL) { bAdjustPriv = TRUE; } else { CloseHandle(hToken); } // // Enable the restore privilege // if(bAdjustPriv) { Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled); } if (NT_SUCCESS(Status)) { error = RegLoadKey(hKey, lpSubKey, lpFile); // // Restore the privilege to its previous state // if(bAdjustPriv) { Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled); if (!NT_SUCCESS(Status)) { DebugMsg((DM_WARNING, TEXT("MyRegLoadKey: Failed to restore RESTORE privilege to previous enabled state"))); } } // // Check if the hive was loaded // if (error != ERROR_SUCCESS) { ReportError(NULL, PI_NOUI, 2, EVENT_REGLOADKEYFAILED, GetErrString(error, szErr), lpFile); DebugMsg((DM_WARNING, TEXT("MyRegLoadKey: Failed to load subkey <%s>, error =%d"), lpSubKey, error)); } #if defined(_WIN64) else { // // Notify Wow64 service that it need to watch this hive if it care to do so // if ( hKey == HKEY_USERS ) Wow64RegNotifyLoadHiveUserSid ( lpSubKey ); } #endif } else { error = Status; DebugMsg((DM_WARNING, TEXT("MyRegLoadKey: Failed to enable restore privilege to load registry key, err = %08x"), error)); } DebugMsg((DM_VERBOSE, TEXT("MyRegLoadKey: Returning %08x"), error)); return error; } //************************************************************* // // MyRegUnLoadKey() // // Purpose: Unloads a registry key // // Parameters: hKey - Registry handle // lpSubKey - Subkey to be unloaded // // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/19/95 ericflo Ported // //************************************************************* BOOL MyRegUnLoadKey(HKEY hKey, LPTSTR lpSubKey) { BOOL bResult = TRUE; LONG error; LONG eTmp; NTSTATUS Status = STATUS_SUCCESS; BOOLEAN WasEnabled; HKEY hSubKey; HANDLE hToken = NULL; BOOL bAdjustPriv = FALSE; #if defined(_WIN64) // // Notify wow64 service to release any resources // if ( hKey == HKEY_USERS ) Wow64RegNotifyUnloadHiveUserSid ( lpSubKey ); #endif // // Check to see if we are impersonating. // if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken) || hToken == NULL) { bAdjustPriv = TRUE; } else { CloseHandle(hToken); } // // Enable the restore privilege // if (bAdjustPriv) { Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled); } if (NT_SUCCESS(Status)) { error = RegUnLoadKey(hKey, lpSubKey); // // If the key didn't unload, check to see if it exists. // If the key doesn't exist, then it was probably cleaned up by // WatchHiveRefCount, but it certainly isn't loaded, so this // function should succeed. // if (error != ERROR_SUCCESS) { eTmp = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &hSubKey); if (eTmp == ERROR_FILE_NOT_FOUND) { error = ERROR_SUCCESS; } else if (eTmp == ERROR_SUCCESS) { RegCloseKey( hSubKey ); } } if ( error != ERROR_SUCCESS) { // // RegUnlodKey returns ERROR_WRITE_PROTECT if hive is already scheduled for unloading // if (error == ERROR_WRITE_PROTECT) { DebugMsg((DM_VERBOSE, TEXT("MyRegUnloadKey: user hive is already scheduled for unloading"))); } else { DebugMsg((DM_WARNING, TEXT("MyRegUnLoadKey: Failed to unmount hive %08x"), error)); } bResult = FALSE; } // // Restore the privilege to its previous state // if (bAdjustPriv) { Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled); if (!NT_SUCCESS(Status)) { DebugMsg((DM_WARNING, TEXT("MyRegUnLoadKey: Failed to restore RESTORE privilege to previous enabled state"))); } } } else { DebugMsg((DM_WARNING, TEXT("MyRegUnLoadKey: Failed to enable restore privilege to unload registry key"))); error = Status; bResult = FALSE; } DebugMsg((DM_VERBOSE, TEXT("MyRegUnLoadKey: Returning %d."), bResult)); SetLastError(error); return bResult; } //************************************************************* // // UpgradeLocalProfile() // // Purpose: Upgrades a local profile from a 3.x profile // to a profile directory structure. // // Parameters: lpProfile - Profile Information // lpOldProfile - Previous profile file // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 7/6/95 ericflo Created // //************************************************************* BOOL UpgradeLocalProfile (LPPROFILE lpProfile, LPTSTR lpOldProfile) { TCHAR szSrc[MAX_PATH]; TCHAR szDest[MAX_PATH]; LPTSTR lpSrcEnd, lpDestEnd; BOOL bRetVal = FALSE; DWORD dwSize, dwFlags; HANDLE hOldToken; DWORD dwErr; dwErr = GetLastError(); // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("UpgradeLocalProfile: Entering"))); // // Setup the temporary buffers // lstrcpy (szSrc, lpOldProfile); lstrcpy (szDest, lpProfile->lpLocalProfile); lpDestEnd = CheckSlash (szDest); lstrcpy (lpDestEnd, c_szNTUserDat); // // Copy the hive // if (!CopyFile(szSrc, szDest, FALSE)) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: CopyFile failed to copy hive with error = %d"), GetLastError())); return FALSE; } // // Delete the old hive // DeleteFile (szSrc); // // Copy log file // lstrcat (szSrc, c_szLog); lstrcat (szDest, c_szLog); if (!CopyFile(szSrc, szDest, FALSE)) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: CopyFile failed to copy hive log with error = %d"), GetLastError())); } // // Delete the old hive log // DeleteFile (szSrc); // // Copy in the new shell folders from the default // if ( !(lpProfile->dwInternalFlags & DEFAULT_NET_READY) ) { CheckNetDefaultProfile (lpProfile); } if (lpProfile->lpDefaultProfile && *lpProfile->lpDefaultProfile) { ExpandEnvironmentStrings(lpProfile->lpDefaultProfile, szSrc, MAX_PATH); if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to impersonate user"))); goto IssueLocalDefault; } dwFlags = (lpProfile->dwFlags & PI_NOUI) ? CPD_NOERRORUI : 0; dwFlags |= CPD_IGNOREHIVE | CPD_CREATETITLE; dwFlags |= CPD_IGNOREENCRYPTEDFILES | CPD_IGNORELONGFILENAMES; if (CopyProfileDirectoryEx (szSrc, lpProfile->lpLocalProfile, dwFlags, NULL, NULL)) { bRetVal = TRUE; } // // Go back to system security context // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to revert to self"))); } if ((!bRetVal) && (GetLastError() == ERROR_DISK_FULL)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to Copy default profile. Disk is FULL"))); goto Exit; } } IssueLocalDefault: if (!bRetVal) { dwSize = ARRAYSIZE(szSrc); if (!GetDefaultUserProfileDirectory(szSrc, &dwSize)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to get default user profile."))); goto Exit; } if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to impersonate user"))); goto Exit; } dwFlags = (lpProfile->dwFlags & PI_NOUI) ? CPD_NOERRORUI : 0; dwFlags |= CPD_IGNOREHIVE | CPD_CREATETITLE; dwFlags |= CPD_IGNOREENCRYPTEDFILES | CPD_IGNORELONGFILENAMES; bRetVal = CopyProfileDirectoryEx (szSrc, lpProfile->lpLocalProfile, dwFlags, NULL, NULL); // // Go back to system security context // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to revert to self"))); } } if (!bRetVal) dwErr = GetLastError(); Exit: SetLastError(dwErr); return bRetVal; } //************************************************************* // // UpgradeCentralProfile() // // Purpose: Upgrades a central profile from a 3.x profile // to a profile directory structure. // // Parameters: lpProfile - Profile Information // lpOldProfile - Previous profile file // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 7/6/95 ericflo Created // //************************************************************* BOOL UpgradeCentralProfile (LPPROFILE lpProfile, LPTSTR lpOldProfile) { TCHAR szSrc[MAX_PATH]; TCHAR szDest[MAX_PATH]; LPTSTR lpSrcEnd, lpDestEnd, lpDot; BOOL bRetVal = FALSE; BOOL bMandatory = FALSE; DWORD dwSize, dwFlags; HANDLE hOldToken; DWORD dwErr; dwErr = GetLastError(); // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: Entering"))); // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Failed to impersonate user"))); return FALSE; } // // Setup the source buffer // lstrcpy (szSrc, lpOldProfile); // // Determine the profile type // lpDot = szSrc + lstrlen(szSrc) - 4; if (*lpDot == TEXT('.')) { if (!lstrcmpi (lpDot, c_szMAN)) { bMandatory = TRUE; } } // // Setup the destination buffer // lstrcpy (szDest, lpProfile->lpRoamingProfile); lpDestEnd = CheckSlash (szDest); if (bMandatory) { lstrcpy (lpDestEnd, c_szNTUserMan); } else { lstrcpy (lpDestEnd, c_szNTUserDat); } // // Copy the hive // if (!CopyFile(szSrc, szDest, FALSE)) { DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: CopyFile failed to copy hive with error = %d"), GetLastError())); DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Source = <%s>"), szSrc)); DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Destination = <%s>"), szDest)); dwErr = GetLastError(); goto Exit; } // // Copy log file // lstrcpy (lpDot, c_szLog); lstrcat (szDest, c_szLog); if (!CopyFile(szSrc, szDest, FALSE)) { DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: CopyFile failed to copy hive log with error = %d"), GetLastError())); DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: Source = <%s>"), szSrc)); DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: Destination = <%s>"), szDest)); } // // Copy in the new shell folders from the default // if ( !(lpProfile->dwInternalFlags & DEFAULT_NET_READY) ) { CheckNetDefaultProfile (lpProfile); } if (lpProfile->lpDefaultProfile && *lpProfile->lpDefaultProfile) { ExpandEnvironmentStrings(lpProfile->lpDefaultProfile, szSrc, MAX_PATH); dwFlags = (lpProfile->dwFlags & PI_NOUI) ? CPD_NOERRORUI : 0; dwFlags |= CPD_IGNOREHIVE | CPD_CREATETITLE; dwFlags |= CPD_IGNOREENCRYPTEDFILES | CPD_IGNORELONGFILENAMES; if (CopyProfileDirectoryEx (szSrc, lpProfile->lpRoamingProfile, dwFlags, NULL, NULL)) { bRetVal = TRUE; } } if (!bRetVal) { dwSize = ARRAYSIZE(szSrc); if (!GetDefaultUserProfileDirectory(szSrc, &dwSize)) { DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Failed to get default user profile."))); dwErr = GetLastError(); goto Exit; } dwFlags = (lpProfile->dwFlags & PI_NOUI) ? CPD_NOERRORUI : 0; dwFlags |= CPD_IGNOREHIVE | CPD_CREATETITLE; dwFlags |= CPD_IGNOREENCRYPTEDFILES | CPD_IGNORELONGFILENAMES; bRetVal = CopyProfileDirectoryEx (szSrc, lpProfile->lpRoamingProfile, dwFlags, NULL, NULL); } if (!bRetVal) dwErr = GetLastError(); Exit: // // Go back to system security context // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Failed to revert to self"))); } return bRetVal; } //************************************************************* // // CreateSecureDirectory() // // Purpose: Creates a secure directory that only the user, // admin, and system have access to in the normal case // and for only the user and system in the restricted case. // // // Parameters: lpProfile - Profile Information // lpDirectory - Directory Name // pSid - Sid (used by CreateUserProfile) // fRestricted - Flag to set restricted access. // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 7/20/95 ericflo Created // 9/30/98 ushaji added fRestricted flag // 7/18/00 santanuc modified to avoid deadlock when Documents and Settings directory is encrypted // //************************************************************* BOOL CreateSecureDirectory (LPPROFILE lpProfile, LPTSTR lpDirectory, PSID pSid, BOOL fRestricted) { SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; PACL pAcl = NULL; PSID psidUser = NULL, psidSystem = NULL, psidAdmin = NULL; DWORD cbAcl, aceIndex; ACE_HEADER * lpAceHeader; BOOL bRetVal = FALSE; BOOL bFreeSid = TRUE; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Entering with <%s>"), lpDirectory)); if (!lpProfile && !pSid) { // // Attempt to create the directory // if (CreateNestedDirectoryEx(lpDirectory, NULL, FALSE)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Created the directory <%s>"), lpDirectory)); bRetVal = TRUE; } else { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to created the directory <%s>"), lpDirectory)); } goto Exit; } // // Get the SIDs we'll need for the DACL // if (pSid) { psidUser = pSid; bFreeSid = FALSE; } else { if((psidUser = GetUserSid(lpProfile->hTokenUser)) == NULL) { DebugMsg((DM_WARNING, TEXT("CreateSecureDirectory: GetUserSid returned NULL. error = %08x"), GetLastError())); goto Exit; } } // // Get the system sid // if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to initialize system sid. Error = %d"), GetLastError())); goto Exit; } // // Get the Admin sid only if Frestricted is off // if (!fRestricted) { if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Failed to initialize admin sid. Error = %d"), GetLastError())); goto Exit; } } // // Allocate space for the ACL // if (!fRestricted) { cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) + (2 * GetLengthSid (psidAdmin)) + sizeof(ACL) + (6 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))); } else { cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) + sizeof(ACL) + (4 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))); } pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl); if (!pAcl) { goto Exit; } if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to initialize acl. Error = %d"), GetLastError())); goto Exit; } // // Add Aces for User, System, and Admin. Non-inheritable ACEs first // aceIndex = 0; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidUser)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } aceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } if (!fRestricted) { aceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } } // // Now the inheritable ACEs // aceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidUser)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } if (!GetAce(pAcl, aceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); aceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } if (!GetAce(pAcl, aceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); if (!fRestricted) { aceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } } if (!GetAce(pAcl, aceIndex, (LPVOID*)&lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to get ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } lpAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE); // // Put together the security descriptor // if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to initialize security descriptor. Error = %d"), GetLastError())); goto Exit; } if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to set security descriptor dacl. Error = %d"), GetLastError())); goto Exit; } // // Add the security descriptor to the sa structure // sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE; // // Attempt to create the directory // if (CreateNestedDirectoryEx(lpDirectory, &sa, FALSE)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Created the directory <%s>"), lpDirectory)); bRetVal = TRUE; } else { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to created the directory <%s>"), lpDirectory)); } Exit: if (bFreeSid && psidUser) { DeleteUserSid (psidUser); } if (psidSystem) { FreeSid(psidSystem); } if (psidAdmin) { FreeSid(psidAdmin); } if (pAcl) { GlobalFree (pAcl); } return bRetVal; } //************************************************************* // // GetUserDomainName() // // Purpose: Gets the current user's domain name // // Parameters: lpProfile - Profile Information // lpDomainName - Receives the user's domain name // lpDomainNameSize - Size of the lpDomainName buffer (truncates the name to this size) // // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL GetUserDomainName (LPPROFILE lpProfile, LPTSTR lpDomainName, LPDWORD lpDomainNameSize) { BOOL bResult = FALSE; LPTSTR lpTemp, lpDomain = NULL; HANDLE hOldToken; DWORD dwErr; TCHAR szErr[MAX_PATH]; dwErr = GetLastError(); // // if no lpProfile is passed e.g. in setup.c and so just ignore. // lpDomainName[0] = TEXT('\0'); if (!lpProfile) { DebugMsg((DM_WARNING, TEXT("GetUserDomainName: lpProfile structure is NULL, returning"))); return FALSE; } // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("GetUserDomainName: Failed to impersonate user"))); dwErr = GetLastError(); goto Exit; } // // Get the username in NT4 format // lpDomain = MyGetUserNameEx (NameSamCompatible); RevertToUser(&hOldToken); if (!lpDomain) { DebugMsg((DM_WARNING, TEXT("GetUserDomainName: MyGetUserNameEx failed for NT4 style name with %d"), GetLastError())); dwErr = GetLastError(); ReportError (NULL, PI_NOUI, 1, EVENT_FAILED_USERNAME, GetErrString(dwErr, szErr)); goto Exit; } // // Look for the \ between the domain and username and replace // it with a NULL // lpTemp = lpDomain; while (*lpTemp && ((*lpTemp) != TEXT('\\'))) lpTemp++; if (*lpTemp != TEXT('\\')) { DebugMsg((DM_WARNING, TEXT("GetUserDomainName: Failed to find slash in NT4 style name: <%s>"), lpDomain)); dwErr = ERROR_INVALID_DATA; goto Exit; } *lpTemp = TEXT('\0'); lstrcpyn (lpDomainName, lpDomain, (*lpDomainNameSize)-1); // // Success // DebugMsg((DM_VERBOSE, TEXT("GetUserDomainName: DomainName = <%s>"), lpDomainName)); bResult = TRUE; Exit: if (lpDomain) { LocalFree (lpDomain); } SetLastError(dwErr); return bResult; } //************************************************************* // // ComputeLocalProfileName() // // Purpose: Constructs the pathname of the local profile // for this user. It will attempt to create // a directory of the username, and then if // unsccessful it will try the username.xxx // where xxx is a three digit number // // Parameters: lpProfile - Profile Information // lpUserName - UserName // lpProfileImage - Profile directory (unexpanded) // cchMaxProfileImage - lpProfileImage buffer size // lpExpProfileImage - Expanded directory // cchMaxExpProfileImage - lpExpProfileImage buffer size // pSid - User's sid // bWin9xUpg - Flag to say whether it is win9x upgrade // // Return: TRUE if successful // FALSE if an error occurs // // Comments: lpProfileImage should be initialized with the // root profile path and the trailing backslash. // if it is a win9x upgrade give back the user's dir and don't do // conflict resolution. // // History: Date Author Comment // 6/20/95 ericflo Created // //************************************************************* BOOL ComputeLocalProfileName (LPPROFILE lpProfile, LPCTSTR lpUserName, LPTSTR lpProfileImage, DWORD cchMaxProfileImage, LPTSTR lpExpProfileImage, DWORD cchMaxExpProfileImage, PSID pSid, BOOL bWin9xUpg) { int i = 0; TCHAR szNumber[5], lpUserDomain[50], szDomainName[50+3]; LPTSTR lpEnd; BOOL bRetVal = FALSE; BOOL bResult; HANDLE hFile; WIN32_FIND_DATA fd; DWORD dwDomainNamelen; DWORD dwErr; // // Check buffer size // dwDomainNamelen = ARRAYSIZE(lpUserDomain); if ((DWORD)(lstrlen(lpProfileImage) + lstrlen(lpUserName) + dwDomainNamelen + 2 + 5 + 1) > cchMaxProfileImage) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: buffer too small"))); SetLastError(ERROR_BUFFER_OVERFLOW); return FALSE; } // // Place the username onto the end of the profile image // lpEnd = CheckSlash (lpProfileImage); lstrcpy (lpEnd, lpUserName); // // Expand the profile path // ExpandEnvironmentStrings(lpProfileImage, lpExpProfileImage, cchMaxExpProfileImage); // // Does this directory exist? // hFile = FindFirstFile (lpExpProfileImage, &fd); if (hFile == INVALID_HANDLE_VALUE) { // // Attempt to create the directory, if it returns an error bail // CreateSecureDirectory does not return an error for already_exists // so this should be ok. // bResult = CreateSecureDirectory(lpProfile, lpExpProfileImage, pSid, FALSE); if (bResult) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: generated the profile directory <%s>"), lpExpProfileImage)); bRetVal = TRUE; } else { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: trying to create dir <%s> returned %d"), lpExpProfileImage, GetLastError())); bRetVal = FALSE; } goto Exit; } else { FindClose (hFile); if (bWin9xUpg) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: generated the profile directory <%s> in win9xupg case"), lpExpProfileImage)); bRetVal = TRUE; goto Exit; } } // // get the User Domain Name // if (!GetUserDomainName(lpProfile, lpUserDomain, &dwDomainNamelen)) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: Couldn't get the User Domain"))); *lpUserDomain = TEXT('\0'); } lpEnd = lpProfileImage + lstrlen(lpProfileImage); // // Place the " (DomainName)" onto the end of the username // if ((*lpUserDomain) != TEXT('\0')) { TCHAR szFormat[30]; LoadString (g_hDllInstance, IDS_PROFILEDOMAINNAME_FORMAT, szFormat, ARRAYSIZE(szFormat)); wsprintf(szDomainName, szFormat, lpUserDomain); lstrcpy(lpEnd, szDomainName); // // Expand the profile path // ExpandEnvironmentStrings(lpProfileImage, lpExpProfileImage, cchMaxExpProfileImage); // // Does this directory exist? // hFile = FindFirstFile (lpExpProfileImage, &fd); if (hFile == INVALID_HANDLE_VALUE) { // // Attempt to create the directory // bResult = CreateSecureDirectory(lpProfile, lpExpProfileImage, pSid, FALSE); if (bResult) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: generated the profile directory <%s>"), lpExpProfileImage)); bRetVal = TRUE; } else { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: trying to create dir <%s> returned %d"), lpExpProfileImage, GetLastError())); bRetVal = FALSE; } goto Exit; } else { FindClose (hFile); } } // // Failed to create the directory for some reason. // Now try username (DomanName).000, username (DomanName).001, etc // lpEnd = lpProfileImage + lstrlen(lpProfileImage); for (i=0; i < 1000; i++) { // // Convert the number to a string and attach it. // wsprintf (szNumber, TEXT(".%.3d"), i); lstrcpy (lpEnd, szNumber); // // Expand the profile path // ExpandEnvironmentStrings(lpProfileImage, lpExpProfileImage, cchMaxExpProfileImage); // // Does this directory exist? // hFile = FindFirstFile (lpExpProfileImage, &fd); if (hFile == INVALID_HANDLE_VALUE) { // // Attempt to create the directory // bResult = CreateSecureDirectory(lpProfile, lpExpProfileImage, pSid, FALSE); if (bResult) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: generated the profile directory <%s>"), lpExpProfileImage)); bRetVal = TRUE; } else { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: trying to create dir <%s> returned %d"), lpExpProfileImage, GetLastError())); bRetVal = FALSE; } goto Exit; } else { FindClose (hFile); } } DebugMsg((DM_WARNING, TEXT("ComputeLocalProfileName: Could not generate a profile directory. Error = %d"), GetLastError())); Exit: if (bRetVal && lpProfile && (lpProfile->dwFlags & PI_HIDEPROFILE)) { SetFileAttributes(lpExpProfileImage, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | GetFileAttributes(lpExpProfileImage)); } return bRetVal; } //************************************************************* // // SetMachineProfileKeySecurity // // Purpose: Sets the security on the profile key under HKLM/ProfileList // // Parameters: lpProfile - Profile information // lpKeyName - Name of the registry key // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 2/22/99 ushaji adapted // 2/3/00 weiruc fixed function comment // fixed bug 441598 // //************************************************************* BOOL SetMachineProfileKeySecurity (LPPROFILE lpProfile, LPTSTR lpKeyName) { SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; PACL pAcl = NULL; PSID psidSystem = NULL, psidAdmin = NULL, psidUsers = NULL; PSID psidThisUser = NULL; DWORD cbAcl, aceIndex; ACE_HEADER * lpAceHeader; BOOL bRetVal = FALSE; HKEY hKeyProfile=NULL; DWORD Error, dwDisp; // // Get the system sid // if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to initialize system sid. Error = %d"), GetLastError())); goto Exit; } // // Get the Admin sid // if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to initialize admin sid. Error = %d"), GetLastError())); goto Exit; } // // Get the users sid // if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &psidUsers)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to initialize authenticated users sid. Error = %d"), GetLastError())); goto Exit; } // // Get this users sid // if((psidThisUser = GetUserSid(lpProfile->hTokenUser)) == NULL) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to get the user's sid. Error = %d"), GetLastError())); goto Exit; } // // Allocate space for the ACL. (No Inheritable Aces) // cbAcl = (GetLengthSid (psidSystem)) + (GetLengthSid (psidAdmin)) + (GetLengthSid (psidUsers)) + (GetLengthSid (psidThisUser)) + sizeof(ACL) + (4 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))); pAcl = (PACL) GlobalAlloc(GMEM_FIXED, cbAcl); if (!pAcl) { goto Exit; } if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to initialize acl. Error = %d"), GetLastError())); goto Exit; } // // Add Aces. Non-inheritable ACEs first // aceIndex = 0; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidSystem)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } aceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS, psidAdmin)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } aceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_READ, psidUsers)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } aceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, KEY_ALL_ACCESS ^ (WRITE_DAC | WRITE_OWNER), psidThisUser)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } // // Put together the security descriptor // if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to initialize security descriptor. Error = %d"), GetLastError())); goto Exit; } if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Failed to set security descriptor dacl. Error = %d"), GetLastError())); goto Exit; } Error = RegCreateKeyEx(HKEY_LOCAL_MACHINE, lpKeyName, 0, NULL, REG_OPTION_NON_VOLATILE, WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL, NULL, &hKeyProfile, &dwDisp); if (Error != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Couldn't open registry key to set security. Error = %d"), Error)); SetLastError(Error); goto Exit; } // // Set the security // Error = RegSetKeySecurity(hKeyProfile, DACL_SECURITY_INFORMATION, &sd); if (Error != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SetMachineProfileKeySecurity: Couldn't set security. Error = %d"), Error)); SetLastError(Error); goto Exit; } else { bRetVal = TRUE; } Exit: if (psidSystem) { FreeSid(psidSystem); } if (psidAdmin) { FreeSid(psidAdmin); } if (psidUsers) { FreeSid(psidUsers); } if (psidThisUser) { FreeSid(psidThisUser); } if (pAcl) { GlobalFree (pAcl); } if (hKeyProfile) { RegCloseKey(hKeyProfile); } return bRetVal; } //************************************************************* // // CreateLocalProfileKey() // // Purpose: Creates a registry key pointing at the user profile // // Parameters: lpProfile - Profile information // phKey - Handle to registry key if successful // bKeyExists - TRUE if the registry key already existed // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/20/95 ericflo Ported // //************************************************************* BOOL CreateLocalProfileKey (LPPROFILE lpProfile, PHKEY phKey, BOOL *bKeyExists) { TCHAR LocalProfileKey[MAX_PATH]; DWORD Disposition; DWORD RegErr = ERROR_SUCCESS + 1; BOOL Result; LPTSTR SidString; DWORD dwErr; dwErr = GetLastError(); SidString = GetSidString(lpProfile->hTokenUser); if (SidString != NULL) { // // Call the RegCreateKey api in the user's context // lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); lstrcat(LocalProfileKey, TEXT("\\")); lstrcat(LocalProfileKey, SidString); RegErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, 0, 0, KEY_READ | KEY_WRITE, NULL, phKey, &Disposition); if (RegErr == ERROR_SUCCESS) { *bKeyExists = (BOOL)(Disposition & REG_OPENED_EXISTING_KEY); // // If the key didn't exist before and profile is not mandatory, set the security on it. // if ((!(*bKeyExists)) && (!(lpProfile->dwInternalFlags & PROFILE_MANDATORY))) { if (!SetMachineProfileKeySecurity(lpProfile, LocalProfileKey)) { DebugMsg((DM_WARNING, TEXT("CreateLocalProfileKey: SetMachineProfileKeySecurity Failed. Error = %d"), GetLastError())); } } else { DebugMsg((DM_VERBOSE, TEXT("CreateLocalProfileKey: Not setting additional Security"))); } } else { DebugMsg((DM_WARNING, TEXT("CreateLocalProfileKey: Failed trying to create the local profile key <%s>, error = %d."), LocalProfileKey, RegErr)); dwErr = RegErr; } DeleteSidString(SidString); } SetLastError(dwErr); return(RegErr == ERROR_SUCCESS); } //************************************************************* // // GetExistingLocalProfileImage() // // Purpose: opens the profileimagepath // // Parameters: lpProfile - Profile information // // Return: TRUE if the profile image is reachable // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/20/95 ericflo Ported // 9/26/98 ushaji Modified // //************************************************************* BOOL GetExistingLocalProfileImage(LPPROFILE lpProfile) { HKEY hKey = NULL; BOOL bKeyExists; LPTSTR lpProfileImage = NULL; LPTSTR lpExpProfileImage = NULL; LPTSTR lpOldProfileImage = NULL; LPTSTR lpExpandedPath, lpEnd; DWORD cbExpProfileImage = sizeof(TCHAR)*MAX_PATH; HANDLE hFile; WIN32_FIND_DATA fd; DWORD cb; DWORD err; DWORD dwType; DWORD dwSize; LONG lResult; DWORD dwInternalFlags = 0; BOOL bRetVal = FALSE; LPTSTR SidString; HANDLE hOldToken; lpProfile->lpLocalProfile[0] = TEXT('\0'); if (!PatchNewProfileIfRequired(lpProfile->hTokenUser)) { DebugMsg((DM_WARNING, TEXT("GetExistingLocalProfileImage: Patch Profile Image failed"))); return FALSE; } if (!CreateLocalProfileKey(lpProfile, &hKey, &bKeyExists)) { return FALSE; // not reachable and cannot keep a local copy } // // Allocate memory for Local variables to avoid stack overflow // lpProfileImage = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!lpProfileImage) { DebugMsg((DM_WARNING, TEXT("GetExistingLocalProfileImage: Out of memory"))); goto Exit; } lpExpProfileImage = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!lpExpProfileImage) { DebugMsg((DM_WARNING, TEXT("GetExistingLocalProfileImage: Out of memory"))); goto Exit; } lpOldProfileImage = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!lpOldProfileImage) { DebugMsg((DM_WARNING, TEXT("GetExistingLocalProfileImage: Out of memory"))); goto Exit; } if (bKeyExists) { // // Check if the local profile image is valid. // DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Found entry in profile list for existing local profile"))); err = RegQueryValueEx(hKey, PROFILE_IMAGE_VALUE_NAME, 0, &dwType, (LPBYTE)lpExpProfileImage, &cbExpProfileImage); if (err == ERROR_SUCCESS && cbExpProfileImage) { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Local profile image filename = <%s>"), lpExpProfileImage)); if (dwType == REG_EXPAND_SZ) { // // Expand the profile image filename // cb = sizeof(TCHAR)*MAX_PATH; lpExpandedPath = (LPTSTR)LocalAlloc(LPTR, cb); if (lpExpandedPath) { ExpandEnvironmentStrings(lpExpProfileImage, lpExpandedPath, cb); lstrcpy(lpExpProfileImage, lpExpandedPath); LocalFree(lpExpandedPath); } DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Expanded local profile image filename = <%s>"), lpExpProfileImage)); } // // Query for the internal flags // dwSize = sizeof(DWORD); err = RegQueryValueEx (hKey, PROFILE_STATE, NULL, &dwType, (LPBYTE) &dwInternalFlags, &dwSize); if (err != ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Failed to query internal flags with error %d"), err)); } // // if we do not have a fully loaded profile, mark it as new // if it was not called with Liteload // if (dwInternalFlags & PROFILE_PARTLY_LOADED) { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: We do not have a fully loaded profile on this machine"))); // // retain the partially loaded flag and remove it at the end of // restoreuserprofile.. // lpProfile->dwInternalFlags |= PROFILE_PARTLY_LOADED; if (!(lpProfile->dwFlags & PI_LITELOAD)) { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Treating this profile as new"))); lpProfile->dwInternalFlags |= PROFILE_NEW_LOCAL; } } // // if due to leak we are getting the old TEMP profile then preserve // the internal flag. This will allow to revert back to .bak profile // correctly when the leak is fixed. // if (dwInternalFlags & PROFILE_TEMP_ASSIGNED) { lpProfile->dwInternalFlags |= dwInternalFlags; } // // Call FindFirst to see if we need to migrate this profile // hFile = FindFirstFile (lpExpProfileImage, &fd); if (hFile == INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Local profile image filename we got from our profile list doesn't exit. Error = %d"), GetLastError())); bRetVal = FALSE; goto Exit; } FindClose(hFile); // // If this is a file, then we need to migrate it to // the new directory structure. (from a 3.5 machine) // if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { lstrcpy (lpOldProfileImage, lpExpProfileImage); if (CreateLocalProfileImage(lpProfile, lpProfile->lpUserName)) { if (UpgradeLocalProfile (lpProfile, lpOldProfileImage)) bRetVal = TRUE; else { DebugMsg((DM_WARNING, TEXT("GetExistingLocalProfileImage: Failed to upgrade 3.5 profiles"))); bRetVal = FALSE; } } else { DebugMsg((DM_WARNING, TEXT("GetExistingLocalProfileImage: Failed to create a new profile to upgrade"))); bRetVal = FALSE; } goto Exit; } // // Test if a mandatory profile exists // lpEnd = CheckSlash (lpExpProfileImage); lstrcpy (lpEnd, c_szNTUserMan); // // Impersonate the user, before trying to access ntuser, ntuser.man // fail, if we can not access.. // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("GetExistingLocalProfileImage: Failed to impersonate user"))); bRetVal = FALSE; goto Exit; } if (GetFileAttributes(lpExpProfileImage) != -1) { // // This is just to tag that the local profile is a mandatory profile // lpProfile->dwInternalFlags |= PROFILE_LOCALMANDATORY; DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Found local mandatory profile image file ok <%s>"), lpExpProfileImage)); *(lpEnd - 1) = TEXT('\0'); lstrcpy(lpProfile->lpLocalProfile, lpExpProfileImage); // // Since this profile was mandatory, treat it as if it has never // synced with the server. // lpProfile->ftProfileUnload.dwLowDateTime = 0; lpProfile->ftProfileUnload.dwHighDateTime = 0; RevertToUser(&hOldToken); bRetVal = TRUE; // local copy is valid and reachable goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: No local mandatory profile. Error = %d"), GetLastError())); } // // Test if a normal profile exists // lstrcpy (lpEnd, c_szNTUserDat); if (GetFileAttributes(lpExpProfileImage) != -1) { RevertToUser(&hOldToken); DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Found local profile image file ok <%s>"), lpExpProfileImage)); *(lpEnd - 1) = TEXT('\0'); lstrcpy(lpProfile->lpLocalProfile, lpExpProfileImage); // // Read the time this profile was unloaded // dwSize = sizeof(lpProfile->ftProfileUnload.dwLowDateTime); lResult = RegQueryValueEx (hKey, PROFILE_UNLOAD_TIME_LOW, NULL, &dwType, (LPBYTE) &lpProfile->ftProfileUnload.dwLowDateTime, &dwSize); if (lResult == ERROR_SUCCESS) { dwSize = sizeof(lpProfile->ftProfileUnload.dwHighDateTime); lResult = RegQueryValueEx (hKey, PROFILE_UNLOAD_TIME_HIGH, NULL, &dwType, (LPBYTE) &lpProfile->ftProfileUnload.dwHighDateTime, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Failed to query high profile unload time with error %d"), lResult)); lpProfile->ftProfileUnload.dwLowDateTime = 0; lpProfile->ftProfileUnload.dwHighDateTime = 0; } } else { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Failed to query low profile unload time with error %d"), lResult)); lpProfile->ftProfileUnload.dwLowDateTime = 0; lpProfile->ftProfileUnload.dwHighDateTime = 0; } bRetVal = TRUE; // local copy is valid and reachable goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Local profile image filename we got from our profile list doesn't exit. <%s> Error = %d"), lpExpProfileImage, GetLastError())); } // // Revert to User before continuing // RevertToUser(&hOldToken); } } Exit: if (lpProfileImage) { LocalFree(lpProfileImage); } if (lpExpProfileImage) { LocalFree(lpExpProfileImage); } if (lpOldProfileImage) { LocalFree(lpOldProfileImage); } if (hKey) { err = RegCloseKey(hKey); if (err != STATUS_SUCCESS) { DebugMsg((DM_WARNING, TEXT("GetExistingLocalProfileImage: Failed to close registry key, error = %d"), err)); } } return bRetVal; } //************************************************************* // // CreateLocalProfileImage() // // Purpose: creates the profileimagepath // // Parameters: lpProfile - Profile information // lpBaseName - Base Name from which profile dir name // will be generated. // // Return: TRUE if the profile image is creatable // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/20/95 ericflo Ported // 9/26/98 ushaji Modified // //************************************************************* BOOL CreateLocalProfileImage(LPPROFILE lpProfile, LPTSTR lpBaseName) { HKEY hKey; BOOL bKeyExists; TCHAR lpProfileImage[MAX_PATH]; TCHAR lpExpProfileImage[MAX_PATH]; DWORD cbExpProfileImage = sizeof(TCHAR)*MAX_PATH; DWORD err; DWORD dwSize; PSID UserSid; BOOL bRetVal = FALSE; lpProfile->lpLocalProfile[0] = TEXT('\0'); if (!CreateLocalProfileKey(lpProfile, &hKey, &bKeyExists)) { return FALSE; // not reachable and cannot keep a local copy } // // No local copy found, try to create a new one. // DebugMsg((DM_VERBOSE, TEXT("CreateLocalProfileImage: One way or another we haven't got an existing local profile, try and create one"))); dwSize = ARRAYSIZE(lpProfileImage); if (!GetProfilesDirectoryEx(lpProfileImage, &dwSize, FALSE)) { DebugMsg((DM_WARNING, TEXT("CreateLocalProfileImage: Failed to get profile root directory."))); goto Exit; } if (ComputeLocalProfileName(lpProfile, lpBaseName, lpProfileImage, MAX_PATH, lpExpProfileImage, MAX_PATH, NULL, FALSE)) { // // Add this image file to our profile list for this user // err = RegSetValueEx(hKey, PROFILE_IMAGE_VALUE_NAME, 0, REG_EXPAND_SZ, (LPBYTE)lpProfileImage, sizeof(TCHAR)*(lstrlen(lpProfileImage) + 1)); if (err == ERROR_SUCCESS) { lstrcpy(lpProfile->lpLocalProfile, lpExpProfileImage); // // Get the sid of the logged on user // UserSid = GetUserSid(lpProfile->hTokenUser); if (UserSid != NULL) { // // Store the user sid under the Sid key of the local profile // err = RegSetValueEx(hKey, TEXT("Sid"), 0, REG_BINARY, (BYTE*)UserSid, RtlLengthSid(UserSid)); if (err != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CreateLocalProfileImage: Failed to set 'sid' value of user in profile list, error = %d"), err)); SetLastError(err); } // // We're finished with the user sid // DeleteUserSid(UserSid); bRetVal = TRUE; } else { DebugMsg((DM_WARNING, TEXT("CreateLocalProfileImage: Failed to get sid of logged on user, so unable to update profile list"))); SetLastError(err); } } else { DebugMsg((DM_WARNING, TEXT("CreateLocalProfileImage: Failed to update profile list for user with local profile image filename, error = %d"), err)); SetLastError(err); } } Exit: err = RegCloseKey(hKey); if (err != STATUS_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CreateLocalProfileImage: Failed to close registry key, error = %d"), err)); SetLastError(err); } return bRetVal; } //************************************************************* // // IssueDefaultProfile() // // Purpose: Issues the specified default profile to a user // // Parameters: lpProfile - Profile Information // lpDefaultProfile - Default profile location // lpLocalProfile - Local profile location // lpSidString - User's sid // bMandatory - Issue mandatory profile // // Return: TRUE if profile was successfully setup // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/22/95 ericflo Created // //************************************************************* BOOL IssueDefaultProfile (LPPROFILE lpProfile, LPTSTR lpDefaultProfile, LPTSTR lpLocalProfile, LPTSTR lpSidString, BOOL bMandatory) { LPTSTR lpEnd, lpTemp; TCHAR szProfile[MAX_PATH]; TCHAR szTempProfile[MAX_PATH]; BOOL bProfileLoaded = FALSE; WIN32_FIND_DATA fd; HANDLE hFile; LONG error; DWORD dwFlags; HANDLE hOldToken; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Entering. lpDefaultProfile = <%s> lpLocalProfile = <%s>"), lpDefaultProfile, lpLocalProfile)); // // First expand the default profile // if (!ExpandEnvironmentStrings(lpDefaultProfile, szProfile, MAX_PATH)) { DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: ExpandEnvironmentStrings Failed with error %d"), GetLastError())); return FALSE; } // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: Failed to impersonate user"))); return FALSE; } // // Does the default profile directory exist? // hFile = FindFirstFile (szProfile, &fd); if (hFile == INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Default profile <%s> does not exist."), szProfile)); RevertToUser(&hOldToken); return FALSE; } FindClose(hFile); // // Copy profile to user profile // dwFlags = CPD_CREATETITLE | CPD_IGNORESECURITY | CPD_IGNORELONGFILENAMES | CPD_IGNORECOPYERRORS; if (lpProfile->dwFlags & (PI_LITELOAD | PI_HIDEPROFILE)) { dwFlags |= CPD_SYSTEMFILES | CPD_SYSTEMDIRSONLY; } else dwFlags |= CPD_IGNOREENCRYPTEDFILES; // // Call it with force copy unless there might be a partial profile locally // if (!(lpProfile->dwInternalFlags & PROFILE_PARTLY_LOADED)) { dwFlags |= CPD_FORCECOPY; } if (!CopyProfileDirectoryEx (szProfile, lpLocalProfile, dwFlags, NULL, NULL)) { DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); RevertToUser(&hOldToken); return FALSE; } // // Rename the profile is a mandatory one was requested. // lstrcpy (szProfile, lpLocalProfile); lpEnd = CheckSlash (szProfile); if (bMandatory) { DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Mandatory profile was requested."))); lstrcpy (szTempProfile, szProfile); lstrcpy (lpEnd, c_szNTUserMan); hFile = FindFirstFile (szProfile, &fd); if (hFile != INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Mandatory profile already exists."))); FindClose(hFile); } else { DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Renaming ntuser.dat to ntuser.man"))); lpTemp = CheckSlash(szTempProfile); lstrcpy (lpTemp, c_szNTUserDat); if (!MoveFile(szTempProfile, szProfile)) { DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: MoveFile returned false. Error = %d"), GetLastError())); } } } else { lstrcpy (lpEnd, c_szNTUserDat); } // // Revert to being 'ourself' // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: Failed to revert to self"))); } // // Try to load the new profile // error = MyRegLoadKey(HKEY_USERS, lpSidString, szProfile); bProfileLoaded = (error == ERROR_SUCCESS); if (!bProfileLoaded) { DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: MyRegLoadKey failed with error %d"), error)); SetLastError(error); if (error == ERROR_BADDB) { ReportError(lpProfile->hTokenUser, lpProfile->dwFlags, 0, EVENT_FAILED_LOAD_1009); } return FALSE; } DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Leaving successfully"))); return TRUE; } //************************************************************* // // DeleteProfileEx () // // Purpose: Deletes the specified profile from the // registry and disk. // // Parameters: lpSidString - Registry subkey // lpProfileDir - Profile directory // bBackup - Backup profile before deleting // szComputerName - Computer name. This parameter will be NULL // for local computer. // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/23/95 ericflo Created // //************************************************************* BOOL DeleteProfileEx (LPCTSTR lpSidString, LPTSTR lpLocalProfile, DWORD dwDeleteFlags, HKEY hKeyLM, LPCTSTR szComputerName) { LONG lResult; TCHAR szTemp[MAX_PATH]; TCHAR szUserGuid[MAX_PATH], szBuffer[MAX_PATH]; TCHAR szRegBackup[MAX_PATH]; HKEY hKey; DWORD dwType, dwSize, dwErr; BOOL bRetVal=TRUE; LPTSTR lpEnd = NULL; BOOL bBackup; bBackup = dwDeleteFlags & DP_BACKUP; dwErr = GetLastError(); // // Cleanup the registry first. // delete the guid only if we don't have a bak to keep track of // if (lpSidString && *lpSidString) { // // If profile in use then do not delete it // if (IsProfileInUse(szComputerName, lpSidString)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Fail to delete profile with sid %s as it is still in use."), lpSidString)); dwErr = ERROR_INVALID_PARAMETER; bRetVal = FALSE; goto Exit; } if (!(dwDeleteFlags & DP_BACKUPEXISTS)) { lstrcpy(szTemp, PROFILE_LIST_PATH); lstrcat(szTemp, TEXT("\\")); lstrcat(szTemp, lpSidString); // // get the user guid // lResult = RegOpenKeyEx(hKeyLM, szTemp, 0, KEY_READ, &hKey); if (lResult == ERROR_SUCCESS) { // // Query for the user guid // dwSize = MAX_PATH * sizeof(TCHAR); lResult = RegQueryValueEx (hKey, PROFILE_GUID, NULL, &dwType, (LPBYTE) szUserGuid, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: Failed to query profile guid with error %d"), lResult)); } else { lstrcpy(szTemp, PROFILE_GUID_PATH); lstrcat(szTemp, TEXT("\\")); lstrcat(szTemp, szUserGuid); // // Delete the profile guid from the guid list // lResult = RegDeleteKey(hKeyLM, szTemp); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: failed to delete profile guid. Error = %d"), lResult)); } } RegCloseKey(hKey); } } lstrcpy(szTemp, PROFILE_LIST_PATH); lstrcat(szTemp, TEXT("\\")); lstrcat(szTemp, lpSidString); if (bBackup) { lstrcpy(szRegBackup, szTemp); lstrcat(szRegBackup, c_szBAK); lResult = RegRenameKey(hKeyLM, szTemp, szRegBackup); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: Unable to rename registry entry. Error = %d"), lResult)); dwErr = lResult; bRetVal = FALSE; } } else { lResult = RegDeleteKey(hKeyLM, szTemp); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: Unable to delete registry entry. Error = %d"), lResult)); dwErr = lResult; bRetVal = FALSE; } } } if (bBackup) { lResult = RegOpenKeyEx(hKeyLM, szRegBackup, 0, KEY_ALL_ACCESS, &hKey); if (lResult == ERROR_SUCCESS) { DWORD dwInternalFlags; dwSize = sizeof(DWORD); lResult = RegQueryValueEx (hKey, PROFILE_STATE, NULL, &dwType, (LPBYTE)&dwInternalFlags, &dwSize); if (lResult == ERROR_SUCCESS) { dwInternalFlags |= PROFILE_THIS_IS_BAK; lResult = RegSetValueEx (hKey, PROFILE_STATE, 0, REG_DWORD, (LPBYTE) &dwInternalFlags, sizeof(dwInternalFlags)); } else { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: Failed to query profile internalflags with error %d"), lResult)); } RegCloseKey(hKey); } } else { if (!Delnode (lpLocalProfile)) { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: Delnode failed. Error = %d"), GetLastError())); dwErr = GetLastError(); bRetVal = FALSE; } } if (dwDeleteFlags & DP_DELBACKUP) { goto Exit; // don't delete any more stuff because the user actually might be logged in. } // // Delete the Group Policy per user stuff.. // lstrcpy(szBuffer, GP_XXX_SID_PREFIX); lpEnd = CheckSlash(szBuffer); lstrcpy(lpEnd, lpSidString); if (!RegDelnode (hKeyLM, szBuffer)) { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: Failed to delete the group policy key %s"), szBuffer)); } lstrcpy(szBuffer, GP_EXTENSIONS_SID_PREFIX); lpEnd = CheckSlash(szBuffer); lstrcpy(lpEnd, lpSidString); if (!RegDelnode (hKeyLM, szBuffer)) { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: Failed to delete the group policy extensions key %s"), szBuffer)); } DeletePolicyState( lpSidString ); Exit: SetLastError(dwErr); return bRetVal; } //************************************************************* // // UpgradeProfile() // // Purpose: Called after a profile is successfully loaded. // Stamps build number into the profile, and if // appropriate upgrades the per-user settings // that NT setup wants done. // // Parameters: lpProfile - Profile Information // pEnv - Environment block // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 7/7/95 ericflo Created // //************************************************************* BOOL UpgradeProfile (LPPROFILE lpProfile, LPVOID pEnv) { HKEY hKey; DWORD dwDisp, dwType, dwSize, dwBuildNumber; LONG lResult; BOOL bUpgrade = FALSE; BOOL bDoUserdiff = TRUE; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Entering"))); // // Query for the build number // lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser, WINLOGON_KEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UpgradeProfile: Failed to open winlogon key. Error = %d"), lResult)); return FALSE; } dwSize = sizeof(dwBuildNumber); lResult = RegQueryValueEx (hKey, PROFILE_BUILD_NUMBER, NULL, &dwType, (LPBYTE)&dwBuildNumber, &dwSize); if (lResult == ERROR_SUCCESS) { // // Found the build number. If the profile build is greater, // we don't want to process the userdiff hive // if (dwBuildNumber >= g_dwBuildNumber) { DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Build numbers match"))); bDoUserdiff = FALSE; } } else { dwBuildNumber = 0; } if (bDoUserdiff) { // // Set the build number // lResult = RegSetValueEx (hKey, PROFILE_BUILD_NUMBER, 0, REG_DWORD, (LPBYTE) &g_dwBuildNumber, sizeof(g_dwBuildNumber)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UpgradeProfile: Failed to set build number. Error = %d"), lResult)); } } // // Close the registry key // RegCloseKey (hKey); if (bDoUserdiff) { // // Apply changes to user's hive that NT setup needs. // if (!ProcessUserDiff(lpProfile, dwBuildNumber, pEnv)) { DebugMsg((DM_WARNING, TEXT("UpgradeProfile: ProcessUserDiff failed"))); } } DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Leaving Successfully"))); return TRUE; } //************************************************************* // // SetProfileTime() // // Purpose: Sets the timestamp on the remote profile and // local profile to be the same regardless of the // file system type being used. // // Parameters: lpProfile - Profile Information // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 9/25/95 ericflo Ported // //************************************************************* BOOL SetProfileTime(LPPROFILE lpProfile) { HANDLE hFileCentral; HANDLE hFileLocal; FILETIME ft; TCHAR szProfile[MAX_PATH]; LPTSTR lpEnd; HANDLE hOldToken; // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to impersonate user"))); return FALSE; } // // Create the central filename // lstrcpy (szProfile, lpProfile->lpRoamingProfile); lpEnd = CheckSlash (szProfile); if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } hFileCentral = CreateFile(szProfile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFileCentral == INVALID_HANDLE_VALUE) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't open central profile <%s>, error = %d"), szProfile, GetLastError())); if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to revert to self"))); } return FALSE; } else { if (!GetFileTime(hFileCentral, NULL, NULL, &ft)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't get time of central profile, error = %d"), GetLastError())); } } // // Revert to being 'ourself' // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to revert to self"))); } // // Create the local filename // lstrcpy (szProfile, lpProfile->lpLocalProfile); lpEnd = CheckSlash (szProfile); if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } hFileLocal = CreateFile(szProfile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFileLocal == INVALID_HANDLE_VALUE) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't open local profile <%s>, error = %d"), szProfile, GetLastError())); } else { if (!SetFileTime(hFileLocal, NULL, NULL, &ft)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't set time on local profile, error = %d"), GetLastError())); } if (!GetFileTime(hFileLocal, NULL, NULL, &ft)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't get time on local profile, error = %d"), GetLastError())); } CloseHandle(hFileLocal); } // // Reset time of central profile in case of discrepencies in // times of different file systems. // // // Impersonate the user // if (!ImpersonateUser(lpProfile->hTokenUser, &hOldToken)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to impersonate user"))); CloseHandle(hFileCentral); return FALSE; } // // Set the time on the central profile // if (!SetFileTime(hFileCentral, NULL, NULL, &ft)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: couldn't set time on local profile, error = %d"), GetLastError())); } CloseHandle(hFileCentral); // // Revert to being 'ourself' // if (!RevertToUser(&hOldToken)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to revert to self"))); } return TRUE; } //************************************************************* // // IsCacheDeleted() // // Purpose: Determines if the locally cached copy of the // roaming profile should be deleted. // // Parameters: void // // Return: TRUE if local cache should be deleted // FALSE if not // // Comments: // // History: Date Author Comment // 6/28/96 ericflo Created // //************************************************************* BOOL IsCacheDeleted (void) { BOOL bRetVal = FALSE; DWORD dwSize, dwType; HKEY hKey; // // Open the winlogon registry key // if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { // // Check for the flag. // dwSize = sizeof(BOOL); RegQueryValueEx (hKey, DELETE_ROAMING_CACHE, NULL, &dwType, (LPBYTE) &bRetVal, &dwSize); RegCloseKey (hKey); } if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { // // Check for the flag. // dwSize = sizeof(BOOL); RegQueryValueEx (hKey, DELETE_ROAMING_CACHE, NULL, &dwType, (LPBYTE) &bRetVal, &dwSize); RegCloseKey (hKey); } return bRetVal; } //************************************************************* // // GetProfileType() // // Purpose: Finds out some characterstics of a loaded profile // // Parameters: dwFlags - Returns the various profile flags // // Return: TRUE if successful // FALSE if an error occurs // // Comments: should be called after impersonation. // // History: Date Author Comment // 11/10/98 ushaji Created // //************************************************************* BOOL WINAPI GetProfileType(DWORD *dwFlags) { LPTSTR SidString; DWORD error, dwErr; HKEY hSubKey; BOOL bRetVal = FALSE; LPPROFILE lpProfile = NULL; HANDLE hToken; if (!dwFlags) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } *dwFlags = 0; dwErr = GetLastError(); // // Get the token for the caller // if (!OpenThreadToken (GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken)) { if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { DebugMsg((DM_WARNING, TEXT("GetProfileType: Failed to get token with %d"), GetLastError())); return FALSE; } } // // Get the Sid string for the user // SidString = GetProfileSidString(hToken); if (!SidString) { DebugMsg((DM_WARNING, TEXT("GetProfileType: Failed to get sid string for user"))); dwErr = GetLastError(); goto Exit; } error = RegOpenKeyEx(HKEY_USERS, SidString, 0, KEY_READ, &hSubKey); if (error == ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("GetProfileType: Profile already loaded."))); RegCloseKey(hSubKey); } else { DebugMsg((DM_WARNING, TEXT("GetProfileType: Profile is not loaded."))); dwErr = error; goto Exit; } lpProfile = LoadProfileInfo(NULL, hToken, NULL); if (!lpProfile) { DebugMsg((DM_WARNING, TEXT("GetProfileType: Couldn't load Profile Information."))); dwErr = GetLastError(); *dwFlags = 0; goto Exit; } if (lpProfile->dwInternalFlags & PROFILE_GUEST_USER) *dwFlags |= PT_TEMPORARY; if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) *dwFlags |= PT_MANDATORY; // external API, retaining the mandatory flag if (lpProfile->dwInternalFlags & PROFILE_READONLY) *dwFlags |= PT_MANDATORY; if (((lpProfile->dwUserPreference != USERINFO_LOCAL)) && ((lpProfile->dwInternalFlags & PROFILE_UPDATE_CENTRAL) || (lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL))) { *dwFlags |= PT_ROAMING; if (IsCacheDeleted()) { DebugMsg((DM_VERBOSE, TEXT("GetProfileType: Profile is to be deleted"))); *dwFlags |= PT_TEMPORARY; } } if (lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED) *dwFlags |= PT_TEMPORARY; bRetVal = TRUE; Exit: if (SidString) DeleteSidString(SidString); SetLastError(dwErr); if (lpProfile) { if (lpProfile->lpLocalProfile) { LocalFree (lpProfile->lpLocalProfile); } if (lpProfile->lpRoamingProfile) { LocalFree (lpProfile->lpRoamingProfile); } LocalFree (lpProfile); } CloseHandle (hToken); if (bRetVal) { DebugMsg((DM_VERBOSE, TEXT("GetProfileType: ProfileFlags is %d"), *dwFlags)); } return bRetVal; } //************************************************************* // // DumpOpenRegistryHandle() // // Purpose: Dumps the existing reg handle into the debugger // // Parameters: lpKeyName - The key name to the key in the form of // \registry\user.... // // // Return: Nothing // // Comments: // // History: Date Author Comment //************************************************************* void DumpOpenRegistryHandle(LPTSTR lpkeyName) { UNICODE_STRING UnicodeKeyName; OBJECT_ATTRIBUTES keyAttributes; ULONG HandleCount = 0; BOOL bBreakOnUnloadFailure=FALSE; HKEY hKey; DWORD dwSize, dwType; // // Initialize unicode string for our in params // RtlInitUnicodeString(&UnicodeKeyName, lpkeyName); // // Initialize the Obja structure // InitializeObjectAttributes( &keyAttributes, &UnicodeKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL ); NtQueryOpenSubKeys(&keyAttributes, &HandleCount); DebugMsg((DM_WARNING, TEXT("DumpOpenRegistryHandle: %d user registry Handles leaked from %s"), HandleCount, lpkeyName)); // // for debugging sometimes it is necessary to break at the point of // failure // if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(bBreakOnUnloadFailure); RegQueryValueEx (hKey, TEXT("BreakOnHiveUnloadFailure"), NULL, &dwType, (LPBYTE) &bBreakOnUnloadFailure, &dwSize); RegCloseKey (hKey); } if (bBreakOnUnloadFailure) DebugBreak(); } //************************************************************* // // ExtractProfileFromBackup() // // Purpose: Extracts the profile from backup if required. // // Parameters: hToken - User Token // SidString - // dwBackupFlags - Backup Flags. // indicating that profile already exists. // Profile created from backup // 0 indicates no such profile exists // // // Return: (BOOL) TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 9/21/99 ushaji Created // //************************************************************* #define EX_ALREADY_EXISTS 1 #define EX_PROFILE_CREATED 2 BOOL ExtractProfileFromBackup(HANDLE hToken, LPTSTR SidString, DWORD *dwBackupFlags) { TCHAR LocalKey[MAX_PATH], *lpEnd, szLocalProfile; TCHAR LocalBackupKey[MAX_PATH]; HKEY hKey=NULL; DWORD dwType, dwSize; DWORD lResult; LPTSTR lpExpandedPath; DWORD cbExpProfileImage = sizeof(TCHAR)*MAX_PATH; TCHAR lpExpProfileImage[MAX_PATH]; BOOL bRetVal = TRUE; DWORD dwInternalFlags; DWORD cb; *dwBackupFlags = 0; lstrcpy(LocalKey, PROFILE_LIST_PATH); lpEnd = CheckSlash (LocalKey); lstrcpy(lpEnd, SidString); lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LocalKey, 0, KEY_ALL_ACCESS, &hKey); if (lResult == ERROR_SUCCESS) { dwSize = sizeof(DWORD); lResult = RegQueryValueEx (hKey, PROFILE_STATE, NULL, &dwType, (LPBYTE) &dwInternalFlags, &dwSize); if (lResult == ERROR_SUCCESS) { // // if there is a sid key, check whether this is a temp profile // if (dwInternalFlags & PROFILE_TEMP_ASSIGNED) { DWORD dwDeleteFlags = 0; if (dwInternalFlags & PROFILE_BACKUP_EXISTS) { dwDeleteFlags |= DP_BACKUPEXISTS; } // // We need the path to pass to DeleteProfile // lResult = RegQueryValueEx(hKey, PROFILE_IMAGE_VALUE_NAME, 0, &dwType, (LPBYTE)lpExpProfileImage, &cbExpProfileImage); if (lResult == ERROR_SUCCESS && cbExpProfileImage) { DebugMsg((DM_VERBOSE, TEXT("ExtractProfileFromBackup: Local profile image filename = <%s>"), lpExpProfileImage)); if (dwType == REG_EXPAND_SZ) { // // Expand the profile image filename // cb = sizeof(lpExpProfileImage); lpExpandedPath = (LPTSTR)LocalAlloc(LPTR, cb); if (lpExpandedPath) { ExpandEnvironmentStrings(lpExpProfileImage, lpExpandedPath, ARRAYSIZE(lpExpProfileImage)); lstrcpy(lpExpProfileImage, lpExpandedPath); LocalFree(lpExpandedPath); } DebugMsg((DM_VERBOSE, TEXT("ExtractProfileFromBackup: Expanded local profile image filename = <%s>"), lpExpProfileImage)); } if (!DeleteProfileEx (SidString, lpExpProfileImage, dwDeleteFlags, HKEY_LOCAL_MACHINE, NULL)) { DebugMsg((DM_WARNING, TEXT("ExtractProfileFromBackup: DeleteProfileDirectory returned false (2). Error = %d"), GetLastError())); lResult = GetLastError(); goto Exit; } else { if (!(dwInternalFlags & PROFILE_BACKUP_EXISTS)) { DebugMsg((DM_VERBOSE, TEXT("ExtractProfileFromBackup: Temprorary profile but there is no backup"))); bRetVal = TRUE; goto Exit; } } } else { DebugMsg((DM_VERBOSE, TEXT("ExtractProfileFromBackup: Couldn't get the local profile path"))); bRetVal = FALSE; goto Exit; } } else { *dwBackupFlags |= EX_ALREADY_EXISTS; DebugMsg((DM_VERBOSE, TEXT("ExtractProfileFromBackup: A profile already exists"))); goto Exit; } } else { DebugMsg((DM_VERBOSE, TEXT("GetExistingLocalProfileImage: Failed to query internal flags with error %d"), lResult)); bRetVal = FALSE; goto Exit; } RegCloseKey(hKey); hKey = NULL; } else { DebugMsg((DM_VERBOSE, TEXT("ExtractProfileFromBackup: Failed to open key %s with error %d"), LocalKey, lResult)); } // // Now try to get the profile from the backup // lstrcpy(LocalBackupKey, LocalKey); lstrcat(LocalBackupKey, c_szBAK); lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LocalBackupKey, 0, KEY_ALL_ACCESS, &hKey); if (lResult == ERROR_SUCCESS) { RegCloseKey(hKey); hKey = NULL; // // Check whether the key exists should already be done before this // lResult = RegRenameKey(HKEY_LOCAL_MACHINE, LocalBackupKey, LocalKey); if (lResult == ERROR_SUCCESS) { lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LocalKey, 0, KEY_ALL_ACCESS, &hKey); if (lResult == ERROR_SUCCESS) { DWORD dwInternalFlags; dwSize = sizeof(DWORD); lResult = RegQueryValueEx (hKey, PROFILE_STATE, NULL, &dwType, (LPBYTE)&dwInternalFlags, &dwSize); if (lResult == ERROR_SUCCESS) { dwInternalFlags &= ~PROFILE_THIS_IS_BAK; lResult = RegSetValueEx (hKey, PROFILE_STATE, 0, REG_DWORD, (LPBYTE) &dwInternalFlags, sizeof(dwInternalFlags)); } RegCloseKey(hKey); hKey = NULL; } else { DebugMsg((DM_WARNING, TEXT("DeleteProfileEx: Failed to open LocalKey with error %d"), lResult)); } bRetVal = TRUE; *dwBackupFlags |= EX_PROFILE_CREATED; DebugMsg((DM_VERBOSE, TEXT("ExtractProfileFromBackup: Profile created from Backup"))); goto Exit; } else { DebugMsg((DM_WARNING, TEXT("ExtractProfileFromBackup: Couldn't rename key %s -> %s. Error = %d"), LocalBackupKey, LocalKey, lResult)); bRetVal = FALSE; goto Exit; } } else { DebugMsg((DM_VERBOSE, TEXT("ExtractProfileFromBackup: Couldn't open backup profile key. Error = %d"), lResult)); } Exit: if (hKey) RegCloseKey(hKey); if (!bRetVal) SetLastError(lResult); return bRetVal; } //************************************************************* // // PatchNewProfileIfRequired() // // Purpose: if the old sid and the new sid are not the same, delete the old // from the profile list and update the guidlist // // Parameters: hToken - User Token // // Return: (BOOL) TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 11/16/98 ushaji Created // //************************************************************* BOOL PatchNewProfileIfRequired(HANDLE hToken) { TCHAR LocalOldProfileKey[MAX_PATH], LocalNewProfileKey[MAX_PATH], *lpEnd; HKEY hNewKey=NULL; BOOL bRetVal = FALSE; DWORD dwType, dwDisp, dwSize; LONG lResult; LPTSTR OldSidString=NULL, SidString=NULL; PSID UserSid; DWORD dwBackupFlags; HMODULE hMsiLib = NULL; PFNMSINOTIFYSIDCHANGE pfnMsiNotifySidChange; // // Get the current sid. // SidString = GetSidString(hToken); if (!SidString) { DebugMsg((DM_WARNING, TEXT("PatchNewProfileIfRequred: No SidString found"))); return FALSE; } if (ExtractProfileFromBackup(hToken, SidString, &dwBackupFlags)) { if ((dwBackupFlags & EX_ALREADY_EXISTS) || (dwBackupFlags & EX_PROFILE_CREATED)) { DebugMsg((DM_VERBOSE, TEXT("PatchNewProfileIfRequred: A profile already exists with the current sid, exitting"))); bRetVal = TRUE; goto Exit; } } else { // // Treat it as if no such profile exists // DebugMsg((DM_VERBOSE, TEXT("PatchNewProfileIfRequred: ExtractProfileFromBackup returned error %d"), GetLastError())); } // // Get the old sid. // OldSidString = GetOldSidString(hToken, PROFILE_GUID_PATH); if (!OldSidString) { DebugMsg((DM_VERBOSE, TEXT("PatchNewProfileIfRequred: No OldSidString found"))); bRetVal = TRUE; goto Exit; } // // if old sid and new sid are the same quit // if (lstrcmpi(OldSidString, SidString) == 0) { DebugMsg((DM_VERBOSE, TEXT("PatchNewProfileIfRequred: Old and the new sid are the same, exitting"))); bRetVal = TRUE; goto Exit; } if (ExtractProfileFromBackup(hToken, OldSidString, &dwBackupFlags)) { if ((dwBackupFlags & EX_ALREADY_EXISTS) || (dwBackupFlags & EX_PROFILE_CREATED)) { DebugMsg((DM_VERBOSE, TEXT("PatchNewProfileIfRequred: A profile with the old sid found"))); } } else { // // Treat it as if no such profile exists // DebugMsg((DM_VERBOSE, TEXT("PatchNewProfileIfRequred: ExtractProfileFromBackup returned error %d"), GetLastError())); } lstrcpy(LocalNewProfileKey, PROFILE_LIST_PATH); lpEnd = CheckSlash (LocalNewProfileKey); lstrcpy(lpEnd, SidString); lstrcpy(LocalOldProfileKey, PROFILE_LIST_PATH); lpEnd = CheckSlash (LocalOldProfileKey); lstrcpy(lpEnd, OldSidString); lResult = RegRenameKey(HKEY_LOCAL_MACHINE, LocalOldProfileKey, LocalNewProfileKey); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("PatchNewProfileIfRequred: Failed to rename profile mapping key with error %d"), lResult)); goto Exit; } lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, LocalNewProfileKey, 0, 0, 0, KEY_WRITE, NULL, &hNewKey, &dwDisp); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("PatchNewProfileIfRequred: Failed to open new profile mapping key with error %d"), lResult)); goto Exit; } // // Get the sid of the logged on user // UserSid = GetUserSid(hToken); if (UserSid != NULL) { // // Store the user sid under the Sid key of the local profile // lResult = RegSetValueEx(hNewKey, TEXT("Sid"), 0, REG_BINARY, (BYTE*)UserSid, RtlLengthSid(UserSid)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("PatchNewProfileIfRequred: Failed to set 'sid' value of user in profile list, error = %d"), lResult)); } // // We're finished with the user sid // DeleteUserSid(UserSid); } // // Set the guid->sid corresp. // if (!SetOldSidString(hToken, SidString, PROFILE_GUID_PATH)) { DebugMsg((DM_WARNING, TEXT("PatchNewProfileIfRequred: Couldn't set the old Sid in the GuidList"))); } // // Make a call to msi lib to notify sid change of user, so that it can update installation information // hMsiLib = LoadLibrary(TEXT("msi.dll")); if (hMsiLib) { pfnMsiNotifySidChange = (PFNMSINOTIFYSIDCHANGE) GetProcAddress(hMsiLib, #ifdef UNICODE "MsiNotifySidChangeW"); #else "MsiNotifySidChangeA"); #endif if (pfnMsiNotifySidChange) { (*pfnMsiNotifySidChange)(OldSidString, SidString); } else { DebugMsg((DM_WARNING, TEXT("PatchNewProfileIfRequred: GetProcAddress returned failure. error %d"), GetLastError())); } FreeLibrary(hMsiLib); } else { DebugMsg((DM_WARNING, TEXT("PatchNewProfileIfRequred: LoadLibrary returned failure. error %d"), GetLastError())); } bRetVal = TRUE; Exit: if (SidString) DeleteSidString(SidString); if (OldSidString) DeleteSidString(OldSidString); if (hNewKey) RegCloseKey(hNewKey); return bRetVal; } //************************************************************* // // IncrementProfileRefCount() // // Purpose: Increments Profile Ref Count // // Parameters: lpProfile - Profile Information // bInitilize - dwRef should be initialized // // Return: Ref Count // // Comments: This functions ref counts independent of ability // to load/unload the hive. // // Caveat: // We have changed the machanism here to use ref counting // and not depend on unloadability of ntuser.dat. NT4 // apps might have forgotten to unloaduserprofiles // and might still be working because the handle got // closed automatically when processes // exitted. This will be treated as an App Bug. // // // History: Date Author Comment // 1/12/99 ushaji Created // //************************************************************* DWORD IncrementProfileRefCount(LPPROFILE lpProfile, BOOL bInitialize) { LPTSTR SidString, lpEnd; TCHAR LocalProfileKey[MAX_PATH]; LONG lResult; HKEY hKey; DWORD dwType, dwSize, dwCount, dwDisp, dwRef=0; // // Get the Sid string for the user // SidString = GetSidString(lpProfile->hTokenUser); if (!SidString) { DebugMsg((DM_WARNING, TEXT("IncrementProfileRefCount: Failed to get sid string for user"))); return 0; } // // Open the profile mapping // lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); lpEnd = CheckSlash (LocalProfileKey); lstrcpy(lpEnd, SidString); lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, 0, 0, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisp); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("IncrementProfileRefCount: Failed to open profile mapping key with error %d"), lResult)); DeleteSidString(SidString); return 0; } // // Query for the profile ref count. // dwSize = sizeof(DWORD); if (!bInitialize) { lResult = RegQueryValueEx (hKey, PROFILE_REF_COUNT, 0, &dwType, (LPBYTE) &dwRef, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("IncrementProfileRefCount: Failed to query profile reference count with error %d"), lResult)); } } dwRef++; // // Set the profile Ref count // lResult = RegSetValueEx (hKey, PROFILE_REF_COUNT, 0, REG_DWORD, (LPBYTE) &dwRef, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("IncrementProfileRefCount: Failed to save profile reference count with error %d"), lResult)); } DeleteSidString(SidString); RegCloseKey (hKey); return dwRef; } //************************************************************* // // DecrementProfileRefCount() // // Purpose: Deccrements Profile Ref Count // // Parameters: lpProfile - Profile Information // // Return: Ref Count // // Comments: This functions ref counts independent of ability // to load/unload the hive. // // History: Date Author Comment // 1/12/99 ushaji Created // //************************************************************* DWORD DecrementProfileRefCount(LPPROFILE lpProfile) { LPTSTR SidString, lpEnd; TCHAR LocalProfileKey[MAX_PATH]; LONG lResult; HKEY hKey; DWORD dwType, dwSize, dwCount, dwDisp, dwRef=0; // // Get the Sid string for the user // SidString = GetSidString(lpProfile->hTokenUser); if (!SidString) { DebugMsg((DM_WARNING, TEXT("DecrementProfileRefCount: Failed to get sid string for user"))); return 0; } // // Open the profile mapping // lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); lpEnd = CheckSlash (LocalProfileKey); lstrcpy(lpEnd, SidString); lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, 0, 0, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisp); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DecrementProfileRefCount: Failed to open profile mapping key with error %d"), lResult)); DeleteSidString(SidString); return 0; } // // Query for the profile ref count. // dwSize = sizeof(DWORD); lResult = RegQueryValueEx (hKey, PROFILE_REF_COUNT, 0, &dwType, (LPBYTE) &dwRef, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("DecrementProfileRefCount: Failed to query profile reference count with error %d"), lResult)); } if (dwRef) { dwRef--; } else { DebugMsg((DM_WARNING, TEXT("DecrementRefCount: Ref Count is already zero !!!!!!"))); } // // Set the profile Ref count // lResult = RegSetValueEx (hKey, PROFILE_REF_COUNT, 0, REG_DWORD, (LPBYTE) &dwRef, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DecrementProfileRefCount: Failed to save profile reference count with error %d"), lResult)); } DeleteSidString(SidString); RegCloseKey (hKey); return dwRef; } //************************************************************* // // SaveProfileInfo() // // Purpose: Saves key parts of the lpProfile structure // in the registry for UnloadUserProfile to use. // // Parameters: lpProfile - Profile information // // Return: (BOOL) TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 12/4/95 ericflo Created // //************************************************************* BOOL SaveProfileInfo(LPPROFILE lpProfile) { LPTSTR SidString, lpEnd; TCHAR LocalProfileKey[MAX_PATH]; LONG lResult; HKEY hKey; DWORD dwType, dwSize, dwCount, dwDisp; LPTSTR szUserGuid = NULL; // // Get the Sid string for the user // SidString = GetSidString(lpProfile->hTokenUser); if (!SidString) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to get sid string for user"))); return FALSE; } // // Open the profile mapping // lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); lpEnd = CheckSlash (LocalProfileKey); lstrcpy(lpEnd, SidString); lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, 0, 0, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisp); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to open profile mapping key with error %d"), lResult)); SetLastError(lResult); DeleteSidString(SidString); return FALSE; } // // Save the flags // lResult = RegSetValueEx (hKey, PROFILE_FLAGS, 0, REG_DWORD, (LPBYTE) &lpProfile->dwFlags, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to save flags with error %d"), lResult)); } // // Save the internal flags // lResult = RegSetValueEx (hKey, PROFILE_STATE, 0, REG_DWORD, (LPBYTE) &lpProfile->dwInternalFlags, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to save flags2 with error %d"), lResult)); } // // Save the central profile path only if it is non-null. // That way it will allow a roaming user/administrator to change roaming profile to local // and then go back to roaming again. // // // lpProfilePath contains the actual roaming share name whereas lpRoamingProfile contains path // name wrt to mapped drive name. If lpProfilePath is NULL then use lpRoamingProfile which // is a NULL string. // lResult = RegSetValueEx(hKey, PROFILE_CENTRAL_PROFILE, 0, REG_SZ, (LPBYTE) (lpProfile->lpProfilePath ? lpProfile->lpProfilePath : lpProfile->lpRoamingProfile), (lstrlen((lpProfile->lpProfilePath ? lpProfile->lpProfilePath : lpProfile->lpRoamingProfile)) + 1) * sizeof(TCHAR)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to save central profile with error %d"), lResult)); } // // local profile path, saved in CreateLocalProfileImage // // // Save the profile load time // if (!(lpProfile->dwFlags & PI_LITELOAD)) { lResult = RegSetValueEx (hKey, PROFILE_LOAD_TIME_LOW, 0, REG_DWORD, (LPBYTE) &lpProfile->ftProfileLoad.dwLowDateTime, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to save low profile load time with error %d"), lResult)); } lResult = RegSetValueEx (hKey, PROFILE_LOAD_TIME_HIGH, 0, REG_DWORD, (LPBYTE) &lpProfile->ftProfileLoad.dwHighDateTime, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to save high profile load time with error %d"), lResult)); } } // // Set the user's GUID if this is a new profile // if (!(lpProfile->dwInternalFlags & PROFILE_TEMP_ASSIGNED) && (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL)) { szUserGuid = GetUserGuid(lpProfile->hTokenUser); if (szUserGuid) { lResult = RegSetValueEx (hKey, PROFILE_GUID, 0, REG_SZ, (LPBYTE) szUserGuid, (lstrlen(szUserGuid)+1)*sizeof(TCHAR)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Failed to save user guid with error %d"), lResult)); } LocalFree(szUserGuid); } // // Save the guid->sid corresp. for the next time // if (!SetOldSidString(lpProfile->hTokenUser, SidString, PROFILE_GUID_PATH)) { DebugMsg((DM_WARNING, TEXT("SaveProfileInfo: Couldn't set the old Sid in the GuidList"))); } } DeleteSidString(SidString); RegCloseKey (hKey); return(TRUE); } //************************************************************* // // LoadProfileInfo() // // Purpose: Loads key parts of the lpProfile structure // in the registry for UnloadUserProfile to use. // // Parameters: hTokenClient - Caller's token. // hTokenUser - User's token // hKeyCurrentUser - User registry key handle // // Return: LPPROFILE if successful // NULL if not // // Comments: This function doesn't re-initialize all of the // fields in the PROFILE structure. // // History: Date Author Comment // 12/5/95 ericflo Created // //************************************************************* LPPROFILE LoadProfileInfo (HANDLE hTokenClient, HANDLE hTokenUser, HKEY hKeyCurrentUser) { LPPROFILE lpProfile; LPTSTR SidString = NULL, lpEnd; TCHAR szBuffer[MAX_PATH]; LONG lResult; HKEY hKey = NULL; DWORD dwType, dwSize; UINT i; BOOL bSuccess = FALSE; DWORD dwErr = 0; dwErr = GetLastError(); // // Allocate an internal Profile structure to work with. // lpProfile = (LPPROFILE) LocalAlloc (LPTR, sizeof(USERPROFILE)); if (!lpProfile) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to allocate memory"))); dwErr = GetLastError(); goto Exit; } // // Save the data passed in. // lpProfile->hTokenClient = hTokenClient; lpProfile->hTokenUser = hTokenUser; lpProfile->hKeyCurrentUser = hKeyCurrentUser; // // Allocate memory for the various paths // lpProfile->lpLocalProfile = (LPTSTR)LocalAlloc (LPTR, MAX_PATH * sizeof(TCHAR)); if (!lpProfile->lpLocalProfile) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to alloc memory for local profile path. Error = %d"), GetLastError())); dwErr = GetLastError(); goto Exit; } lpProfile->lpRoamingProfile = (LPTSTR)LocalAlloc (LPTR, MAX_PATH * sizeof(TCHAR)); if (!lpProfile->lpRoamingProfile) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to alloc memory for central profile path. Error = %d"), GetLastError())); dwErr = GetLastError(); goto Exit; } // // Get the Sid string for the user // SidString = GetProfileSidString(lpProfile->hTokenUser); if (!SidString) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to get sid string for user"))); dwErr = GetLastError(); goto Exit; } // // Open the profile mapping // lstrcpy(szBuffer, PROFILE_LIST_PATH); lpEnd = CheckSlash (szBuffer); lstrcpy(lpEnd, SidString); lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, KEY_READ, &hKey); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to open profile mapping key with error %d"), lResult)); dwErr = lResult; goto Exit; } // // Query for the flags // dwSize = sizeof(DWORD); lResult = RegQueryValueEx (hKey, PROFILE_FLAGS, NULL, &dwType, (LPBYTE) &lpProfile->dwFlags, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query flags with error %d"), lResult)); dwErr = lResult; goto Exit; } // // Query for the internal flags // dwSize = sizeof(DWORD); lResult = RegQueryValueEx (hKey, PROFILE_STATE, NULL, &dwType, (LPBYTE) &lpProfile->dwInternalFlags, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query internal flags with error %d"), lResult)); dwErr = lResult; goto Exit; } // // Query for the user preference value // lpProfile->dwUserPreference = USERINFO_UNDEFINED; dwSize = sizeof(DWORD); RegQueryValueEx (hKey, USER_PREFERENCE, NULL, &dwType, (LPBYTE) &lpProfile->dwUserPreference, &dwSize); // // Query for the central profile path // dwSize = MAX_PATH * sizeof(TCHAR); lResult = RegQueryValueEx (hKey, PROFILE_CENTRAL_PROFILE, NULL, &dwType, (LPBYTE) lpProfile->lpRoamingProfile, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("LoadProfileInfo: Failed to query central profile with error %d"), lResult)); lpProfile->lpRoamingProfile[0] = TEXT('\0'); } // // Query for the local profile path. The local profile path // needs to be expanded so read it into the temporary buffer. // dwSize = sizeof(szBuffer); lResult = RegQueryValueEx (hKey, PROFILE_IMAGE_VALUE_NAME, NULL, &dwType, (LPBYTE) szBuffer, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query local profile with error %d"), lResult)); dwErr = lResult; goto Exit; } // // Expand the local profile // ExpandEnvironmentStrings(szBuffer, lpProfile->lpLocalProfile, MAX_PATH); // // Query for the profile load time // lpProfile->ftProfileLoad.dwLowDateTime = 0; lpProfile->ftProfileLoad.dwHighDateTime = 0; if (!(lpProfile->dwFlags & PI_LITELOAD)) { dwSize = sizeof(lpProfile->ftProfileLoad.dwLowDateTime); lResult = RegQueryValueEx (hKey, PROFILE_LOAD_TIME_LOW, NULL, &dwType, (LPBYTE) &lpProfile->ftProfileLoad.dwLowDateTime, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query low profile load time with error %d"), lResult)); dwErr = lResult; goto Exit; } dwSize = sizeof(lpProfile->ftProfileLoad.dwHighDateTime); lResult = RegQueryValueEx (hKey, PROFILE_LOAD_TIME_HIGH, NULL, &dwType, (LPBYTE) &lpProfile->ftProfileLoad.dwHighDateTime, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query high profile load time with error %d"), lResult)); dwErr = lResult; goto Exit; } } // // Sucess! // bSuccess = TRUE; Exit: if (hKey) { RegCloseKey (hKey); } if (SidString) { DeleteSidString(SidString); } // // If the profile information was successfully loaded, return // lpProfile now. Otherwise, free any memory and return NULL. // if (bSuccess) { SetLastError(dwErr); return lpProfile; } if (lpProfile) { if (lpProfile->lpRoamingProfile) { LocalFree (lpProfile->lpRoamingProfile); } if (lpProfile->lpLocalProfile) { LocalFree (lpProfile->lpLocalProfile); } LocalFree (lpProfile); } SetLastError(dwErr); return NULL; } //************************************************************* // // CheckForSlowLink() // // Purpose: Checks if the network connection is slow. // // Parameters: lpProfile - Profile Information // dwTime - Time delta // lpPath - UNC path to test // bDlgLogin - Type of Dialog // // Return: TRUE if profile should be downloaded // FALSE if not (use local) // // Comments: // // History: Date Author Comment // 2/21/96 ericflo Created // //************************************************************* BOOL CheckForSlowLink(LPPROFILE lpProfile, DWORD dwTime, LPTSTR lpPath, BOOL bDlgLogin) { DWORD dwSlowTimeOut, dwSlowDlgTimeOut, dwSlowLinkDetectEnabled, dwSlowLinkUIEnabled; ULONG ulTransferRate; DWORD dwType, dwSize; BOOL bRetVal = TRUE; HKEY hKey; LONG lResult; BOOL bSlow = FALSE; BOOL bLegacyCheck = TRUE; LPTSTR lpPathTemp, lpTempSrc, lpTempDest; LPSTR lpPathTempA; struct hostent *hostp; ULONG inaddr, ulSpeed; DWORD dwResult; PWSOCK32_API pWSock32; LPTSTR szSidUser; handle_t hIfProfileDialog; LPTSTR lpRPCEndPoint = NULL; DWORD dwErr = ERROR_SUCCESS; RPC_ASYNC_STATE AsyncHnd; RPC_STATUS status; // // If the User Preferences states to always use the local // profile then we can exit now with true. The profile // won't actually be downloaded. In RestoreUserProfile, // this will be filtered out, and only the local will be used. // if (lpProfile->dwUserPreference == USERINFO_LOCAL) { return TRUE; } // // Get the slow link detection flag, slow link timeout, // dialog box timeout values, and default profile to use. // dwSlowTimeOut = SLOW_LINK_TIMEOUT; dwSlowDlgTimeOut = PROFILE_DLG_TIMEOUT; dwSlowLinkDetectEnabled = 1; dwSlowLinkUIEnabled = 0; ulTransferRate = SLOW_LINK_TRANSFER_RATE; bRetVal = FALSE; lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hKey); if (lResult == ERROR_SUCCESS) { dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("SlowLinkDetectEnabled"), NULL, &dwType, (LPBYTE) &dwSlowLinkDetectEnabled, &dwSize); dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("SlowLinkTimeOut"), NULL, &dwType, (LPBYTE) &dwSlowTimeOut, &dwSize); dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("ProfileDlgTimeOut"), NULL, &dwType, (LPBYTE) &dwSlowDlgTimeOut, &dwSize); dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("SlowLinkUIEnabled"), NULL, &dwType, (LPBYTE) &dwSlowLinkUIEnabled, &dwSize); dwSize = sizeof(BOOL); RegQueryValueEx (hKey, TEXT("SlowLinkProfileDefault"), NULL, &dwType, (LPBYTE) &bRetVal, &dwSize); dwSize = sizeof(ULONG); RegQueryValueEx (hKey, TEXT("UserProfileMinTransferRate"), NULL, &dwType, (LPBYTE) &ulTransferRate, &dwSize); RegCloseKey (hKey); } lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey); if (lResult == ERROR_SUCCESS) { dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("SlowLinkDetectEnabled"), NULL, &dwType, (LPBYTE) &dwSlowLinkDetectEnabled, &dwSize); dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("SlowLinkTimeOut"), NULL, &dwType, (LPBYTE) &dwSlowTimeOut, &dwSize); dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("ProfileDlgTimeOut"), NULL, &dwType, (LPBYTE) &dwSlowDlgTimeOut, &dwSize); dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("SlowLinkUIEnabled"), NULL, &dwType, (LPBYTE) &dwSlowLinkUIEnabled, &dwSize); dwSize = sizeof(BOOL); RegQueryValueEx (hKey, TEXT("SlowLinkProfileDefault"), NULL, &dwType, (LPBYTE) &bRetVal, &dwSize); dwSize = sizeof(ULONG); RegQueryValueEx (hKey, TEXT("UserProfileMinTransferRate"), NULL, &dwType, (LPBYTE) &ulTransferRate, &dwSize); RegCloseKey (hKey); } // // If slow link detection is disabled, then always download // the profile. // if (!dwSlowLinkDetectEnabled || !ulTransferRate) { return TRUE; } // // If slow link timeout is set to 0 then always consider the link as slow link // if (!dwSlowTimeOut) { bSlow = TRUE; bLegacyCheck = FALSE; } // // If lpPath is UNC path and we yet not decided that link is slow, then try // pinging the server // if (!bSlow && (*lpPath == TEXT('\\')) && (*(lpPath+1) == TEXT('\\'))) { lpPathTemp = (LPTSTR)LocalAlloc (LPTR, (lstrlen(lpPath)+1) * sizeof(TCHAR)); if (lpPathTemp) { lpTempSrc = lpPath+2; lpTempDest = lpPathTemp; while ((*lpTempSrc != TEXT('\\')) && *lpTempSrc) { *lpTempDest = *lpTempSrc; lpTempDest++; lpTempSrc++; } *lpTempDest = TEXT('\0'); lpPathTempA = ProduceAFromW(lpPathTemp); if (lpPathTempA) { pWSock32 = LoadWSock32(); if ( pWSock32 ) { hostp = pWSock32->pfngethostbyname(lpPathTempA); if (hostp) { inaddr = *(long *)hostp->h_addr; dwResult = PingComputer (inaddr, &ulSpeed); if (dwResult == ERROR_SUCCESS) { if (ulSpeed) { // // If the delta time is greater that the timeout time, then this // is a slow link. // if (ulSpeed < ulTransferRate) { bSlow = TRUE; } } bLegacyCheck = FALSE; } } } FreeProducedString(lpPathTempA); } LocalFree (lpPathTemp); } } if (bLegacyCheck) { // // If the delta time is less that the timeout time, then it // is ok to download their profile (fast enough net connection). // if (dwTime < dwSlowTimeOut) { return TRUE; } } else { if (!bSlow) { return TRUE; } } // // Display the slow link dialog // // If someone sets the dialog box timeout to 0, then we // don't want to prompt the user. Just do the default // if ((dwSlowLinkUIEnabled) && (dwSlowDlgTimeOut > 0) && (!(lpProfile->dwFlags & PI_NOUI))) { szSidUser = GetSidString(lpProfile->hTokenUser); if (szSidUser) { lpRPCEndPoint = cUserProfileManager.GetRPCEndPoint(szSidUser); if (lpRPCEndPoint && GetInterface(&hIfProfileDialog, lpRPCEndPoint)) { DebugMsg((DM_VERBOSE, TEXT("CheckForSlowLink: RPC End point %s"), lpRPCEndPoint)); status = RpcAsyncInitializeHandle(&AsyncHnd, sizeof(RPC_ASYNC_STATE)); if (status != RPC_S_OK) { dwErr = status; DebugMsg((DM_WARNING, TEXT("CheckForSlowLink: RpcAsyncInitializeHandle failed. err = %d"), dwErr)); } else { AsyncHnd.UserInfo = NULL; // App specific info, not req AsyncHnd.NotificationType = RpcNotificationTypeEvent; // Init the notification event AsyncHnd.u.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (AsyncHnd.u.hEvent) { RpcTryExcept { cliSlowLinkDialog(&AsyncHnd, hIfProfileDialog, dwSlowDlgTimeOut, bRetVal, &bRetVal, bDlgLogin); } RpcExcept(1) { dwErr = RpcExceptionCode(); DebugMsg((DM_WARNING, TEXT("CheckForSlowLink: Calling SlowLinkDialog took exception. err = %d"), dwErr)); } RpcEndExcept DebugMsg((DM_VERBOSE, TEXT("CheckForSlowLink: waiting on rpc async event"))); if (WaitForSingleObject(AsyncHnd.u.hEvent, (dwSlowDlgTimeOut + 10)*1000) == WAIT_OBJECT_0) { RpcAsyncCompleteCall(&AsyncHnd, (PVOID)&dwErr); } else { dwErr = GetLastError(); RpcAsyncCancelCall(&AsyncHnd, TRUE); DebugMsg((DM_WARNING, TEXT("CheckForSlowLink: Timeout occurs. Client not responding"), dwErr)); } // Release the resource CloseHandle(AsyncHnd.u.hEvent); } else { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CheckForSlowLink: create event failed. error %d"), dwErr)); } } if (dwErr != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("CheckForSlowLink: fail to show message error %d"), GetLastError())); } ReleaseInterface(&hIfProfileDialog); } DeleteSidString(szSidUser); } else { DebugMsg((DM_WARNING, TEXT("CheckForSlowLink: Unable to get SID string from token."))); } if (!lpRPCEndPoint) { SLOWLINKDLGINFO info; info.dwTimeout = dwSlowDlgTimeOut; info.bSyncDefault = bRetVal; DebugMsg((DM_VERBOSE, TEXT("CheckForSlowLink: Calling DialogBoxParam"))); if (bDlgLogin) { bRetVal = (BOOL)DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_LOGIN_SLOW_LINK), NULL, LoginSlowLinkDlgProc, (LPARAM)&info); } else { bRetVal = (BOOL)DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_LOGOFF_SLOW_LINK), NULL, LogoffSlowLinkDlgProc, (LPARAM)&info); } } } if (!bRetVal) { lpProfile->dwInternalFlags |= PROFILE_SLOW_LINK; DebugMsg((DM_VERBOSE, TEXT("CheckForSlowLink: The profile is across a slow link"))); } return bRetVal; } //************************************************************* // // LoginSlowLinkDlgProc() // // Purpose: Dialog box procedure for the slow link dialog // at login time // // Parameters: hDlg - handle to the dialog box // uMsg - window message // wParam - wParam // lParam - lParam // // Return: TRUE if message was processed // FALSE if not // // Comments: // // History: Date Author Comment // 2/13/96 ericflo Created // //************************************************************* INT_PTR APIENTRY LoginSlowLinkDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { TCHAR szBuffer[10]; static DWORD dwSlowLinkTime; BOOL bDownloadDefault; switch (uMsg) { case WM_INITDIALOG: SetForegroundWindow(hDlg); CenterWindow (hDlg); // // Set the default button and focus // if (((LPSLOWLINKDLGINFO)lParam)->bSyncDefault) { SetFocus (GetDlgItem(hDlg, IDC_DOWNLOAD)); } else { HWND hwnd; LONG style; // // Set the default button to Local // hwnd = GetDlgItem (hDlg, IDC_DOWNLOAD); style = GetWindowLong (hwnd, GWL_STYLE); style &= ~(BS_DEFPUSHBUTTON | BS_NOTIFY); style |= BS_PUSHBUTTON; SetWindowLong (hwnd, GWL_STYLE, style); hwnd = GetDlgItem (hDlg, IDC_LOCAL); style = GetWindowLong (hwnd, GWL_STYLE); style &= ~(BS_PUSHBUTTON | BS_DEFPUSHBUTTON); style |= (BS_DEFPUSHBUTTON | BS_NOTIFY); SetWindowLong (hwnd, GWL_STYLE, style); SetFocus (GetDlgItem(hDlg, IDC_LOCAL)); } SetWindowLongPtr (hDlg, DWLP_USER, ((LPSLOWLINKDLGINFO)lParam)->bSyncDefault); dwSlowLinkTime = ((LPSLOWLINKDLGINFO)lParam)->dwTimeout; wsprintf (szBuffer, TEXT("%d"), dwSlowLinkTime); SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); SetTimer (hDlg, 1, 1000, NULL); return FALSE; case WM_TIMER: if (dwSlowLinkTime >= 1) { dwSlowLinkTime--; wsprintf (szBuffer, TEXT("%d"), dwSlowLinkTime); SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); } else { // // Time's up. Do the default action. // bDownloadDefault = (BOOL) GetWindowLongPtr (hDlg, DWLP_USER); if (bDownloadDefault) { PostMessage (hDlg, WM_COMMAND, IDC_DOWNLOAD, 0); } else { PostMessage (hDlg, WM_COMMAND, IDC_LOCAL, 0); } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_DOWNLOAD: if (HIWORD(wParam) == BN_KILLFOCUS) { bDownloadDefault = (BOOL) GetWindowLongPtr (hDlg, DWLP_USER); if (bDownloadDefault) { KillTimer (hDlg, 1); ShowWindow(GetDlgItem(hDlg, IDC_TIMEOUT), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_TIMETITLE), SW_HIDE); } } else if (HIWORD(wParam) == BN_CLICKED) { DebugMsg((DM_VERBOSE, TEXT("LoginSlowLinkDlgProc:: Killing DialogBox because download button was clicked"))); KillTimer (hDlg, 1); EndDialog(hDlg, TRUE); } break; case IDC_LOCAL: if (HIWORD(wParam) == BN_KILLFOCUS) { bDownloadDefault = (BOOL) GetWindowLongPtr (hDlg, DWLP_USER); if (!bDownloadDefault) { KillTimer (hDlg, 1); ShowWindow(GetDlgItem(hDlg, IDC_TIMEOUT), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_TIMETITLE), SW_HIDE); } break; } else if (HIWORD(wParam) == BN_CLICKED) { DebugMsg((DM_VERBOSE, TEXT("LoginSlowLinkDlgProc:: Killing DialogBox because local button was clicked"))); KillTimer (hDlg, 1); EndDialog(hDlg, FALSE); } break; case IDCANCEL: bDownloadDefault = (BOOL) GetWindowLongPtr (hDlg, DWLP_USER); // // Nothing to do. Save the state and return. // DebugMsg((DM_VERBOSE, TEXT("LoginSlowLinkDlgProc:: Killing DialogBox because local/cancel button was clicked"))); KillTimer (hDlg, 1); // // Return Whatever is the default in this case.. // EndDialog(hDlg, bDownloadDefault); break; default: break; } break; } return FALSE; } //************************************************************* // // LogoffSlowLinkDlgProc() // // Purpose: Dialog box procedure for the slow link dialog // at login time // // Parameters: hDlg - handle to the dialog box // uMsg - window message // wParam - wParam // lParam - lParam // // Return: TRUE if message was processed // FALSE if not // // Comments: // // History: Date Author Comment // 2/13/96 ericflo Created // //************************************************************* INT_PTR APIENTRY LogoffSlowLinkDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { TCHAR szBuffer[10]; static DWORD dwSlowLinkTime; BOOL bUploadDefault; switch (uMsg) { case WM_INITDIALOG: SetForegroundWindow(hDlg); CenterWindow (hDlg); // // Set the default button and focus // if (((LPSLOWLINKDLGINFO)lParam)->bSyncDefault) { SetFocus (GetDlgItem(hDlg, IDC_UPLOAD)); } else { HWND hwnd; LONG style; // // Set the default button to Local // hwnd = GetDlgItem (hDlg, IDC_UPLOAD); style = GetWindowLong (hwnd, GWL_STYLE); style &= ~(BS_DEFPUSHBUTTON | BS_NOTIFY); style |= BS_PUSHBUTTON; SetWindowLong (hwnd, GWL_STYLE, style); hwnd = GetDlgItem (hDlg, IDC_NOUPLOAD); style = GetWindowLong (hwnd, GWL_STYLE); style &= ~(BS_PUSHBUTTON | BS_DEFPUSHBUTTON); style |= (BS_DEFPUSHBUTTON | BS_NOTIFY); SetWindowLong (hwnd, GWL_STYLE, style); SetFocus (GetDlgItem(hDlg, IDC_NOUPLOAD)); } SetWindowLongPtr (hDlg, DWLP_USER, ((LPSLOWLINKDLGINFO)lParam)->bSyncDefault); dwSlowLinkTime = ((LPSLOWLINKDLGINFO)lParam)->dwTimeout; wsprintf (szBuffer, TEXT("%d"), dwSlowLinkTime); SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); SetTimer (hDlg, 1, 1000, NULL); return FALSE; case WM_TIMER: if (dwSlowLinkTime >= 1) { dwSlowLinkTime--; wsprintf (szBuffer, TEXT("%d"), dwSlowLinkTime); SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); } else { // // Time's up. Do the default action. // bUploadDefault = (BOOL) GetWindowLongPtr (hDlg, DWLP_USER); if (bUploadDefault) { PostMessage (hDlg, WM_COMMAND, IDC_UPLOAD, 0); } else { PostMessage (hDlg, WM_COMMAND, IDC_NOUPLOAD, 0); } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_UPLOAD: if (HIWORD(wParam) == BN_KILLFOCUS) { bUploadDefault = (BOOL) GetWindowLongPtr (hDlg, DWLP_USER); if (bUploadDefault) { KillTimer (hDlg, 1); ShowWindow(GetDlgItem(hDlg, IDC_TIMEOUT), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_TIMETITLE), SW_HIDE); } } else if (HIWORD(wParam) == BN_CLICKED) { DebugMsg((DM_VERBOSE, TEXT("LogoffSlowLinkDlgProc:: Killing DialogBox because upload button was clicked"))); KillTimer (hDlg, 1); EndDialog(hDlg, TRUE); } break; case IDC_NOUPLOAD: if (HIWORD(wParam) == BN_KILLFOCUS) { bUploadDefault = (BOOL) GetWindowLongPtr (hDlg, DWLP_USER); if (!bUploadDefault) { KillTimer (hDlg, 1); ShowWindow(GetDlgItem(hDlg, IDC_TIMEOUT), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_TIMETITLE), SW_HIDE); } break; } else if (HIWORD(wParam) == BN_CLICKED) { DebugMsg((DM_VERBOSE, TEXT("LogoffSlowLinkDlgProc:: Killing DialogBox because Don't Upload button was clicked"))); KillTimer (hDlg, 1); EndDialog(hDlg, FALSE); } break; case IDCANCEL: bUploadDefault = (BOOL) GetWindowLongPtr (hDlg, DWLP_USER); // // Nothing to do. Save the state and return. // DebugMsg((DM_VERBOSE, TEXT("LogoffSlowLinkDlgProc:: Killing DialogBox because cancel button was clicked"))); KillTimer (hDlg, 1); // // Return Whatever is the default in this case.. // EndDialog(hDlg, bUploadDefault); break; default: break; } break; } return FALSE; } //************************************************************* // // GetUserPreferenceValue() // // Purpose: Gets the User Preference flags // // Parameters: hToken - User's token // // Return: Value // // Comments: // // History: Date Author Comment // 2/22/96 ericflo Created // //************************************************************* DWORD GetUserPreferenceValue(HANDLE hToken) { TCHAR LocalProfileKey[MAX_PATH]; DWORD RegErr, dwType, dwSize, dwTmpVal, dwRetVal = USERINFO_UNDEFINED; LPTSTR lpEnd; LPTSTR SidString; HKEY hkeyProfile, hkeyPolicy; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hkeyPolicy) == ERROR_SUCCESS) { dwSize = sizeof(dwTmpVal); RegQueryValueEx(hkeyPolicy, PROFILE_LOCALONLY, NULL, &dwType, (LPBYTE) &dwTmpVal, &dwSize); RegCloseKey (hkeyPolicy); if (dwTmpVal == 1) { dwRetVal = USERINFO_LOCAL; return dwRetVal; } } SidString = GetProfileSidString(hToken); if (SidString != NULL) { // // Query for the UserPreference value // lstrcpy(LocalProfileKey, PROFILE_LIST_PATH); lpEnd = CheckSlash (LocalProfileKey); lstrcpy(lpEnd, SidString); RegErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, KEY_READ, &hkeyProfile); if (RegErr == ERROR_SUCCESS) { dwSize = sizeof(dwRetVal); RegQueryValueEx(hkeyProfile, USER_PREFERENCE, NULL, &dwType, (LPBYTE) &dwRetVal, &dwSize); RegCloseKey (hkeyProfile); } lstrcat(LocalProfileKey, c_szBAK); RegErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LocalProfileKey, 0, KEY_READ, &hkeyProfile); if (RegErr == ERROR_SUCCESS) { dwSize = sizeof(dwRetVal); RegQueryValueEx(hkeyProfile, USER_PREFERENCE, NULL, &dwType, (LPBYTE) &dwRetVal, &dwSize); RegCloseKey (hkeyProfile); } DeleteSidString(SidString); } return dwRetVal; } //************************************************************* // // IsTempProfileAllowed() // // Purpose: Gets the temp profile policy // // Parameters: // // Return: true if temp profile can be created, false otherwise // // Comments: // // History: Date Author Comment // 2/8/99 ushaji Created // //************************************************************* BOOL IsTempProfileAllowed() { HKEY hKey; LONG lResult; DWORD dwSize, dwType; DWORD dwRetVal = PROFILEERRORACTION_TEMP; lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey); if (lResult == ERROR_SUCCESS) { dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("ProfileErrorAction"), NULL, &dwType, (LPBYTE) &dwRetVal, &dwSize); RegCloseKey (hKey); } DebugMsg((DM_VERBOSE, TEXT("IsTempProfileAllowed: Returning %d"), (dwRetVal == PROFILEERRORACTION_TEMP))); return (dwRetVal == PROFILEERRORACTION_TEMP); } //************************************************************* // // MoveUserProfiles() // // Purpose: Moves all user profiles from source location // to the new profile location // // Parameters: lpSrcDir - Source directory // lpDestDir - Destination directory // // Notes: The source directory should be given in the same // format as the pathnames appear in the ProfileList // registry key. eg: normally the profile paths // are in this form: %SystemRoot%\Profiles. The // path passed to this function should be in the unexpanded // format. // // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL MoveUserProfiles (LPCTSTR lpSrcDir, LPCTSTR lpDestDir) { BOOL bResult = TRUE; LONG lResult; DWORD dwIndex, dwType, dwSize, dwDisp; DWORD dwLength, dwLengthNeeded, dwStrLen; PSECURITY_DESCRIPTOR pSD; LPTSTR lpEnd, lpNewPathEnd, lpNameEnd; TCHAR szName[75]; TCHAR szTemp[MAX_PATH + 1]; TCHAR szOldProfilePath[MAX_PATH + 1]; TCHAR szNewProfilePath[MAX_PATH + 1]; TCHAR szExpOldProfilePath[MAX_PATH + 1] = {0}; TCHAR szExpNewProfilePath[MAX_PATH + 1]; WIN32_FILE_ATTRIBUTE_DATA fad; INT iSrcDirLen; HKEY hKeyProfileList, hKeyProfile, hKeyFolders; FILETIME ftWrite; // // Make sure we don't try to move on top of ourselves // if (lstrcmpi (lpSrcDir, lpDestDir) == 0) { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: Old profiles directory and new profiles directory are the same."))); bResult = FALSE; goto Exit; } // // Open the profile list // lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, PROFILE_LIST_PATH, 0, KEY_READ, &hKeyProfileList); if (lResult != ERROR_SUCCESS) { if (lResult != ERROR_PATH_NOT_FOUND) { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: Failed to open profile list registry key with %d"), lResult)); bResult = FALSE; } goto DoDefaults; } // // Enumerate the profiles // lstrcpy (szTemp, PROFILE_LIST_PATH); lpEnd = CheckSlash (szTemp); iSrcDirLen = lstrlen (lpSrcDir); dwIndex = 0; dwSize = ARRAYSIZE(szName); while (RegEnumKeyEx (hKeyProfileList, dwIndex, szName, &dwSize, NULL, NULL, NULL, &ftWrite) == ERROR_SUCCESS) { // // Check if this profile is in use // if (RegOpenKeyEx(HKEY_USERS, szName, 0, KEY_READ, &hKeyProfile) == ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("MoveUserProfiles: Skipping <%s> because it is in use."), szName)); RegCloseKey (hKeyProfile); goto LoopAgain; } // // Open the key for a specific profile // lstrcpy (lpEnd, szName); if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szTemp, 0, KEY_READ | KEY_WRITE, &hKeyProfile) == ERROR_SUCCESS) { // // Query for the previous profile location // szOldProfilePath[0] = TEXT('\0'); dwSize = ARRAYSIZE(szOldProfilePath) * sizeof(TCHAR); RegQueryValueEx (hKeyProfile, PROFILE_IMAGE_VALUE_NAME, NULL, &dwType, (LPBYTE) szOldProfilePath, &dwSize); // // If the profile is located in the source directory, // move it to the new profiles directory. // if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, szOldProfilePath, iSrcDirLen, lpSrcDir, iSrcDirLen) == CSTR_EQUAL) { // // Copy the user's name into a buffer we can change // lstrcpy (szName, (szOldProfilePath + iSrcDirLen + 1)); // // If the user's name has a .000, .001, etc at the end, // remove that. // dwStrLen = lstrlen(szName); if (dwStrLen > 3) { lpNameEnd = szName + dwStrLen - 4; if (*lpNameEnd == TEXT('.')) { *lpNameEnd = TEXT('\0'); } } // // Call ComputeLocalProfileName to get the new // profile directory (this also creates the directory) // lstrcpy (szNewProfilePath, lpDestDir); if (!ComputeLocalProfileName (NULL, szName, szNewProfilePath, ARRAYSIZE(szNewProfilePath), szExpNewProfilePath, ARRAYSIZE(szExpNewProfilePath), NULL, FALSE)) { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: Failed to generate unique directory name for <%s>"), szName)); goto LoopAgain; } DebugMsg((DM_VERBOSE, TEXT("MoveUserProfiles: Moving <%s> to <%s>"), szOldProfilePath, szNewProfilePath)); ExpandEnvironmentStrings (szOldProfilePath, szExpOldProfilePath, ARRAYSIZE(szExpOldProfilePath)); // // Copy the ACLs from the old location to the new // dwLength = 1024; pSD = (PSECURITY_DESCRIPTOR)LocalAlloc (LPTR, dwLength); if (pSD) { if (GetFileSecurity (szExpOldProfilePath, DACL_SECURITY_INFORMATION, pSD, dwLength, &dwLengthNeeded) && (dwLengthNeeded == 0)) { SetFileSecurity (szExpNewProfilePath, DACL_SECURITY_INFORMATION, pSD); } else { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: Failed to allocate get security descriptor with %d. dwLengthNeeded = %d"), GetLastError(), dwLengthNeeded)); } LocalFree (pSD); } else { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: Failed to allocate memory for SD with %d."), GetLastError())); } // // Copy the files from the old location to the new // if (CopyProfileDirectory (szExpOldProfilePath, szExpNewProfilePath, CPD_COPYIFDIFFERENT)) { DebugMsg((DM_VERBOSE, TEXT("MoveUserProfiles: Profile copied successfully."))); // // Change the registry to point at the new profile // lResult = RegSetValueEx (hKeyProfile, PROFILE_IMAGE_VALUE_NAME, 0, REG_EXPAND_SZ, (LPBYTE) szNewProfilePath, ((lstrlen(szNewProfilePath) + 1) * sizeof(TCHAR))); if (lResult == ERROR_SUCCESS) { // // Delete the old profile // Delnode (szExpOldProfilePath); } else { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: Failed to set new profile path in registry with %d."), lResult)); } } else { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: CopyProfileDirectory failed."))); } } RegCloseKey (hKeyProfile); } LoopAgain: dwIndex++; dwSize = ARRAYSIZE(szName); } RegCloseKey (hKeyProfileList); DoDefaults: lstrcpy (szOldProfilePath, lpSrcDir); ExpandEnvironmentStrings (szOldProfilePath, szExpOldProfilePath, ARRAYSIZE(szExpOldProfilePath)); lpEnd = CheckSlash(szExpOldProfilePath); // // Now try to move the Default User profile // lstrcpy (lpEnd, DEFAULT_USER); if (GetFileAttributesEx (szExpOldProfilePath, GetFileExInfoStandard, &fad)) { dwSize = ARRAYSIZE(szExpNewProfilePath); if (!GetDefaultUserProfileDirectoryEx(szExpNewProfilePath, &dwSize, TRUE)) { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: Failed to query default user profile directory."))); goto Exit; } if (CopyProfileDirectory (szExpOldProfilePath, szExpNewProfilePath, CPD_COPYIFDIFFERENT)) { Delnode (szExpOldProfilePath); } } // // Delnode the Network Default User profile if it exists // lstrcpy (lpEnd, DEFAULT_USER_NETWORK); Delnode (szExpOldProfilePath); // // Now try to move the All Users profile // lstrcpy (lpEnd, ALL_USERS); if (GetFileAttributesEx (szExpOldProfilePath, GetFileExInfoStandard, &fad)) { dwSize = ARRAYSIZE(szExpNewProfilePath); if (!GetAllUsersProfileDirectoryEx(szExpNewProfilePath, &dwSize, TRUE)) { DebugMsg((DM_WARNING, TEXT("MoveUserProfiles: Failed to query all users profile directory."))); goto Exit; } if (CopyProfileDirectory (szExpOldProfilePath, szExpNewProfilePath, CPD_COPYIFDIFFERENT)) { Delnode (szExpOldProfilePath); } } // // If possible, remove the old profiles directory // ExpandEnvironmentStrings (lpSrcDir, szExpOldProfilePath, ARRAYSIZE(szExpOldProfilePath)); RemoveDirectory (szExpOldProfilePath); Exit: return bResult; } //************************************************************* // // PrepareProfileForUse() // // Purpose: Prepares the profile for use on this machine. // // Parameters: lpProfile - Profile information // pEnv - Environment block in per user basis // // Return: TRUE if successful // FALSE if an error occurs // //************************************************************* BOOL PrepareProfileForUse (LPPROFILE lpProfile, LPVOID pEnv) { TCHAR szTemp[MAX_PATH]; TCHAR szExpTemp[MAX_PATH]; HKEY hKey; HKEY hKeyShellFolders = NULL; DWORD dwSize; DWORD dwType; DWORD dwDisp; DWORD dwStrLen; DWORD i; DWORD dwErr; PSHELL32_API pShell32Api; // // Load Shell32.dll. Give up if it fails. // if ( ERROR_SUCCESS != LoadShell32Api( &pShell32Api ) ) { return TRUE; } // // Calculate the length of the user profile environment variable // dwStrLen = lstrlen (TEXT("%USERPROFILE%")); // // Open the Shell Folders key // RegCreateKeyEx(lpProfile->hKeyCurrentUser, SHELL_FOLDERS, 0, 0, 0, KEY_WRITE, NULL, &hKeyShellFolders, &dwDisp); // // Open the User Shell Folders key // if (RegOpenKeyEx (lpProfile->hKeyCurrentUser, USER_SHELL_FOLDERS, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { // // Enumerate the folders we know about // for (i=0; i < g_dwNumShellFolders; i++) { // // Query for the unexpanded path name // szTemp[0] = TEXT('\0'); dwSize = sizeof(szTemp); if (RegQueryValueEx (hKey, c_ShellFolders[i].lpFolderName, NULL, &dwType, (LPBYTE) szTemp, &dwSize) == ERROR_SUCCESS) { // // Expand the path name // ExpandUserEnvironmentStrings (pEnv, szTemp, szExpTemp, ARRAYSIZE(szExpTemp)); // // If this is a local directory, create it and set the // hidden bit if appropriate // if (c_ShellFolders[i].bLocal) { if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, TEXT("%USERPROFILE%"), dwStrLen, szTemp, dwStrLen) == CSTR_EQUAL) { if (CreateNestedDirectory (szExpTemp, NULL)) { if (c_ShellFolders[i].iFolderResourceID != 0) { dwErr = pShell32Api->pfnShSetLocalizedName( szExpTemp, c_ShellFolders[i].lpFolderResourceDLL, c_ShellFolders[i].iFolderResourceID ); if (dwErr != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("PrepareProfileForUse: SHSetLocalizedName failed for directory <%s>. Error = %d"), szExpTemp, dwErr)); } } if (c_ShellFolders[i].bHidden) { SetFileAttributes(szExpTemp, FILE_ATTRIBUTE_HIDDEN); } else { SetFileAttributes(szExpTemp, FILE_ATTRIBUTE_NORMAL); } } else { DebugMsg((DM_WARNING, TEXT("PrepareProfileForUse: Failed to create directory <%s> with %d."), szExpTemp, GetLastError())); } } } // // Set the expanded path in the Shell Folders key. // This helps some apps that look at the Shell Folders // key directly instead of using the shell api // if (hKeyShellFolders) { RegSetValueEx (hKeyShellFolders, c_ShellFolders[i].lpFolderName, 0, REG_SZ, (LPBYTE) szExpTemp, ((lstrlen(szExpTemp) + 1) * sizeof(TCHAR))); } } } RegCloseKey (hKey); } // // Close the Shell Folders key // if (hKeyShellFolders) { RegCloseKey (hKeyShellFolders); } // // Now check that the temp directory exists. // if (RegOpenKeyEx (lpProfile->hKeyCurrentUser, TEXT("Environment"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) { // // Check for TEMP // szTemp[0] = TEXT('\0'); dwSize = sizeof(szTemp); if (RegQueryValueEx (hKey, TEXT("TEMP"), NULL, &dwType, (LPBYTE) szTemp, &dwSize) == ERROR_SUCCESS) { if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, TEXT("%USERPROFILE%"), dwStrLen, szTemp, dwStrLen) == CSTR_EQUAL) { ExpandUserEnvironmentStrings (pEnv, szTemp, szExpTemp, ARRAYSIZE(szExpTemp)); if (!CreateNestedDirectory (szExpTemp, NULL)) { DebugMsg((DM_WARNING, TEXT("PrepareProfileForUse: Failed to create temp directory <%s> with %d."), szExpTemp, GetLastError())); } } } // // Check for TMP // szTemp[0] = TEXT('\0'); dwSize = sizeof(szTemp); if (RegQueryValueEx (hKey, TEXT("TMP"), NULL, &dwType, (LPBYTE) szTemp, &dwSize) == ERROR_SUCCESS) { if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, TEXT("%USERPROFILE%"), dwStrLen, szTemp, dwStrLen) == CSTR_EQUAL) { ExpandUserEnvironmentStrings (pEnv, szTemp, szExpTemp, ARRAYSIZE(szExpTemp)); if (!CreateNestedDirectory (szExpTemp, NULL)) { DebugMsg((DM_WARNING, TEXT("PrepareProfileForUse: Failed to create temp directory with %d."), GetLastError())); } } } RegCloseKey (hKey); } return TRUE; } //************************************************************* // // DeleteProfile() // // Purpose: Deletes the profile // // Parameters: // // Return: true if successful // // Comments: // // History: Date Author Comment // 4/12/99 ushaji Created // 6/27/00 santanuc Bug Fix #100787 // // TBD: Change some of the DeleteProfileEx calls to DeleteProfile // //************************************************************* BOOL DeleteProfile (LPCTSTR lpSidString, LPCTSTR lpProfilePath, LPCTSTR szComputerName) { LPTSTR lpEnd; TCHAR szBuffer[MAX_PATH], szProfilePath[MAX_PATH]; LONG lResult; HKEY hKey = NULL; HKEY hKeyCurrentVersion = NULL; HKEY hKeyNetCache = NULL; DWORD dwType, dwSize; BOOL bSuccess = FALSE; DWORD dwErr = 0; HKEY hKeyLocalLM; BOOL bRemoteReg = FALSE; BOOL bEnvVarsSet = FALSE; TCHAR szOrigSysRoot[MAX_PATH], szOrigSysDrive[MAX_PATH], tDrive; TCHAR szShareName[MAX_PATH], szFileSystemName[MAX_PATH]; DWORD MaxCompLen, FileSysFlags; TCHAR szSystemRoot[MAX_PATH], szSystemDrive[MAX_PATH]; DWORD dwBufferSize; TCHAR szTemp[MAX_PATH]; DWORD dwInternalFlags=0, dwDeleteFlags=0, dwFlags=0; LPTSTR szNetComputerName = NULL; HMODULE hMsiLib = NULL; PFNMSIDELETEUSERDATA pfnMsiDeleteUserData; if (!lpSidString) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (szComputerName) { if ( !IsUNCPath(szComputerName) ) { // Prefixed computer name with slashes if not present szNetComputerName = (LPTSTR)LocalAlloc (LPTR, (lstrlen(TEXT("\\\\")) + lstrlen(szComputerName) + 1) * sizeof(TCHAR)); if (!szNetComputerName) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to allocate memory for computer name with %d"),dwErr)); goto Exit; } lstrcpy(szNetComputerName, TEXT("\\\\")); lstrcat(szNetComputerName, szComputerName); szComputerName = szNetComputerName; } GetEnvironmentVariable(TEXT("SystemRoot"), szOrigSysRoot, MAX_PATH); GetEnvironmentVariable(TEXT("SystemDrive"), szOrigSysDrive, MAX_PATH); lResult = RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyLocalLM); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to open remote registry %d"), lResult)); dwErr = lResult; goto Exit; } bRemoteReg = TRUE; // // Get the value of %SystemRoot% and %SystemDrive% relative to the computer // lResult = RegOpenKeyEx(hKeyLocalLM, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &hKeyCurrentVersion); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to open remote registry CurrentVersion %d"), lResult)); dwErr = lResult; goto Exit; } dwBufferSize = MAX_PATH * sizeof(TCHAR); lResult = RegQueryValueEx(hKeyCurrentVersion, TEXT("SystemRoot"), NULL, NULL, (BYTE *) szTemp, &dwBufferSize); RegCloseKey (hKeyCurrentVersion); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to open remote registry SystemRoot %d"), lResult)); dwErr = lResult; goto Exit; } szTemp[1] = TEXT('$'); // // These needs to be set if there are additional places below which uses envvars... // lstrcpy(szSystemRoot, szComputerName); lstrcat(szSystemRoot, TEXT("\\")); lstrcpy(szSystemDrive, szComputerName); lstrcat(szSystemDrive, TEXT("\\")); lpEnd = szSystemDrive+lstrlen(szSystemDrive); lstrcpyn(lpEnd, szTemp, 3); lpEnd = szSystemRoot+lstrlen(szSystemRoot); lstrcpy(lpEnd, szTemp); SetEnvironmentVariable(TEXT("SystemRoot"), szSystemRoot); SetEnvironmentVariable(TEXT("SystemDrive"), szSystemDrive); bEnvVarsSet = TRUE; } else { hKeyLocalLM = HKEY_LOCAL_MACHINE; } // // If profile in use then do not delete it // if (IsProfileInUse(szComputerName, lpSidString)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Fail to delete profile with sid %s as it is still in use."), lpSidString)); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } dwErr = GetLastError(); // // Open the profile mapping // lstrcpy(szProfilePath, PROFILE_LIST_PATH); lpEnd = CheckSlash (szProfilePath); lstrcpy(lpEnd, lpSidString); lResult = RegOpenKeyEx(hKeyLocalLM, szProfilePath, 0, KEY_READ, &hKey); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to open profile mapping key with error %d"), lResult)); dwErr = lResult; goto Exit; } dwSize = sizeof(DWORD); lResult = RegQueryValueEx (hKey, PROFILE_FLAGS, NULL, &dwType, (LPBYTE)&dwFlags, &dwSize); if (ERROR_SUCCESS == lResult && (dwFlags & PI_HIDEPROFILE)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Fail to delete profile with sid %s as PI_HIDEPROFILE flag is specifed."), lpSidString)); dwErr = ERROR_INVALID_PARAMETER; goto Exit; } if (!lpProfilePath) { TCHAR szTemp[MAX_PATH]; // // Get the profile path... // dwSize = sizeof(szTemp); lResult = RegQueryValueEx (hKey, PROFILE_IMAGE_VALUE_NAME, NULL, &dwType, (LPBYTE) szTemp, &dwSize); dwSize = sizeof(DWORD); lResult = RegQueryValueEx (hKey, PROFILE_STATE, NULL, &dwType, (LPBYTE)&dwInternalFlags, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to query local profile with error %d"), lResult)); dwErr = lResult; goto Exit; } if (!ExpandEnvironmentStrings(szTemp, szBuffer, MAX_PATH)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to expand %s, error %d"), szTemp, GetLastError())); dwErr = lResult; goto Exit; } } else { lstrcpy(szBuffer, lpProfilePath); } if (dwInternalFlags & PROFILE_THIS_IS_BAK) dwDeleteFlags |= DP_DELBACKUP; // // Do not fail if for some reason we could not delete the profiledir // bSuccess = DeleteProfileEx(lpSidString, szBuffer, dwDeleteFlags, hKeyLocalLM, szComputerName); if (!bSuccess) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to delete directory, %s with error %d"), szBuffer, dwErr)); } // // Delete the user's trash.. // if (szComputerName) { lstrcpy (szShareName, szComputerName); lstrcat(szShareName, TEXT("\\")); lpEnd = szShareName+lstrlen(szShareName); lstrcat(lpEnd, TEXT("A$\\")); } else { lstrcpy(szShareName, TEXT("a:\\")); lpEnd = szShareName; } for (tDrive = TEXT('A'); tDrive <= TEXT('Z'); tDrive++) { *lpEnd = tDrive; if ((!szComputerName) && (GetDriveType(szShareName) == DRIVE_REMOTE)) { DebugMsg((DM_VERBOSE, TEXT("DeleteProfile: Ignoring Drive %s because it is not local"), szShareName)); continue; } if (!GetVolumeInformation(szShareName, NULL, 0, NULL, &MaxCompLen, &FileSysFlags, szFileSystemName, MAX_PATH)) continue; if ((szFileSystemName) && (lstrcmp(szFileSystemName, TEXT("NTFS")) == 0)) { TCHAR szRecycleBin[MAX_PATH]; lstrcpy(szRecycleBin, szShareName); lstrcat(szRecycleBin, TEXT("Recycler\\")); lstrcat(szRecycleBin, lpSidString); Delnode(szRecycleBin); DebugMsg((DM_VERBOSE, TEXT("DeleteProfile: Deleting trash directory at %s"), szRecycleBin)); } } // // Queue for csc cleanup.. // if (RegOpenKeyEx(hKeyLocalLM, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\NetCache"), 0, KEY_WRITE, &hKeyNetCache) == ERROR_SUCCESS) { HKEY hKeyNextLogOff; if (RegCreateKey(hKeyNetCache, TEXT("PurgeAtNextLogoff"), &hKeyNextLogOff) == ERROR_SUCCESS) { if (RegSetValueEx(hKeyNextLogOff, lpSidString, 0, REG_SZ, (BYTE *)TEXT(""), sizeof(TCHAR)) == ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("DeleteProfile: Queued for csc cleanup at next logoff"))); } else { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Could not set the Sid Value under NextLogoff key"))); } RegCloseKey(hKeyNextLogOff); } else { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Could not create the PurgeAtNextLogoff key"))); } RegCloseKey(hKeyNetCache); } else { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Could not open the NetCache key"))); } // // Delete appmgmt specific stuff.. // if (!ExpandEnvironmentStrings(APPMGMT_DIR_ROOT, szBuffer, MAX_PATH)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to expand %s, error %d"), APPMGMT_DIR_ROOT, GetLastError())); goto Exit; } // // Delete the appmgmt directory // lpEnd = CheckSlash(szBuffer); lstrcpy(lpEnd, lpSidString); if (!Delnode(szBuffer)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to delete the appmgmt dir %s, error %d"), szBuffer, GetLastError())); } // // Reset the environment variables so that api's down the line // do not get confused // if (bEnvVarsSet) { SetEnvironmentVariable(TEXT("SystemRoot"), szOrigSysRoot); SetEnvironmentVariable(TEXT("SystemDrive"), szOrigSysDrive); bEnvVarsSet = FALSE; } // // Delete msi registry values // lstrcpy(szBuffer, APPMGMT_REG_MANAGED); lpEnd = CheckSlash(szBuffer); lstrcpy(lpEnd, lpSidString); if (!RegDelnode (hKeyLocalLM, szBuffer)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to delete the appmgmt key %s"), szBuffer)); } // // Delete rsop data // if (!RsopDeleteUserNameSpace((LPTSTR)szComputerName, (LPTSTR)lpSidString)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Failed to delete rsop data"))); } // // Clean Darwin information // hMsiLib = LoadLibrary(TEXT("msi.dll")); if (hMsiLib) { pfnMsiDeleteUserData = (PFNMSIDELETEUSERDATA) GetProcAddress(hMsiLib, #ifdef UNICODE "MsiDeleteUserDataW"); #else "MsiDeleteUserDataA"); #endif if (pfnMsiDeleteUserData) { (*pfnMsiDeleteUserData)(lpSidString, szComputerName, NULL); } else { DebugMsg((DM_WARNING, TEXT("DeleteProfile: GetProcAddress returned failure. error %d"), GetLastError())); } FreeLibrary(hMsiLib); } else { DebugMsg((DM_WARNING, TEXT("DeleteProfile: LoadLibrary returned failure. error %d"), GetLastError())); } Exit: if (hKey) RegCloseKey(hKey); if (bRemoteReg) { RegCloseKey(hKeyLocalLM); } if ( szNetComputerName ) LocalFree(szNetComputerName); if (bEnvVarsSet) { SetEnvironmentVariable(TEXT("SystemRoot"), szOrigSysRoot); SetEnvironmentVariable(TEXT("SystemDrive"), szOrigSysDrive); } SetLastError(dwErr); return bSuccess; } //************************************************************* // // SetNtUserIniAttributes() // // Purpose: Sets system-bit on ntuser.ini // // Parameters: // // Return: true if successful // // Comments: // // History: Date Author Comment // 7/7/99 ushaji Created // //************************************************************* BOOL SetNtUserIniAttributes(LPTSTR szDir) { TCHAR szBuffer[MAX_PATH]; HANDLE hFileNtUser; LPTSTR lpEnd; DWORD dwWritten; lstrcpy (szBuffer, szDir); lpEnd = CheckSlash (szBuffer); lstrcpy (lpEnd, c_szNTUserIni); // // Mark the file with system bit // hFileNtUser = CreateFile(szBuffer, GENERIC_ALL, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, NULL); if (INVALID_HANDLE_VALUE == hFileNtUser) SetFileAttributes (szBuffer, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); else { // // The WritePrivateProfile* functions do not write in unicode // unless the file already exists in unicode format. Therefore, // Precreate a unicode file so that // the WritePrivateProfile* functions can preserve the // Make sure that the ini file is unicode by writing spaces into it. // WriteFile(hFileNtUser, L"\xfeff\r\n", 3 * sizeof(WCHAR), &dwWritten, NULL); WriteFile(hFileNtUser, L" \r\n", 7 * sizeof(WCHAR), &dwWritten, NULL); CloseHandle(hFileNtUser); } return TRUE; } //************************************************************* // // CUserProfile::HandleRegKeyLeak // // Purpose: If registry key leaked, save the hive and call // WatchHiveRefCount to get the hive unloaded later // when the keys are released. // // Parameters: // // lpSidString User's sid in string form. // lpProfile User's LPPROFILE structure. // bUnloadHiveSucceeded Indicates that we should save the hive // to a temp file. // dwWatchHiveFlags (in, out) WHRC_ flags. // dwCopyTmpHive (out) CPD_ flag to indicate to // CopyProfileDirectory whether or not a temp // hive file should be used. // tszTmpHiveFile (out) The tmp hive file name. // privilege. // // Return: Error code to indicate if the hive is successfully saved to // a temp file. If yes, return ERROR_SUCCESS. Otherwise, return // an error code that indicates why. // // Comments: // // History: Date Author Comment // 5/31/00 weiruc Created // //************************************************************* DWORD CUserProfile::HandleRegKeyLeak(LPTSTR lpSidString, LPPROFILE lpProfile, BOOL bUnloadHiveSucceeded, DWORD* dwWatchHiveFlags, DWORD* dwCopyTmpHive, LPTSTR pTmpHiveFile) { HRESULT hres; HKEY hkCurrentUser = NULL; NTSTATUS status; BOOLEAN WasEnabled; DWORD dwErr = ERROR_SUCCESS; TCHAR szErr[MAX_PATH]; BOOL bAdjustPriv = FALSE; HANDLE hToken = NULL; LPTSTR lpUserName; if(!bUnloadHiveSucceeded) { // // Reopen the user hive. // if((dwErr = RegOpenKeyEx(HKEY_USERS, lpSidString, 0, KEY_ALL_ACCESS, &hkCurrentUser)) != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("HandleRegKeyLeak: RegOpenKeyEx failed with %08x"), dwErr)); if(dwErr == ERROR_FILE_NOT_FOUND) { // // If ERROR_FILE_NOT_FOUND, then the hive has been unloaded // between RegUnloadKey and here. Procceed without calling // WatchHiveRefCount. // DebugMsg((DM_VERBOSE, TEXT("HandleRegKeyLeak: Hive is already unloaded"))); *dwWatchHiveFlags &= ~WHRC_UNLOAD_HIVE; dwErr = ERROR_SUCCESS; } goto NOTIFY_REGISTRY; } // // Make the tmp hive file name: \ntuser.tmp // if(lstrlen(lpProfile->lpLocalProfile) + lstrlen(c_szNTUserTmp) + 2 > MAX_PATH) { // // If the tmp hive file name exceeds MAX_PATH give up. // dwErr = ERROR_BAD_PATHNAME; goto NOTIFY_REGISTRY; } lstrcpy(pTmpHiveFile, lpProfile->lpLocalProfile); lstrcat(pTmpHiveFile, TEXT("\\")); lstrcat(pTmpHiveFile, c_szNTUserTmp); // // Delete existing tmp file if any. // DeleteFile(pTmpHiveFile); // // Flush the hive. // RegFlushKey(hkCurrentUser); // // Check to see if we are impersonating. // if(!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &hToken) || hToken == NULL) { bAdjustPriv = TRUE; } else { CloseHandle(hToken); } if(bAdjustPriv) { status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &WasEnabled); if(!NT_SUCCESS(status)) { DebugMsg((DM_WARNING, TEXT("HandleRegKeyLeak: RtlAdjustPrivilege failed with error %08x"), status)); dwErr = ERROR_ACCESS_DENIED; goto NOTIFY_REGISTRY; } DebugMsg((DM_VERBOSE, TEXT("HandleRegKeyLeak: RtlAdjustPrivilege succeeded!"))); } // // Save the hive to the tmp file. // if((dwErr = RegSaveKey(hkCurrentUser, pTmpHiveFile, NULL)) != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("HandleRegKeyLeak: RegSaveKey failed with %08x"), dwErr)); if (!(lpProfile->dwFlags & PI_LITELOAD)) { // // Only write event log when not in liteload mode. // there are known problems with liteLoad loading because // of which eventlog can get full during stress // ReportError(NULL, PI_NOUI, 1, EVENT_FAILED_HIVE_UNLOAD, GetErrString(dwErr, szErr)); } DeleteFile(pTmpHiveFile); goto NOTIFY_REGISTRY; } // // Set the hidden attribute on the temp hive file, so that when it get copied in the // actual hive file it should not reset the hidden attribute // if (!SetFileAttributes(pTmpHiveFile, FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN)) { DebugMsg((DM_WARNING, TEXT("HandleRegKeyLeak: Failed to set the hidden attribute on temp hive file with error %d"), GetLastError())); } *dwCopyTmpHive = CPD_USETMPHIVEFILE; // // Log an event only if we schedule the hive for unloading. // If it is already scheduled for unloading (RegUnloadKey returns // ERROR_WRITE_PROTECT in that case) then do not give this message. // if (*dwWatchHiveFlags & WHRC_UNLOAD_HIVE) { lpUserName = GetUserNameFromSid(lpSidString); ReportError(NULL, PI_NOUI | EVENT_WARNING_TYPE, 1, EVENT_HIVE_SAVED, lpUserName); if (lpUserName != lpSidString) { LocalFree(lpUserName); } } DebugMsg((DM_VERBOSE, TEXT("HandleRegKeyLeak: RegSaveKey succeeded!"))); if(bAdjustPriv) { // // Restore the privilege. // status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, WasEnabled, FALSE, &WasEnabled); if (!NT_SUCCESS(status)) { DebugMsg((DM_WARNING, TEXT("HandleRegKeyLeak: Failed to restore RESTORE privilege to previous enabled state %08x"), status)); } else { DebugMsg((DM_VERBOSE, TEXT("HandleRegKeyLeak: RtlAdjustPrivilege succeeded!"))); } } } NOTIFY_REGISTRY: if(hkCurrentUser) { RegCloseKey(hkCurrentUser); DebugMsg((DM_VERBOSE, TEXT("HandleRegKeyLeak: hkCurrentUser closed"))); } if(*dwWatchHiveFlags) { // // Watch for the hive ref count. // if((hres = WatchHiveRefCount(lpSidString, *dwWatchHiveFlags)) != S_OK) { DebugMsg((DM_WARNING, TEXT("HandleRegKeyLeak: Calling WatchHiveRefCount failed. err = %08x"), hres)); } else { DebugMsg((DM_VERBOSE, TEXT("HandleRegKeyLeak: Calling WatchHiveRefCount (%s) succeeded"), lpSidString)); } } // // In UnloadUserProfile, Without this registry leak fix, the code // goes to Exit immediately // if unloading of the user's hive fails without doing any of the // stuff below. But with the fix, we'll fall through here and reconcile // the local and the central profiles. The code below also cleans up // local profiles, i.e., delete temp profiles, guest user profiles, // etc. We have 2 choices here: // 1. We can let the cleaning up happen, in which case files that // are not in use can be cleaned up. This would mean that the // next time when the user logs in, his/her profile will no // longer be loaded, even though his/her hive might still be // loaded. In other words, in TestIfUserProfileLoaded instead // of relying simply on testing whether or not the hive is still // loaded, we have to actually look at the ref count to tell if // a profile is still loaded. In this case the WHRC code will // only need to clean up those files that can not be cleaned up // here. // 2. Do not clean up here. The scenario will remain basically the // same. Next time when the user logs on, his/her profile will // still be loaded, so no change to TestIfUserProfileLoaded. The // WHRC code will handle the complete cleaning up. // We implemented choise #2 because it's easier in coding. In the // future consider using choice #1. // return dwErr; } //************************************************************* // // AllocAndExpandProfilePath() // // Purpose: Gets a few predetermined env variables in the profile path // expanded // // Parameters: // lpProfile // // Return: true if successful // // Comments: // // Tt gets the environment variables and keeps it locally. // //************************************************************* LPTSTR AllocAndExpandProfilePath( LPPROFILEINFO lpProfileInfo) { TCHAR szUserName[MAX_PATH]; DWORD dwPathLen=0, cFullPath=0; TCHAR szFullPath[MAX_PATH+1]; LPTSTR pszFullPath=NULL; szUserName[0] = TEXT('\0'); GetEnvironmentVariable (USERNAME_VARIABLE, szUserName, 100); SetEnvironmentVariable (USERNAME_VARIABLE, lpProfileInfo->lpUserName); // // Expand the profile path using current settings // cFullPath = ExpandEnvironmentStrings(lpProfileInfo->lpProfilePath, szFullPath, MAX_PATH); if (cFullPath) { pszFullPath = (LPTSTR)LocalAlloc(LPTR, (1+ cFullPath) * sizeof(TCHAR)); if (pszFullPath) { lstrcpyn( pszFullPath, szFullPath, cFullPath * sizeof(TCHAR)); } } else { pszFullPath = NULL; } // // restore the env block // if (szUserName[0] != TEXT('\0')) SetEnvironmentVariableW (USERNAME_VARIABLE, szUserName); else SetEnvironmentVariableW (USERNAME_VARIABLE, NULL); return(pszFullPath); } //************************************************************* // // MAP::MAP() // // Constructor for class MAP. // //************************************************************* MAP::MAP() { for(DWORD i = 0; i < MAXIMUM_WAIT_OBJECTS; i++) { rghEvents[i] = NULL; rgSids[i] = NULL; } dwItems = 0; pNext = NULL; } //************************************************************* // // MAP::Delete // // Delete an work item from a map. Switch the last item into the now // empty spot. Caller has to hold the critical section csMap. // // Parameters: // // dwIndex index into the work list // // Return value: // // None. // // History: // // Created weiruc 3/2/2000 // //************************************************************* void MAP::Delete(DWORD dwIndex) { // // Switch the last work item into the newly finished work item position. // if(rghEvents[dwIndex]) { CloseHandle(rghEvents[dwIndex]); rghEvents[dwIndex] = NULL; } if(rgSids[dwIndex]) { LocalFree(rgSids[dwIndex]); rgSids[dwIndex] = NULL; } if(dwIndex < dwItems - 1) { rghEvents[dwIndex] = rghEvents[dwItems - 1]; rgSids[dwIndex] = rgSids[dwItems - 1]; } rgSids[dwItems - 1] = NULL; rghEvents[dwItems - 1] = NULL; dwItems--; } //************************************************************* // // MAP::Insert // // Insert an work item into a map. Caller must hold csMap. // the items need to be added before the count is changed // because WorkerThreadMain accesses the map without holding // a lock. // // Parameters: // // HANDLE Event to be inserted. // LPTSTR Sid string to be inserted. // // Return value: // // None. // // History: // // Created weiruc 3/2/2000 // //************************************************************* void MAP::Insert(HANDLE hEvent, LPTSTR ptszSid) { rghEvents[dwItems] = hEvent; rgSids[dwItems] = ptszSid; dwItems++; } //************************************************************* // // MAP::GetSid // // Get a sid by the index; Caller has to hold csMap. // // Parameters: // // dwIndex index // // Return value: // // The sid. // // History: // // Created weiruc 3/2/2000 // //************************************************************* LPTSTR MAP::GetSid(DWORD dwIndex) { LPTSTR ptszTmpSid = rgSids[dwIndex]; rgSids[dwIndex] = NULL; return ptszTmpSid; } //************************************************************* // // CHashTable::CHashTable // // CHashTable class initializer. // // Parameters: // // Return value: // // None. // // History: // // Created weiruc 3/2/2000 // //************************************************************* void CHashTable::Initialize() { for(DWORD i = 0; i < NUM_OF_BUCKETS; i++) { Table[i] = NULL; } } //************************************************************* // // CHashTable::Hash // // Hash a string. // // Parameters: // // pctszString the string to be hashed // // Return value: // // Hash value. // // History: // // Created weiruc 3/2/2000 // //************************************************************* DWORD CHashTable::Hash(LPTSTR ptszString) { DWORD dwHashValue = 0; TCHAR* ptch = ptszString; while(*ptch != TEXT('\0')) { dwHashValue += *ptch; ptch++; } return dwHashValue % NUM_OF_BUCKETS; } //************************************************************* // // CHashTable::IsInTable // // Check to see if a string is already in this hash table. This function // is not thread safe. Caller must ensure thread safety when calling this // function from multiple threads. // // Parameters: // // ptszString the string to be checked. // ppCSEntry buffer for the pointer to the CSEntry stored. // // Return value: // // TRUE/FALSE // // History: // // Created weiruc 5/25/2000 // //************************************************************* BOOL CHashTable::IsInTable(LPTSTR ptszString, CSEntry** ppCSEntry) { DWORD dwHashValue = Hash(ptszString); PBUCKET pbucket; PBUCKET pTmp; // // Check to see if ptszString is already in the hash table. // for(pTmp = Table[dwHashValue]; pTmp != NULL; pTmp = pTmp->pNext) { if(lstrcmp(pTmp->ptszString, ptszString) == 0) { if (ppCSEntry) { *ppCSEntry = pTmp->pEntry; } return TRUE; } } return FALSE; } //************************************************************* // // CHashTable::HashAdd // // Add a string into the hash table. This function doesn't check to see // if the string is already in the table. The caller is responsible for // calling IsInTable before calling this function. This function // is not thread safe. Caller must ensure thread safety when calling this // function from multiple threads. // // Parameters: // // ptszString the string to be added. // pCSEntry the CS entry to be added // // Return value: // // TRUE/FALSE indicating success/failure. The function will fail if // the item is already in the hash table, or if we are out of memory. // // History: // // Created weiruc 3/2/2000 // //************************************************************* BOOL CHashTable::HashAdd(LPTSTR ptszString, CSEntry* pCSEntry) { DWORD dwHashValue = Hash(ptszString); PBUCKET pbucket; PBUCKET pTmp; pbucket = new BUCKET(ptszString, pCSEntry); if(pbucket == NULL) { DebugMsg((DM_WARNING, TEXT("Can't insert %s. Out of memory"), ptszString)); return FALSE; } pbucket->pNext = Table[dwHashValue]; Table[dwHashValue] = pbucket; DebugMsg((DM_VERBOSE, TEXT("CHashTable::HashAdd: %s added in bucket %d"), ptszString, dwHashValue)); return TRUE; } //************************************************************* // // CHashTable::HashDelete // // Delete a string from the hash table. This function // is not thread safe. Caller must ensure thread safety when calling this // function from multiple threads. // // Parameters: // // ptszString the string to be deleted. // // Return value: // // none. // // History: // // Created weiruc 3/2/2000 // //************************************************************* void CHashTable::HashDelete(LPTSTR ptszString) { PBUCKET pPrev, pCur; DWORD dwHashValue = Hash(ptszString); if(Table[dwHashValue] == NULL) { return; } pCur = Table[dwHashValue]; if(lstrcmp(pCur->ptszString, ptszString) == 0) { Table[dwHashValue] = Table[dwHashValue]->pNext; pCur->pNext = NULL; delete pCur; DebugMsg((DM_VERBOSE, TEXT("CHashTable::HashDelete: %s deleted"), ptszString)); return; } for(pPrev = Table[dwHashValue], pCur = pPrev->pNext; pCur != NULL; pPrev = pCur, pCur = pCur->pNext) { if(lstrcmp(pCur->ptszString, ptszString) == 0) { pPrev->pNext = pCur->pNext; pCur->pNext = NULL; DebugMsg((DM_VERBOSE, TEXT("CHashTable::HashDelete: %s deleted"), ptszString)); delete pCur; return; } } } //************************************************************* // // Called by and only by console winlogon process. // //************************************************************* void WINAPI InitializeUserProfile() { cUserProfileManager.Initialize(); } //************************************************************* // // Called by CreateThread // //************************************************************* DWORD ThreadMain(PMAP pThreadMap) { return cUserProfileManager.WorkerThreadMain(pThreadMap); } //************************************************************* // // CSyncManager::Initialize() // // Initialize the critical section that protects the CS // entries list and the hash table. // // Parameters: // // void // // Return value: // // TRUE/FALSE to indicate if initialization succeeded or failed. // // History: // // 6/16/00 weiruc Created // //************************************************************* BOOL CSyncManager::Initialize() { BOOL bRet = TRUE; cTable.Initialize(); // // Initialize the critical section that protects the cs entry list. // __try { if(!InitializeCriticalSectionAndSpinCount(&cs, 0x80000000)) { DebugMsg((DM_WARNING, TEXT("CSyncManager::Initialize: InitializeCriticalSectionAndSpinCount failed with %08x"), GetLastError())); bRet = FALSE; } DebugMsg((DM_VERBOSE, TEXT("CSyncManager::Initialize: critical section initialized"))); } __except(EXCEPTION_EXECUTE_HANDLER) { DebugMsg((DM_WARNING, TEXT("CSyncManager::Initialize: InitializeCriticalSection failed"))); bRet = FALSE; } return bRet; } //************************************************************* // // CSyncManager::EnterLock() // // Get a user's profile lock. // // Parameters: // // pSid - User's sid string // // Return value: // // TRUE/FALSE. GetLastError to get error. // // History: // // 6/16/00 weiruc Created // //************************************************************* BOOL CSyncManager::EnterLock(LPTSTR pSid, LPTSTR lpRPCEndPoint) { DWORD dwError = ERROR_SUCCESS; CSEntry* pEntry = NULL; DebugMsg((DM_VERBOSE, TEXT("CSyncManager::EnterLock <%s>"), pSid)); EnterCriticalSection(&cs); // // Look up entry in the hash table. // if(cTable.IsInTable(pSid, &pEntry)) { DebugMsg((DM_VERBOSE, TEXT("CSyncManager::EnterLock: Found existing entry"))); } else { DebugMsg((DM_VERBOSE, TEXT("CSyncManager::EnterLock: No existing entry found"))); pEntry = new CSEntry; if(!pEntry) { dwError = ERROR_OUTOFMEMORY; DebugMsg((DM_WARNING, TEXT("CSyncManager::EnterLock: Can't create new CSEntry %08x"), dwError)); goto Exit; } if(!pEntry->Initialize(pSid)) { dwError = GetLastError(); DebugMsg((DM_WARNING, TEXT("CSyncManager::EnterLock: Can not initialize new entry %08x"), dwError)); goto Exit; } DebugMsg((DM_VERBOSE, TEXT("CSyncManager::EnterLock: New entry created"))); // // Insert the new entry in the list. // pEntry->pNext = pCSList; pCSList = pEntry; // // Add the new entry into the hash table. // cTable.HashAdd(pEntry->pSid, pEntry); } pEntry->IncrementRefCount(); LeaveCriticalSection(&cs); pEntry->EnterCS(); pEntry->SetRPCEndPoint(lpRPCEndPoint); return TRUE; Exit: LeaveCriticalSection(&cs); if(pEntry) { delete pEntry; } SetLastError(dwError); return FALSE; } //************************************************************* // // CSyncManager::LeaveLock() // // Release a user's profile lock // // Parameters: // // pSid - The user's sid string // // Return value: // // TRUE/FALSE // // History: // // 6/16/00 weiruc Created // //************************************************************* BOOL CSyncManager::LeaveLock(LPTSTR pSid) { BOOL bRet = FALSE; DWORD dwError = ERROR_SUCCESS; CSEntry* pPrev; CSEntry* pCur; CSEntry* pToBeDeleted; DebugMsg((DM_VERBOSE, TEXT("CSyncManager::LeaveLock <%s>"), pSid)); EnterCriticalSection(&cs); // // Look up the critical section entry. // if(!cTable.IsInTable(pSid, &pCur)) { DebugMsg((DM_WARNING, TEXT("CSyncManager::LeaveLock: User not found!!!!"))); dwError = ERROR_NOT_FOUND; goto Exit; } pCur->LeaveCS(); bRet = TRUE; DebugMsg((DM_VERBOSE, TEXT("CSyncManager::LeaveLock: Lock released"))); // // If there's more user waiting for this lock, return. // if(!pCur->NoMoreUser()) { goto Exit; } // // Nobody is waiting on this lock anymore, delete it from the hash table. // cTable.HashDelete(pSid); // // Delete from the cs list. // pToBeDeleted = pCur; if(pCur == pCSList) { // // Entry is the first one in the list. // pCSList = pCSList->pNext; pCur->Uninitialize(); delete pCur; DebugMsg((DM_VERBOSE, TEXT("CSyncManager::LeaveLock: Lock deleted"))); } else { for(pPrev = pCSList, pCur = pCSList->pNext; pCur; pPrev = pCur, pCur = pCur->pNext) { if(pCur == pToBeDeleted) { pPrev->pNext = pCur->pNext; pCur->Uninitialize(); delete pCur; DebugMsg((DM_VERBOSE, TEXT("CSyncManager::DestroyCSEntry: Entry deleted"))); goto Exit; } } } Exit: LeaveCriticalSection(&cs); SetLastError(dwError); return bRet; } //************************************************************* // // CSyncManager::GetRPCEndPoint() // // Purpose: returns the RPCEndPoint registered by client // // Parameters: // // pSid - User's sid string // // Return: // // LPTSTR // // Comments: // // History: Date Author Comment // 10/25/00 santanuc Created // //************************************************************* LPTSTR CSyncManager::GetRPCEndPoint(LPTSTR pSid) { CSEntry* pEntry = NULL; LPTSTR lpRPCEndPoint; EnterCriticalSection(&cs); // // Look up entry in the hash table. // if(cTable.IsInTable(pSid, &pEntry)) { lpRPCEndPoint = pEntry->GetRPCEndPoint(); } else { lpRPCEndPoint = NULL; } LeaveCriticalSection(&cs); return lpRPCEndPoint; } //************************************************************* // // CSEntry::Initialize() // // Initialize the user's critical section. This function can // only be called by the sync manager. // // Parameters: // // pSid - The user's sid string // // Return value: // // TRUE/FALSE // // History: // // 6/16/00 weiruc Created // //************************************************************* BOOL CSEntry::Initialize(LPTSTR pSidParam) { BOOL bRet = FALSE; DWORD dwError = ERROR_SUCCESS; pSid = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pSidParam) + 1) * sizeof(TCHAR)); if(!pSid) { dwError = GetLastError(); DebugMsg((DM_WARNING, TEXT("CSEntry::Initialize: LocalAlloc failed with %08x"), dwError)); goto Exit; } lstrcpy(pSid, pSidParam); __try { if(!InitializeCriticalSectionAndSpinCount(&csUser, 0x80000000)) { dwError = GetLastError(); DebugMsg((DM_WARNING, TEXT("CSEntry::Initialize: InitializeCriticalSectionAndSpinCount failed with %08x"), dwError)); } else { bRet = TRUE; } } __except(EXCEPTION_EXECUTE_HANDLER) { dwError = GetExceptionCode(); DebugMsg((DM_WARNING, TEXT("CSEntry::Initialize: InitializeCriticalSectionAndSpinCount exception %08x"), dwError)); } Exit: SetLastError(dwError); return bRet; } //************************************************************* // // CSEntry::Uninitialize() // // Delete the user's critical section. This function can // only be called by the sync manager. // // Parameters: // // void. // // Return value: // // void // // History: // // 6/16/00 weiruc Created // //************************************************************* void CSEntry::Uninitialize() { DeleteCriticalSection(&csUser); if (pSid) { LocalFree(pSid); } } //************************************************************* // // CSEntry::EnterCS() // // Enter a user's critical section // // Parameters: // // void. // // Return value: // // void // // History: // // 6/16/00 weiruc Created // //************************************************************* void CSEntry::EnterCS() { EnterCriticalSection(&csUser); } //************************************************************* // // CSEntry::LeaveCS() // // Leave a user's critical section // // Parameters: // // void. // // Return value: // // void // // History: // // 6/16/00 weiruc Created // //************************************************************* void CSEntry::LeaveCS() { dwRef--; LeaveCriticalSection(&csUser); } //************************************************************* // // CSEntry::NoMoreUser() // // Are there more users? // // Parameters: // // void // // Return value: // // TRUE/FALSE // // History: // // 6/16/00 weiruc Created // //************************************************************* BOOL CSEntry::NoMoreUser() { return dwRef == 0; } //************************************************************* // // CSEntry::IncrementRefCount() // // Increment the reference count. // // Parameters: // // void // // Return value: // // void // // History: // // 8/24/00 santanuc Created // //************************************************************* void CSEntry::IncrementRefCount() { dwRef++; } //************************************************************* // // CSEntry::SetRPCEndPoint() // // Store the RPCEndPoint. Memory freed by the ~CSEntry // // Parameters: // // lpRPCEndPoint // // Return value: // // void // // History: // // 8/24/00 santanuc Created // //************************************************************* void CSEntry::SetRPCEndPoint(LPTSTR lpRPCEndPoint) { if (lpRPCEndPoint) { szRPCEndPoint = (LPTSTR)LocalAlloc(LPTR, (lstrlen(lpRPCEndPoint)+1)*sizeof(TCHAR)); if (szRPCEndPoint) { lstrcpy(szRPCEndPoint, lpRPCEndPoint); } } } //************************************************************* // // EnterUserProfileLock() // // Get the user profile lock for a user // // Parameters: // // pSid - The user's sid string // // Return value: // // HRESULT // // History: // // 6/16/00 weiruc Created // //************************************************************* DWORD WINAPI EnterUserProfileLock(LPTSTR pSid) { CSEntry* pEntry = NULL; DWORD dwErr = ERROR_ACCESS_DENIED; handle_t hIfUserProfile; BOOL bBindInterface = FALSE; if(cUserProfileManager.IsConsoleWinlogon()) { if(!cUserProfileManager.EnterUserProfileLockLocal(pSid)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("EnterUserProfileLock: GetUserProfileMutex returned %d"), dwErr)); goto Exit; } } else { if (!GetInterface(&hIfUserProfile, cszRPCEndPoint)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("EnterUserProfileLock: GetInterface returned %d"), dwErr)); goto Exit; } bBindInterface = TRUE; RpcTryExcept { dwErr = cliEnterUserProfileLockRemote(hIfUserProfile, pSid); } RpcExcept(1) { dwErr = RpcExceptionCode(); DebugMsg((DM_WARNING, TEXT("EnterUserProfileLock: EnterUserProfileLockRemote took exception error %d"), dwErr)); } RpcEndExcept if (dwErr != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("EnterUserProfileLock: EnterUserProfileLockRemote returned error %d"), dwErr)); goto Exit; } } dwErr = ERROR_SUCCESS; Exit: if (bBindInterface) { if (!ReleaseInterface(&hIfUserProfile)) { DebugMsg((DM_WARNING, TEXT("EnterUserProfileLock: ReleaseInterface failed."))); } } // // Return. // SetLastError(dwErr); return dwErr; } //************************************************************* // // LeaveUserProfileLock() // // Leave the user profile lock // // Parameters: // // pSid - The user's sid string // // Return value: // // HRESULT // // History: // // 6/16/00 weiruc Created // //************************************************************* DWORD WINAPI LeaveUserProfileLock(LPTSTR pSid) { CSEntry* pEntry = NULL; DWORD dwErr = ERROR_ACCESS_DENIED; handle_t hIfUserProfile; BOOL bBindInterface = FALSE; if(cUserProfileManager.IsConsoleWinlogon()) { cUserProfileManager.LeaveUserProfileLockLocal(pSid); } else { if (!GetInterface(&hIfUserProfile, cszRPCEndPoint)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("LeaveUserProfileLock: GetInterface returned %d"), dwErr)); goto Exit; } bBindInterface = TRUE; RpcTryExcept { dwErr = cliLeaveUserProfileLockRemote(hIfUserProfile, pSid); } RpcExcept(1) { dwErr = RpcExceptionCode(); DebugMsg((DM_WARNING, TEXT("LeaveUserProfileLock: LeaveUserProfileLockRemote took exception error %d"), dwErr)); } RpcEndExcept if (dwErr != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LeaveUserProfileLock: LeaveUserProfileLockRemote returned error %d"), dwErr)); goto Exit; } } dwErr = ERROR_SUCCESS; Exit: if (bBindInterface) { if (!ReleaseInterface(&hIfUserProfile)) { DebugMsg((DM_WARNING, TEXT("LeaveUserProfileLock: ReleaseInterface failed."))); } } // // Return. // SetLastError(dwErr); return dwErr; } //************************************************************* // // IsProfileInUse() // // Purpose: Determines if the given profile is currently in use // // Parameters: szComputer - Name of the machine // lpSid - Sid (text) to test // // Return: TRUE if in use // FALSE if not // // Comments: // // History: Date Author Comment // 8/28/00 santanuc Created // //************************************************************* BOOL IsProfileInUse (LPCTSTR szComputer, LPCTSTR lpSid) { LONG lResult; HKEY hKeyUsers, hKeyProfile; BOOL bRemoteReg = FALSE; BOOL bRetVal = FALSE; if (szComputer) { lResult = RegConnectRegistry(szComputer, HKEY_USERS, &hKeyUsers); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("IsProfileInUse: Failed to open remote registry %d"), lResult)); return TRUE; } bRemoteReg = TRUE; } else { hKeyUsers = HKEY_USERS; } if (RegOpenKeyEx (hKeyUsers, lpSid, 0, KEY_READ, &hKeyProfile) == ERROR_SUCCESS) { RegCloseKey (hKeyProfile); bRetVal = TRUE; } else { LPTSTR lpSidClasses; lpSidClasses = (LPTSTR)LocalAlloc(LPTR, (lstrlen(lpSid)+lstrlen(TEXT("_Classes"))+1)*sizeof(TCHAR)); if (lpSidClasses) { lstrcpy(lpSidClasses, lpSid); lstrcat(lpSidClasses, TEXT("_Classes")); if (RegOpenKeyEx (hKeyUsers, lpSidClasses, 0, KEY_READ, &hKeyProfile) == ERROR_SUCCESS) { RegCloseKey (hKeyProfile); bRetVal = TRUE; } LocalFree(lpSidClasses); } } if (bRemoteReg) { RegCloseKey(hKeyUsers); } return bRetVal; } //************************************************************* // // IsUIRequired() // // Purpose: Determines if the profile error message requires // If the ref count is > 1 then we do not required // error reporting. If ref count is 1 then we check // // // Parameters: hToken - User's token // // Return: TRUE if error message req // FALSE if not // // Comments: // // History: Date Author Comment // 10/27/00 santanuc Created // //************************************************************* BOOL IsUIRequired(HANDLE hToken) { LPTSTR lpSidString = GetSidString(hToken); BOOL bRetVal = FALSE; TCHAR szBuffer[MAX_PATH]; LPTSTR lpEnd; HKEY hKeyProfile; DWORD dwType, dwFlags, dwRef, dwSize; if (lpSidString) { lstrcpy(szBuffer, PROFILE_LIST_PATH); lpEnd = CheckSlash (szBuffer); lstrcpy(lpEnd, lpSidString); if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, szBuffer, 0, KEY_READ, &hKeyProfile) == ERROR_SUCCESS) { dwSize = sizeof(DWORD); if (RegQueryValueEx (hKeyProfile, PROFILE_REF_COUNT, NULL, &dwType, (LPBYTE) &dwRef, &dwSize) == ERROR_SUCCESS) { if (dwRef == 1) { dwSize = sizeof(DWORD); if (RegQueryValueEx (hKeyProfile, PROFILE_FLAGS, NULL, &dwType, (LPBYTE) &dwFlags, &dwSize) == ERROR_SUCCESS) { if (!(dwFlags & (PI_NOUI | PI_LITELOAD))) { bRetVal = TRUE; } } else { DebugMsg((DM_WARNING, TEXT("IsUIRequired: Failed to query value for flags."))); } } } else { DebugMsg((DM_WARNING, TEXT("IsUIRequired: Failed to query value for ref count."))); } RegCloseKey(hKeyProfile); } else { DebugMsg((DM_WARNING, TEXT("IsUIRequired: Failed to open key %s"), szBuffer)); } DeleteSidString(lpSidString); } return bRetVal; } //************************************************************* // // CheckRUPShare() // // Purpose: Determines if the RUP share is CSCed, if it is // then issue an event log warning. // // Parameters: lpProfilePath - User's roaming profile path // // Return: None // // Comments: // //************************************************************* void CheckRUPShare(LPTSTR lpProfilePath) { LPTSTR lpServer, lpShare, lpCopy; PSHARE_INFO_1005 pBufPtr1, pBufPtr2; BOOL bIssueWarning = FALSE; if (!lpProfilePath || !IsUNCPath(lpProfilePath)) { return; } lpCopy = (LPTSTR)LocalAlloc(LPTR, (lstrlen(lpProfilePath)+1) * sizeof(TCHAR)); if (!lpCopy) { DebugMsg((DM_WARNING, TEXT("CheckRUPShare: Failed to allocate memory"))); return; } lstrcpy(lpCopy, lpProfilePath); ConvertToShareName(lpCopy); lpServer = lpCopy; lpShare = lpCopy+2; // Skip initial two slashes while (*lpShare != TCHAR('\\') && *lpShare != TCHAR('\0')) lpShare++; if (*lpShare == TCHAR('\\')) { *lpShare = TCHAR('\0'); lpShare++; if (NetShareGetInfo(lpServer, lpShare, 1005, (LPBYTE *)&pBufPtr1) == ERROR_SUCCESS) { if ((pBufPtr1->shi1005_flags & CSC_MASK) == CSC_CACHE_NONE) { bIssueWarning = FALSE; } else if (pBufPtr1->shi1005_flags & SHI1005_FLAGS_DFS_ROOT) { // // If share is DFS root then we need to check the DfsLink to see // whether csc is disabled on it // // Construct the dfs link lstrcpy(lpCopy, lpProfilePath); int iDfsLink = 0; lpServer = lpCopy; lpShare = lpCopy+2; // Skip initial two slashes while ((iDfsLink < 3) && *lpShare != TCHAR('\0')) { if (*lpShare == TCHAR('\\')) { iDfsLink++; } lpShare++; } if (*lpShare != TCHAR('\0')) { *(lpShare-1) = TCHAR('\0'); } if (iDfsLink >= 2) { PDFS_INFO_3 pDfsBuf; // Query for the actual server and share if (NetDfsGetInfo(lpServer, NULL, NULL, 3, (LPBYTE *)&pDfsBuf) == NERR_Success) { if (pDfsBuf->NumberOfStorages >= 1) { lpServer = (LPTSTR)LocalAlloc(LPTR, (lstrlen(pDfsBuf->Storage->ServerName)+3) * sizeof(WCHAR)); if (!lpServer) { DebugMsg((DM_WARNING, TEXT("CheckRUPShare: Failed to allocate memory"))); goto Exit; } lstrcpy(lpServer, TEXT("\\\\")); lstrcat(lpServer, pDfsBuf->Storage->ServerName); // Get csc information from actual server and share if (NetShareGetInfo(lpServer, pDfsBuf->Storage->ShareName, 1005, (LPBYTE *)&pBufPtr2) == ERROR_SUCCESS) { if ((pBufPtr2->shi1005_flags & CSC_MASK) == CSC_CACHE_NONE) { bIssueWarning = FALSE; } else { bIssueWarning = TRUE; } NetApiBufferFree(pBufPtr2); } LocalFree(lpServer); } NetApiBufferFree(pDfsBuf); } } } else { bIssueWarning = TRUE; } NetApiBufferFree(pBufPtr1); if (bIssueWarning) { ReportError(NULL, PI_NOUI | EVENT_WARNING_TYPE, 0, EVENT_CSC_ON_PROFILE_SHARE); } } } Exit: LocalFree(lpCopy); } //************************************************************* // // IsPartialRoamingProfile() // // Purpose: determines if roaming profile contains a partial // copy or not. This is indicated by setting a flag // in ntuser.ini. // // Parameters: lpProfile - User's profile // // Return: TRUE : If Roaming profile contains a Partial // profile due to LITE_LOAD unload. // FALSE: otherwise. // // Comments: // //************************************************************* BOOL IsPartialRoamingProfile(LPPROFILE lpProfile) { TCHAR szLastUploadState[20]; LPTSTR szNTUserIni = NULL; LPTSTR lpEnd; BOOL bRetVal = FALSE; // // Allocate memory for Local variables to avoid stack overflow // szNTUserIni = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szNTUserIni) { DebugMsg((DM_WARNING, TEXT("IsPartialRoamingProfile: Out of memory"))); goto Exit; } lstrcpy (szNTUserIni, lpProfile->lpRoamingProfile); lpEnd = CheckSlash (szNTUserIni); lstrcpy (lpEnd, c_szNTUserIni); GetPrivateProfileString (PROFILE_LOAD_TYPE, PROFILE_LAST_UPLOAD_STATE, COMPLETE_PROFILE, szLastUploadState, ARRAYSIZE(szLastUploadState), szNTUserIni); if (lstrcmpi(szLastUploadState, PARTIAL_PROFILE) == 0) { bRetVal = TRUE; } Exit: if (szNTUserIni) LocalFree(szNTUserIni); return bRetVal; } //************************************************************* // // TouchLocalHive() // // Purpose: Check whether in local machine user profile is // switching from local to roaming for first time. If // yes and we have a existing hive in RUP share then // always overwrite the local hive with hive in RUP // share. This is to avoid wrong hive usage due to // cached login. // // // Parameters: lpProfile - User's profile // // Return: None // // Comments: // //************************************************************* void TouchLocalHive(LPPROFILE lpProfile) { LPTSTR szBuffer = NULL, lpEnd; LPTSTR SidString = NULL; HKEY hKey = NULL; HANDLE hFile = NULL; DWORD dwSize, dwType; LONG lResult; const LONGLONG datetime1980 = 0x01A8E79FE1D58000; // 1/1/80, origin of DOS datetime union { FILETIME ft; LONGLONG datetime; }; if ((lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL) || (lpProfile->dwInternalFlags & PROFILE_MANDATORY)) { goto Exit; } // // Set the time to base // datetime = datetime1980; // // Allocate local buffer // szBuffer = (LPTSTR) LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); if (!szBuffer) { DebugMsg((DM_WARNING, TEXT("TouchLocalHive: Out of memory"))); goto Exit; } // // Get the Sid string for the user // SidString = GetSidString(lpProfile->hTokenUser); if (!SidString) { DebugMsg((DM_WARNING, TEXT("TouchLocalHive: Failed to get sid string for user"))); goto Exit; } // // Open the profile mapping // lstrcpy(szBuffer, PROFILE_LIST_PATH); lpEnd = CheckSlash (szBuffer); lstrcpy(lpEnd, SidString); lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuffer, 0, KEY_READ, &hKey); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("TouchLocalHive: Failed to open profile mapping key with error %d"), lResult)); goto Exit; } // // Query for the central profile path // dwSize = MAX_PATH * sizeof(TCHAR); lResult = RegQueryValueEx (hKey, PROFILE_CENTRAL_PROFILE, NULL, &dwType, (LPBYTE) szBuffer, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("TouchLocalHive: Failed to query central profile with error %d"), lResult)); goto Exit; } if (szBuffer[0] == TEXT('\0')) { // // So we are switching from local to roaming profile for first time // // // Make sure we don't overrun our temporary buffer // if ((lstrlen(lpProfile->lpLocalProfile) + 1 + lstrlen(c_szNTUserDat) + 1) > MAX_PATH) { DebugMsg((DM_VERBOSE, TEXT("TouchLocalHive: Failed because temporary buffer is too small."))); goto Exit; } // // Copy the local profile path to a temporary buffer // we can munge it. // lstrcpy (szBuffer, lpProfile->lpLocalProfile); // // Add the slash if appropriate and then tack on // ntuser.dat. // lpEnd = CheckSlash(szBuffer); lstrcpy(lpEnd, c_szNTUserDat); // // See if this file exists // DebugMsg((DM_VERBOSE, TEXT("TouchLocalHive: Testing <%s>"), szBuffer)); hFile = CreateFile(szBuffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("TouchLocalHive: Found a user hive."))); // // Set the local hive time to base i.e 1/1/1980, so that RUP hive // overwrites this hive during profile merge // if (SetFileTime(hFile, NULL, NULL, &ft)) { DebugMsg((DM_VERBOSE, TEXT("TouchLocalHive: Touched user hive."))); } else { DebugMsg((DM_WARNING, TEXT("TouchLocalHive: Fail to touch user hive."))); } CloseHandle(hFile); } } Exit: if (szBuffer) { LocalFree(szBuffer); } if (SidString) { DeleteSidString(SidString); } if (hKey) { RegCloseKey(hKey); } } //************************************************************* // // RegisterDialogInterface() // // Purpose: Registers IProfileDialog interface // // Parameters: szRPCEndPoint - RPCEndPoint name // // Return: TRUE if successfully registered // FALSE if not // // Comments: // // History: Date Author Comment // 10/27/00 santanuc Created // //************************************************************* BOOL RegisterDialogInterface(LPTSTR szRPCEndPoint) { RPC_STATUS status = RPC_S_OK; // // Specify to use the local rpc protocol sequence // status = RpcServerUseProtseqEp(cszRPCProtocol, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, szRPCEndPoint, NULL); // Security descriptor if (status != RPC_S_OK && status != RPC_S_DUPLICATE_ENDPOINT) { DebugMsg((DM_WARNING, TEXT("RegisterErrorDialogInterface: RpcServerUseProtseqEp fails with error %ld"), status)); goto Exit; } // // Register the IUserProfile interface // status = RpcServerRegisterIfEx(IProfileDialog_v1_0_s_ifspec, // interface to register NULL, // MgrTypeUuid NULL, // MgrEpv; null means use default RPC_IF_AUTOLISTEN, // auto-listen interface RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // max concurrent calls NULL); // no callback if (status != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("RegisterErrorDialogInterface: RpcServerRegisterIfEx fails with error %ld"), status)); } Exit: return (status == RPC_S_OK); } //************************************************************* // // UnRegisterDialogInterface() // // Purpose: UnRegisters IProfileDialog interface // // Parameters: // // Return: TRUE if successfully unregistered // FALSE if not // // Comments: // // History: Date Author Comment // 10/27/00 santanuc Created // //************************************************************* BOOL UnRegisterDialogInterface(void) { RPC_STATUS status = RPC_S_OK; // unregister the server endpoint status = RpcServerUnregisterIf(IProfileDialog_v1_0_s_ifspec, NULL, TRUE); if (status != RPC_S_OK) { DebugMsg((DM_WARNING, TEXT("UnRegisterErrorDialogInterface: RpcServerUnregisterIf fails with error %ld"), status)); } return (status == RPC_S_OK); } //************************************************************* // // ErrorDialog() // // Purpose: ErrorDialog api of IProfileDialog interface // Display error message on client's desktop // // Parameters: // // Return: void // // Comments: // // History: Date Author Comment // 10/27/00 santanuc Created // //************************************************************* void ErrorDialog(IN PRPC_ASYNC_STATE pAsync, IN handle_t hBindHandle, IN DWORD dwTimeOut, IN LPTSTR lpErrMsg) { DWORD dwRetVal = ERROR_SUCCESS; ErrorDialogEx(dwTimeOut, lpErrMsg); RpcAsyncCompleteCall(pAsync, (PVOID)&dwRetVal); } //************************************************************* // // SlowLinkDialog() // // Purpose: SlowLinkDialog api of IProfileDialog interface // Display SlowLink message on client's desktop // // Parameters: // // Return: void // // Comments: // // History: Date Author Comment // 10/27/00 santanuc Created // //************************************************************* void SlowLinkDialog(IN PRPC_ASYNC_STATE pAsync, IN handle_t hBindHandle, IN DWORD dwTimeOut, IN BOOL bDefault, OUT BOOL *bpResponse, IN BOOL bDlgLogin) { SLOWLINKDLGINFO info; DWORD dwRetVal = ERROR_SUCCESS; info.dwTimeout = dwTimeOut; info.bSyncDefault = bDefault; DebugMsg((DM_VERBOSE, TEXT("SlowLinkDialog: Calling DialogBoxParam"))); if (bDlgLogin) { *bpResponse = (BOOL)DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_LOGIN_SLOW_LINK), NULL, LoginSlowLinkDlgProc, (LPARAM)&info); } else { *bpResponse = (BOOL)DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_LOGOFF_SLOW_LINK), NULL, LogoffSlowLinkDlgProc, (LPARAM)&info); } RpcAsyncCompleteCall(pAsync, (PVOID)&dwRetVal); } // // RPC routines // void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t count) { DebugMsg((DM_VERBOSE, TEXT("MIDL_user_allocate enter"))); return(malloc(count)); } void __RPC_USER MIDL_user_free(void __RPC_FAR * p) { DebugMsg((DM_VERBOSE, TEXT("MIDL_user_free enter"))); free(p); } void __RPC_USER PCONTEXT_HANDLE_rundown (PCONTEXT_HANDLE phContext) { DebugMsg((DM_VERBOSE, TEXT("PCONTEXT_HANDLE_rundown : Client died with open context"))); ReleaseClientContext_s(&phContext); } //****************************************************************************** // // CheckRoamingShareOwnership() // // Purpose: Check the ownership of the roaming user's profile on the server. // If the owner is not the user or not an admin, this function will // fail, and an error message will be issued. Administrator can set // a policy "CompatibleRUPSecurity" to disable this check. // // Parameters: // lpDir - profile directory on the server // hTokenUser - user's token // // Return: S_OK on success, else for failure // // Comments: // // History: Date Author Comment // 03/21/2002 mingzhu Created // //****************************************************************************** HRESULT CheckRoamingShareOwnership(LPTSTR lpDir, HANDLE hTokenUser) { HRESULT hr = E_FAIL; BOOL bDisableCheck = FALSE; HKEY hSubKey = NULL; DWORD dwRegValue; DWORD dwSize; DWORD dwType; DWORD cbSD; BOOL bDefaultOwner; DWORD dwErr; PSID pSidAdmin = NULL; PSID pSidUser = NULL; PSID pSidOwner = NULL; PSECURITY_DESCRIPTOR psd = NULL; SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; // // Output a debug message for entering the function. // DebugMsg((DM_VERBOSE, TEXT("CheckRoamingShareOwnership: checking ownership for %s"), lpDir)); // // Check for the policy to see if this check has been disabled // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) { dwSize = sizeof(dwRegValue); if (RegQueryValueEx(hSubKey, TEXT("CompatibleRUPSecurity"), NULL, &dwType, (LPBYTE) &dwRegValue, &dwSize) == ERROR_SUCCESS) { bDisableCheck = (BOOL)(dwRegValue); } RegCloseKey(hSubKey); } if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) { dwSize = sizeof(dwRegValue); if (RegQueryValueEx(hSubKey, TEXT("CompatibleRUPSecurity"), NULL, &dwType, (LPBYTE) &dwRegValue, &dwSize) == ERROR_SUCCESS) { bDisableCheck = (BOOL)(dwRegValue); } RegCloseKey(hSubKey); } if (bDisableCheck) { DebugMsg((DM_VERBOSE, TEXT("CheckRoamingShareOwnership: policy set to disable ownership check"))); hr = S_OK; goto Exit; } // // Get the security of the directory, should fail with ERROR_INSUFFICIENT_BUFFER // GetFileSecurity(lpDir, OWNER_SECURITY_INFORMATION, NULL, 0, &cbSD); dwErr = GetLastError(); if (dwErr != ERROR_INSUFFICIENT_BUFFER) { DebugMsg((DM_WARNING, TEXT("CheckRoamingShareOwnership : GetFileSecurity failed with %d"), dwErr)); hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } // // Allocate memory for SD // psd = (PSECURITY_DESCRIPTOR) LocalAlloc (LPTR, cbSD); if (!psd) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CheckRoamingShareOwnership : LocalAlloc failed with %d"), dwErr)); hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } // // Try it again // if (!GetFileSecurity(lpDir, OWNER_SECURITY_INFORMATION, psd, cbSD, &cbSD)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CheckRoamingShareOwnership : GetFileSecurity failed with %d"), dwErr)); hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } // // Get the owner in SD // if (!GetSecurityDescriptorOwner(psd, &pSidOwner, &bDefaultOwner)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CheckRoamingShareOwnership: Failed to get security descriptor owner. Error = %d"), dwErr)); hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } // // Get the Admin sid // if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSidAdmin)) { dwErr = GetLastError(); DebugMsg((DM_WARNING, TEXT("CheckRoamingShareOwnership: Failed to initialize admin sid. Error = %d"), dwErr)); hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } // // Get the user sid // pSidUser = GetUserSid(hTokenUser); if (pSidUser == NULL) { DebugMsg((DM_WARNING, TEXT("CheckRoamingShareOwnership: GetUserSid returned NULL"))); hr = E_FAIL; goto Exit; } // // Check the owner // if (EqualSid(pSidAdmin, pSidOwner)) { DebugMsg((DM_VERBOSE, TEXT("CheckRoamingShareOwnership: owner is admin"))); hr = S_OK; } else if (EqualSid(pSidUser, pSidOwner)) { DebugMsg((DM_VERBOSE, TEXT("CheckRoamingShareOwnership: owner is the right user"))); hr = S_OK; } else { LPTSTR lpSidOwner = NULL; if (ConvertSidToStringSid(pSidOwner, &lpSidOwner)) { DebugMsg((DM_WARNING, TEXT("CheckRoamingShareOwnership: owner is %s!"), lpSidOwner)); LocalFree(lpSidOwner); } else { DebugMsg((DM_WARNING, TEXT("CheckRoamingShareOwnership: owner is someone else!"))); } hr = HRESULT_FROM_WIN32(ERROR_INVALID_OWNER); } Exit: if (psd) { LocalFree(psd); } if (pSidAdmin) { FreeSid(pSidAdmin); } if (pSidUser) { DeleteUserSid(pSidUser); } return hr; }