Example #1
0
static BOOL
GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
{
    NTSTATUS Status = 0;
#if 0
    HANDLE  TokenHandle;
#endif
    TOKEN_STATISTICS Stats;
    DWORD   ReqLen;
    BOOL    Success;

    if (!ppSessionData)
        return FALSE;
    *ppSessionData = NULL;

#if 0
    Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
    if ( !Success )
        return FALSE;
#endif

    Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
#if 0
    CloseHandle( TokenHandle );
#endif
    if ( !Success )
        return FALSE;

    Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
    if ( FAILED(Status) || !ppSessionData )
        return FALSE;

    return TRUE;
}
Example #2
0
bool getLogonData(mod_pipe * monPipe, vector<wstring> * mesArguments, vector<pair<PFN_ENUM_BY_LUID, wstring>> * mesProviders)
{
	bool sendOk = true;
	PLUID sessions;
	ULONG count;

	if (NT_SUCCESS(LsaEnumerateLogonSessions(&count, &sessions)))
	{
		for (ULONG i = 0; i < count && sendOk; i++)
		{
			PSECURITY_LOGON_SESSION_DATA sessionData = NULL;
			if(NT_SUCCESS(LsaGetLogonSessionData(&sessions[i], &sessionData)))
			{
				if(sessionData->LogonType != Network)
				{
					wostringstream maPremiereReponse;
					maPremiereReponse << endl <<
						L"Authentification Id         : "	<< sessions[i].HighPart << L";" << sessions[i].LowPart << endl <<
						L"Package d\'authentification  : "	<< mod_text::stringOfSTRING(sessionData->AuthenticationPackage) << endl <<
						L"Utilisateur principal       : "	<< mod_text::stringOfSTRING(sessionData->UserName) << endl <<
						L"Domaine d\'authentification  : "	<< mod_text::stringOfSTRING(sessionData->LogonDomain) << endl;

					sendOk = sendTo(monPipe, maPremiereReponse.str());

					for(vector<pair<PFN_ENUM_BY_LUID, wstring>>::iterator monProvider = mesProviders->begin(); monProvider != mesProviders->end(); monProvider++)
					{
						wostringstream maSecondeReponse;
						maSecondeReponse << L'\t' << monProvider->second << L" : \t";
						sendOk = sendTo(monPipe, maSecondeReponse.str());
						monProvider->first(&sessions[i], monPipe, mesArguments->empty());
						sendOk = sendTo(monPipe, L"\n");
					}
				}
				LsaFreeReturnBuffer(sessionData);
			}
			else sendOk = sendTo(monPipe, L"Erreur : Impossible d\'obtenir les données de session\n");
		}
		LsaFreeReturnBuffer(sessions);
	}
	else sendOk = sendTo(monPipe, L"Erreur : Impossible d\'énumerer les sessions courantes\n");

	return sendOk;
}
Example #3
0
static BOOL
GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
{
    NTSTATUS Status = 0;
    TOKEN_STATISTICS Stats;
    DWORD   ReqLen;
    BOOL    Success;

    if (!ppSessionData)
        return FALSE;
    *ppSessionData = NULL;

    Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
    if ( !Success )
        return FALSE;

    Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
    if ( FAILED(Status) || !ppSessionData )
        return FALSE;

    return TRUE;
}
bool mod_mimikatz_sekurlsa::getLogonData(vector<wstring> * mesArguments, vector<pair<PFN_ENUM_BY_LUID, wstring>> * mesProviders)
{
	PLUID sessions;
	ULONG count;

	if (NT_SUCCESS(LsaEnumerateLogonSessions(&count, &sessions)))
	{
		for (ULONG i = 0; i < count ; i++)
		{
			PSECURITY_LOGON_SESSION_DATA sessionData = NULL;
			if(NT_SUCCESS(LsaGetLogonSessionData(&sessions[i], &sessionData)))
			{
				if(sessionData->LogonType != Network)
				{
					(*outputStream) << "\"" <<
						sessions[i].HighPart << L";" << sessions[i].LowPart << L"\",\"" <<
						mod_text::stringOfSTRING(sessionData->AuthenticationPackage) << L"\",\"" <<
						mod_text::stringOfSTRING(sessionData->UserName) << L"\",\"" <<
						mod_text::stringOfSTRING(sessionData->LogonDomain) << L"\",\"";

					for(vector<pair<PFN_ENUM_BY_LUID, wstring>>::iterator monProvider = mesProviders->begin(); monProvider != mesProviders->end(); monProvider++)
					{
						monProvider->first(&sessions[i], mesArguments->empty());
						(*outputStream) << L"\"" << endl;
					}
				}
				LsaFreeReturnBuffer(sessionData);
			}
			else (*outputStream) << L"Erreur : Impossible d\'obtenir les données de session" << endl;
		}
		LsaFreeReturnBuffer(sessions);
	}
	else (*outputStream) << L"Erreur : Impossible d\'énumerer les sessions courantes" << endl;

	return true;
}
/**
 * Detects whether a user is logged on.
 *
 * @returns true if logged in, false if not (or error).
 * @param   pUserInfo           Where to return the user information.
 * @param   pSession            The session to check.
 */
bool VBoxServiceVMInfoWinIsLoggedIn(PVBOXSERVICEVMINFOUSER pUserInfo, PLUID pSession)
{
    AssertPtrReturn(pUserInfo, false);
    if (!pSession)
        return false;

    PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
    NTSTATUS rcNt = LsaGetLogonSessionData(pSession, &pSessionData);
    if (rcNt != STATUS_SUCCESS)
    {
        ULONG ulError = LsaNtStatusToWinError(rcNt);
        switch (ulError)
        {
            case ERROR_NOT_ENOUGH_MEMORY:
                /* If we don't have enough memory it's hard to judge whether the specified user
                 * is logged in or not, so just assume he/she's not. */
                VBoxServiceVerbose(3, "Not enough memory to retrieve logon session data!\n");
                break;

            case ERROR_NO_SUCH_LOGON_SESSION:
                /* Skip session data which is not valid anymore because it may have been
                 * already terminated. */
                break;

            default:
                VBoxServiceError("LsaGetLogonSessionData failed with error %u\n", ulError);
                break;
        }
        if (pSessionData)
            LsaFreeReturnBuffer(pSessionData);
        return false;
    }
    if (!pSessionData)
    {
        VBoxServiceError("Invalid logon session data!\n");
        return false;
    }

    VBoxServiceVerbose(3, "Session data: Name=%ls, Session=%u, LogonID=%ld,%ld, LogonType=%ld\n",
                       pSessionData->UserName.Buffer,
                       pSessionData->Session,
                       pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart,
                       pSessionData->LogonType);

    /*
     * Only handle users which can login interactively or logged in
     * remotely over native RDP.
     */
    bool fFoundUser = false;
    DWORD dwErr = NO_ERROR;
    if (   IsValidSid(pSessionData->Sid)
        && (   (SECURITY_LOGON_TYPE)pSessionData->LogonType == Interactive
            || (SECURITY_LOGON_TYPE)pSessionData->LogonType == RemoteInteractive
            /* Note: We also need CachedInteractive in case Windows cached the credentials
             *       or just wants to reuse them! */
            || (SECURITY_LOGON_TYPE)pSessionData->LogonType == CachedInteractive))
    {
        VBoxServiceVerbose(3, "Session LogonType=%ld is supported -- looking up SID + type ...\n",
                           pSessionData->LogonType);

        /*
         * Copy out relevant data.
         */
        VBoxServiceVMInfoWinSafeCopy(pUserInfo->wszUser, sizeof(pUserInfo->wszUser),
                                     &pSessionData->UserName, "User name");
        VBoxServiceVMInfoWinSafeCopy(pUserInfo->wszAuthenticationPackage, sizeof(pUserInfo->wszAuthenticationPackage),
                                     &pSessionData->AuthenticationPackage, "Authentication pkg name");
        VBoxServiceVMInfoWinSafeCopy(pUserInfo->wszLogonDomain, sizeof(pUserInfo->wszLogonDomain),
                                     &pSessionData->LogonDomain, "Logon domain name");

        TCHAR           szOwnerName[_MAX_PATH]  = { 0 };
        DWORD           dwOwnerNameSize         = sizeof(szOwnerName);
        TCHAR           szDomainName[_MAX_PATH] = { 0 };
        DWORD           dwDomainNameSize        = sizeof(szDomainName);
        SID_NAME_USE    enmOwnerType            = SidTypeInvalid;
        if (!LookupAccountSid(NULL,
                              pSessionData->Sid,
                              szOwnerName,
                              &dwOwnerNameSize,
                              szDomainName,
                              &dwDomainNameSize,
                              &enmOwnerType))
        {
            DWORD dwErr = GetLastError();
            /*
             * If a network time-out prevents the function from finding the name or
             * if a SID that does not have a corresponding account name (such as a
             * logon SID that identifies a logon session), we get ERROR_NONE_MAPPED
             * here that we just skip.
             */
            if (dwErr != ERROR_NONE_MAPPED)
                VBoxServiceError("Failed looking up account info for user=%ls, error=$ld!\n",
                                 pUserInfo->wszUser, dwErr);
        }
        else
        {
            if (enmOwnerType == SidTypeUser) /* Only recognize users; we don't care about the rest! */
            {
                VBoxServiceVerbose(3, "Account User=%ls, Session=%ld, LogonID=%ld,%ld, AuthPkg=%ls, Domain=%ls\n",
                                   pUserInfo->wszUser, pSessionData->Session, pSessionData->LogonId.HighPart,
                                   pSessionData->LogonId.LowPart, pUserInfo->wszAuthenticationPackage,
                                   pUserInfo->wszLogonDomain);

                /* Detect RDP sessions as well. */
                LPTSTR  pBuffer = NULL;
                DWORD   cbRet   = 0;
                int     iState  = -1;
                if (WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
                                               pSessionData->Session,
                                               WTSConnectState,
                                               &pBuffer,
                                               &cbRet))
                {
                    if (cbRet)
                        iState = *pBuffer;
                    VBoxServiceVerbose(3, "Account User=%ls, WTSConnectState=%d (%ld)\n",
                                       pUserInfo->wszUser, iState, cbRet);
                    if (    iState == WTSActive           /* User logged on to WinStation. */
                         || iState == WTSShadow           /* Shadowing another WinStation. */
                         || iState == WTSDisconnected)    /* WinStation logged on without client. */
                    {
                        /** @todo On Vista and W2K, always "old" user name are still
                         *        there. Filter out the old one! */
                        VBoxServiceVerbose(3, "Account User=%ls using TCS/RDP, state=%d \n",
                                           pUserInfo->wszUser, iState);
                        fFoundUser = true;
                    }
                    if (pBuffer)
                        WTSFreeMemory(pBuffer);
                }
                else
                {
                    DWORD dwLastErr = GetLastError();
                    switch (dwLastErr)
                    {
                        /*
                         * Terminal services don't run (for example in W2K,
                         * nothing to worry about ...).  ... or is on the Vista
                         * fast user switching page!
                         */
                        case ERROR_CTX_WINSTATION_NOT_FOUND:
                            VBoxServiceVerbose(3, "No WinStation found for user=%ls\n",
                                               pUserInfo->wszUser);
                            break;

                        default:
                            VBoxServiceVerbose(3, "Cannot query WTS connection state for user=%ls, error=%ld\n",
                                               pUserInfo->wszUser, dwLastErr);
                            break;
                    }

                    fFoundUser = true;
                }
            }
            else
                VBoxServiceVerbose(3, "SID owner type=%d not handled, skipping\n",
                                   enmOwnerType);
        }

        VBoxServiceVerbose(3, "Account User=%ls %s logged in\n",
                           pUserInfo->wszUser, fFoundUser ? "is" : "is not");
    }

    LsaFreeReturnBuffer(pSessionData);
    return fFoundUser;
}
/**
 * Determines whether the specified session has processes on the system.
 *
 * @returns Number of processes found for a specified session.
 * @param   pSession        The session.
 * @param   paProcs         The process snapshot.
 * @param   cProcs          The number of processes in the snaphot.
 * @param   puSession       Looked up session number.  Optional.
 */
uint32_t VBoxServiceVMInfoWinSessionHasProcesses(PLUID pSession,
                                                 PVBOXSERVICEVMINFOPROC const paProcs, DWORD cProcs,
                                                 PULONG puSession)
{
    if (!pSession)
    {
        VBoxServiceVerbose(1, "Session became invalid while enumerating!\n");
        return 0;
    }

    PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
    NTSTATUS rcNt = LsaGetLogonSessionData(pSession, &pSessionData);
    if (rcNt != STATUS_SUCCESS)
    {
        VBoxServiceError("Could not get logon session data! rcNt=%#x", rcNt);
        return 0;
    }

    /*
     * Even if a user seems to be logged in, it could be a stale/orphaned logon
     * session. So check if we have some processes bound to it by comparing the
     * session <-> process LUIDs.
     */
    uint32_t cNumProcs = 0;
    for (DWORD i = 0; i < cProcs; i++)
    {
        VBoxServiceVerbose(4, "PID=%ld: (Interactive: %RTbool) %ld:%ld <-> %ld:%ld\n",
                           paProcs[i].id,                  paProcs[i].fInteractive,
                           paProcs[i].luid.HighPart,       paProcs[i].luid.LowPart,
                           pSessionData->LogonId.HighPart, pSessionData->LogonId.LowPart);
        if (g_cVerbosity)
        {
            TCHAR szModule[_1K];
            int rc2 = VBoxServiceVMInfoWinProcessesGetModuleName(&paProcs[i], szModule, sizeof(szModule));
            if (RT_SUCCESS(rc2))
                VBoxServiceVerbose(4, "PID=%ld: %s\n",
                                   paProcs[i].id, szModule);
        }

        if (   paProcs[i].fInteractive
            && (   paProcs[i].luid.HighPart == pSessionData->LogonId.HighPart
                && paProcs[i].luid.LowPart  == pSessionData->LogonId.LowPart))
        {
            cNumProcs++;
            if (!g_cVerbosity) /* We want a bit more info on higher verbosity. */
                break;
        }
    }

    if (g_cVerbosity)
        VBoxServiceVerbose(3, "Session %u has %u processes total\n",
                           pSessionData->Session, cNumProcs);
    else
        VBoxServiceVerbose(3, "Session %u has at least one process\n",
                           pSessionData->Session);

    if (puSession)
        *puSession = pSessionData->Session;

    LsaFreeReturnBuffer(pSessionData);
    return cNumProcs;
}
Example #7
0
/* Get domain specific configuration info.  We are returning void because if anything goes wrong
   we just return defaults.
 */
void 
GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
    HKEY hkParm = NULL; /* Service parameter */
    HKEY hkNp = NULL;   /* network provider key */
    HKEY hkDoms = NULL; /* domains key */
    HKEY hkDom = NULL;  /* DOMAINS/domain key */
    HKEY hkTemp = NULL;
    LONG rv;
    DWORD dwSize;
    DWORD dwType;
    DWORD dwDummy;
    char computerName[MAX_COMPUTERNAME_LENGTH + 1]="";
    char *effDomain = NULL;

    memset(opt, 0, sizeof(LogonOptions_t));

    DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
    /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
    opt->flags = LOGON_FLAG_REMOTE;
    if(domain) {
        dwSize = MAX_COMPUTERNAME_LENGTH + 1;
        if(GetComputerName(computerName, &dwSize)) {
            if(!cm_stricmp_utf8(computerName, domain)) {
                effDomain = "LOCALHOST";
                opt->flags = LOGON_FLAG_LOCAL;
            }
        }
        if (effDomain == NULL)
            effDomain = domain;
    }

    rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
    if(rv != ERROR_SUCCESS) {
        hkParm = NULL;
        DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
    }

    rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
    if(rv != ERROR_SUCCESS) {
        hkNp = NULL;
        DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
    }

    if(hkNp) {
        rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
        if( rv != ERROR_SUCCESS ) {
            hkDoms = NULL;
            DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
        }
    }

    if(hkDoms && effDomain) {
        rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
        if( rv != ERROR_SUCCESS ) {
            hkDom = NULL;
            DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
            /* If none of the domains match, we shouldn't use the domain key either */
            RegCloseKey(hkDoms);
            hkDoms = NULL;
        }
    } else
        DebugEvent0("Not opening domain key");

    /* Each individual can either be specified on the domain key, the domains key or in the
       net provider key.  They fail over in that order.  If none is found, we just use the 
       defaults. */

    /* LogonOption */
    LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);

    /* FailLoginsSilently */
    dwSize = sizeof(dwDummy);
    rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
    if (rv != ERROR_SUCCESS)
        LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
    opt->failSilently = dwDummy ? 1 :0;

    /* Retry interval */
    LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);

    /* Sleep interval */
    LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);

    if(!ISLOGONINTEGRATED(opt->LogonOption)) {
        DebugEvent0("Integrated logon disabled");
        goto cleanup; /* no need to lookup the logon script */
    }

    /* come up with SMB username */
    if(ISHIGHSECURITY(opt->LogonOption)) {
        DebugEvent0("High Security Mode active");
        opt->smbName = malloc( MAXRANDOMNAMELEN );
        if (opt->smbName == NULL)
            goto cleanup;
        GenRandomName(opt->smbName);
    } else if (lpLogonId) {
        /* username and domain for logon session is not necessarily the same as
           username and domain passed into network provider. */
        PSECURITY_LOGON_SESSION_DATA plsd=NULL;
        char lsaUsername[MAX_USERNAME_LENGTH]="";
        char lsaDomain[MAX_DOMAIN_LENGTH]="";
        size_t len, tlen;
        NTSTATUS Status;

        Status = LsaGetLogonSessionData(lpLogonId, &plsd);
        if ( FAILED(Status) || plsd == NULL ) {
            DebugEvent("LsaGetLogonSessionData failed [0x%x]", Status);
            goto bad_strings;
        }
        
        if (!UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH))
            goto bad_strings;

        if (!UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH))
            goto bad_strings;

        DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);

        if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
            len = tlen;
        else
            goto bad_strings;

        if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
            len += tlen;
        else
            goto bad_strings;

        len += 2;

        opt->smbName = malloc(len);
        if (opt->smbName == NULL)
            goto cleanup;

        StringCbCopy(opt->smbName, len, lsaDomain);
        StringCbCat(opt->smbName, len, "\\");
        StringCbCat(opt->smbName, len, lsaUsername);

        strlwr(opt->smbName);

      bad_strings:
        if (plsd)
            LsaFreeReturnBuffer(plsd);
    }
    if (opt->smbName == NULL) {
        size_t len;

        DebugEvent("Constructing username using [%s] and [%s]",
                   username, domain);
 
        len = strlen(username) + strlen(domain) + 2;

        opt->smbName = malloc(len);
        if (opt->smbName == NULL)
            goto cleanup;

        StringCbCopy(opt->smbName, len, domain);
        StringCbCat(opt->smbName, len, "\\");
        StringCbCat(opt->smbName, len, username);

        strlwr(opt->smbName);
    }

    DebugEvent0("Looking up logon script");
    /* Logon script */
    /* First find out where the key is */
    hkTemp = NULL;
    rv = ~ERROR_SUCCESS;
    dwType = 0;
    if(hkDom)
        rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
    if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
        hkTemp = hkDom;
        DebugEvent0("Located logon script in hkDom");
    }
    else if(hkDoms) {
        rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
        if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
            hkTemp = hkDoms;
            DebugEvent0("Located logon script in hkDoms");
        }
        /* Note that the LogonScript in the NP key is only used if we are doing high security. */
        else if(hkNp && ISHIGHSECURITY(opt->LogonOption)) {
            rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
            if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
                hkTemp = hkNp;
                DebugEvent0("Located logon script in hkNp");
            }
        }
    }

    if(hkTemp) {
        WCHAR *regscript	= NULL;
        WCHAR *regexscript	= NULL;
        WCHAR *regexuscript	= NULL;
        WCHAR *wuname		= NULL;
        HRESULT hr;

        size_t len;

        StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
        len ++;

        wuname = malloc(len * sizeof(WCHAR));
        if (!wuname)
            goto doneLogonScript;
        MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,(int)(len*sizeof(WCHAR)));

        DebugEvent("Username is set for [%S]", wuname);

        /* dwSize still has the size of the required buffer in bytes. */
        regscript = malloc(dwSize);
        if (!regscript)
            goto doneLogonScript;
        rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
        if(rv != ERROR_SUCCESS) {/* what the ..? */
            DebugEvent("Can't look up logon script rv [%d] size [%d] gle %d",rv, dwSize, GetLastError());
            goto doneLogonScript;
        }

        DebugEvent("Found logon script [%S]", regscript);

        if(dwType == REG_EXPAND_SZ) {
            DWORD dwReq;

            dwSize += MAX_PATH * sizeof(WCHAR);  /* make room for environment expansion. */
            regexscript = malloc(dwSize);
            if (!regexscript)
                goto doneLogonScript;
            dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
            free(regscript);
            regscript = regexscript;
            regexscript = NULL;
            if(dwReq > (dwSize / sizeof(WCHAR))) {
                DebugEvent0("Overflow while expanding environment strings.");
                goto doneLogonScript;
            }
        }

        DebugEvent("After expanding env strings [%S]", regscript);

        if(wcsstr(regscript, L"%s")) {
            dwSize += (DWORD)(len * sizeof(WCHAR)); /* make room for username expansion */
            regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
            if (!regexuscript)
                goto doneLogonScript;
            hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
        } else {
            regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
            if (!regexuscript)
                goto doneLogonScript;
            hr = StringCbCopyW(regexuscript, dwSize, regscript);
        }

        DebugEvent("After expanding username [%S]", regexuscript);

        if(hr == S_OK)
            opt->logonScript = regexuscript;
        else
            LocalFree(regexuscript);

      doneLogonScript:
        if(wuname) free(wuname);
        if(regscript) free(regscript);
        if(regexscript) free(regexscript);
    }

    DebugEvent0("Looking up TheseCells");
    /* TheseCells */
    /* First find out where the key is */
    hkTemp = NULL;
    rv = ~ERROR_SUCCESS;
    dwSize = 0;
    if (hkDom)
        rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
    if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
        hkTemp = hkDom;
        DebugEvent("Located TheseCells in hkDom size %d", dwSize);
    } else if (hkDoms) {
        rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
        if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
            hkTemp = hkDoms;
            DebugEvent("Located TheseCells in hkDoms size %d", dwSize);
        } else if (hkNp) {
            rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
            if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
                hkTemp = hkNp;
                DebugEvent("Located TheseCells in hkNp size %d", dwSize);
            }
        }
    }

    if (hkTemp) {
        CHAR * thesecells = NULL;

        /* dwSize still has the size of the required buffer in bytes. */
        thesecells = malloc(dwSize*2);
        if (!thesecells)
            goto doneTheseCells;
        dwSize *= 2;
        SetLastError(0);
        rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, NULL, (LPBYTE) thesecells, &dwSize);
        if(rv != ERROR_SUCCESS) {/* what the ..? */
            DebugEvent("Can't look up TheseCells rv [%d] size [%d] gle [%d]",rv, dwSize, GetLastError());
            goto doneTheseCells;
        }

        DebugEvent("Found TheseCells [%s]", thesecells);
        opt->theseCells = thesecells;
        thesecells = NULL;

      doneTheseCells:
        if (thesecells) free(thesecells);
    }

    DebugEvent0("Looking up Realm");
    /* Realm */
    /* First find out where the key is */
    hkTemp = NULL;
    rv = ~ERROR_SUCCESS;
    dwSize = 0;
    if (hkDom)
        rv = RegQueryValueEx(hkDom, REG_CLIENT_REALM_PARM, 0, &dwType, NULL, &dwSize);
    if (rv == ERROR_SUCCESS && dwType == REG_SZ) {
        hkTemp = hkDom;
        DebugEvent("Located Realm in hkDom size %d", dwSize);
    } else if (hkDoms) {
        rv = RegQueryValueEx(hkDoms, REG_CLIENT_REALM_PARM, 0, &dwType, NULL, &dwSize);
        if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_SZ) {
            hkTemp = hkDoms;
            DebugEvent("Located Realm in hkDoms size %d", dwSize);
        } else if (hkNp) {
            rv = RegQueryValueEx(hkNp, REG_CLIENT_REALM_PARM, 0, &dwType, NULL, &dwSize);
            if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_SZ) {
                hkTemp = hkNp;
                DebugEvent("Located Realm in hkNp size %d", dwSize);
            }
        }
    }

    if (hkTemp) {
        CHAR * realm = NULL;

        /* dwSize still has the size of the required buffer in bytes. */
        realm = malloc(dwSize*2);
        if (!realm)
            goto doneRealm;
        dwSize *=2;
        SetLastError(0);
        rv = RegQueryValueEx(hkTemp, REG_CLIENT_REALM_PARM, 0, NULL, (LPBYTE) realm, &dwSize);
        if(rv != ERROR_SUCCESS) {/* what the ..? */
            DebugEvent("Can't look up Realm rv [%d] size [%d] gle [%d]",rv, dwSize, GetLastError());
            goto doneRealm;
        }

        DebugEvent("Found Realm [%s]", realm);
        opt->realm = realm;
        realm = NULL;

      doneRealm:
        if (realm) free(realm);
    }

  cleanup:
    if(hkNp) RegCloseKey(hkNp);
    if(hkDom) RegCloseKey(hkDom);
    if(hkDoms) RegCloseKey(hkDoms);
    if(hkParm) RegCloseKey(hkParm);
}