//************************************************************* // // profile.hxx // // Header file for Profile.cpp // // Microsoft Confidential // Copyright (c) Microsoft Corporation 2000 // All rights reserved // //************************************************************* #ifndef _PROFILE_HXX_ #define _PROFILE_HXX_ #include "iprofile.h" // // Number of buckets in the hash table. // #define NUM_OF_BUCKETS 23 // // Flags used by WatchHiveRefCount. // #define WHRC_UNLOAD_HIVE 0x00000001 #define WHRC_UNLOAD_CLASSESROOT 0x00000002 #define WHRC_NOT_HIVE_OPEN_HANDLE 0x00000004 // // .Default HKEY_USERS // const LPTSTR DEFAULT_HKU = TEXT(".DEFAULT"); // // Entries which contain the user profile critical sections. These entries are // used by the synchronization manager. // class CSEntry { public: CSEntry() { pNext = NULL; pSid = NULL; dwRef = 0; szRPCEndPoint = NULL; } ~CSEntry() { pNext = NULL; pSid = NULL; if (szRPCEndPoint) LocalFree(szRPCEndPoint); } friend class CSyncManager; BOOL Initialize(LPTSTR pSid); void Uninitialize(); void EnterCS(); void LeaveCS(); BOOL NoMoreUser(); void IncrementRefCount(); LPTSTR GetRPCEndPoint(void) { return szRPCEndPoint; } void SetRPCEndPoint(LPTSTR lpRPCEndPoint); private: class CSEntry* pNext; LPTSTR pSid; CRITICAL_SECTION csUser; LPTSTR szRPCEndPoint; DWORD dwRef; }; // // Hash table. Uses chained bucket. // class BUCKET { public: BUCKET(LPTSTR ptszStr, CSEntry* pEntryParam) { ptszString = ptszStr; pEntry = pEntryParam; pNext = NULL; } ~BUCKET() { ptszString = NULL; pEntry = NULL; pNext = NULL; } BUCKET* pNext; LPTSTR ptszString; CSEntry* pEntry; }; typedef BUCKET* PBUCKET; class CHashTable { public: CHashTable() {} ~CHashTable() {} void Initialize(); DWORD Hash(LPTSTR ptszString); BOOL IsInTable(LPTSTR ptszString, CSEntry** ppCSEntry = NULL); BOOL HashAdd(LPTSTR ptszString, CSEntry* pCSEntry = NULL); void HashDelete(LPTSTR ptszString); private: PBUCKET Table[NUM_OF_BUCKETS]; }; // // The synchronization manager. This class synchronizes LoadUserProfile/ // UnloadUserProfile calls. // class CSyncManager { public: // // Constructor. // CSyncManager() { pCSList = NULL; } // // Initializes the table, the list, and the critical section. // BOOL Initialize(); // // Sync functions. These functions are protected by a critical section // No two users can update their locks at the same time. This can be // optimized but optimization requires a lot more code. This is also the // only place where user's profile locks gets held and released. // BOOL EnterLock(LPTSTR pSid, LPTSTR lpRPCEndPoint); BOOL LeaveLock(LPTSTR pSid); LPTSTR GetRPCEndPoint(LPTSTR pSid); private: CHashTable cTable; // All the user profile critical section's associated sids. CSEntry* pCSList; CRITICAL_SECTION cs; }; // // Mapping between profile work lists and threads. This is for the registry // key leak fix. // class MAP { public: MAP(); ~MAP() {} friend class CUserProfile; // // Delete/insert a work item from/into the map. // void Delete(DWORD dwIndex); void Insert(HANDLE hEvent, LPTSTR ptszSid); BOOL IsEmpty() { return dwItems <= 1; } LPTSTR GetSid(DWORD dwIndex); private: MAP* pNext; // // These two arrays must always be in sync. // HANDLE rghEvents[MAXIMUM_WAIT_OBJECTS]; LPTSTR rgSids[MAXIMUM_WAIT_OBJECTS]; DWORD dwItems; }; typedef MAP* PMAP; // // The IUserProfile interface functions use this class api to do the core processing. User profiles are loaded // unloaded through the api provided in this class. Console winlogon is the server and only one global instance // of this class runs in console winlogon. // class CUserProfile { public: // // Constructor/Destructor. // CUserProfile() {bInitialized = FALSE; bConsoleWinlogon = FALSE; } ~CUserProfile() {}; // // Initialization function. // void Initialize(); // // Are we in console winlogon process? // BOOL IsConsoleWinlogon() { return bConsoleWinlogon; } // // Main function for the worker threads. // DWORD WorkerThreadMain(PMAP pmap); // // Make getting the user profile lock easier. // BOOL EnterUserProfileLockLocal(LPTSTR pSid); BOOL LeaveUserProfileLockLocal(LPTSTR pSid); // // The actual LoadUserProfile/UnloadUserProfile that does all the work. // BOOL LoadUserProfileP(HANDLE hTokenClient, HANDLE hTokenUser, LPPROFILEINFO lpProfileInfo, LPTSTR lpRPCEndPoint); BOOL UnloadUserProfileP(HANDLE hTokenClient, HANDLE hTokenUser, HKEY hProfile, LPTSTR lpRPCEndPoint); // // Returns the RPCEndPoint associated with registered IProfileDialog interface // LPTSTR GetRPCEndPoint(LPTSTR pSid); private: // // Handles the situation when keys are leaked from the registry. // DWORD HandleRegKeyLeak(LPTSTR lpSidString, LPPROFILE lpProfile, BOOL bUnloadHiveSucceeded, DWORD* dwWatchHiveFlags, DWORD* dwCopyTmpHive, LPTSTR pTmpHiveFile); // // This function is called when a registry key is leaked. // STDMETHODIMP WatchHiveRefCount(LPCTSTR pctszSid, DWORD dwWHRCFlags); // // Get the reference count. // long GetRefCountAndFlags(LPCTSTR ptszSid, HKEY* phkPL, DWORD* dwRefCount, DWORD* dwInternalFlags); // // Add a new work item to both the map structure and a worker thread. // HRESULT AddWorkItem(LPCTSTR ptszSid, HANDLE hEvent); // // Delete the profile as well if necessary, i.e., // temporary profiles, guest profiles, and mandatory profiles. // void CleanupUserProfile(LPTSTR ptszSid, HKEY* phkProfileList); // // Reg leak fix structures. This hash table holds the sids of all the // unloaded user registry hives. // CRITICAL_SECTION csMap; PMAP pMap; CHashTable cTable; // // LoadUserProfile/UnloadUserProfile synchronization manager. // CSyncManager cSyncMgr; // // Tells the caller if we are already initialized. Also tells us if we are // in the console winlogon process because it's the only process that'll // initialize this object. // BOOL bInitialized; // // Tells us if we are in console winlogon process // BOOL bConsoleWinlogon; }; // // Functions prototype for binding rpc handle // BOOL GetInterface(handle_t *phIfHandle, LPTSTR lpRPCEndPoint); BOOL ReleaseInterface(handle_t *phIfHandle); #endif