Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

15230 lines
436 KiB

//*************************************************************
//
// 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;
}