/*++

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:

    <alias> <date> <comments>

--*/

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