//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1993 - 1999.
//
//  File:       CLocalMachine.cpp
//
//  Contents:   implementation of CLocalMachine
//
//----------------------------------------------------------------------------

#include "priv.h"

#include "UserOM.h"
#include "LogonIPC.h"
#include "CInteractiveLogon.h"
#include "WinUser.h"
#include "trayp.h"      // for TM_REFRESH
#include <lmaccess.h>   // for NetUserModalsGet
#include <lmapibuf.h>   // for NetApiBufferFree
#include <lmerr.h>      // for NERR_Success
#include <ntlsa.h>
#include <cfgmgr32.h>
//
// IUnknown Interface
//

ULONG CLocalMachine::AddRef()
{
    _cRef++;
    return _cRef;
}


ULONG CLocalMachine::Release()
{
    ASSERT(_cRef > 0);
    _cRef--;

    if (_cRef > 0)
    {
        return _cRef;
    }

    delete this;
    return 0;
}


HRESULT CLocalMachine::QueryInterface(REFIID riid, void **ppvObj)
{
    static const QITAB qit[] = 
    {
        QITABENT(CLocalMachine, IDispatch),
        QITABENT(CLocalMachine, ILocalMachine),
        {0},
    };

    return QISearch(this, qit, riid, ppvObj);
}


//
// IDispatch Interface
//

STDMETHODIMP CLocalMachine::GetTypeInfoCount(UINT* pctinfo)
{ 
    return CIDispatchHelper::GetTypeInfoCount(pctinfo); 
}


STDMETHODIMP CLocalMachine::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{ 
    return CIDispatchHelper::GetTypeInfo(itinfo, lcid, pptinfo); 
}


STDMETHODIMP CLocalMachine::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{ 
    return CIDispatchHelper::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); 
}


STDMETHODIMP CLocalMachine::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
    return CIDispatchHelper::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}


//
// ILocalMachine Interface
//



STDMETHODIMP CLocalMachine::get_MachineName(VARIANT* pvar)
{
    HRESULT hr;
    DWORD cch;
    WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH+1];

    if (pvar)
    {
        pvar->vt = VT_BSTR;
        cch = MAX_COMPUTERNAME_LENGTH+1;
        if (GetComputerNameW(szMachineName, &cch))
        {
            pvar->bstrVal = SysAllocString(szMachineName);
        }
        else
        {
            pvar->bstrVal = SysAllocString(TEXT(""));
        }
        hr = S_OK;
    }
    else
    {
        hr = E_INVALIDARG;
    }

    return hr;
}


DWORD BuildAccountSidFromRid(LPCWSTR pszServer, DWORD dwRid, PSID* ppSid)
{
    DWORD dwErr = ERROR_SUCCESS;
    PUSER_MODALS_INFO_2 umi2;
    NET_API_STATUS nasRet;

    // Get the account domain Sid on the target machine
    nasRet = NetUserModalsGet(pszServer, 2, (LPBYTE*)&umi2);

    if ( nasRet == NERR_Success )
    {
        UCHAR cSubAuthorities;
        PSID pSid;

        cSubAuthorities = *GetSidSubAuthorityCount(umi2->usrmod2_domain_id);

        // Allocate storage for new the Sid (domain Sid + account Rid)
        pSid = (PSID)LocalAlloc(LPTR, GetSidLengthRequired((UCHAR)(cSubAuthorities+1)));

        if ( pSid != NULL )
        {
            if ( InitializeSid(pSid,
                               GetSidIdentifierAuthority(umi2->usrmod2_domain_id),
                               (BYTE)(cSubAuthorities+1)) )
            {
                // Copy existing subauthorities from domain Sid to new Sid
                for (UINT i = 0; i < cSubAuthorities; i++)
                {
                    *GetSidSubAuthority(pSid, i) = *GetSidSubAuthority(umi2->usrmod2_domain_id, i);
                }

                // Append Rid to new Sid
                *GetSidSubAuthority(pSid, cSubAuthorities) = dwRid;

                *ppSid = pSid;
            }
            else
            {
                dwErr = GetLastError();
                LocalFree(pSid);
            }
        }
        else
        {
            dwErr = GetLastError();
        }

        NetApiBufferFree(umi2);
    }
    else
    {
        dwErr = nasRet;
    }

    return dwErr;
}

BYTE s_rgbGuestSid[sizeof(SID) + (SID_MAX_SUB_AUTHORITIES-1)*sizeof(ULONG)] = {0};

DWORD GetGuestSid(PSID* ppSid)
{
    DWORD dwErr = ERROR_SUCCESS;

    if (0 == *GetSidSubAuthorityCount((PSID)s_rgbGuestSid))
    {
        PSID pSid = NULL;
        dwErr = BuildAccountSidFromRid(NULL, DOMAIN_USER_RID_GUEST, &pSid);

        if (ERROR_SUCCESS == dwErr)
        {
            CopySid(sizeof(s_rgbGuestSid), (PSID)s_rgbGuestSid, pSid);
            LocalFree(pSid);
        }
    }

    // There is no need to free the returned PSID (static buffer)
    *ppSid = (PSID)s_rgbGuestSid;

    return dwErr;
}

WCHAR s_szGuest[UNLEN + sizeof('\0')]     =   L"";

LPCWSTR GetGuestAccountName(void)
{
    if (s_szGuest[0] == L'\0')
    {
        DWORD           dwGuestSize, dwDomainSize;
        WCHAR           szDomain[DNLEN + sizeof('\0')];
        PSID            pSID;
        SID_NAME_USE    eUse;

        dwGuestSize = ARRAYSIZE(s_szGuest);
        dwDomainSize = ARRAYSIZE(szDomain);
        if ((ERROR_SUCCESS != GetGuestSid(&pSID)) ||
            !LookupAccountSidW(NULL,
                               pSID,
                               s_szGuest,
                               &dwGuestSize,
                               szDomain,
                               &dwDomainSize,
                               &eUse))
        {
            // Huh?  No Guest account on this machine. Try English.
            lstrcpyW(s_szGuest, L"Guest");

            // Try to go the other way and lookup the SID.
            // If this fails, we're SOL.
            *GetSidSubAuthorityCount((PSID)s_rgbGuestSid) = 0;
            dwGuestSize = sizeof(s_rgbGuestSid);
            dwDomainSize = ARRAYSIZE(szDomain);
            LookupAccountNameW(NULL,
                               s_szGuest,
                               (PSID)s_rgbGuestSid,
                               &dwGuestSize,
                               szDomain,
                               &dwDomainSize,
                               &eUse);
        }
    }
    return(s_szGuest);
}

STDMETHODIMP CLocalMachine::get_isGuestEnabled(ILM_GUEST_FLAGS flags, VARIANT_BOOL* pbEnabled)
{
    HRESULT         hr = S_OK;
    DWORD           dwErr;
    BOOL            bEnabled = FALSE;
    USER_INFO_1     *pusri1 = NULL;
    DWORD           dwFlags = (DWORD)(flags & (ILM_GUEST_INTERACTIVE_LOGON | ILM_GUEST_NETWORK_LOGON));

    if (NULL == pbEnabled)
        return E_POINTER;

    //  First check to see if the guest account is truly enabled

    dwErr = NetUserGetInfo(NULL, GetGuestAccountName(), 1, (LPBYTE*)&pusri1);
    if ((ERROR_SUCCESS == dwErr) && ((pusri1->usri1_flags & UF_ACCOUNTDISABLE) == 0))
    {
        // Guest is enabled
        bEnabled = TRUE;

        // Do they want to check the LSA logon rights?
        if (0 != dwFlags)
        {
            BOOL bDenyInteractiveLogon = FALSE;
            BOOL bDenyNetworkLogon = FALSE;
            LSA_HANDLE hLsa;
            LSA_OBJECT_ATTRIBUTES oa = {0};

            oa.Length = sizeof(oa);
            dwErr = LsaNtStatusToWinError(LsaOpenPolicy(NULL, &oa, POLICY_LOOKUP_NAMES, &hLsa));

            if (ERROR_SUCCESS == dwErr)
            {
                PSID pSid;

                dwErr = GetGuestSid(&pSid);
                if (ERROR_SUCCESS == dwErr)
                {
                    PLSA_UNICODE_STRING pAccountRights;
                    ULONG cRights;

                    // Get the list of LSA rights assigned to the Guest account
                    //
                    // Note that SE_INTERACTIVE_LOGON_NAME is often inherited via
                    // group membership, so its absence doesn't mean much. We could
                    // bend over backwards and check group membership and such, but
                    // Guest normally gets SE_INTERACTIVE_LOGON_NAME one way or
                    // another, so we only check for SE_DENY_INTERACTIVE_LOGON_NAME
                    // here.

                    dwErr = LsaNtStatusToWinError(LsaEnumerateAccountRights(hLsa, pSid, &pAccountRights, &cRights));
                    if (ERROR_SUCCESS == dwErr)
                    {
                        PLSA_UNICODE_STRING pRight;
                        for (pRight = pAccountRights; cRights > 0 && 0 != dwFlags; pRight++, cRights--)
                        {
                            if (0 != (dwFlags & ILM_GUEST_INTERACTIVE_LOGON) &&
                                CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT,
                                                             NORM_IGNORECASE,
                                                             SE_DENY_INTERACTIVE_LOGON_NAME,
                                                             -1,
                                                             pRight->Buffer,
                                                             pRight->Length/2))
                            {
                                bDenyInteractiveLogon = TRUE;
                                dwFlags &= ~ILM_GUEST_INTERACTIVE_LOGON;
                            }
                            else if (0 != (dwFlags & ILM_GUEST_NETWORK_LOGON) &&
                                CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT,
                                                             NORM_IGNORECASE,
                                                             SE_DENY_NETWORK_LOGON_NAME,
                                                             -1,
                                                             pRight->Buffer,
                                                             pRight->Length/2))
                            {
                                bDenyNetworkLogon = TRUE;
                                dwFlags &= ~ILM_GUEST_NETWORK_LOGON;
                            }
                        }
                        LsaFreeMemory(pAccountRights);
                    }
                    else if (ERROR_FILE_NOT_FOUND == dwErr)
                    {
                        // Guest isn't in LSA's database, so we know it can't
                        // have either of the deny logon rights.
                        dwErr = ERROR_SUCCESS;
                    }
                }
                LsaClose(hLsa);
            }

            if (bDenyInteractiveLogon || bDenyNetworkLogon)
                bEnabled = FALSE;
        }
    }

    if (NULL != pusri1)
    {
        (NET_API_STATUS)NetApiBufferFree(pusri1);
    }

    hr = HRESULT_FROM_WIN32(dwErr);

    *pbEnabled = bEnabled ? VARIANT_TRUE : VARIANT_FALSE;

    return hr;
}

STDMETHODIMP CLocalMachine::EnableGuest(ILM_GUEST_FLAGS flags)
{
    DWORD           dwErr;
    USER_INFO_1     *pusri1;
    DWORD dwFlags = (DWORD)(flags & (ILM_GUEST_INTERACTIVE_LOGON | ILM_GUEST_NETWORK_LOGON));

    //  First truly enable the guest account. Do this ALL the time.

    dwErr = NetUserGetInfo(NULL, GetGuestAccountName(), 1, (LPBYTE*)&pusri1);
    if (ERROR_SUCCESS == dwErr)
    {
        pusri1->usri1_flags &= ~UF_ACCOUNTDISABLE;
        dwErr = NetUserSetInfo(NULL, GetGuestAccountName(), 1, (LPBYTE)pusri1, NULL);
        if (ERROR_SUCCESS == dwErr && 0 != dwFlags)
        {
            LSA_HANDLE hLsa;
            LSA_OBJECT_ATTRIBUTES oa = {0};

            oa.Length = sizeof(oa);
            dwErr = LsaNtStatusToWinError(LsaOpenPolicy(NULL, &oa, POLICY_LOOKUP_NAMES, &hLsa));

            if (ERROR_SUCCESS == dwErr)
            {
                PSID pSid;

                dwErr = GetGuestSid(&pSid);
                if (ERROR_SUCCESS == dwErr)
                {
                    if (0 != (dwFlags & ILM_GUEST_INTERACTIVE_LOGON))
                    {
                        DECLARE_CONST_UNICODE_STRING(usDenyLogon, SE_DENY_INTERACTIVE_LOGON_NAME);
                        NTSTATUS status = LsaRemoveAccountRights(hLsa, pSid, FALSE, (PLSA_UNICODE_STRING)&usDenyLogon, 1);
                        dwErr = LsaNtStatusToWinError(status);
                    }
                    if (0 != (dwFlags & ILM_GUEST_NETWORK_LOGON))
                    {
                        DECLARE_CONST_UNICODE_STRING(usDenyLogon, SE_DENY_NETWORK_LOGON_NAME);
                        NTSTATUS status = LsaRemoveAccountRights(hLsa, pSid, FALSE, (PLSA_UNICODE_STRING)&usDenyLogon, 1);
                        if (ERROR_SUCCESS == dwErr)
                            dwErr = LsaNtStatusToWinError(status);
                    }

                    if (ERROR_FILE_NOT_FOUND == dwErr)
                    {
                        //
                        // NTRAID#NTBUG9-396428-2001/05/16-jeffreys
                        //
                        // This means Guest isn't in LSA's database, so we know
                        // it can't have either of the deny logon rights. Since
                        // we were trying to remove one or both rights, count
                        // this as success.
                        //
                        dwErr = ERROR_SUCCESS;
                    }
                }
                LsaClose(hLsa);
            }
        }
        (NET_API_STATUS)NetApiBufferFree(pusri1);
    }

    return HRESULT_FROM_WIN32(dwErr);
}

STDMETHODIMP CLocalMachine::DisableGuest(ILM_GUEST_FLAGS flags)
{
    DWORD dwErr = ERROR_SUCCESS;
    DWORD dwFlags = (DWORD)(flags & (ILM_GUEST_INTERACTIVE_LOGON | ILM_GUEST_NETWORK_LOGON));

    if (0 != dwFlags)
    {
        LSA_HANDLE hLsa;
        LSA_OBJECT_ATTRIBUTES oa = {0};

        // Turn on DenyInteractiveLogon and/or DenyNetworkLogon, but don't
        // necessarily change the enabled state of the guest account.

        oa.Length = sizeof(oa);
        dwErr = LsaNtStatusToWinError(LsaOpenPolicy(NULL, &oa, POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, &hLsa));

        if (ERROR_SUCCESS == dwErr)
        {
            PSID pSid;

            dwErr = GetGuestSid(&pSid);
            if (ERROR_SUCCESS == dwErr)
            {
                if (0 != (dwFlags & ILM_GUEST_INTERACTIVE_LOGON))
                {
                    DECLARE_CONST_UNICODE_STRING(usDenyLogon, SE_DENY_INTERACTIVE_LOGON_NAME);
                    NTSTATUS status = LsaAddAccountRights(hLsa, pSid, (PLSA_UNICODE_STRING)&usDenyLogon, 1);
                    dwErr = LsaNtStatusToWinError(status);
                }
                if (0 != (dwFlags & ILM_GUEST_NETWORK_LOGON))
                {
                    DECLARE_CONST_UNICODE_STRING(usDenyLogon, SE_DENY_NETWORK_LOGON_NAME);
                    NTSTATUS status = LsaAddAccountRights(hLsa, pSid, (PLSA_UNICODE_STRING)&usDenyLogon, 1);
                    if (ERROR_SUCCESS == dwErr)
                        dwErr = LsaNtStatusToWinError(status);
                }
            }
            LsaClose(hLsa);
        }

        if (ERROR_SUCCESS == dwErr)
        {
            // If both  SE_DENY_INTERACTIVE_LOGON_NAME and SE_DENY_NETWORK_LOGON_NAME
            // are turned on, then we might as well disable the account altogether.
            if ((ILM_GUEST_INTERACTIVE_LOGON | ILM_GUEST_NETWORK_LOGON) == dwFlags)
            {
                // We just turned both on, so disable guest below
                dwFlags = 0;
            }
            else
            {
                VARIANT_BOOL bEnabled;

                if (ILM_GUEST_INTERACTIVE_LOGON == dwFlags)
                {
                    // We just turned on SE_DENY_INTERACTIVE_LOGON_NAME, check
                    // for SE_DENY_NETWORK_LOGON_NAME.
                    flags = ILM_GUEST_NETWORK_LOGON;
                }
                else if (ILM_GUEST_NETWORK_LOGON == dwFlags)
                {
                    // We just turned on SE_DENY_NETWORK_LOGON_NAME, check
                    // for SE_DENY_INTERACTIVE_LOGON_NAME.
                    flags = ILM_GUEST_INTERACTIVE_LOGON;
                }
                else
                {
                    // Getting here implies that someone defined a new flag.
                    // Setting flags to ILM_GUEST_ACCOUNT causes a benign
                    // result in all cases (we only disable guest if guest
                    // is already disabled).
                    flags = ILM_GUEST_ACCOUNT;
                }

                if (SUCCEEDED(get_isGuestEnabled(flags, &bEnabled)) && (VARIANT_FALSE == bEnabled))
                {
                    // Both are on, so disable guest below
                    dwFlags = 0;
                }
            }
        }
    }

    if (0 == dwFlags)
    {
        USER_INFO_1 *pusri1;

        //  Truly disable the guest account.

        dwErr = NetUserGetInfo(NULL, GetGuestAccountName(), 1, (LPBYTE*)&pusri1);
        if (ERROR_SUCCESS == dwErr)
        {
            pusri1->usri1_flags |= UF_ACCOUNTDISABLE;
            dwErr = NetUserSetInfo(NULL, GetGuestAccountName(), 1, (LPBYTE)pusri1, NULL);
            (NET_API_STATUS)NetApiBufferFree(pusri1);
        }
    }

    return HRESULT_FROM_WIN32(dwErr);
}

STDMETHODIMP CLocalMachine::get_isFriendlyUIEnabled(VARIANT_BOOL* pbEnabled)

{
    *pbEnabled = ShellIsFriendlyUIActive() ? VARIANT_TRUE : VARIANT_FALSE;
    return(S_OK);
}

STDMETHODIMP CLocalMachine::put_isFriendlyUIEnabled(VARIANT_BOOL bEnabled)

{
    HRESULT hr;

    if (ShellEnableFriendlyUI(bEnabled != VARIANT_FALSE ? TRUE : FALSE) != FALSE)
    {
        RefreshStartMenu();
        hr = S_OK;
    }
    else
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }
    return(hr);
}

STDMETHODIMP CLocalMachine::get_isMultipleUsersEnabled(VARIANT_BOOL* pbEnabled)

{
    *pbEnabled = ShellIsMultipleUsersEnabled() ? VARIANT_TRUE : VARIANT_FALSE;
    return(S_OK);
}

STDMETHODIMP CLocalMachine::put_isMultipleUsersEnabled(VARIANT_BOOL bEnabled)

{
    HRESULT hr;

    if (ShellEnableMultipleUsers(bEnabled != VARIANT_FALSE ? TRUE : FALSE) != FALSE)
    {
        RefreshStartMenu();
        hr = S_OK;
    }
    else
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }
    return(hr);
}

STDMETHODIMP CLocalMachine::get_isRemoteConnectionsEnabled(VARIANT_BOOL* pbEnabled)

{
    *pbEnabled = ShellIsRemoteConnectionsEnabled() ? VARIANT_TRUE : VARIANT_FALSE;
    return(S_OK);
}

STDMETHODIMP CLocalMachine::put_isRemoteConnectionsEnabled(VARIANT_BOOL bEnabled)

{
    HRESULT hr;

    if (ShellEnableRemoteConnections(bEnabled != VARIANT_FALSE ? TRUE : FALSE) != FALSE)
    {
        RefreshStartMenu();
        hr = S_OK;
    }
    else
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }
    return(hr);
}

BOOL _CanEject()
{
    BOOL fEjectAllowed = FALSE;

    if(SHRestricted(REST_NOSMEJECTPC))  //Is there a policy restriction?
        return FALSE;

    CM_Is_Dock_Station_Present(&fEjectAllowed);

    return SHTestTokenPrivilege(NULL, SE_UNDOCK_NAME) &&
           fEjectAllowed  &&
           !GetSystemMetrics(SM_REMOTESESSION);
}

STDMETHODIMP CLocalMachine::get_isUndockEnabled(VARIANT_BOOL* pbEnabled)

{
    CLogonIPC   objLogon;

    if (objLogon.IsLogonServiceAvailable())
    {
        *pbEnabled = objLogon.TestEjectAllowed() ? VARIANT_TRUE : VARIANT_FALSE;
    }
    else
    {
        *pbEnabled = _CanEject() ? VARIANT_TRUE : VARIANT_FALSE;
    }
    return(S_OK);
}

STDMETHODIMP CLocalMachine::get_isShutdownAllowed(VARIANT_BOOL* pbShutdownAllowed)

{
    CLogonIPC   objLogon;

    if (objLogon.IsLogonServiceAvailable())
    {
        *pbShutdownAllowed = objLogon.TestShutdownAllowed() ? VARIANT_TRUE : VARIANT_FALSE;
    }
    else
    {
        *pbShutdownAllowed = VARIANT_FALSE;
    }
    return(S_OK);
}

STDMETHODIMP CLocalMachine::get_isGuestAccessMode(VARIANT_BOOL* pbForceGuest)
{
    *pbForceGuest = SUCCEEDED(_IsGuestAccessMode()) ? VARIANT_TRUE : VARIANT_FALSE;
    return S_OK;
}


STDMETHODIMP CLocalMachine::get_isOfflineFilesEnabled(VARIANT_BOOL *pbEnabled)
{
    HRESULT hr = S_OK;
    *pbEnabled = VARIANT_FALSE;
        
    HINSTANCE hInstCscdll = LoadLibrary(TEXT("cscdll.dll"));
    if (NULL != hInstCscdll)
    {
        typedef BOOL (WINAPI *LPCSCENABLED)(void);
        LPCSCENABLED pfnCscEnabled = (LPCSCENABLED)GetProcAddress(hInstCscdll, "CSCIsCSCEnabled");
        if (NULL != pfnCscEnabled)
        {
            if ((*pfnCscEnabled)())
            {
                *pbEnabled = VARIANT_TRUE;
            }
        }
        else
        {
            hr = ResultFromLastError();
        }
        FreeLibrary(hInstCscdll);
    }
    else
    {
        hr = ResultFromLastError();
    }
    return hr;
}


WCHAR s_szAdmin[UNLEN + sizeof('\0')]     =   L"";

LPCWSTR GetAdminAccountName(void)
{
    if (s_szAdmin[0] == L'\0')
    {
        BOOL bSuccess = FALSE;
        PSID pSid;

        if (ERROR_SUCCESS == BuildAccountSidFromRid(NULL,
                                                    DOMAIN_USER_RID_ADMIN,
                                                    &pSid))
        {
            DWORD           dwAdminSize, dwDomainSize;
            WCHAR           szDomain[DNLEN + sizeof('\0')];
            SID_NAME_USE    eUse;

            dwAdminSize = ARRAYSIZE(s_szAdmin);
            dwDomainSize = ARRAYSIZE(szDomain);

            bSuccess = LookupAccountSidW(NULL,
                                         pSid,
                                         s_szAdmin,
                                         &dwAdminSize,
                                         szDomain,
                                         &dwDomainSize,
                                         &eUse);
            LocalFree(pSid);
        }
        if (!bSuccess)
        {
            lstrcpyW(s_szAdmin, L"Administrator");
        }
    }
    return(s_szAdmin);
}



STDMETHODIMP CLocalMachine::get_AccountName(VARIANT varAccount, VARIANT* pvar)
{
    DWORD dwRID = 0;
    LPCWSTR pszName = NULL;

    if (NULL == pvar)
        return E_POINTER;

    switch (varAccount.vt)
    {
    case VT_I4:
    case VT_UI4:
        dwRID = varAccount.ulVal;
        break;

    case VT_BSTR:
        if (0 == StrCmpIW(varAccount.bstrVal, L"Guest"))
            dwRID = DOMAIN_USER_RID_GUEST;
        else if (0 == StrCmpIW(varAccount.bstrVal, L"Administrator"))
            dwRID = DOMAIN_USER_RID_ADMIN;
        else
            return E_INVALIDARG;
        break;

    default:
        return E_INVALIDARG;
    }

    switch (dwRID)
    {
    case DOMAIN_USER_RID_GUEST:
        pszName = GetGuestAccountName();
        break;

    case DOMAIN_USER_RID_ADMIN:
        pszName = GetAdminAccountName();
        break;

    default:
        return E_INVALIDARG;
    }

    pvar->vt = VT_BSTR;
    pvar->bstrVal = SysAllocString(pszName);

    return(S_OK);
}

STDMETHODIMP CLocalMachine::TurnOffComputer()
{
    HRESULT hr;
    CLogonIPC   objLogon;

    if (!objLogon.IsLogonServiceAvailable())
    {
        return E_FAIL;
    }

    if (objLogon.TurnOffComputer ())
        hr = S_OK;
    else
        hr = E_FAIL;

    return hr;
}

STDMETHODIMP CLocalMachine::UndockComputer()
{
    HRESULT hr;
    CLogonIPC   objLogon;

    if (!objLogon.IsLogonServiceAvailable())
    {
        return E_FAIL;
    }

    if (objLogon.EjectComputer())
        hr = S_OK;
    else
        hr = E_FAIL;
    return hr;
}

STDMETHODIMP CLocalMachine::SignalUIHostFailure()
{
    CLogonIPC   objLogon;

    if (!objLogon.IsLogonServiceAvailable())
    {
        return E_FAIL;
    }

    objLogon.SignalUIHostFailure ();
    return S_OK;
}

STDMETHODIMP CLocalMachine::AllowExternalCredentials()

{
    CLogonIPC   objLogon;

    if (!objLogon.IsLogonServiceAvailable())
    {
        return E_FAIL;
    }

    if (!objLogon.AllowExternalCredentials ())
    {
        return E_NOTIMPL;
    }
    else
    {
        return S_OK;
    }
}

STDMETHODIMP CLocalMachine::RequestExternalCredentials()
{
    CLogonIPC   objLogon;

    if (!objLogon.IsLogonServiceAvailable())
    {
        return E_FAIL;
    }

    objLogon.RequestExternalCredentials ();
    return S_OK;
}

STDMETHODIMP CLocalMachine::LogonWithExternalCredentials(BSTR pstrUsername, BSTR pstrDomain, BSTR pstrPassword, VARIANT_BOOL* pbRet)
{
    HRESULT hr;
    CLogonIPC   objLogon;
    TCHAR   szUsername[UNLEN + sizeof('\0')],
            szDomain[DNLEN + sizeof('\0')],
            szPassword[PWLEN + sizeof('\0')];

    if (pstrUsername)
    {
        lstrcpyn(szUsername, pstrUsername, ARRAYSIZE(szUsername));
    }
    else
    {
        szUsername[0] = TEXT('\0');
    }
    if (pstrDomain)
    {
        lstrcpyn(szDomain, pstrDomain, ARRAYSIZE(szDomain));
    }
    else
    {
        szDomain[0] = TEXT('\0');
    }
    if (pstrPassword)
    {
        lstrcpyn(szPassword, pstrPassword, ARRAYSIZE(szPassword));
    }
    else
    {
        szPassword[0] = TEXT('\0');
    }
        
    if (!objLogon.IsLogonServiceAvailable())
    {
        *pbRet = VARIANT_FALSE;
        return S_OK;
    }

    if (objLogon.LogUserOn (szUsername, szDomain, szPassword))
        *pbRet = VARIANT_TRUE;
    else
        *pbRet = VARIANT_FALSE;


    if (*pbRet)
    {
        hr = S_OK;
    }
    else
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
    }

    return hr;
}

//  --------------------------------------------------------------------------
//  CLocalMachine::InitiateInteractiveLogon
//
//  Arguments:  pstrUsername    =   User name.
//              pstrDomain      =   Domain.
//              pstrPassword    =   Password (in clear text).
//              pbRet           =   Result (returned).
//
//  Returns:    HRESULT
//
//  Purpose:    Send a request for interactive logon using CInteractiveLogon.
//              It's magic. I don't care how it works.
//
//  History:    2000-12-06  vtan        created
//  --------------------------------------------------------------------------

STDMETHODIMP CLocalMachine::InitiateInteractiveLogon(BSTR pstrUsername, BSTR pstrDomain, BSTR pstrPassword, DWORD dwTimeout, VARIANT_BOOL* pbRet)

{
    DWORD   dwErrorCode;

    dwErrorCode = CInteractiveLogon::Initiate(pstrUsername, pstrDomain, pstrPassword, dwTimeout);
    *pbRet = (ERROR_SUCCESS == dwErrorCode) ? VARIANT_TRUE : VARIANT_FALSE;
    return(HRESULT_FROM_WIN32(dwErrorCode));
}

//  --------------------------------------------------------------------------
//  CLocalMachine::RefreshStartMenu
//
//  Arguments:  <none>
//
//  Returns:    <none>
//
//  Purpose:    Finds the shell tray window and sends it a message to refresh
//              its contents.
//
//  History:    2000-08-01  vtan        created
//  --------------------------------------------------------------------------

void    CLocalMachine::RefreshStartMenu (void)

{
    HWND    hwndTray;

    hwndTray = FindWindow(TEXT("Shell_TrayWnd"), NULL);
    if (hwndTray != NULL)
    {
        TBOOL(PostMessage(hwndTray, TM_REFRESH, 0, 0));
    }
}

CLocalMachine::CLocalMachine() : _cRef(1), CIDispatchHelper(&IID_ILocalMachine, &LIBID_SHGINALib)
{
    DllAddRef();
}


CLocalMachine::~CLocalMachine()
{
    ASSERT(_cRef == 0);
    DllRelease();
}


STDAPI CLocalMachine_Create(REFIID riid, LPVOID* ppv)
{
    HRESULT hr = E_OUTOFMEMORY;
    CLocalMachine* pLocalMachine = new CLocalMachine();

    if (pLocalMachine)
    {
        hr = pLocalMachine->QueryInterface(riid, ppv);
        pLocalMachine->Release();
    }

    return hr;
}