mirror of https://github.com/tongzx/nt5src
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
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;
|
|
}
|
|
|