/*++ Copyright (c) 2000 Microsoft Corporation Module Name: users.c Abstract: Creates user profiles and enumerates users Author: Jim Schmidt (jimschm) 15-May-2000 Revision History: --*/ // // Includes // #include "pch.h" #include "ism.h" #include "ismp.h" #define DBG_ISMUSERS "IsmUsers" // // Strings // #define S_TEMP_HKCU TEXT("$HKCU$") // // Constants // // None // // Macros // // None // // Types // typedef BOOL (WINAPI GETDEFAULTUSERPROFILEDIRECTORY)(PTSTR ProfileDir, PDWORD Size); typedef GETDEFAULTUSERPROFILEDIRECTORY * PGETDEFAULTUSERPROFILEDIRECTORY; typedef BOOL (WINAPI GETPROFILESDIRECTORY)(PTSTR ProfileDir, PDWORD Size); typedef GETPROFILESDIRECTORY * PGETPROFILESDIRECTORY; typedef LONG (WINAPI REGOVERRIDEPREDEFKEY)(HKEY hKey, HKEY hNewHKey); typedef REGOVERRIDEPREDEFKEY * PREGOVERRIDEPREDEFKEY; typedef BOOL (WINAPI CONVERTSIDTOSTRINGSID)(PSID Sid, PTSTR *SidString); typedef CONVERTSIDTOSTRINGSID * PCONVERTSIDTOSTRINGSID; typedef BOOL (WINAPI CREATEUSERPROFILE)( PSID Sid, PCTSTR UserName, PCTSTR UserHive, PTSTR ProfileDir, DWORD DirSize, BOOL IsWin9xUpgrade ); typedef CREATEUSERPROFILE * PCREATEUSERPROFILE; typedef BOOL (WINAPI OLDCREATEUSERPROFILE)( PSID Sid, PCTSTR UserName, PCTSTR UserHive, PTSTR ProfileDir, DWORD DirSize ); typedef OLDCREATEUSERPROFILE * POLDCREATEUSERPROFILE; typedef BOOL (WINAPI GETUSERPROFILEDIRECTORY)(HANDLE hToken, PTSTR lpProfileDir, PDWORD lpcchSize); typedef GETUSERPROFILEDIRECTORY * PGETUSERPROFILEDIRECTORY; typedef BOOL (WINAPI DELETEPROFILE)(PCTSTR lpSidString, PCTSTR lpProfilePath, PCTSTR lpComputerName); typedef DELETEPROFILE * PDELETEPROFILE; // // Globals // PTEMPORARYPROFILE g_CurrentOverrideUser; // // Macro expansion list // // None // // Private function prototypes // // None // // Macro expansion definition // // None // // Code // HANDLE pGetUserEnvLib ( VOID ) { static HANDLE lib; if (lib) { return lib; } lib = LoadLibrary (TEXT("userenv.dll")); if (!lib) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_LOAD_USERENV)); } return lib; } HANDLE pGetAdvApi32Lib ( VOID ) { static HANDLE lib; if (lib) { return lib; } lib = LoadLibrary (TEXT("advapi32.dll")); if (!lib) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_LOAD_ADVAPI32)); } return lib; } BOOL pOurGetDefaultUserProfileDirectory ( OUT PTSTR ProfileDir, IN OUT PDWORD Size ) { HANDLE lib; PGETDEFAULTUSERPROFILEDIRECTORY getDefaultUserProfileDirectory; lib = pGetUserEnvLib(); if (!lib) { return FALSE; } #ifdef UNICODE getDefaultUserProfileDirectory = (PGETDEFAULTUSERPROFILEDIRECTORY) GetProcAddress (lib, "GetDefaultUserProfileDirectoryW"); #else getDefaultUserProfileDirectory = (PGETDEFAULTUSERPROFILEDIRECTORY) GetProcAddress (lib, "GetDefaultUserProfileDirectoryA"); #endif if (!getDefaultUserProfileDirectory) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_FIND_GETDEFAULTUSERPROFILEDIRECTORY)); return FALSE; } return getDefaultUserProfileDirectory (ProfileDir, Size); } BOOL pOurGetProfilesDirectory ( OUT PTSTR ProfileDir, IN OUT PDWORD Size ) { HANDLE lib; PGETPROFILESDIRECTORY getProfilesDirectory; lib = pGetUserEnvLib(); if (!lib) { return FALSE; } #ifdef UNICODE getProfilesDirectory = (PGETPROFILESDIRECTORY) GetProcAddress (lib, "GetProfilesDirectoryW"); #else getProfilesDirectory = (PGETPROFILESDIRECTORY) GetProcAddress (lib, "GetProfilesDirectoryA"); #endif if (!getProfilesDirectory) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_FIND_GETPROFILESDIRECTORY)); return FALSE; } return getProfilesDirectory (ProfileDir, Size); } LONG pOurConvertSidToStringSid ( IN PSID Sid, IN PTSTR *SidString ) { HANDLE lib; PCONVERTSIDTOSTRINGSID convertSidToStringSid; BOOL result = FALSE; DWORD error; lib = pGetAdvApi32Lib(); if (!lib) { error = GetLastError(); if (error == ERROR_SUCCESS) { SetLastError (ERROR_PROC_NOT_FOUND); } } else { #ifdef UNICODE convertSidToStringSid = (PCONVERTSIDTOSTRINGSID) GetProcAddress(lib, "ConvertSidToStringSidW"); #else convertSidToStringSid = (PCONVERTSIDTOSTRINGSID) GetProcAddress(lib, "ConvertSidToStringSidA"); #endif if (convertSidToStringSid) { result = convertSidToStringSid (Sid, SidString); } } return result; } BOOL pOurGetUserProfileDirectory ( IN HANDLE Token, IN PTSTR ProfileDir, IN PDWORD ProfileDirSize ) { HANDLE lib; PGETUSERPROFILEDIRECTORY getUserProfileDirectory; BOOL result = FALSE; DWORD error; lib = pGetUserEnvLib(); if (!lib) { error = GetLastError(); if (error == ERROR_SUCCESS) { SetLastError (ERROR_PROC_NOT_FOUND); } } else { #ifdef UNICODE getUserProfileDirectory = (PGETUSERPROFILEDIRECTORY) GetProcAddress (lib, "GetUserProfileDirectoryW"); #else getUserProfileDirectory = (PGETUSERPROFILEDIRECTORY) GetProcAddress (lib, "GetUserProfileDirectoryA"); #endif if (getUserProfileDirectory) { result = getUserProfileDirectory (Token, ProfileDir, ProfileDirSize); } } return result; } BOOL pOurDeleteProfile ( IN PCTSTR UserStringSid, IN PCTSTR UserProfilePath, IN PCTSTR ComputerName ) { HANDLE lib; PDELETEPROFILE deleteProfile; BOOL result = FALSE; DWORD error; lib = pGetUserEnvLib(); if (!lib) { error = GetLastError(); if (error == ERROR_SUCCESS) { SetLastError (ERROR_PROC_NOT_FOUND); } } else { #ifdef UNICODE deleteProfile = (PDELETEPROFILE) GetProcAddress (lib, "DeleteProfileW"); #else deleteProfile = (PDELETEPROFILE) GetProcAddress (lib, "DeleteProfileA"); #endif if (deleteProfile) { result = deleteProfile (UserStringSid, UserProfilePath, ComputerName); } } return result; } LONG pOurRegOverridePredefKey ( IN HKEY hKey, IN HKEY hNewHKey ) { HANDLE lib; PREGOVERRIDEPREDEFKEY regOverridePredefKey; LONG result; lib = pGetAdvApi32Lib(); if (!lib) { result = GetLastError(); if (result == ERROR_SUCCESS) { result = ERROR_PROC_NOT_FOUND; } } else { regOverridePredefKey = (PREGOVERRIDEPREDEFKEY) GetProcAddress (lib, "RegOverridePredefKey"); if (!regOverridePredefKey) { result = GetLastError(); } else { result = regOverridePredefKey (hKey, hNewHKey); } } return result; } BOOL pOurCreateUserProfile ( IN PSID Sid, IN PCTSTR UserName, IN PCTSTR UserHive, OUT PTSTR ProfileDir, IN DWORD DirSize ) { HANDLE lib; PCREATEUSERPROFILE createUserProfile; POLDCREATEUSERPROFILE oldCreateUserProfile; MIG_OSVERSIONINFO versionInfo; BOOL useNew = FALSE; lib = pGetUserEnvLib(); if (!lib) { return FALSE; } if (IsmGetOsVersionInfo (g_IsmCurrentPlatform, &versionInfo)) { if ((versionInfo.OsMajorVersion > OSMAJOR_WINNT5) || (versionInfo.OsMajorVersion == OSMAJOR_WINNT5 && ((versionInfo.OsMinorVersion > OSMINOR_WINNT51) || ((versionInfo.OsMinorVersion == OSMINOR_WINNT51) && (versionInfo.OsBuildNumber >= 2464))))) { useNew = TRUE; } } if (useNew) { #ifdef UNICODE createUserProfile = (PCREATEUSERPROFILE) GetProcAddress (lib, (PCSTR) 154); #else createUserProfile = (PCREATEUSERPROFILE) GetProcAddress (lib, (PCSTR) 153); #endif if (!createUserProfile) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_FIND_CREATEUSERPROFILE)); return FALSE; } return createUserProfile ( Sid, UserName, UserHive, ProfileDir, DirSize, FALSE ); } else { #ifdef UNICODE oldCreateUserProfile = (POLDCREATEUSERPROFILE) GetProcAddress (lib, (PCSTR) 110); #else oldCreateUserProfile = (POLDCREATEUSERPROFILE) GetProcAddress (lib, (PCSTR) 109); #endif if (!oldCreateUserProfile) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_FIND_CREATEUSERPROFILE)); return FALSE; } return oldCreateUserProfile ( Sid, UserName, UserHive, ProfileDir, DirSize ); } } BOOL pCloneDefaultUserProfile ( IN PSID Sid, IN PCTSTR UserName, OUT PTSTR OutUserProfileRoot ) { TCHAR userProfile[MAX_TCHAR_PATH]; BOOL result = FALSE; __try { if (!pOurCreateUserProfile ( Sid, UserName, NULL, userProfile, ARRAYSIZE(userProfile) )) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_CREATE_PROFILE, UserName)); __leave; } MYASSERT (OutUserProfileRoot); StringCopy (OutUserProfileRoot, userProfile); result = TRUE; } __finally { if (result) { LOG ((LOG_INFORMATION, (PCSTR) MSG_PROFILE_INFO, UserName, OutUserProfileRoot)); } } return result; } PTEMPORARYPROFILE OpenTemporaryProfile ( IN PCTSTR UserName, IN PCTSTR Domain ) { DWORD sidSize; DWORD domainSize; SID_NAME_USE use; PTSTR domainBuffer = NULL; PSID sidBuffer = NULL; PTSTR sidString = NULL; PTEMPORARYPROFILE result = NULL; PCTSTR accountName = NULL; TCHAR userProfileRoot[MAX_TCHAR_PATH]; PCTSTR hiveFile = NULL; LONG rc; HKEY key = NULL; PMHANDLE allocPool; BOOL b; __try { // // Generate the account name // if (!UserName || !Domain) { DEBUGMSG ((DBG_WHOOPS, "EstablishTemporaryProfile requires user and domain")); __leave; } accountName = JoinPaths (Domain, UserName); // // Obtain the buffer sizes needed to obtain the user's SID // sidSize = 0; domainSize = 0; b = LookupAccountName ( NULL, accountName, NULL, &sidSize, NULL, &domainSize, &use ); if (!b && GetLastError() != ERROR_INSUFFICIENT_BUFFER) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_FIND_ACCOUNT, accountName)); __leave; } // // Allocate the buffers // domainBuffer = AllocText (domainSize); sidBuffer = MemAllocUninit (sidSize); if (!domainBuffer || !sidBuffer) { __leave; } // // Get the SID // b = LookupAccountName ( NULL, accountName, sidBuffer, &sidSize, domainBuffer, &domainSize, &use ); if (!b) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_FIND_ACCOUNT_SID, accountName)); __leave; } if (use != SidTypeUser) { SetLastError (ERROR_INVALID_ACCOUNT_NAME); LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_NOT_USER_ACCOUNT, accountName)); __leave; } // // Copy the default profile // b = pCloneDefaultUserProfile (sidBuffer, UserName, userProfileRoot); if (!b) { __leave; } // // convert SID into a string SID // if (!pOurConvertSidToStringSid (sidBuffer, &sidString) || !sidString) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CONVERT_SID_FAILURE)); __leave; } // // Load the user's hive // RegUnLoadKey (HKEY_USERS, sidString); hiveFile = JoinPaths (userProfileRoot, TEXT("ntuser.dat")); rc = RegLoadKey (HKEY_USERS, sidString, hiveFile); if (rc != ERROR_SUCCESS) { SetLastError (rc); LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_LOAD_HIVE, hiveFile)); __leave; } // // Make the hive the new HKCU // key = OpenRegKey (HKEY_USERS, sidString); if (!key) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_MAP_HIVE, hiveFile)); __leave; } if (g_CurrentOverrideUser) { pOurRegOverridePredefKey (HKEY_CURRENT_USER, NULL); g_CurrentOverrideUser = NULL; } rc = pOurRegOverridePredefKey (HKEY_CURRENT_USER, key); if (rc != ERROR_SUCCESS) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_REDIRECT_HIVE, hiveFile)); __leave; } // // Prepare outbound handle // allocPool = PmCreateNamedPool ("TempProfile"); if (!allocPool) { __leave; } result = (PTEMPORARYPROFILE) PmGetMemory (allocPool, sizeof (TEMPORARYPROFILE)); if (!result) { __leave; } g_CurrentOverrideUser = result; result->AllocPool = allocPool; result->UserName = PmDuplicateString (allocPool, UserName); result->DomainName = PmDuplicateString (allocPool, Domain); result->AccountName = PmDuplicateString (allocPool, accountName); result->UserProfileRoot = PmDuplicateString (allocPool, userProfileRoot); result->MapKey = PmDuplicateString (allocPool, sidString); result->UserStringSid = PmDuplicateString (allocPool, sidString); result->UserHive = PmDuplicateString (allocPool, hiveFile); result->UserSid = (PSID) PmDuplicateMemory ( allocPool, sidBuffer, GetLengthSid (sidBuffer) ); } __finally { FreePathString (hiveFile); FreePathString (accountName); FreeText (domainBuffer); if (sidBuffer) { FreeAlloc (sidBuffer); INVALID_POINTER (sidBuffer); } if (key) { CloseRegKey (key); } if (!result) { if (sidString) { RegTerminateCache (); RegUnLoadKey (HKEY_USERS, sidString); } pOurRegOverridePredefKey (HKEY_CURRENT_USER, NULL); } if (sidString) { LocalFree (sidString); } } return result; } BOOL SelectTemporaryProfile ( IN PTEMPORARYPROFILE Profile ) { LONG rc; HKEY key; if (g_CurrentOverrideUser == Profile) { return TRUE; } key = OpenRegKey (HKEY_LOCAL_MACHINE, Profile->MapKey); if (!key) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_OPEN_USER_REGISTRY, Profile->UserName)); return FALSE; } if (g_CurrentOverrideUser) { pOurRegOverridePredefKey (HKEY_CURRENT_USER, NULL); g_CurrentOverrideUser = NULL; } rc = pOurRegOverridePredefKey (HKEY_CURRENT_USER, key); CloseRegKey (key); if (rc == ERROR_SUCCESS) { g_CurrentOverrideUser = Profile; return TRUE; } return FALSE; } BOOL CloseTemporaryProfile ( IN PTEMPORARYPROFILE Profile, IN BOOL MakeProfilePermanent ) { BOOL result = TRUE; LONG rc; DWORD error; MIG_OSVERSIONINFO osVersionInfo; if (g_CurrentOverrideUser == Profile) { pOurRegOverridePredefKey (HKEY_CURRENT_USER, NULL); g_CurrentOverrideUser = NULL; } RegTerminateCache (); rc = RegUnLoadKey (HKEY_USERS, Profile->MapKey); DEBUGMSG_IF (( rc != ERROR_SUCCESS, DBG_WHOOPS, "Can't unload mapped hive: rc=%u; check for registry handle leaks", rc )); if (MakeProfilePermanent) { if (!pOurCreateUserProfile ( Profile->UserSid, Profile->UserName, Profile->UserHive, NULL, 0 )) { // on Win2k it is known that this will fail with error ERROR_SHARING_VIOLATION // but the hive will actually be OK. So, if this is Win2k // and the error is ERROR_SHARING_VIOLATION we'll just consider a success. result = FALSE; error = GetLastError (); if (IsmGetOsVersionInfo (PLATFORM_DESTINATION, &osVersionInfo)) { if ((osVersionInfo.OsType == OSTYPE_WINDOWSNT) && (osVersionInfo.OsMajorVersion == OSMAJOR_WINNT5) && (osVersionInfo.OsMinorVersion == OSMINOR_GOLD) && (error == ERROR_SHARING_VIOLATION) ) { result = TRUE; } } if (!result) { SetLastError (error); } } } if (result) { PmDestroyPool (Profile->AllocPool); INVALID_POINTER (Profile); } return result; } BOOL MapUserProfile ( IN PCTSTR UserStringSid, IN PCTSTR UserProfilePath ) { PCTSTR hiveFile = NULL; LONG rc; HKEY key; // // Unload UserStringSid if loaded // RegUnLoadKey (HKEY_USERS, UserStringSid); hiveFile = JoinPaths (UserProfilePath, TEXT("ntuser.dat")); rc = RegLoadKey (HKEY_USERS, UserStringSid, hiveFile); if (rc != ERROR_SUCCESS) { SetLastError (rc); LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_LOAD_HIVE, hiveFile)); FreePathString (hiveFile); return FALSE; } // // Make the hive the new HKCU // key = OpenRegKey (HKEY_USERS, UserStringSid); if (!key) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_MAP_HIVE, hiveFile)); RegUnLoadKey (HKEY_USERS, UserStringSid); FreePathString (hiveFile); return FALSE; } rc = pOurRegOverridePredefKey (HKEY_CURRENT_USER, key); if (rc != ERROR_SUCCESS) { LOG ((LOG_MODULE_ERROR, (PCSTR) MSG_CANT_REDIRECT_HIVE, hiveFile)); CloseRegKey (key); RegTerminateCache (); RegUnLoadKey (HKEY_USERS, UserStringSid); FreePathString (hiveFile); return FALSE; } CloseRegKey (key); FreePathString (hiveFile); return TRUE; } BOOL UnmapUserProfile ( IN PCTSTR UserStringSid ) { LONG rc; pOurRegOverridePredefKey (HKEY_CURRENT_USER, NULL); RegTerminateCache (); rc = RegUnLoadKey (HKEY_USERS, UserStringSid); DEBUGMSG_IF (( rc != ERROR_SUCCESS, DBG_WHOOPS, "Can't unmap user profile: rc=%u; check for registry handle leaks", rc )); return TRUE; } BOOL DeleteUserProfile ( IN PCTSTR UserStringSid, IN PCTSTR UserProfilePath ) { RegTerminateCache (); RegUnLoadKey (HKEY_USERS, UserStringSid); return pOurDeleteProfile (UserStringSid, UserProfilePath, NULL); } PCURRENT_USER_DATA GetCurrentUserData ( VOID ) { PCURRENT_USER_DATA result = NULL; HANDLE token; DWORD bytesRequired; PTOKEN_USER tokenUser; PMHANDLE allocPool; PTSTR sidString = NULL; TCHAR userName[256]; DWORD nameSize; TCHAR userDomain[256]; DWORD domainSize; SID_NAME_USE dontCare; // // Open the process token. // if (!OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &token)) { return FALSE; } bytesRequired = 0; if (GetTokenInformation (token, TokenUser, NULL, 0, &bytesRequired)) { return FALSE; } if (GetLastError () != ERROR_INSUFFICIENT_BUFFER) { return FALSE; } tokenUser = (PTOKEN_USER) MemAllocUninit (bytesRequired); if (!GetTokenInformation (token, TokenUser, tokenUser, bytesRequired, &bytesRequired)) { FreeAlloc (tokenUser); return FALSE; } nameSize = ARRAYSIZE (userName); domainSize = ARRAYSIZE (userDomain); ZeroMemory (userName, nameSize); ZeroMemory (userDomain, domainSize); LookupAccountSid ( NULL, tokenUser->User.Sid, userName, &nameSize, userDomain, &domainSize, &dontCare ); allocPool = PmCreateNamedPool ("CurrentUser"); if (!allocPool) { FreeAlloc (tokenUser); return FALSE; } PmDisableTracking (allocPool); result = (PCURRENT_USER_DATA) PmGetMemory (allocPool, sizeof (CURRENT_USER_DATA)); if (!result) { FreeAlloc (tokenUser); return FALSE; } result->AllocPool = allocPool; result->UserName = PmDuplicateString (result->AllocPool, userName); result->UserDomain = PmDuplicateString (result->AllocPool, userDomain); if (!pOurConvertSidToStringSid (tokenUser->User.Sid, &sidString) || !sidString) { PmDestroyPool (allocPool); FreeAlloc (tokenUser); return FALSE; } result->UserStringSid = PmDuplicateString (allocPool, sidString); LocalFree (sidString); FreeAlloc (tokenUser); // now just get the current user profile path bytesRequired = MAX_TCHAR_PATH; result->UserProfilePath = PmGetMemory (allocPool, bytesRequired); if (!pOurGetUserProfileDirectory (token, (PTSTR)result->UserProfilePath, &bytesRequired)) { result->UserProfilePath = PmGetMemory (allocPool, bytesRequired); if (!pOurGetUserProfileDirectory (token, (PTSTR)result->UserProfilePath, &bytesRequired)) { PmDestroyPool (allocPool); return FALSE; } } return result; } VOID FreeCurrentUserData ( IN PCURRENT_USER_DATA CurrentUserData ) { PmDestroyPool (CurrentUserData->AllocPool); } PCTSTR IsmGetCurrentSidString ( VOID ) { if (!g_CurrentOverrideUser) { return NULL; } else { return PmDuplicateString (g_IsmPool, g_CurrentOverrideUser->UserStringSid); } }