//************************************************************* // // Profile management routines // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1995 // All rights reserved // //************************************************************* #include "uenv.h" // // Local function proto-types // BOOL CheckNetDefaultProfile (LPPROFILE lpProfile); BOOL ParseProfilePath(LPPROFILE lpProfile, LPTSTR lpProfilePath); BOOL RestoreUserProfile(LPPROFILE lpProfile); BOOL TestIfUserProfileLoaded(HANDLE hUserToken, LPPROFILEINFO lpProfileInfo); BOOL GetTempProfileDir(LPPROFILE lpProfile, LPTSTR lpProfileImage); BOOL ComputeLocalProfileName (LPPROFILE lpProfile, LPTSTR lpUserName, LPTSTR lpProfileImage, DWORD cchMaxProfileImage, LPTSTR lpExpProfileImage, DWORD cchMaxExpProfileImage); BOOL CreateLocalProfileKey (LPPROFILE lpProfile, PHKEY phKey, BOOL *bKeyExists); BOOL GetLocalProfileImage(LPPROFILE lpProfile, BOOL *bNewUser); BOOL IsCentralProfileReachable(LPPROFILE lpProfile, BOOL *bCreateCentralProfile, BOOL *bMandatory); BOOL UpdateToLatestProfile(LPPROFILE lpProfile, LPTSTR lpCentralProfile, LPTSTR lpLocalProfile, LPTSTR lpSidString); BOOL IssueDefaultProfile (LPPROFILE lpProfile, LPTSTR lpDefaultProfile, LPTSTR lpLocalProfile, LPTSTR lpSidString, BOOL bMandatory); BOOL UpgradeCentralProfile (LPPROFILE lpProfile, LPTSTR lpOldProfile); BOOL UpgradeProfile (LPPROFILE lpProfile); BOOL IsUserAGuest(LPPROFILE lpProfile); BOOL IsUserAnAdminMember(LPPROFILE lpProfile); BOOL SaveProfileInfo (LPPROFILE lpProfile); LPPROFILE LoadProfileInfo(HANDLE hToken); BOOL CheckForSlowLink(LPPROFILE lpProfile, DWORD dwTime); BOOL APIENTRY SlowLinkDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); DWORD GetUserPreferenceValue(HANDLE hToken); BOOL APIENTRY ChooseProfileDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); DWORD ApplySecurityToRegistryTree(HKEY RootKey, PSECURITY_DESCRIPTOR pSD); //************************************************************* // // 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: // // History: Date Author Comment // 6/6/95 ericflo Created // //************************************************************* BOOL WINAPI LoadUserProfile (HANDLE hToken, LPPROFILEINFO lpProfileInfo) { LPPROFILE lpProfile; BOOL bResult = FALSE; HANDLE hEvent = NULL; TCHAR szEventName[MAX_PATH]; DWORD dwResult; SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; #if DBG // // 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, but PI_APPLYPOLICY is set."))); } } #endif // // Check Parameters // if (lpProfileInfo->dwSize != sizeof(PROFILEINFO)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: lpProfileInfo->dwSize != sizeof(PROFILEINFO)"))); SetLastError(ERROR_INVALID_PARAMETER); goto Exit; } if (!lpProfileInfo->lpUserName || !(*lpProfileInfo->lpUserName)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: received a NULL pointer for lpUserName."))); SetLastError(ERROR_INVALID_PARAMETER); goto Exit; } // // Create an event to prevent multiple threads/process from trying to // load the profile at the same time. // wsprintf (szEventName, TEXT("userenv: %s"), lpProfileInfo->lpUserName); CharLower (szEventName); InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ); SetSecurityDescriptorDacl ( &sd, TRUE, // Dacl present NULL, // NULL Dacl FALSE // Not defaulted ); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE; sa.nLength = sizeof( sa ); hEvent = CreateEvent ( &sa, TRUE, TRUE, szEventName); if (!hEvent) { if ( GetLastError() == ERROR_INVALID_HANDLE ) { hEvent = OpenEvent( EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, szEventName ); } if ( !hEvent ) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to create event %s. Error = %d."), szEventName, GetLastError())); goto Exit; } } if ((WaitForSingleObject (hEvent, INFINITE) == WAIT_FAILED)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to wait on the event. Error = %d."), GetLastError())); goto Exit; } // // This will clear the event so other threads/process will have to // wait in the WaitForSingleObject call. // ResetEvent (hEvent); // // Check if the profile is loaded already. // if (TestIfUserProfileLoaded(hToken, lpProfileInfo)) { bResult = TRUE; goto Exit; } // // Allocate an internal Profile structure to work with. // lpProfile = (LPPROFILE) LocalAlloc (LPTR, sizeof(PROFILE)); if (!lpProfile) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: Failed to allocate memory"))); goto Exit; } // // Save the data passed in. // lpProfile->dwFlags = lpProfileInfo->dwFlags; lpProfile->dwUserPreference = GetUserPreferenceValue(hToken); lpProfile->hToken = hToken; lstrcpy (lpProfile->szUserName, lpProfileInfo->lpUserName); if (lpProfileInfo->lpDefaultPath) { lstrcpy (lpProfile->szDefaultProfile, lpProfileInfo->lpDefaultPath); } if (lpProfileInfo->lpServerName) { lstrcpy (lpProfile->szServerName, lpProfileInfo->lpServerName); } if (lpProfileInfo->dwFlags & PI_APPLYPOLICY) { if (lpProfileInfo->lpPolicyPath) { lstrcpy (lpProfile->szPolicyPath, lpProfileInfo->lpPolicyPath); } } // // 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, lpProfileInfo->lpProfilePath)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ParseProfilePath returned FALSE"))); SetLastError(ERROR_INVALID_PARAMETER); LocalFree (lpProfile); goto Exit; } // // The real central profile directory is... // DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: ParseProfilePath returned a directory of <%s>"), lpProfile->szCentralProfile)); } // // Load the user's profile // if (!RestoreUserProfile(lpProfile)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: RestoreUserProfile returned FALSE"))); LocalFree (lpProfile); goto Exit; } // // Set the USERPROFILE environment variable into this process's // environmnet. This allows ExpandEnvironmentStrings to be used // in the userdiff processing. // SetEnvironmentVariable (TEXT("USERPROFILE"), lpProfile->szLocalProfile); // // Upgrade the profile if appropriate. // if (!UpgradeProfile(lpProfile)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: UpgradeProfile returned FALSE"))); } // // Apply Policy // if (lpProfile->dwFlags & PI_APPLYPOLICY) { if (!ApplyPolicy(lpProfile)) { DebugMsg((DM_WARNING, TEXT("LoadUserProfile: ApplyPolicy returned FALSE"))); } } // // Save the outgoing parameters // lpProfileInfo->hProfile = (HANDLE) lpProfile->hKeyCurrentUser; // // Save the profile information in the registry. // SaveProfileInfo (lpProfile); // // Free the structure // LocalFree (lpProfile); // // Success! // bResult = TRUE; Exit: if (hEvent) { // // This will set the event so other threads/process can continue. // SetEvent (hEvent); CloseHandle (hEvent); } // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("LoadUserProfile: Leaving with a value of %d. hProfile = <0x%x>"), bResult, lpProfileInfo->hProfile)); DebugMsg((DM_VERBOSE, TEXT("========================================================="))); return bResult; } //************************************************************* // // CheckNetDefaultProfile() // // Purpose: Checks if a network profile exists and // caches it locally if it is valid. // // 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 // //************************************************************* BOOL CheckNetDefaultProfile (LPPROFILE lpProfile) { HANDLE hFile; WIN32_FIND_DATA fd; TCHAR szBuffer[MAX_PATH]; TCHAR szLocalDir[MAX_PATH]; LPTSTR lpEnd; BOOL bRetVal = TRUE; BOOL bProfileReady =FALSE; BOOL bDeleteLocal = FALSE; LPTSTR lpNetPath = lpProfile->szDefaultProfile; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Entering, lpNetPath = <%s>"), lpNetPath)); // // Expand the local profile directory // ExpandEnvironmentStrings(DEFAULT_NET_PROFILE, szLocalDir, MAX_PATH); // // 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."))); goto CheckLocal; } // // 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."))); goto CheckLocal; } FindClose (hFile); // // We found a valid network profile. // DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Found a valid network profile."))); if (CopyProfileDirectory (lpNetPath, szLocalDir, CPD_IGNORECOPYERRORS | CPD_COPYIFDIFFERENT | CPD_SYNCHRONIZE )) { bProfileReady = TRUE; goto Exit; } DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Failed to copy network profile to local cache."))); } else { // // If the network default user profile does not // exist, then we want to delete it off of local // machines. // if (GetLastError() == ERROR_FILE_NOT_FOUND) { bDeleteLocal = TRUE; } } CheckLocal: // // See if local network copy exists // hFile = FindFirstFile (szLocalDir, &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."))); bRetVal = FALSE; goto Exit; } // // If the network copy has been deleted, then delete this // local copy also and just use the normal Default User profile. // if (bDeleteLocal) { DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Removing local copy of network default user profile."))); Delnode (szLocalDir); goto Exit; } // // Is there a ntuser.* file in this directory? // lstrcpy (szBuffer, szLocalDir); 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."))); bRetVal = FALSE; goto Exit; } FindClose (hFile); // // We found a valid local profile. // bProfileReady = TRUE; } Exit: // // If we are leaving successfully, then // save the local profile directory. // if (bRetVal && bProfileReady) { DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: setting default profile to <%s>"), szLocalDir)); lstrcpy (lpProfile->szDefaultProfile, szLocalDir); } else { DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: setting default profile to NULL"))); *lpProfile->szDefaultProfile = TEXT('\0'); } // // Tag the internal flags so we don't do this again. // lpProfile->dwInternalFlags |= DEFAULT_NET_READY; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("CheckNetDefaultProfile: Leaving with a value of %d."), bRetVal)); return bRetVal; } //************************************************************* // // ParseProfilePath() // // Purpose: Parses the profile path to determine if // it points at a directory or a filename. // If the path points to a filename, a subdirectory // of a similar name is created. // // 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) { WIN32_FIND_DATA fd; HANDLE hResult; DWORD dwError; TCHAR szProfilePath[MAX_PATH]; TCHAR szExt[5]; LPTSTR lpEnd; UINT uiExtCount; BOOL bRetVal = FALSE; BOOL bUpgradeCentral = FALSE; BOOL bMandatory = FALSE; DWORD dwStart, dwDelta; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Entering, lpProfilePath = <%s>"), lpProfilePath)); // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to impersonate user"))); return FALSE; } // // Start by calling FindFirstFile so we have file attributes // to work with. // dwStart = GetTickCount(); hResult = FindFirstFile(lpProfilePath, &fd); dwDelta = GetTickCount() - dwStart; DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Tick Count = %d"), dwDelta)); // // It's magic time... // if (hResult != INVALID_HANDLE_VALUE) { // // FindFirst File found something. // First close the handle, then look at // the file attributes. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: FindFirstFile found something with attributes <0x%x>"), fd.dwFileAttributes)); FindClose(hResult); // // If we found a directory, copy the path to // the result buffer and exit. // if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a directory"))); CheckForSlowLink (lpProfile, dwDelta); lstrcpy (lpProfile->szCentralProfile, lpProfilePath); bRetVal = TRUE; goto Exit; } // // We found a file. // Jump to the filename generation code. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a file"))); // // We set this flag now, but it is only used if a new // central directory is created. // bUpgradeCentral = TRUE; goto GenerateDirectoryName; } // // FindFirstFile failed. Look at the error to determine why. // dwError = GetLastError(); DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: FindFirstFile failed with error %d"), dwError)); if ( (dwError == ERROR_FILE_NOT_FOUND) || (dwError == ERROR_PATH_NOT_FOUND) ) { DWORD dwStrLen; // // Nothing found with this name. If the name // does not end in .usr or .man, attempt to create // the directory. // dwStrLen = lstrlen (lpProfilePath); if (dwStrLen >= 4) { lpEnd = lpProfilePath + dwStrLen - 4; if ( (lstrcmpi(lpEnd, c_szUSR) != 0) && (lstrcmpi(lpEnd, c_szMAN) != 0) ) { if (CreateSecureDirectory(lpProfile, lpProfilePath, NULL)) { // // Successfully created the directory. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Succesfully created the sub-directory"))); CheckForSlowLink (lpProfile, dwDelta); lstrcpy (lpProfile->szCentralProfile, lpProfilePath); bRetVal = TRUE; goto Exit; } else { // // Failed to create the subdirectory // DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to create user sub-directory. Error = %d"), GetLastError())); } } } } else if (dwError == ERROR_ACCESS_DENIED) { DebugMsg((DM_WARNING, TEXT("ParseProfilePath: You don't have permission to your central profile server! Error = %d"), dwError)); if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { ReportError(lpProfile->dwFlags, IDS_ACCESSDENIED, lpProfilePath); } goto DisableAndExit; } DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Did not create the sub-directory. Generating a new name."))); GenerateDirectoryName: // // If we made it here, either: // // 1) a file exists with the same name // 2) the directory couldn't be created // 3) the profile path ends in .usr or .man // // Make a local copy of the path so we can munge it. // lstrcpy (szProfilePath, lpProfilePath); DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Entering name generating code working with a path of <%s>."), szProfilePath)); // // Does this path have a filename extension? // lpEnd = szProfilePath + lstrlen (szProfilePath) - 1; while (*lpEnd && (lpEnd >= szProfilePath)) { if (*lpEnd == TEXT('.')) break; if (*lpEnd == TEXT('\\')) break; lpEnd--; } if (*lpEnd != TEXT('.')) { // // The path does not have an extension. Append .pds // lpEnd = szProfilePath + lstrlen (szProfilePath); lstrcpy (lpEnd, c_szPDS); } else { // // The path has an extension. Append the new // directory extension (.pds or .pdm). // if (lstrcmpi(lpEnd, c_szMAN) == 0) { lstrcpy (lpEnd, c_szPDM); bMandatory = TRUE; } else { lstrcpy (lpEnd, c_szPDS); } } // // Call FindFirstFile to see if this directory exists. // hResult = FindFirstFile(szProfilePath, &fd); if (hResult != INVALID_HANDLE_VALUE) { // // FindFirst File found something. // First close the handle, then look at // the file attributes. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: FindFirstFile(2) found something with attributes <0x%x>"), fd.dwFileAttributes)); FindClose(hResult); // // If we found a directory, copy the path to // the result buffer and exit. // if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a directory"))); if (bMandatory) { lstrcpy (lpProfile->szCentralProfile, szProfilePath); lpProfile->dwInternalFlags |= PROFILE_MANDATORY; } else { CheckForSlowLink (lpProfile, dwDelta); lstrcpy (lpProfile->szCentralProfile, szProfilePath); } bRetVal = TRUE; goto Exit; } // // We found a file that matches the generated name. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Found a file with the name we generated."))); if (!bMandatory) { CheckForSlowLink (lpProfile, dwDelta); } if (bMandatory || ((lpProfile->dwUserPreference != USERINFO_LOCAL) && !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK))) { ReportError(lpProfile->dwFlags, IDS_FAILEDDIRCREATE, szProfilePath); } goto DisableAndExit; } // // FindFirstFile failed. Look at the error to determine why. // dwError = GetLastError(); DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: FindFirstFile failed with error %d"), dwError)); // // If we are working with a mandatory profile, // disable the central profile and try to log // on with a cache. // if (bMandatory) { DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Central mandatory profile is unreachable to due error %d."), dwError)); if (IsUserAnAdminMember(lpProfile)) { ReportError(lpProfile->dwFlags, IDS_MANDATORY_NOT_AVAILABLE, dwError); lpProfile->szCentralProfile[0] = TEXT('\0'); lpProfile->dwInternalFlags |= PROFILE_MANDATORY; bRetVal = TRUE; } else { ReportError(lpProfile->dwFlags, IDS_MANDATORY_NOT_AVAILABLE2, dwError); } goto Exit; } // // The user has a roaming profile, so it is ok to call // CheckForSlowLink now. // CheckForSlowLink (lpProfile, dwDelta); if ( (dwError == ERROR_FILE_NOT_FOUND) || (dwError == ERROR_PATH_NOT_FOUND) ) { // // Attempt to create the directory. // if (CreateSecureDirectory(lpProfile, szProfilePath, NULL)) { // // Successfully created the directory. // DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Succesfully created the sub-directory"))); lstrcpy (lpProfile->szCentralProfile, szProfilePath); if (bUpgradeCentral) { bRetVal = UpgradeCentralProfile (lpProfile, lpProfilePath); } else { bRetVal = TRUE; } if (bRetVal) { // // Success // CheckForSlowLink (lpProfile, dwDelta); goto Exit; } else { // // Delete the directory we created above. // Delnode (lpProfile->szCentralProfile); } } else { DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Failed to create the sub-directory"))); if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { ReportError(lpProfile->dwFlags, IDS_FAILEDDIRCREATE2, szProfilePath, GetLastError()); } goto DisableAndExit; } } // // The central profile isn't reachable, or failed to upgrade. // Disable the central profile and try to log // on with a cache. // dwError = GetLastError(); DebugMsg((DM_VERBOSE, TEXT("ParseProfilePath: Central profile is unreachable to due error %d, switching to local profile only."), dwError)); if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { ReportError(lpProfile->dwFlags, IDS_CENTRAL_NOT_AVAILABLE2, dwError); } DisableAndExit: lpProfile->szCentralProfile[0] = TEXT('\0'); bRetVal = TRUE; Exit: // // Revert to being 'ourself' // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("ParseProfilePath: Failed to revert to self"))); } 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; LPTSTR lpCentralProfile; LPTSTR lpLocalProfile; BOOL bProfileLoaded = FALSE; BOOL bNewUser = TRUE; LPTSTR SidString; LONG error = ERROR_SUCCESS; TCHAR szProfile[MAX_PATH]; LPTSTR lpEnd; BOOL bRet; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Entering"))); // // Get the Sid string for the current user // SidString = GetSidString(lpProfile->hToken); if (!SidString) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to get sid string for user"))); return FALSE; } // // Initialization // lpCentralProfile = lpProfile->szCentralProfile; DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Profile path = <%s>"), lpCentralProfile ? lpCentralProfile : TEXT(""))); if (!lpCentralProfile || !(*lpCentralProfile)) { IsProfilePathNULL = TRUE; } // // Test if this user is a guest. // if (IsUserAGuest(lpProfile)) { lpProfile->dwInternalFlags |= PROFILE_GUEST_USER; DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: User is a Guest"))); } // // Test if this user is an admin. // if (IsUserAnAdminMember(lpProfile)) { 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); 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 floating"))); 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; } } } else { if (!IsProfilePathNULL) { error = GetLastError(); DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: IsCentralProfileReachable returned FALSE. error = %d"), error)); ReportError(lpProfile->dwFlags, IDS_CENTRAL_NOT_AVAILABLE, error); } } // // Determine if the local copy of the profilemage is available. // IsLocalReachable = GetLocalProfileImage(lpProfile, &bNewUser); if (IsLocalReachable) { lpProfile->dwInternalFlags |= PROFILE_USE_CACHE; lpProfile->dwInternalFlags |= bNewUser ? PROFILE_NEW_LOCAL : 0; } else { if (!GetTempProfileDir(lpProfile, lpProfile->szLocalProfile)) { error = GetLastError(); DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: GetTempProfileDir failed with error %d. Unable to issue temporary profile!"), error)); ReportError(lpProfile->dwFlags, IDS_TEMP_DIR_FAILED, lpProfile->szLocalProfile, error); goto Exit; } } lpLocalProfile = lpProfile->szLocalProfile; DebugMsg((DM_VERBOSE, TEXT("Local profile %s reachable"), IsLocalReachable ? TEXT("is") : TEXT("is not"))); DebugMsg((DM_VERBOSE, TEXT("Local profile name is <%s>"), lpLocalProfile)); // // 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: About to call UpdateToLatestProfile"))); bRet = UpdateToLatestProfile(lpProfile, lpCentralProfile, lpLocalProfile, SidString); if (!bRet) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: UpdatetoLatestProfile failed. Issuing default profile"))); lpProfile->dwInternalFlags &= ~PROFILE_UPDATE_CENTRAL; lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; goto IssueDefault; } lstrcpy (szProfile, lpLocalProfile); lpEnd = CheckSlash(szProfile); if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } error = MyRegLoadKey(lpProfile, 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 { lpProfile->dwInternalFlags &= ~PROFILE_UPDATE_CENTRAL; lpProfile->dwInternalFlags |= PROFILE_DELETE_CACHE; ReportError(lpProfile->dwFlags, IDS_FAILED_LOAD_LOCAL, error); 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 (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } error = MyRegLoadKey(lpProfile, HKEY_USERS, SidString, szProfile); bProfileLoaded = (error == ERROR_SUCCESS); if (!bProfileLoaded) { DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: MyRegLoadKey returned FALSE."))); ReportError(lpProfile->dwFlags, IDS_FAILED_LOAD_LOCAL, error); } 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"))); // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to impersonate user"))); goto Exit; } bRet = CopyProfileDirectory (lpCentralProfile, lpLocalProfile, CPD_IGNORECOPYERRORS | CPD_COPYIFDIFFERENT | CPD_SYNCHRONIZE); // // Revert to being 'ourself' // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to revert to self"))); } // // Check return value // if (!bRet) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); goto Exit; } lstrcpy (szProfile, lpLocalProfile); lpEnd = CheckSlash(szProfile); if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } error = MyRegLoadKey(lpProfile,HKEY_USERS, SidString, szProfile); bProfileLoaded = (error == ERROR_SUCCESS); if (bProfileLoaded) { goto Exit; } // // If a temporary cache exists, delete it, since we will // generate a new one below. // if (!(lpProfile->dwInternalFlags & PROFILE_USE_CACHE)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Deleting temporary profile directory <%s>."), lpLocalProfile)); if (!DeleteProfile (NULL, lpLocalProfile, TRUE)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: DeleteProfile returned false. Error = %d"), GetLastError())); } } } 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) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Deleting cached profile directory <%s>."), lpLocalProfile)); lpProfile->dwInternalFlags &= ~PROFILE_DELETE_CACHE; if (!DeleteProfile (SidString, lpLocalProfile, TRUE)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: DeleteProfileDirectory returned false. Error = %d"), GetLastError())); } } // // Create a local profile to work with // if (!(lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL)) { if (lpProfile->dwInternalFlags & PROFILE_USE_CACHE) { if (!GetLocalProfileImage(lpProfile, &bNewUser)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: GetLocalProfileImage failed."))); ReportError(lpProfile->dwFlags, IDS_TEMP_DIR_FAILED, GetLastError()); goto Exit; } } else { lstrcpy (szProfile, CONFIG_FILE_PATH); if (!ComputeLocalProfileName(lpProfile, lpProfile->szUserName, szProfile, MAX_PATH, lpLocalProfile, MAX_PATH)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: ComputeLocalProfileName failed."))); goto Exit; } } } // // If a default profile location was specified, try // that first. // if ( !(lpProfile->dwInternalFlags & DEFAULT_NET_READY) ) { // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to impersonate user"))); goto IssueLocalDefault; } CheckNetDefaultProfile (lpProfile); // // Go back to system security context // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to revert to self"))); } } if ( lpProfile->szDefaultProfile && *lpProfile->szDefaultProfile) { if (IssueDefaultProfile (lpProfile, lpProfile->szDefaultProfile, 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. // if (IssueDefaultProfile (lpProfile, DEFAULT_PROFILE, 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."))); 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)) { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: SetupNewHive failed"))); bProfileLoaded = FALSE; } } 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; DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to open current user key. Error = %d"), error)); } } if (!bProfileLoaded) { // // 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->dwFlags, IDS_ADMIN_OVERRIDE, GetLastError()); bProfileLoaded = TRUE; } else { DebugMsg((DM_WARNING, TEXT("RestoreUserProfile: Failed to save settings in user hive or failed to apply security. Error = %d"), GetLastError())); ReportError(lpProfile->dwFlags, IDS_FAILED_LOAD_PROFILE, GetLastError()); if (lpProfile->hKeyCurrentUser) { RegCloseKey (lpProfile->hKeyCurrentUser); } MyRegUnLoadKey(HKEY_USERS, SidString); } } 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->szCentralProfile = <%s>"), lpProfile->szCentralProfile)); DebugMsg((DM_VERBOSE, TEXT("lpProfile->szLocalProfile = <%s>"), lpProfile->szLocalProfile)); DebugMsg((DM_VERBOSE, TEXT("lpProfile->dwInternalFlags = 0x%x"), lpProfile->dwInternalFlags)); // // Free up the user's sid string // DeleteSidString(SidString); DebugMsg((DM_VERBOSE, TEXT("RestoreUserProfile: Leaving."))); return bProfileLoaded; } //************************************************************* // // 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 = GetSidString(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); if (error == ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("TestIfUserProfileLoaded: Profile already loaded."))); // // This key will be closed in UnloadUserProfile // lpProfileInfo->hProfile = (HANDLE) hSubKey; } DeleteSidString(SidString); 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; 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->hToken); 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; } // // Allocate space for the ACL // cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) + (2 * GetLengthSid (psidAdmin)) + sizeof(ACL) + (6 * (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; } // // 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, &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, &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, &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)); } RegCloseKey(RootKey); } Exit: // // Free the sids and acl // if (bFreeSid && psidUser) { DeleteUserSid (psidUser); } 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); } //end //************************************************************* // // 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 // Error = RegSetKeySecurity(RootKey, DACL_SECURITY_INFORMATION, pSD); if (Error != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryTree: Failed to set security on registry key, error = %d"), Error)); return Error; } // // Open each sub-key and apply security to its sub-tree // SubKeyIndex = 0; SubKeyName = 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) { DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryKey : Failed to open sub-key %s, error = %d"), SubKeyName, Error)); break; } // // Apply security to the sub-tree // Error = ApplySecurityToRegistryTree(SubKey, pSD); // // We're finished with the sub-key // IgnoreError = RegCloseKey(SubKey); if (IgnoreError != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryKey : Failed to close registry key, error = %d"), Error)); } // // See if we set the security on the sub-tree successfully. // if (Error != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("ApplySecurityToRegistryKey : Failed to apply security to sub-key %s, error = %d"), SubKeyName, Error)); break; } // // Go enumerate the next sub-key // SubKeyIndex ++; } GlobalFree (SubKeyName); return Error; } //************************************************************* // // 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; SECURITY_DESCRIPTOR sd; 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; DWORD dwFlags = 0; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: 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->hToken); dwFlags = lpProfile->dwFlags; } if (!psidUser) { DebugMsg((DM_WARNING, TEXT("SetupNewHive: 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("SetupNewHive: 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("SetupNewHive: Failed to initialize admin sid. Error = %d"), GetLastError())); goto Exit; } // // Allocate space for the ACL // cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) + (2 * GetLengthSid (psidAdmin)) + sizeof(ACL) + (6 * (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("SetupNewHive: 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("SetupNewHive: 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("SetupNewHive: 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("SetupNewHive: Failed to add ace for admin. Error = %d"), GetLastError())); goto Exit; } // // Now the inheritable ACEs // AceIndex++; if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidUser)) { DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Failed to add ace for user. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: 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("SetupNewHive: Failed to add ace for system. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: 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("SetupNewHive: Failed to add ace for admin. Error = %d"), GetLastError())); goto Exit; } if (!GetAce(pAcl, AceIndex, &lpAceHeader)) { DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: 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("SetupNewHive: Failed to initialize security descriptor. Error = %d"), GetLastError())); goto Exit; } if (!SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE)) { DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Failed to set security descriptor dacl. Error = %d"), GetLastError())); goto Exit; } // // 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 { // // Set the security descriptor on the entire tree // Error = ApplySecurityToRegistryTree(RootKey, &sd); if (Error == ERROR_SUCCESS) { TCHAR szSubKey[MAX_PATH]; // // 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); lstrcat (szSubKey, TEXT("\\")); lstrcat (szSubKey, POLICIES_KEY); if (!SecureUserKey(lpProfile, szSubKey, pSid)) { DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to secure policies key"))); } bRetVal = TRUE; } else { DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to apply security to user registry tree, error = %d"), Error)); ReportError(dwFlags, IDS_SECURITY_FAILED, Error); } RegFlushKey (RootKey); IgnoreError = RegCloseKey(RootKey); if (IgnoreError != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("SetupNewHive: Failed to close reg key, error = %d"), IgnoreError)); } } Exit: // // Free the sids and acl // if (bFreeSid && psidUser) { DeleteUserSid (psidUser); } if (psidSystem) { FreeSid(psidSystem); } if (psidAdmin) { FreeSid(psidAdmin); } if (pAcl) { GlobalFree (pAcl); } // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("SetupNewHive: Leaving with a return value of %d"), bRetVal)); 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) { WIN32_FIND_DATA fd; HANDLE hFile; TCHAR szProfile[MAX_PATH]; LPTSTR lpProfilePath, lpEnd; BOOL bRetVal = FALSE; DWORD dwError; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Entering"))); // // Setup default values // *bMandatory = FALSE; *bCreateCentralProfile = FALSE; // // Check parameters // if (lpProfile->szCentralProfile[0] == TEXT('\0')) { DebugMsg((DM_VERBOSE, TEXT("IsCentralProfileReachable: Null path. Leaving"))); return FALSE; } lpProfilePath = lpProfile->szCentralProfile; // // 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."))); return FALSE; } // // Copy the profile path to a temporary buffer // we can munge it. // lstrcpy (szProfile, lpProfilePath); // // Add the slash if appropriate and then tack on // ntuser.man. // lpEnd = CheckSlash(szProfile); lstrcpy(lpEnd, c_szNTUserMan); // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Failed to impersonate user"))); return FALSE; } // // 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 (dwError == ERROR_FILE_NOT_FOUND) { 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 (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("IsCentralProfileReachable: Failed to revert to self"))); } return bRetVal; } //************************************************************* // // MyRegLoadKey() // // Purpose: Loads a hive into the registry // // Parameters: lpProfile - Profile Info // 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(LPPROFILE lpProfile, HKEY hKey, LPTSTR lpSubKey, LPTSTR lpFile) { NTSTATUS Status; BOOLEAN WasEnabled; int error; // // Enable the restore privilege // Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled); if (NT_SUCCESS(Status)) { error = RegLoadKey(hKey, lpSubKey, lpFile); // // Restore the privilege to its previous state // 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(PI_NOUI, IDS_REGLOADKEYFAILED, error, lpFile); DebugMsg((DM_WARNING, TEXT("MyRegLoadKey: Failed to load subkey <%s>, error =%d"), lpSubKey, error)); } } else { error = GetLastError(); DebugMsg((DM_WARNING, TEXT("MyRegLoadKey: Failed to enable restore privilege to load registry key"))); } 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; NTSTATUS Status; BOOLEAN WasEnabled; // // Enable the restore privilege // Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled); if (NT_SUCCESS(Status)) { error = RegUnLoadKey(hKey, lpSubKey); if ( error != ERROR_SUCCESS) { bResult = FALSE; } // // Restore the privilege to its previous state // 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"))); bResult = FALSE; } 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; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("UpgradeLocalProfile: Entering"))); // // Setup the temporary buffers // lstrcpy (szSrc, lpOldProfile); lstrcpy (szDest, lpProfile->szLocalProfile); 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) ) { // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to impersonate user"))); goto IssueLocalDefault; } CheckNetDefaultProfile (lpProfile); // // Go back to system security context // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to revert to self"))); } } if (lpProfile->szDefaultProfile && *lpProfile->szDefaultProfile) { ExpandEnvironmentStrings(lpProfile->szDefaultProfile, szSrc, MAX_PATH); if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to impersonate user"))); goto IssueLocalDefault; } if (CopyProfileDirectory (szSrc, lpProfile->szLocalProfile, CPD_IGNOREHIVE | CPD_IGNORECOPYERRORS)) { bRetVal = TRUE; } // // Go back to system security context // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to revert to self"))); } } IssueLocalDefault: if (!bRetVal) { ExpandEnvironmentStrings(DEFAULT_PROFILE, szSrc, MAX_PATH); if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to impersonate user"))); goto Exit; } bRetVal = CopyProfileDirectory (szSrc, lpProfile->szLocalProfile, CPD_IGNOREHIVE | CPD_IGNORECOPYERRORS); // // Go back to system security context // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UpgradeLocalProfile: Failed to revert to self"))); } } Exit: if (bRetVal) { lpProfile->dwInternalFlags |= PROFILE_RUN_SYNCAPP; } 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; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("UpgradeCentralProfile: Entering"))); // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { 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->szCentralProfile); 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)); 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->szDefaultProfile && *lpProfile->szDefaultProfile) { ExpandEnvironmentStrings(lpProfile->szDefaultProfile, szSrc, MAX_PATH); if (CopyProfileDirectory (szSrc, lpProfile->szCentralProfile, CPD_IGNOREHIVE | CPD_IGNORECOPYERRORS)) { bRetVal = TRUE; } } if (!bRetVal) { ExpandEnvironmentStrings(DEFAULT_PROFILE, szSrc, MAX_PATH); bRetVal = CopyProfileDirectory (szSrc, lpProfile->szCentralProfile, CPD_IGNOREHIVE | CPD_IGNORECOPYERRORS); } if (bRetVal) { lpProfile->dwInternalFlags |= PROFILE_RUN_SYNCAPP; } Exit: // // Go back to system security context // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UpgradeCentralProfile: Failed to revert to self"))); } return bRetVal; } //************************************************************* // // GetTempProfileDir() // // Purpose: Generates a temporary profile directory // // Parameters: lpProfile - Profile Information // lpProfileImage - Receives the generated directory // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/20/95 ericflo Created // //************************************************************* BOOL GetTempProfileDir (LPPROFILE lpProfile, LPTSTR lpProfileImage) { TCHAR szProfileImage[MAX_PATH]; TCHAR szExpProfileImage[MAX_PATH]; // // Initialize the profile image // lstrcpy (szProfileImage, CONFIG_FILE_PATH); // // Call the compute function to do the real work. // if (ComputeLocalProfileName (lpProfile, TEMP_PROFILE_NAME_BASE, szProfileImage, MAX_PATH, szExpProfileImage, MAX_PATH)) { // // Save the generated name. // lstrcpy (lpProfileImage, szExpProfileImage); return TRUE; } return FALSE; } //************************************************************* // // CreateSecureDirectory() // // Purpose: Creates a secure directory that only the user, // admin, and system have access to. // // Parameters: lpProfile - Profile Information // lpDirectory - Directory Name // pSid - Sid (used by CreateUserProfile) // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 7/20/95 ericflo Created // //************************************************************* BOOL CreateSecureDirectory (LPPROFILE lpProfile, LPTSTR lpDirectory, PSID pSid) { 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)); // // Get the SIDs we'll need for the DACL // if (pSid) { psidUser = pSid; bFreeSid = FALSE; } else { psidUser = GetUserSid(lpProfile->hToken); } // // 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 // 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 // cbAcl = (2 * GetLengthSid (psidUser)) + (2 * GetLengthSid (psidSystem)) + (2 * GetLengthSid (psidAdmin)) + sizeof(ACL) + (6 * (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; } 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, &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, &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, psidAdmin)) { DebugMsg((DM_VERBOSE, TEXT("CreateSecureDirectory: Failed to add ace (%d). Error = %d"), aceIndex, GetLastError())); goto Exit; } if (!GetAce(pAcl, aceIndex, &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 (CreateNestedDirectory(lpDirectory, &sa)) { 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; } //************************************************************* // // 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 // // Return: TRUE if successful // FALSE if an error occurs // // Comments: lpProfileImage should be initialized with the // root profile path and the trailing backslash. // // History: Date Author Comment // 6/20/95 ericflo Created // //************************************************************* BOOL ComputeLocalProfileName (LPPROFILE lpProfile, LPTSTR lpUserName, LPTSTR lpProfileImage, DWORD cchMaxProfileImage, LPTSTR lpExpProfileImage, DWORD cchMaxExpProfileImage) { int i = 0; TCHAR szNumber[5]; LPTSTR lpEnd; DWORD dwProfileLen; BOOL bRetVal = FALSE; HANDLE hFile; WIN32_FIND_DATA fd; // // Check buffer size // dwProfileLen = lstrlen(lpProfileImage); if ((dwProfileLen + lstrlen(lpUserName) + 4 + 1) > cchMaxProfileImage) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: buffer too small"))); return FALSE; } // // Place the username onto the end of the profile image // lpEnd = lpProfileImage + dwProfileLen; 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 (CreateSecureDirectory(lpProfile, lpExpProfileImage, NULL)) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: generated the profile directory <%s>"), lpExpProfileImage)); bRetVal = TRUE; goto Exit; } } else { FindClose (hFile); } // // Failed to create the directory for some reason. // Now try username.000, username.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 // if (CreateSecureDirectory(lpProfile, lpExpProfileImage, NULL)) { DebugMsg((DM_VERBOSE, TEXT("ComputeLocalProfileName: generated the profile directory <%s>"), lpExpProfileImage)); bRetVal = TRUE; goto Exit; } } else { FindClose (hFile); } } DebugMsg((DM_WARNING, TEXT("ComputeLocalProfileName: Could not generate a profile directory. Error = %d"), GetLastError())); Exit: 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; SidString = GetSidString(lpProfile->hToken); 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); } else { DebugMsg((DM_WARNING, TEXT("CreateLocalProfileKey: Failed trying to create the local profile key <%s>, error = %d."), LocalProfileKey, RegErr)); } DeleteSidString(SidString); } return(RegErr == ERROR_SUCCESS); } //************************************************************* // // GetLocalProfileImage() // // Purpose: Create/opens the profileimagepath // // Parameters: lpProfile - Profile information // bNewUser - set to TRUE if the default profile was issued. // // Return: TRUE if the profile image is reachable // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/20/95 ericflo Ported // //************************************************************* BOOL GetLocalProfileImage(LPPROFILE lpProfile, BOOL *bNewUser) { HKEY hKey; BOOL bKeyExists; TCHAR lpProfileImage[MAX_PATH]; TCHAR lpExpProfileImage[MAX_PATH]; TCHAR lpOldProfileImage[MAX_PATH]; LPTSTR lpExpandedPath, lpEnd; DWORD cbExpProfileImage = sizeof(TCHAR)*MAX_PATH; HANDLE hFile; WIN32_FIND_DATA fd; DWORD cb; DWORD err; DWORD dwType; HANDLE fh; PSID UserSid; BOOL bRetVal = FALSE; BOOL bUpgradeLocal = FALSE; lpProfile->szLocalProfile[0] = TEXT('\0'); *bNewUser = TRUE; if (!CreateLocalProfileKey(lpProfile, &hKey, &bKeyExists)) { return FALSE; // not reachable and cannot keep a local copy } if (bKeyExists) { // // Check if the local profile image is valid. // DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: 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("GetLocalProfileImage: Local profile image filename = <%s>"), lpExpProfileImage)); if (dwType == REG_EXPAND_SZ) { // // Expand the profile image filename // cb = sizeof(lpExpProfileImage); lpExpandedPath = LocalAlloc(LPTR, cb); if (lpExpandedPath) { ExpandEnvironmentStrings(lpExpProfileImage, lpExpandedPath, cb); lstrcpy(lpExpProfileImage, lpExpandedPath); LocalFree(lpExpandedPath); } DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Expanded local profile image filename = <%s>"), lpExpProfileImage)); } // // Call FindFirst to see if we need to migrate this profile // hFile = FindFirstFile (lpExpProfileImage, &fd); if (hFile == INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Local profile image filename we got from our profile list doesn't exit. Error = %d"), GetLastError())); goto CreateLocal; } FindClose(hFile); // // If this is a file, then we need to migrate it to // if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { lstrcpy (lpOldProfileImage, lpExpProfileImage); bUpgradeLocal = TRUE; goto CreateLocal; } // // Test if a mandatory profile exists // lpEnd = CheckSlash (lpExpProfileImage); lstrcpy (lpEnd, c_szNTUserMan); fh = CreateFile(lpExpProfileImage, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fh != INVALID_HANDLE_VALUE) { lpProfile->dwInternalFlags |= PROFILE_MANDATORY; CloseHandle(fh); DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Found local mandatory profile image file ok <%s>"), lpExpProfileImage)); *(lpEnd - 1) = TEXT('\0'); lstrcpy(lpProfile->szLocalProfile, lpExpProfileImage); RegCloseKey(hKey); *bNewUser = FALSE; return TRUE; // local copy is valid and reachable } else { DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: No local mandatory profile. Error = %d"), GetLastError())); } // // Test if a normal profile exists // lstrcpy (lpEnd, c_szNTUserDat); fh = CreateFile(lpExpProfileImage, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fh != INVALID_HANDLE_VALUE) { CloseHandle(fh); DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Found local profile image file ok <%s>"), lpExpProfileImage)); *(lpEnd - 1) = TEXT('\0'); lstrcpy(lpProfile->szLocalProfile, lpExpProfileImage); RegCloseKey(hKey); *bNewUser = FALSE; return TRUE; // local copy is valid and reachable } else { DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: Local profile image filename we got from our profile list doesn't exit. <%s> Error = %d"), lpExpProfileImage, GetLastError())); } } } CreateLocal: // // No local copy found, try to create a new one. // DebugMsg((DM_VERBOSE, TEXT("GetLocalProfileImage: One way or another we haven't got an existing local profile, try and create one"))); lstrcpy(lpProfileImage, CONFIG_FILE_PATH); if (ComputeLocalProfileName(lpProfile, lpProfile->szUserName, lpProfileImage, MAX_PATH, lpExpProfileImage, MAX_PATH)) { // // 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->szLocalProfile, lpExpProfileImage); // // Get the sid of the logged on user // UserSid = GetUserSid(lpProfile->hToken); if (UserSid != NULL) { // // Store the user sid under the Sid key of the local profile // err = RegSetValueEx(hKey, TEXT("Sid"), 0, REG_BINARY, UserSid, RtlLengthSid(UserSid)); if (err != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("GetLocalProfileImage: Failed to set 'sid' value of user in profile list, error = %d"), err)); } // // We're finished with the user sid // DeleteUserSid(UserSid); // // If we are upgrading a profile from a 3.5 machine // do that now. // if (bUpgradeLocal) { if (UpgradeLocalProfile (lpProfile, lpOldProfileImage)) { *bNewUser = FALSE; } } bRetVal = TRUE; } else { DebugMsg((DM_WARNING, TEXT("GetLocalProfileImage: Failed to get sid of logged on user, so unable to update profile list"))); } } else { DebugMsg((DM_WARNING, TEXT("GetLocalProfileImage: Failed to update profile list for user with local profile image filename, error = %d"), err)); } } err = RegCloseKey(hKey); if (err != STATUS_SUCCESS) { DebugMsg((DM_WARNING, TEXT("GetLocalProfileImage: Failed to close registry key, error = %d"), err)); } return bRetVal; } //************************************************************* // // UpdateToLatestProfile() // // Purpose: Determines which profile is newer, and // updates the local cache. // // Parameters: lpProfile - Profile info // lpCentralProfile - Central profile // lpLocalProfile - Local profile // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/21/95 ericflo Created // //************************************************************* BOOL UpdateToLatestProfile(LPPROFILE lpProfile, LPTSTR lpCentralProfile, LPTSTR lpLocalProfile, LPTSTR lpSidString) { HANDLE hLocal; HANDLE hCentral; FILETIME ftLocal; FILETIME ftCentral; BOOL FromCentralToLocal; int DlgReturn; LONG lTimeCompare; TCHAR szProfile[MAX_PATH]; LPTSTR lpEnd; BOOL bRetVal; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Entering. Central = <%s> Local = <%s>"), lpCentralProfile, lpLocalProfile)); // // Setup a temporary buffer to work with // lstrcpy (szProfile, lpCentralProfile); lpEnd = CheckSlash (szProfile); if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to impersonate user"))); return FALSE; } // // Attempt to open the central profile // hCentral = CreateFile(szProfile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hCentral == INVALID_HANDLE_VALUE) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: couldn't open central profile, error = %d"), GetLastError())); if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to revert to self"))); } return TRUE; } else { if (!GetFileTime(hCentral, NULL, NULL, &ftCentral)) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to query central profile file time. Error = %d"), GetLastError())); ftCentral.dwLowDateTime = 0; ftCentral.dwHighDateTime = 0; } CloseHandle(hCentral); } // // Revert to being 'ourself' // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to revert to self"))); } // // Re-initialize the temporary buffer to look // at the local profile. // lstrcpy (szProfile, lpLocalProfile); lpEnd = CheckSlash (szProfile); if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { lstrcpy (lpEnd, c_szNTUserMan); } else { lstrcpy (lpEnd, c_szNTUserDat); } // // Attempt to open the local profile // hLocal = CreateFile(szProfile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hLocal == INVALID_HANDLE_VALUE) { DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: couldn't open local profile, error = %d"), GetLastError())); ftLocal.dwLowDateTime = 0; ftLocal.dwHighDateTime = 0; } else { if (!GetFileTime(hLocal, NULL, NULL, &ftLocal)) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to query local profile file time. Error = %d"), GetLastError())); ftLocal.dwLowDateTime = 0; ftLocal.dwHighDateTime = 0; } CloseHandle(hLocal); } if (lpProfile->dwInternalFlags & PROFILE_NEW_LOCAL) { DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: New local cach has been created. Forcing copy from central."))); FromCentralToLocal = TRUE; } else { // // Decide which file is the most uptodate and use that as the source // for the copy // lTimeCompare = CompareFileTime(&ftCentral, &ftLocal); if (lTimeCompare == -1) { FromCentralToLocal = FALSE; DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Local profile time stamp is newer than central time stamp."))); } else if (lTimeCompare == 1) { FromCentralToLocal = TRUE; DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Central profile time stamp is newer than local time stamp."))); } else { DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Central and local profile times match."))); return TRUE; } } // // If we have a mandatory profile and the cache is newer // than the central, force the central to be downloaded again. // We only want to use the cache if the central is not available. // if ((lpProfile->dwInternalFlags & PROFILE_MANDATORY) && !FromCentralToLocal) { FromCentralToLocal = TRUE; } if (!FromCentralToLocal && !(lpProfile->dwFlags & PI_NOUI)) { HKEY hKey; LONG lResult; DWORD dwType, dwSize, dwDlgTimeOut; // // Ask the user if ok to overwrite the central profile with the // the local profile. // // Get the dialog box timeout // dwDlgTimeOut = PROFILE_DLG_TIMEOUT; lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ, &hKey); if (lResult == ERROR_SUCCESS) { dwSize = sizeof(DWORD); RegQueryValueEx (hKey, TEXT("ProfileDlgTimeOut"), NULL, &dwType, (LPBYTE) &dwDlgTimeOut, &dwSize); RegCloseKey (hKey); } if (dwDlgTimeOut > 0) { DlgReturn = DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_CHOOSE_PROFILE), NULL, ChooseProfileDlgProc, dwDlgTimeOut); if (DlgReturn == IDNO) { // // The user doesn't want to overwrite the central profile. // The central profile becomes the active profile and overwrites // the local copy. // FromCentralToLocal = TRUE; } } } // // If FromCentralToLocal is false, we can exit now, // since we are going to use the cache. // if (!FromCentralToLocal) { return TRUE; } // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to impersonate user"))); return FALSE; } if (lpProfile->dwInternalFlags & PROFILE_MANDATORY) { bRetVal = CopyProfileDirectory (lpCentralProfile, lpLocalProfile, CPD_IGNORECOPYERRORS | CPD_COPYIFDIFFERENT | CPD_SYNCHRONIZE); } else { bRetVal = CopyProfileDirectory (lpCentralProfile, lpLocalProfile, CPD_IGNORECOPYERRORS | CPD_COPYIFDIFFERENT | CPD_SYNCHRONIZE); } // // Revert to being 'ourself' // if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: Failed to revert to self"))); } if (!bRetVal) { DebugMsg((DM_WARNING, TEXT("UpdateToLatestProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); return FALSE; } DebugMsg((DM_VERBOSE, TEXT("UpdateToLatestProfile: Leaving successfully."))); return TRUE; } //************************************************************* // // 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; // // Verbose Output // DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Entering. lpDefaultProfile = <%s> lpLocalProfile = <%s>"), lpDefaultProfile, lpLocalProfile)); // // First expand the default profile // ExpandEnvironmentStrings(lpDefaultProfile, szProfile, MAX_PATH); // // 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)); return FALSE; } FindClose(hFile); // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: Failed to impersonate user"))); return FALSE; } // // Copy profile to user profile // if (!CopyProfileDirectory (szProfile, lpLocalProfile, CPD_FORCECOPY)) { DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); 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 (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("IssueDefaultProfile: Failed to revert to self"))); } // // Try to load the new profile // error = MyRegLoadKey(lpProfile,HKEY_USERS, lpSidString, szProfile); bProfileLoaded = (error == ERROR_SUCCESS); if (!bProfileLoaded) { DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: MyRegLoadKey failed with error %d"), error)); return FALSE; } // // Set the sync app flag // lpProfile->dwInternalFlags |= PROFILE_RUN_SYNCAPP; DebugMsg((DM_VERBOSE, TEXT("IssueDefaultProfile: Leaving successfully"))); return TRUE; } //************************************************************* // // DeleteProfile() // // Purpose: Deletes the specified profile from the // registry and disk. // // Parameters: lpSidString - Registry subkey // lpProfileDir - Profile directory // bBackup - Backup profile before deleting // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 6/23/95 ericflo Created // //************************************************************* BOOL DeleteProfile (LPTSTR lpSidString, LPTSTR lpLocalProfile, BOOL bBackup) { LONG lResult; TCHAR szTemp[MAX_PATH]; // // Cleanup the registry first. // if (lpSidString && *lpSidString) { lstrcpy(szTemp, PROFILE_LIST_PATH); lstrcat(szTemp, TEXT("\\")); lstrcat(szTemp, lpSidString); lResult = RegDeleteKey(HKEY_LOCAL_MACHINE, szTemp); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Unable to delete registry entry. Error = %d"), lResult)); return FALSE; } } if (bBackup) { // // Generate the backup name // lstrcpy (szTemp, lpLocalProfile); lstrcat (szTemp, c_szBAK); // // First delete any previous backup // Delnode (szTemp); // // Attempt to rename the directory // if (!MoveFileEx(lpLocalProfile, szTemp, 0)) { DebugMsg((DM_VERBOSE, TEXT("DeleteProfile: Failed to rename the directory. Error = %d"), GetLastError())); return FALSE; } } else { if (!Delnode (lpLocalProfile)) { DebugMsg((DM_WARNING, TEXT("DeleteProfile: Delnode failed. Error = %d"), GetLastError())); return FALSE; } } return TRUE; } //************************************************************* // // 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 // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // // History: Date Author Comment // 7/7/95 ericflo Created // //************************************************************* BOOL UpgradeProfile (LPPROFILE lpProfile) { HKEY hKey; DWORD dwDisp, dwType, dwSize, dwBuildNumber; LONG lResult; BOOL bUpgrade = FALSE; BOOL bRunSyncApp = 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 they match, // 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)); } } // // Set syncapp flag // if (lpProfile->dwInternalFlags & PROFILE_RUN_SYNCAPP) { bRunSyncApp = TRUE; lResult = RegSetValueEx (hKey, SYNCAPP_REG_VALUE_NAME, 0, REG_DWORD, (LPBYTE) &bRunSyncApp, sizeof(bRunSyncApp)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UpgradeProfile: Failed to set syncapp flag. Error = %d"), lResult)); } DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Set syncapp flag to %d"), bRunSyncApp)); } // // Close the registry key // RegCloseKey (hKey); if (bDoUserdiff) { // // Apply changes to user's hive that NT setup needs. // if (!ProcessUserDiff(lpProfile, dwBuildNumber)) { DebugMsg((DM_WARNING, TEXT("UpgradeProfile: ProcessUserDiff failed"))); } } DebugMsg((DM_VERBOSE, TEXT("UpgradeProfile: Leaving Successfully"))); return TRUE; } //************************************************************* // // IsUserAGuest() // // Purpose: Determines if the user is a member of the guest group. // // Parameters: lpProfile - Profile Information // // Return: TRUE if user is a guest // FALSE if not // Comments: // // History: Date Author Comment // 7/25/95 ericflo Created // //************************************************************* BOOL IsUserAGuest(LPPROFILE lpProfile) { SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; NTSTATUS Status; ULONG InfoLength; PTOKEN_GROUPS TokenGroupList; ULONG GroupIndex; BOOL FoundGuests; PSID GuestsDomainSid; // // Create Guests domain sid. // Status = RtlAllocateAndInitializeSid( &authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0, 0, 0, 0, 0, 0, &GuestsDomainSid ); // // Test if user is in the Guests domain // // // Get a list of groups in the token // Status = NtQueryInformationToken( lpProfile->hToken, // Handle TokenGroups, // TokenInformationClass NULL, // TokenInformation 0, // TokenInformationLength &InfoLength // ReturnLength ); if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) { DebugMsg((DM_WARNING, TEXT("IsUserAGuest: Failed to get group info for guests token, status = 0x%x"), Status)); RtlFreeSid(GuestsDomainSid); return FALSE; } TokenGroupList = GlobalAlloc(GPTR, InfoLength); if (TokenGroupList == NULL) { DebugMsg((DM_WARNING, TEXT("IsUserAGuest: Unable to allocate memory for token groups"))); RtlFreeSid(GuestsDomainSid); return FALSE; } Status = NtQueryInformationToken( lpProfile->hToken, // Handle TokenGroups, // TokenInformationClass TokenGroupList, // TokenInformation InfoLength, // TokenInformationLength &InfoLength // ReturnLength ); if (!NT_SUCCESS(Status)) { DebugMsg((DM_WARNING, TEXT("IsUserAGuest: Failed to query groups for guests token, status = 0x%x"), Status)); GlobalFree(TokenGroupList); RtlFreeSid(GuestsDomainSid); return FALSE; } // // Search group list for guests alias // FoundGuests = FALSE; for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) { if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, GuestsDomainSid)) { FoundGuests = TRUE; break; } } // // Tidy up // GlobalFree(TokenGroupList); RtlFreeSid(GuestsDomainSid); return(FoundGuests); } //************************************************************* // // IsUserAnAdminMember() // // Purpose: Determines if the user is a member of the administrators group. // // Parameters: lpProfile - Profile Information // // Return: TRUE if user is a admin // FALSE if not // Comments: // // History: Date Author Comment // 7/25/95 ericflo Created // //************************************************************* BOOL IsUserAnAdminMember(LPPROFILE lpProfile) { SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY; NTSTATUS Status; ULONG InfoLength; PTOKEN_GROUPS TokenGroupList; ULONG GroupIndex; BOOL FoundAdmins; PSID AdminsDomainSid; // // Create Admins domain sid. // Status = RtlAllocateAndInitializeSid( &authNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdminsDomainSid ); // // Test if user is in the Admins domain // // // Get a list of groups in the token // Status = NtQueryInformationToken( lpProfile->hToken, // Handle TokenGroups, // TokenInformationClass NULL, // TokenInformation 0, // TokenInformationLength &InfoLength // ReturnLength ); if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) { DebugMsg((DM_WARNING, TEXT("IsUserAnAdminMember: Failed to get group info for Admins token, status = 0x%x"), Status)); RtlFreeSid(AdminsDomainSid); return FALSE; } TokenGroupList = GlobalAlloc(GPTR, InfoLength); if (TokenGroupList == NULL) { DebugMsg((DM_WARNING, TEXT("IsUserAnAdminMember: Unable to allocate memory for token groups"))); RtlFreeSid(AdminsDomainSid); return FALSE; } Status = NtQueryInformationToken( lpProfile->hToken, // Handle TokenGroups, // TokenInformationClass TokenGroupList, // TokenInformation InfoLength, // TokenInformationLength &InfoLength // ReturnLength ); if (!NT_SUCCESS(Status)) { DebugMsg((DM_WARNING, TEXT("IsUserAnAdminMember: Failed to query groups for Admins token, status = 0x%x"), Status)); GlobalFree(TokenGroupList); RtlFreeSid(AdminsDomainSid); return FALSE; } // // Search group list for Admins alias // FoundAdmins = FALSE; for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) { if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, AdminsDomainSid)) { FoundAdmins = TRUE; break; } } // // Tidy up // GlobalFree(TokenGroupList); RtlFreeSid(AdminsDomainSid); return(FoundAdmins); } //************************************************************* // // 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; // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to impersonate user"))); return FALSE; } // // Create the central filename // lstrcpy (szProfile, lpProfile->szCentralProfile); 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 (!RevertToSelf()) { 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 (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to revert to self"))); } // // Create the local filename // lstrcpy (szProfile, lpProfile->szLocalProfile); 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 (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("SetProfileTime: Failed to impersonate user"))); return FALSE; } // // Set the time on the central profile // if (hFileCentral != INVALID_HANDLE_VALUE) { 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 (!RevertToSelf()) { 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); } return bRetVal; } //************************************************************* // // 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 // //************************************************************* BOOL WINAPI UnloadUserProfile (HANDLE hToken, HANDLE hProfile) { LPPROFILE lpProfile = NULL; LPTSTR lpSidString = NULL; LONG err, IgnoreError; BOOL bRet, bRetVal = FALSE; HANDLE hEvent = NULL; TCHAR szEventName[MAX_PATH]; DWORD dwResult; SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Entering, hProfile = <0x%x>"), hProfile)); // // Check Parameters // if (!hProfile) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: received a NULL hProfile."))); SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } // // Load profile information // lpProfile = LoadProfileInfo(hToken); if (!lpProfile) { RegCloseKey((HKEY)hProfile); goto Exit; } // // Restore the hKeyCurrentUser parameter // lpProfile->hKeyCurrentUser = (HKEY) hProfile; // // Get the Sid string for the current user // lpSidString = GetSidString(lpProfile->hToken); if (!lpSidString) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to get sid string for user"))); goto Exit; } // // Create an event to prevent multiple threads/process from trying to // unload the profile at the same time. // wsprintf (szEventName, TEXT("userenv: %s"), lpSidString); CharLower (szEventName); InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ); SetSecurityDescriptorDacl ( &sd, TRUE, // Dacl present NULL, // NULL Dacl FALSE // Not defaulted ); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE; sa.nLength = sizeof( sa ); hEvent = CreateEvent ( &sa, TRUE, TRUE, szEventName); if (!hEvent) { if ( GetLastError() == ERROR_INVALID_HANDLE ) { hEvent = OpenEvent( EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, szEventName ); } if ( !hEvent ) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to create event %s. Error = %d."), szEventName, GetLastError())); goto Exit; } } if ((WaitForSingleObject (hEvent, INFINITE) == WAIT_FAILED)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to wait on the event. Error = %d."), GetLastError())); goto Exit; } // // This will clear the event so other threads/process will have to // wait in the WaitForSingleObject call. // ResetEvent (hEvent); // // Flush out the profile which will also sync the log. // err = RegFlushKey(lpProfile->hKeyCurrentUser); if (err != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: 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("UnloadUserProfile: Failed to close the current user key, error = %d"), err)); } // // 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. // if ((lpProfile->dwInternalFlags & PROFILE_MANDATORY) || (lpProfile->dwInternalFlags & PROFILE_GUEST_USER)) { err = MyRegUnLoadKey(HKEY_USERS, lpSidString); if (!err) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Didn't unload the user profile because of error = %d"), GetLastError())); bRetVal = TRUE; goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Succesfully unloaded mandatory/guest profile"))); } IgnoreError = RegFlushKey(HKEY_USERS); if (IgnoreError != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to flush HKEY_USERS, error = %d"), IgnoreError)); } if (IsCacheDeleted() || (lpProfile->dwInternalFlags & PROFILE_GUEST_USER)) { // // Delete the profile // if (!DeleteProfile (lpSidString, lpProfile->szLocalProfile, FALSE)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: DeleteProfileDirectory returned false. Error = %d"), GetLastError())); } } if (err) { bRetVal = TRUE; } goto Exit; } // // Unload the profile // err = MyRegUnLoadKey(HKEY_USERS, lpSidString); if (!err) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Didn't unload user profile <err = %d>"), GetLastError())); bRetVal = TRUE; goto Exit; } else { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Succesfully unloaded profile"))); } // // Copy local profileimage to remote profilepath // if ( ((lpProfile->dwInternalFlags & PROFILE_UPDATE_CENTRAL) || (lpProfile->dwInternalFlags & PROFILE_NEW_CENTRAL)) ) { if ((lpProfile->dwUserPreference != USERINFO_LOCAL) && !(lpProfile->dwInternalFlags & PROFILE_SLOW_LINK)) { DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Copying profile back to %s"), lpProfile->szCentralProfile)); // // Impersonate the user // if (!ImpersonateLoggedOnUser(lpProfile->hToken)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to impersonate user"))); goto Exit; } bRet = CopyProfileDirectory (lpProfile->szLocalProfile, lpProfile->szCentralProfile, CPD_IGNORECOPYERRORS | CPD_COPYIFDIFFERENT | CPD_SYNCHRONIZE); if (!RevertToSelf()) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: Failed to revert to self"))); } // // Check return value // if (!bRet) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: CopyProfileDirectory returned FALSE. Error = %d"), GetLastError())); ReportError(lpProfile->dwFlags, IDS_CENTRAL_UPDATE_FAILED, GetLastError()); goto Exit; } // // 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. // SetProfileTime(lpProfile); if (IsCacheDeleted()) { if (!DeleteProfile (lpSidString, lpProfile->szLocalProfile, FALSE)) { DebugMsg((DM_WARNING, TEXT("UnloadUserProfile: DeleteProfileDirectory returned false (2). Error = %d"), GetLastError())); } } } } // // Success // bRetVal = TRUE; Exit: if (hEvent) { // // This will set the event so other threads/process can continue. // SetEvent (hEvent); CloseHandle (hEvent); } if (lpSidString) { DeleteSidString(lpSidString); } if (lpProfile) { LocalFree (lpProfile); } // // Verbose output // DebugMsg((DM_VERBOSE, TEXT("UnloadUserProfile: Leaving with a return value of %d"), bRetVal)); return bRetVal; } //************************************************************* // // 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; // // Get the Sid string for the user // SidString = GetSidString(lpProfile->hToken); 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_VERBOSE, TEXT("SaveProfileInfo: Failed to open profile mapping key with error %d"), lResult)); return FALSE; } // // Save the flags // lResult = RegSetValueEx (hKey, PROFILE_FLAGS, 0, REG_DWORD, (LPBYTE) &lpProfile->dwFlags, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, 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_VERBOSE, TEXT("SaveProfileInfo: Failed to save flags2 with error %d"), lResult)); } // // Save the central profile path // lResult = RegSetValueEx (hKey, PROFILE_CENTRAL_PROFILE, 0, REG_SZ, (LPBYTE) &lpProfile->szCentralProfile, (lstrlen(lpProfile->szCentralProfile) + 1) * sizeof(TCHAR)); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_VERBOSE, TEXT("SaveProfileInfo: Failed to save central profile with error %d"), lResult)); } RegCloseKey (hKey); DeleteSidString(SidString); return(TRUE); } //************************************************************* // // LoadProfileInfo() // // Purpose: Loads key parts of the lpProfile structure // in the registry for UnloadUserProfile to use. // // Parameters: hToken - User's token // // Return: pointer to lpProfile is 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 hToken) { LPPROFILE lpProfile; LPTSTR SidString, lpEnd; TCHAR szBuffer[MAX_PATH]; LONG lResult; HKEY hKey; DWORD dwType, dwSize; // // Allocate an internal Profile structure to work with. // lpProfile = (LPPROFILE) LocalAlloc (LPTR, sizeof(PROFILE)); if (!lpProfile) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to allocate memory"))); return NULL; } // // Save the data passed in. // lpProfile->hToken = hToken; // // Get the Sid string for the user // SidString = GetSidString(hToken); if (!SidString) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to get sid string for user"))); LocalFree (lpProfile); return NULL; } // // 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)); LocalFree (lpProfile); return NULL; } // // 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)); LocalFree (lpProfile); return NULL; } // // 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)); LocalFree (lpProfile); return NULL; } // // 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 * 2; lResult = RegQueryValueEx (hKey, PROFILE_CENTRAL_PROFILE, NULL, &dwType, (LPBYTE) &lpProfile->szCentralProfile, &dwSize); if (lResult != ERROR_SUCCESS) { DebugMsg((DM_WARNING, TEXT("LoadProfileInfo: Failed to query central profile with error %d"), lResult)); LocalFree (lpProfile); return NULL; } // // Query for the local profile path. The local profile path // needs to be expanded so read it into the temporary buffer. // dwSize = MAX_PATH * 2; 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)); LocalFree (lpProfile); return NULL; } // // Expand the local profile // ExpandEnvironmentStrings(szBuffer, lpProfile->szLocalProfile, MAX_PATH); RegCloseKey (hKey); DeleteSidString(SidString); return(lpProfile); } //************************************************************* // // CheckForSlowLink() // // Purpose: Checks if the network connection is slow. // // Parameters: lpProfile - Profile Information // dwTime - Time delta // // 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) { DWORD dwSlowTimeOut, dwSlowDlgTimeOut, dwSlowLinkDetectEnabled; DWORD dwType, dwSize; BOOL bRetVal; HKEY hKey; LONG lResult; // // If the user doesn't want pop-up's, then they always // get their profile downloaded. // if (lpProfile->dwFlags & PI_NOUI) { return TRUE; } // // 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, // and dialog box timeout values. // dwSlowTimeOut = SLOW_LINK_TIMEOUT; dwSlowDlgTimeOut = PROFILE_DLG_TIMEOUT; dwSlowLinkDetectEnabled = 1; 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); RegCloseKey (hKey); } // // If slow link detection is disabled, then always download // the profile. // if (!dwSlowLinkDetectEnabled) { return TRUE; } // // 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; } // // If the User Preferences states to always use the local // profile on slow links, then we can exit now with false. // if (lpProfile->dwUserPreference == USERINFO_LOCAL_SLOW_LINK) { lpProfile->dwInternalFlags |= PROFILE_SLOW_LINK; return FALSE; } // // Display the slow link dialog // // If someone sets the dialog box timeout to 0, then we // don't want to prompt the user. Just force the profile // to download. // if (dwSlowDlgTimeOut > 0) { bRetVal = DialogBoxParam (g_hDllInstance, MAKEINTRESOURCE(IDD_SLOW_LINK), NULL, SlowLinkDlgProc, dwSlowDlgTimeOut); if (!bRetVal) { lpProfile->dwInternalFlags |= PROFILE_SLOW_LINK; } return bRetVal; } return TRUE; } //************************************************************* // // SlowLinkDlgProc() // // Purpose: Dialog box procedure for the slow link dialog // // 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 // //************************************************************* BOOL APIENTRY SlowLinkDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { TCHAR szBuffer[10]; static DWORD dwSlowLinkTime; switch (uMsg) { case WM_INITDIALOG: CenterWindow (hDlg); dwSlowLinkTime = (DWORD) lParam; wsprintf (szBuffer, TEXT("%d"), dwSlowLinkTime); SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); SetTimer (hDlg, 1, 1000, NULL); return TRUE; case WM_TIMER: if (dwSlowLinkTime >= 1) { dwSlowLinkTime--; wsprintf (szBuffer, TEXT("%d"), dwSlowLinkTime); SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); } else { // // Time's up. Download the profile. // PostMessage (hDlg, WM_COMMAND, IDC_DOWNLOAD, 0); } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_DOWNLOAD: case IDC_LOCAL: case IDCANCEL: // // Nothing to do. Save the state and return. // KillTimer (hDlg, 1); // // Return TRUE to download the profile, // FALSE to use the local profile // EndDialog(hDlg, ((LOWORD(wParam) == IDC_LOCAL) ? FALSE : TRUE)); 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, dwRetVal = USERINFO_UNDEFINED; LPTSTR lpEnd; LPTSTR SidString; HKEY hkeyProfile; SidString = GetSidString(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); } DeleteSidString(SidString); } return dwRetVal; } //************************************************************* // // ChooseProfileDlgProc() // // Purpose: Dialog box procedure for the choose profile dialog // // 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/23/96 ericflo Created // //************************************************************* BOOL APIENTRY ChooseProfileDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { TCHAR szBuffer[10]; static DWORD dwChooseProfileTime; switch (uMsg) { case WM_INITDIALOG: CenterWindow (hDlg); dwChooseProfileTime = (DWORD) lParam; wsprintf (szBuffer, TEXT("%d"), dwChooseProfileTime); SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); SetTimer (hDlg, 1, 1000, NULL); return TRUE; case WM_TIMER: if (dwChooseProfileTime >= 1) { dwChooseProfileTime--; wsprintf (szBuffer, TEXT("%d"), dwChooseProfileTime); SetDlgItemText (hDlg, IDC_TIMEOUT, szBuffer); } else { // // Time's up. Use the local profile. // PostMessage (hDlg, WM_COMMAND, IDC_CP_YES, 0); } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_CP_YES: case IDC_CP_NO: case IDCANCEL: // // Nothing to do. Save the state and return. // KillTimer (hDlg, 1); // // Return IDYES to use the local profile // IDNO to download the central profile // EndDialog(hDlg, ((LOWORD(wParam) == IDC_CP_NO) ? IDNO : IDYES)); break; default: break; } break; } return FALSE; }