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