2828 lines
61 KiB
C++
2828 lines
61 KiB
C++
/*++
|
|
|
|
Copyright (c) 1999-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
HelpSess.cpp
|
|
|
|
Abstract:
|
|
|
|
HelpSess.cpp : Implementation of CRemoteDesktopHelpSession
|
|
|
|
Author:
|
|
|
|
HueiWang 2/17/2000
|
|
|
|
--*/
|
|
#include "stdafx.h"
|
|
|
|
#include <time.h>
|
|
#include <Sddl.h>
|
|
|
|
#include "global.h"
|
|
#include "Sessmgr.h"
|
|
#include "rdshost.h"
|
|
#include "HelpTab.h"
|
|
#include "policy.h"
|
|
#include "HelpAcc.h"
|
|
|
|
#include "HelpMgr.h"
|
|
#include "HelpSess.h"
|
|
#include <rdshost_i.c>
|
|
#include "RemoteDesktopUtils.h"
|
|
#include "RemoteDesktop.h"
|
|
|
|
#include <safsessionresolver_i.c>
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT
|
|
ConvertSidToAccountName(
|
|
IN CComBSTR& SidString,
|
|
IN BSTR* ppszDomain,
|
|
IN BSTR* ppszUserAcc
|
|
//IN LPTSTR* ppszDomain,
|
|
//IN LPTSTR* ppszUserAcc
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Convert a string SID to domain\account.
|
|
|
|
Parameters:
|
|
|
|
ownerSidString : SID in string form to be converted.
|
|
ppszDomain : Pointer to string pointer to receive domain name
|
|
UserAcc : Pointer to string pointer to receive user name
|
|
|
|
Returns:
|
|
|
|
S_OK or error code.
|
|
|
|
Note:
|
|
|
|
Routine uses LocalAlloc() to allocate memory for ppszDomain
|
|
and ppszUserAcc.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PSID pOwnerSid = NULL;
|
|
//LPTSTR pszAccName = NULL;
|
|
BSTR pszAccName = NULL;
|
|
DWORD cbAccName = 0;
|
|
//LPTSTR pszDomainName = NULL;
|
|
BSTR pszDomainName = NULL;
|
|
DWORD cbDomainName = 0;
|
|
SID_NAME_USE SidType;
|
|
BOOL bSuccess;
|
|
|
|
//
|
|
// Convert string form SID to PSID
|
|
//
|
|
if( FALSE == ConvertStringSidToSid( (LPCTSTR)SidString, &pOwnerSid ) )
|
|
{
|
|
// this might also fail if system is in shutdown state.
|
|
dwStatus = GetLastError();
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
if( NULL == ppszDomain || NULL == ppszUserAcc )
|
|
{
|
|
dwStatus = ERROR_INVALID_PARAMETER;
|
|
MYASSERT( FALSE );
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Lookup user account for this SID
|
|
//
|
|
bSuccess = LookupAccountSid(
|
|
NULL,
|
|
pOwnerSid,
|
|
pszAccName,
|
|
&cbAccName,
|
|
pszDomainName,
|
|
&cbDomainName,
|
|
&SidType
|
|
);
|
|
|
|
if( TRUE == bSuccess || ERROR_INSUFFICIENT_BUFFER == GetLastError() )
|
|
{
|
|
//pszAccName = (LPWSTR) LocalAlloc( LPTR, (cbAccName + 1) * sizeof(WCHAR) );
|
|
//pszDomainName = (LPWSTR) LocalAlloc( LPTR, (cbDomainName + 1)* sizeof(WCHAR) );
|
|
|
|
pszAccName = ::SysAllocStringLen( NULL, (cbAccName + 1) );
|
|
pszDomainName = ::SysAllocStringLen( NULL, (cbDomainName + 1) );
|
|
|
|
if( NULL != pszAccName && NULL != pszDomainName )
|
|
{
|
|
bSuccess = LookupAccountSid(
|
|
NULL,
|
|
pOwnerSid,
|
|
pszAccName,
|
|
&cbAccName,
|
|
pszDomainName,
|
|
&cbDomainName,
|
|
&SidType
|
|
);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
bSuccess = FALSE;
|
|
}
|
|
}
|
|
|
|
if( FALSE == bSuccess )
|
|
{
|
|
dwStatus = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
*ppszDomain = pszDomainName;
|
|
*ppszUserAcc = pszAccName;
|
|
pszDomainName = NULL;
|
|
pszAccName = NULL;
|
|
}
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if( NULL != pOwnerSid )
|
|
{
|
|
LocalFree( pOwnerSid );
|
|
}
|
|
|
|
if( NULL != pszAccName )
|
|
{
|
|
//LocalFree( pszAccName );
|
|
::SysFreeString( pszAccName );
|
|
}
|
|
|
|
if( NULL != pszDomainName )
|
|
{
|
|
// LocalFree( pszDomainName );
|
|
::SysFreeString( pszAccName );
|
|
}
|
|
|
|
return HRESULT_FROM_WIN32(dwStatus);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CRemoteDesktopHelpSession
|
|
//
|
|
//
|
|
|
|
CRemoteDesktopHelpSession::CRemoteDesktopHelpSession() :
|
|
m_ulLogonId(UNKNOWN_LOGONID),
|
|
m_ulHelperSessionId(UNKNOWN_LOGONID),
|
|
m_ulHelpSessionFlag(0)
|
|
{
|
|
}
|
|
|
|
|
|
CRemoteDesktopHelpSession::~CRemoteDesktopHelpSession()
|
|
{
|
|
}
|
|
|
|
void
|
|
CRemoteDesktopHelpSession::FinalRelease()
|
|
{
|
|
// Releas help entry
|
|
if( NULL != m_pHelpSession )
|
|
{
|
|
DebugPrintf(
|
|
_TEXT("FinalRelease %s on %s\n"),
|
|
(IsUnsolicitedHelp()) ? L"Unsolicted Help" : L"Solicited Help",
|
|
m_bstrHelpSessionId
|
|
);
|
|
|
|
// Notify disconnect will check if session is in help and bail out if necessary.
|
|
// there is a timing issue that our SCM notification might came after caller close
|
|
// all reference counter to our session object, in this case, SCM notification will
|
|
// trigger reload from database which does not have helper session ID and so will
|
|
// not notify resolver causing helpee been helped message.
|
|
|
|
// We also has AddRef() manually in ResolveXXX call and Release() in
|
|
// NotifyDisconnect(), this will hold the object in memory until SCM
|
|
// notification comes in.
|
|
NotifyDisconnect();
|
|
|
|
CRemoteDesktopHelpSessionMgr::DeleteHelpSessionFromCache( m_bstrHelpSessionId );
|
|
|
|
m_pHelpSession->Close();
|
|
m_pHelpSession = NULL;
|
|
}
|
|
|
|
ULONG count = _Module.Release();
|
|
|
|
DebugPrintf(
|
|
_TEXT("Module Release by CRemoteDesktopHelpSession() %p %d...\n"),
|
|
this,
|
|
count
|
|
);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::put_ICSPort(
|
|
IN DWORD newVal
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Associate ICS port number with this help session.
|
|
|
|
Parameters:
|
|
|
|
newVal : ICS port number.
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
MYASSERT(FALSE);
|
|
|
|
hRes = E_UNEXPECTED;
|
|
return hRes;
|
|
}
|
|
|
|
//
|
|
// Need to immediately update the value...
|
|
//
|
|
m_pHelpSession->m_ICSPort.EnableImmediateUpdate(TRUE);
|
|
m_pHelpSession->m_ICSPort = newVal;
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_ConnectParms(
|
|
OUT BSTR* bstrConnectParms
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Retrieve connection parameter for help session.
|
|
|
|
Parameters:
|
|
|
|
bstrConnectParms : Pointer to BSTR to receive connect parms.
|
|
|
|
Returns:
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
LPTSTR pszAddress = NULL;
|
|
int BufSize;
|
|
DWORD dwBufferRequire;
|
|
DWORD dwNumChars;
|
|
DWORD dwRetry;
|
|
CComBSTR bstrSessId;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Address might have change which might require bigger buffer, retry
|
|
//
|
|
//
|
|
for(dwRetry=0; dwRetry < MAX_FETCHIPADDRESSRETRY; dwRetry++)
|
|
{
|
|
if( NULL != pszAddress )
|
|
{
|
|
LocalFree( pszAddress );
|
|
}
|
|
|
|
//
|
|
// Fetch all address on local machine.
|
|
//
|
|
dwBufferRequire = FetchAllAddresses( NULL, 0 );
|
|
if( 0 == dwBufferRequire )
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
pszAddress = (LPTSTR) LocalAlloc( LPTR, sizeof(TCHAR)*(dwBufferRequire+1) );
|
|
if( NULL == pszAddress )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
dwNumChars = FetchAllAddresses( pszAddress, dwBufferRequire );
|
|
MYASSERT( dwNumChars <= dwBufferRequire );
|
|
if( dwNumChars <= dwBufferRequire )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( NULL == pszAddress )
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Store the IP address
|
|
//
|
|
m_pHelpSession->m_IpAddress = pszAddress;
|
|
|
|
MYASSERT( ((CComBSTR)m_pHelpSession->m_IpAddress).Length() > 0 );
|
|
DebugPrintf(
|
|
_TEXT("IP Address %s\n"),
|
|
(LPTSTR)(CComBSTR)m_pHelpSession->m_IpAddress
|
|
);
|
|
|
|
//
|
|
// Create connection parameters
|
|
//
|
|
hRes = get_HelpSessionId( &bstrSessId );
|
|
if( FAILED(hRes) )
|
|
{
|
|
MYASSERT(FALSE);
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
|
|
MYASSERT( g_TSSecurityBlob.Length() > 0 );
|
|
|
|
*bstrConnectParms = CreateConnectParmsString(
|
|
REMOTEDESKTOP_TSRDP_PROTOCOL,
|
|
CComBSTR(pszAddress),
|
|
CComBSTR(SALEM_CONNECTPARM_UNUSEFILED_SUBSTITUTE),
|
|
CComBSTR(SALEM_CONNECTPARM_UNUSEFILED_SUBSTITUTE),
|
|
bstrSessId,
|
|
CComBSTR(SALEM_CONNECTPARM_UNUSEFILED_SUBSTITUTE),
|
|
CComBSTR(SALEM_CONNECTPARM_UNUSEFILED_SUBSTITUTE),
|
|
g_TSSecurityBlob
|
|
);
|
|
|
|
#if DBG
|
|
if( NULL != *bstrConnectParms )
|
|
{
|
|
DebugPrintf(
|
|
_TEXT("Connect Parms %s\n"),
|
|
*bstrConnectParms
|
|
);
|
|
}
|
|
#endif
|
|
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if( NULL != pszAddress )
|
|
{
|
|
LocalFree( pszAddress );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_TimeOut(
|
|
/*[out, retval]*/ DWORD* pTimeout
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
BOOL bSuccess;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
|
|
if( NULL == pTimeout )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
FILETIME ft;
|
|
SYSTEMTIME sysTime;
|
|
|
|
ft = m_pHelpSession->m_ExpirationTime;
|
|
bSuccess = FileTimeToSystemTime(&ft, &sysTime);
|
|
|
|
if( TRUE == bSuccess )
|
|
{
|
|
if( sysTime.wYear >= 2038 )
|
|
{
|
|
*pTimeout = INT_MAX;
|
|
}
|
|
else
|
|
{
|
|
struct tm gmTime;
|
|
|
|
memset(&gmTime, 0, sizeof(gmTime));
|
|
gmTime.tm_sec = sysTime.wSecond;
|
|
gmTime.tm_min = sysTime.wMinute;
|
|
gmTime.tm_hour = sysTime.wHour;
|
|
gmTime.tm_year = sysTime.wYear - 1900;
|
|
gmTime.tm_mon = sysTime.wMonth - 1;
|
|
gmTime.tm_mday = sysTime.wDay;
|
|
|
|
if((*pTimeout = mktime(&gmTime)) == (time_t)-1)
|
|
{
|
|
*pTimeout = INT_MAX;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT( FALSE );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::put_TimeOut(
|
|
/*[in]*/ DWORD Timeout
|
|
)
|
|
/*++
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
LONG MaxTicketExpiry;
|
|
|
|
//
|
|
// Get default timeout value from registry, not a critical
|
|
// error, if we failed, we just default to 30 days
|
|
//
|
|
hRes = PolicyGetMaxTicketExpiry( &MaxTicketExpiry );
|
|
if( FAILED(hRes) || 0 == MaxTicketExpiry )
|
|
{
|
|
MaxTicketExpiry = DEFAULT_MAXTICKET_EXPIRY;
|
|
}
|
|
|
|
if( Timeout > MaxTicketExpiry )
|
|
{
|
|
hRes = S_FALSE;
|
|
Timeout = MaxTicketExpiry;
|
|
}
|
|
|
|
time_t curTime;
|
|
FILETIME ftTimeOut;
|
|
|
|
// Get the current time.
|
|
time(&curTime);
|
|
|
|
// time out in seconds
|
|
curTime += Timeout;
|
|
|
|
// Convert to FILETIME
|
|
UnixTimeToFileTime( curTime, &ftTimeOut );
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
if( FALSE == m_pHelpSession->IsEntryExpired() )
|
|
{
|
|
//
|
|
// operator =() update registry immediately
|
|
//
|
|
m_pHelpSession->m_ExpirationTime = ftTimeOut;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_HelpSessionId(
|
|
OUT BSTR *pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get help session ID.
|
|
|
|
Parameters:
|
|
|
|
pVal : return Help session ID of this help session instance.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_OUTOFMEMORY
|
|
E_UNEXPECTED
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
|
|
if( NULL == pVal )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
|
|
DebugPrintf(
|
|
_TEXT("get_HelpSessionId() on %s\n"),
|
|
m_bstrHelpSessionId
|
|
);
|
|
|
|
MYASSERT( m_pHelpSession->m_SessionId->Length() > 0 );
|
|
if( m_pHelpSession->m_SessionId->Length() > 0 )
|
|
{
|
|
*pVal = m_pHelpSession->m_SessionId->Copy();
|
|
|
|
if( NULL == *pVal )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT( FALSE );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_UserLogonId(
|
|
OUT long *pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get user's TS session ID, note, non-ts session or Win9x always
|
|
has 0 as user logon id.
|
|
|
|
Parameters:
|
|
|
|
pVal : Return user logon ID.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( NULL == pVal )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if(FALSE == IsSessionValid())
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
*pVal = m_ulLogonId;
|
|
if( UNKNOWN_LOGONID == m_ulLogonId )
|
|
{
|
|
hRes = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MYASSERT( FALSE );
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_AssistantAccountName(
|
|
OUT BSTR *pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get help assistant account name associated with this
|
|
help session.
|
|
|
|
Parameters:
|
|
|
|
pVal : Return help assistant account name associated
|
|
with this help session.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_OUTOFMEMORY
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
// Don't need a lock here.
|
|
|
|
if( NULL != pVal )
|
|
{
|
|
CComBSTR accName;
|
|
|
|
hRes = g_HelpAccount.GetHelpAccountNameEx( accName );
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
*pVal = accName.Copy();
|
|
if( NULL == *pVal )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_HelpSessionName(
|
|
OUT BSTR *pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get help session name associated with this
|
|
help session.
|
|
|
|
Parameters:
|
|
|
|
pVal : Return help session name associated
|
|
with this help session.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
S_FALSE No Help Session Name
|
|
E_OUTOFMEMORY Out of memory
|
|
E_POINTER Invalid parameter
|
|
HRESULT_FROM_WIN32( ERROR_LOCK_VIOLATION );
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
|
|
if(FALSE == IsSessionValid())
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL == pVal )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
if( m_pHelpSession->m_SessionName->Length() > 0 )
|
|
{
|
|
*pVal = m_pHelpSession->m_SessionName->Copy();
|
|
if( NULL == *pVal )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::put_HelpSessionName(
|
|
IN BSTR newVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set help session name associated with this
|
|
help session.
|
|
|
|
Parameters:
|
|
|
|
newVal : New help session name.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_OUTOFMEMORY
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if(FALSE == IsSessionValid())
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( FALSE == IsClientSessionCreator() )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
}
|
|
else if( m_pHelpSession != NULL )
|
|
{
|
|
//
|
|
// NULL will reset help session name
|
|
//
|
|
|
|
//
|
|
// operator =() update registry immediately
|
|
//
|
|
m_pHelpSession->m_SessionName = newVal;
|
|
if( !((CComBSTR)m_pHelpSession->m_SessionName == newVal) )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MYASSERT(FALSE);
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::put_HelpSessionPassword(
|
|
IN BSTR newVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Change help session password associated with this
|
|
help session.
|
|
|
|
Parameters:
|
|
|
|
newVal : New help session password.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_OUTOFMEMORY Out of memory
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( FALSE == IsClientSessionCreator() )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
|
|
//
|
|
// NULL will reset password
|
|
//
|
|
|
|
//
|
|
// operator =() update registry immediately
|
|
//
|
|
m_pHelpSession->m_SessionPwd = newVal;
|
|
|
|
if( !((CComBSTR)m_pHelpSession->m_SessionPwd == newVal) )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT( FALSE );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_HelpSessionDescription(
|
|
OUT BSTR *pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get help session description associated with this
|
|
help session.
|
|
|
|
Parameters:
|
|
|
|
pVal : Return help session description associated
|
|
with this help session.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
S_FALSE No Description
|
|
E_OUTOFMEMORY Out of memory
|
|
E_POINTER Invalid argument
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( NULL == pVal )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( m_pHelpSession != NULL )
|
|
{
|
|
|
|
if( m_pHelpSession->m_SessionDesc->Length() > 0 )
|
|
{
|
|
*pVal = m_pHelpSession->m_SessionDesc->Copy();
|
|
if( NULL == *pVal )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::put_HelpSessionDescription(
|
|
IN BSTR newVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Change help session description associated with this
|
|
help session.
|
|
|
|
Parameters:
|
|
|
|
newVal : new help session description associated
|
|
with this help session.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
|
|
Note:
|
|
|
|
Help Session name and description is reserved for future use
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( FALSE == IsClientSessionCreator() )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
|
|
//
|
|
// NULL will reset description
|
|
//
|
|
|
|
//
|
|
// operator =() update registry immediately
|
|
//
|
|
m_pHelpSession->m_SessionDesc = newVal;
|
|
|
|
if( !((CComBSTR)m_pHelpSession->m_SessionDesc == newVal) )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_EnableResolver(
|
|
OUT BOOL* pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return Session Resolver's CLSID for this help session.
|
|
|
|
Parameters:
|
|
|
|
pVal : Pointer to BSTR to receive pointer to Resolver's CLSID.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_POINTER Invalid argument
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( NULL == pVal )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if(FALSE == IsSessionValid())
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
*pVal = ((long)m_pHelpSession->m_EnableResolver > 0) ? TRUE : FALSE;
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::put_EnableResolver(
|
|
IN BOOL newVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set Session Resolver's CLSID, if input is NULL or empty
|
|
string, Help Session Manager will not invoke resolver.
|
|
|
|
Parameters:
|
|
|
|
Val : Resolver's CLSID
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_OUTOFMEMORY
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( FALSE == IsClientSessionCreator() )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
//
|
|
// NULL will reset resolver's ID for this session
|
|
//
|
|
|
|
//
|
|
// operator =() update registry immediately
|
|
//
|
|
m_pHelpSession->m_EnableResolver = newVal;
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_ResolverBlob(
|
|
OUT BSTR* pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return blob for session resolver to map help session
|
|
to user session/
|
|
|
|
Parameters:
|
|
|
|
pVal : Pointer to BSTR to receive blob.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
S_FALSE No blob
|
|
E_OUTOFMEMORY
|
|
E_POINTER
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( NULL == pVal )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if(FALSE == IsSessionValid())
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
|
|
if( m_pHelpSession->m_SessResolverBlob->Length() > 0 )
|
|
{
|
|
*pVal = m_pHelpSession->m_SessResolverBlob->Copy();
|
|
if( NULL == *pVal )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::put_ResolverBlob(
|
|
IN BSTR newVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add/change blob which will be passed to session
|
|
resolver to map/find user session associated with this
|
|
help session, Help Session Manager does not interpret this
|
|
blob.
|
|
|
|
Parameters:
|
|
|
|
newVal : Pointer to new blob.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_OUTOFMEMORY Out of memory
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( FALSE == IsClientSessionCreator() )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
//
|
|
// NULL will reset resolver's ID for this session
|
|
//
|
|
|
|
//
|
|
// operator =() update registry immediately
|
|
//
|
|
m_pHelpSession->m_SessResolverBlob = newVal;
|
|
if( !((CComBSTR)m_pHelpSession->m_SessResolverBlob == newVal) )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_HelpSessionCreateBlob(
|
|
OUT BSTR* pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return blob for session resolver to map help session
|
|
to user session/
|
|
|
|
Parameters:
|
|
|
|
pVal : Pointer to BSTR to receive blob.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
S_FALSE No blob
|
|
E_OUTOFMEMORY
|
|
E_POINTER
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( NULL == pVal )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if(FALSE == IsSessionValid())
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
|
|
if( m_pHelpSession->m_SessionCreateBlob->Length() > 0 )
|
|
{
|
|
*pVal = m_pHelpSession->m_SessionCreateBlob->Copy();
|
|
if( NULL == *pVal )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = S_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::put_HelpSessionCreateBlob(
|
|
IN BSTR newVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add/change blob which will be passed to session
|
|
resolver to map/find user session associated with this
|
|
help session, Help Session Manager does not interpret this
|
|
blob.
|
|
|
|
Parameters:
|
|
|
|
newVal : Pointer to new blob.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_OUTOFMEMORY Out of memory
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( FALSE == IsClientSessionCreator() )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
//
|
|
// operator =() update registry immediately
|
|
//
|
|
m_pHelpSession->m_SessionCreateBlob = newVal;
|
|
if( !((CComBSTR)m_pHelpSession->m_SessionCreateBlob == newVal) )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_UserHelpSessionRemoteDesktopSharingSetting(
|
|
/*[out, retval]*/ REMOTE_DESKTOP_SHARING_CLASS* pSetting
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return help session's RDS setting.
|
|
|
|
Parameters:
|
|
|
|
pSetting : Pointer to REMOTE_DESKTOP_SHARING_CLASS to
|
|
receive session's RDS setting.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_POINTER Invalid argument.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( NULL == pSetting )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if(FALSE == IsSessionValid())
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
*pSetting = (REMOTE_DESKTOP_SHARING_CLASS)(long)m_pHelpSession->m_SessionRdsSetting;
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::put_UserHelpSessionRemoteDesktopSharingSetting(
|
|
/*[in]*/ REMOTE_DESKTOP_SHARING_CLASS Setting
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set help session's RDS setting.
|
|
|
|
Parameters:
|
|
|
|
Setting : New RDS setting.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
S_FALSE New setting is overrided with
|
|
policy setting.
|
|
HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) User not allow to get help.
|
|
HRESULT_FROM_WIN32( ERROR_SHARING_VIOLATION ) Other help session already has this set
|
|
HRESULT_FROM_WIN32( ERROR_VC_DISCONNECTED ) Session is not connected
|
|
|
|
HRESULT_FROM_WIN32( WinStationQueryInformation() );
|
|
E_OUTOFMEMORY
|
|
|
|
Note:
|
|
|
|
Only one help session can change the RDS setting, all other help session
|
|
will get HRESULT_FROM_WIN32( ERROR_SHARING_VIOLATION ) error return.
|
|
|
|
REMOTE_DESKTOP_SHARING_CLASS also define priviledge
|
|
level, that is user with NO_DESKTOP_SHARING can't
|
|
adjust his/her sharing class, user with CONTROLDESKTOP_PERMISSION_REQUIRE
|
|
can't adjust his/her sharing class to CONTROLDESKTOP_PERMISSION_NOT_REQUIRE
|
|
however, he/she can reset to NO_DESKTOP_SHARING, VIEWDESKTOP_PERMISSION_REQUIRE
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( FALSE == IsClientSessionCreator() )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
//
|
|
// operator =() update registry immediately
|
|
//
|
|
m_pHelpSession->m_SessionRdsSetting = Setting;
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::get_AllowToGetHelp(
|
|
/*[out, retval]*/ BOOL* pVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if user created this help session is
|
|
allowed to get help or not, this is possible that policy change
|
|
after user re-logon.
|
|
|
|
Parameters:
|
|
|
|
pVal : Pointer to BOOL to receive result.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
HRESULT_FROM_WIN32( ERROR_VC_DISCONNECTED ) User is not connected any more.
|
|
E_UNEXPECTED; Internal error.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
|
|
if( NULL == pVal )
|
|
{
|
|
hRes = E_POINTER;
|
|
}
|
|
else if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
if( UNKNOWN_LOGONID == m_ulLogonId )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_VC_DISCONNECTED );
|
|
}
|
|
else if( m_pHelpSession->m_UserSID->Length() == 0 )
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
else
|
|
{
|
|
*pVal = IsUserAllowToGetHelp(
|
|
m_ulLogonId,
|
|
(LPCTSTR) CComBSTRtoLPTSTR( (CComBSTR)m_pHelpSession->m_UserSID )
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::DeleteHelp()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete this help session
|
|
|
|
Parameters:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
S_OK or error code from
|
|
Help Session Manager's DeleteHelpSession().
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CRemoteDesktopHelpSessionMgr::LockIDToSessionMapCache();
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
DebugPrintf(
|
|
_TEXT("CRemoteDesktopHelpSession::DeleteHelp() %s...\n"),
|
|
m_bstrHelpSessionId
|
|
);
|
|
|
|
//
|
|
// BUGBUG : Refer to timing bug, no notification about terminating
|
|
// shadow, and we can't reset session's shadow class. force a
|
|
// reset here for now.
|
|
//
|
|
ResetSessionRDSSetting();
|
|
|
|
//
|
|
// if we are not been help, just delete it, if we are in the middle
|
|
// of help, deleting it from cache and database entry will cause
|
|
// Resolver's OnDisconnect() never got call resulting in user
|
|
// lock in resolver never got release so we update the expiration
|
|
// date to current, expiration thread or next load will trigger
|
|
// actual delete.
|
|
//
|
|
if(GetHelperSessionId() == UNKNOWN_LOGONID)
|
|
{
|
|
CRemoteDesktopHelpSessionMgr::DeleteHelpSessionFromCache( (CComBSTR) m_pHelpSession->m_SessionId );
|
|
if( (DWORD)(long)m_pHelpSession->m_ICSPort > 0 )
|
|
{
|
|
//
|
|
// Destructor does not close ICS port, we only close
|
|
// ICS port when help is deleted.
|
|
//
|
|
ClosePort( (DWORD)(long)m_pHelpSession->m_ICSPort );
|
|
}
|
|
|
|
// Delete will release the entry ref. count
|
|
hRes = m_pHelpSession->Delete();
|
|
m_pHelpSession = NULL;
|
|
m_bDeleted = TRUE;
|
|
}
|
|
else
|
|
{
|
|
put_TimeOut(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
|
|
MYASSERT(FALSE);
|
|
}
|
|
|
|
CRemoteDesktopHelpSessionMgr::UnlockIDToSessionMapCache();
|
|
return hRes;
|
|
}
|
|
|
|
void
|
|
CRemoteDesktopHelpSession::ResolveTicketOwner()
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Convert ticket owner SID to domain\account.
|
|
|
|
Parameters:
|
|
|
|
None.
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
{
|
|
//LPTSTR pszNoviceDomain = NULL;
|
|
//LPTSTR pszNoviceName = NULL;
|
|
|
|
BSTR pszNoviceDomain = NULL;
|
|
BSTR pszNoviceName = NULL;
|
|
|
|
HRESULT hRes = S_OK;
|
|
MYASSERT( IsSessionValid() );
|
|
|
|
if( IsSessionValid() )
|
|
{
|
|
hRes = ConvertSidToAccountName(
|
|
(CComBSTR)m_pHelpSession->m_UserSID,
|
|
&pszNoviceDomain,
|
|
&pszNoviceName
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// help session ticket is deleted
|
|
hRes = E_HANDLE;
|
|
}
|
|
|
|
|
|
//
|
|
// NO ASSERT, ConvertSidToAccountName() already assert.
|
|
//
|
|
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
//
|
|
// DO NOT FREE the memory, once string is attached to CComBSTR,
|
|
// CComBSTR will free it at destructor
|
|
//
|
|
m_EventLogInfo.bstrNoviceDomain.Attach(pszNoviceDomain);
|
|
m_EventLogInfo.bstrNoviceAccount.Attach(pszNoviceName);
|
|
|
|
//m_EventLogInfo.bstrNoviceDomain = pszNoviceDomain;
|
|
//m_EventLogInfo.bstrNoviceAccount = pszNoviceName;
|
|
|
|
//LocalFree(pszNoviceDomain);
|
|
//LocalFree(pszNoviceName);
|
|
}
|
|
else
|
|
{
|
|
m_EventLogInfo.bstrNoviceDomain = g_UnknownString;
|
|
m_EventLogInfo.bstrNoviceAccount = (CComBSTR)m_pHelpSession->m_UserSID;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
CRemoteDesktopHelpSession::ResolveHelperInformation(
|
|
IN ULONG HelperSessionId,
|
|
OUT CComBSTR& bstrExpertIpAddressFromClient,
|
|
OUT CComBSTR& bstrExpertIpAddressFromServer
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Retrieve from TermSrv regarding HelpAssistant session's IP address send from
|
|
expert (mstscax send this) and IP address of client machine retrive from TCPIP
|
|
|
|
Parameters:
|
|
|
|
HelperSessionId : TS session ID of help assistant session.
|
|
bstrExpertIpAddressFromClient : IP address send from mstscax.
|
|
bstrExpertIpAddressFromServer : IP address that TS retrieve from tcpip stack.
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
WINSTATIONCLIENT winstationClient;
|
|
WINSTATIONREMOTEADDRESS winstationRemoteAddress;
|
|
ULONG winstationInfoLen;
|
|
DWORD dwLength = 0;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
//
|
|
// Retrieve client IP address passed from client
|
|
winstationInfoLen = 0;
|
|
ZeroMemory( &winstationClient, sizeof(winstationClient) );
|
|
if(!WinStationQueryInformation(
|
|
SERVERNAME_CURRENT,
|
|
HelperSessionId,
|
|
WinStationClient,
|
|
(PVOID)&winstationClient,
|
|
sizeof(winstationClient),
|
|
&winstationInfoLen
|
|
))
|
|
{
|
|
dwStatus = GetLastError();
|
|
DebugPrintf(
|
|
_TEXT("WinStationQueryInformation() query WinStationClient return %d\n"), dwStatus
|
|
);
|
|
|
|
// Critical error?, fro now, log as 'unknown'.
|
|
bstrExpertIpAddressFromClient = g_UnknownString;
|
|
}
|
|
else
|
|
{
|
|
bstrExpertIpAddressFromClient = winstationClient.ClientAddress;
|
|
}
|
|
|
|
//
|
|
// Retrieve client IP address retrieve from server TCPIP
|
|
winstationInfoLen = 0;
|
|
ZeroMemory( &winstationRemoteAddress, sizeof(winstationRemoteAddress) );
|
|
|
|
if(!WinStationQueryInformation(
|
|
SERVERNAME_CURRENT,
|
|
HelperSessionId,
|
|
WinStationRemoteAddress,
|
|
(PVOID)&winstationRemoteAddress,
|
|
sizeof(winstationRemoteAddress),
|
|
&winstationInfoLen
|
|
))
|
|
{
|
|
dwStatus = GetLastError();
|
|
|
|
DebugPrintf(
|
|
_TEXT("WinStationQueryInformation() query WinStationRemoteAddress return %d %d %d\n"),
|
|
dwStatus,
|
|
sizeof(winstationRemoteAddress),
|
|
winstationInfoLen
|
|
);
|
|
|
|
// Critical error?, for now, log as 'unknown'.
|
|
bstrExpertIpAddressFromServer = g_UnknownString;
|
|
}
|
|
else
|
|
{
|
|
if( AF_INET == winstationRemoteAddress.sin_family )
|
|
{
|
|
// refer to in_addr structure.
|
|
struct in_addr S;
|
|
S.S_un.S_addr = winstationRemoteAddress.ipv4.in_addr;
|
|
|
|
bstrExpertIpAddressFromServer = inet_ntoa(S);
|
|
if(bstrExpertIpAddressFromServer.Length() == 0 )
|
|
{
|
|
MYASSERT(FALSE);
|
|
bstrExpertIpAddressFromServer = g_UnknownString;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we are not yet support IPV6 address, calling WSAAddressToString() will fail with error.
|
|
bstrExpertIpAddressFromServer = g_UnknownString;
|
|
}
|
|
}
|
|
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::ResolveUserSession(
|
|
IN BSTR resolverBlob,
|
|
IN BSTR expertBlob,
|
|
LONG CallerProcessId,
|
|
OUT ULONG_PTR* phHelpCtr,
|
|
OUT LONG* pResolverErrCode,
|
|
OUT long* plUserSession
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Resolve a user help session to user TS session.
|
|
|
|
Parameters:
|
|
|
|
plUserSession : Pointer to long to receive user TS session.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
HRESULT_FROM_WIN32( ERROR_NO_ASSOCIATION ) No resolver for this help session
|
|
HRESULT_FROM_WIN32( ERROR_INVALID_DATA ) Can't convert
|
|
result from CoCreateInstance() or IRDSCallback
|
|
|
|
-*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
UUID ResolverUuid;
|
|
RPC_STATUS rpcStatus;
|
|
ISAFRemoteDesktopCallback* pIResolver;
|
|
long sessionId;
|
|
long HelperSessionId;
|
|
int resolverRetCode;
|
|
WINSTATIONINFORMATION HelperWinstationInfo;
|
|
DWORD dwStatus;
|
|
ULONG winstationInfoLen;
|
|
|
|
CComBSTR bstrExpertAddressFromClient;
|
|
CComBSTR bstrExpertAddressFromTSServer;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
DWORD dwEventLogCode;
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
*pResolverErrCode = SAFERROR_HELPSESSIONEXPIRED;
|
|
return hRes;
|
|
}
|
|
|
|
if( NULL == m_pHelpSession || NULL == pResolverErrCode )
|
|
{
|
|
hRes = E_POINTER;
|
|
*pResolverErrCode = SAFERROR_INVALIDPARAMETERSTRING;
|
|
MYASSERT(FALSE);
|
|
return hRes;
|
|
}
|
|
|
|
if( m_pHelpSession->m_UserSID->Length() == 0 )
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
*pResolverErrCode = SAFERROR_UNKNOWNSESSMGRERROR;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
|
|
//
|
|
// must have user logon ID if we are not using resolver,
|
|
// in pure SALEM SDK, multiple expert can connect
|
|
// using same help ticket, only one can shadow.
|
|
//
|
|
*pResolverErrCode = SAFERROR_NOERROR;
|
|
if( (long)m_pHelpSession->m_EnableResolver == 0 )
|
|
{
|
|
if( UNKNOWN_LOGONID != m_ulLogonId )
|
|
{
|
|
*plUserSession = (long) m_ulLogonId;
|
|
}
|
|
else
|
|
{
|
|
// no resolver for this help session
|
|
hRes = HRESULT_FROM_WIN32( ERROR_NO_ASSOCIATION );
|
|
|
|
// user already logoff
|
|
*pResolverErrCode = SAFERROR_USERNOTFOUND;
|
|
}
|
|
|
|
//
|
|
// We are not using resolver, bail out.
|
|
//
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
|
|
//
|
|
// Retrieve Caller's TS session ID
|
|
//
|
|
hRes = ImpersonateClient();
|
|
|
|
if( FAILED(hRes) )
|
|
{
|
|
*pResolverErrCode = SAFERROR_UNKNOWNSESSMGRERROR;
|
|
return hRes;
|
|
}
|
|
|
|
HelperSessionId = GetUserTSLogonId();
|
|
|
|
EndImpersonateClient();
|
|
|
|
ResolveHelperInformation(
|
|
HelperSessionId,
|
|
bstrExpertAddressFromClient,
|
|
bstrExpertAddressFromTSServer
|
|
);
|
|
|
|
DebugPrintf(
|
|
_TEXT("Expert Session ID %d, Expert Address %s %s\n"),
|
|
HelperSessionId,
|
|
bstrExpertAddressFromClient,
|
|
bstrExpertAddressFromTSServer
|
|
);
|
|
|
|
DebugPrintf(
|
|
_TEXT("Novice %s %s\n"),
|
|
m_EventLogInfo.bstrNoviceDomain,
|
|
m_EventLogInfo.bstrNoviceAccount
|
|
);
|
|
|
|
|
|
//
|
|
// Check if helper session is still active, under stress, we might
|
|
// get this call after help assistant session is gone.
|
|
//
|
|
ZeroMemory( &HelperWinstationInfo, sizeof(HelperWinstationInfo) );
|
|
winstationInfoLen = 0;
|
|
if(!WinStationQueryInformation(
|
|
SERVERNAME_CURRENT,
|
|
HelperSessionId,
|
|
WinStationInformation,
|
|
(PVOID)&HelperWinstationInfo,
|
|
sizeof(HelperWinstationInfo),
|
|
&winstationInfoLen
|
|
))
|
|
{
|
|
dwStatus = GetLastError();
|
|
|
|
DebugPrintf(
|
|
_TEXT("WinStationQueryInformation() return %d\n"), dwStatus
|
|
);
|
|
|
|
hRes = HRESULT_FROM_WIN32( dwStatus );
|
|
*pResolverErrCode = SAFERROR_SESSIONNOTCONNECTED;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
if( HelperWinstationInfo.ConnectState != State_Active )
|
|
{
|
|
DebugPrintf(
|
|
_TEXT("Helper session is %d"),
|
|
HelperWinstationInfo.ConnectState
|
|
);
|
|
|
|
// Helper Session is not active, can't provide help
|
|
hRes = HRESULT_FROM_WIN32( ERROR_NO_ASSOCIATION );
|
|
*pResolverErrCode = SAFERROR_SESSIONNOTCONNECTED;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Either resolver is pending or already in progress,
|
|
// we have exclusive lock so we are safe to reference
|
|
// m_hExpertDisconnect.
|
|
//
|
|
if( UNKNOWN_LOGONID != m_ulHelperSessionId )
|
|
{
|
|
//
|
|
// LOGEVENT : SESSMGR_I_REMOTEASSISTANCE_USERALREADYHELP
|
|
//
|
|
_Module.LogSessmgrEventLog(
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
SESSMGR_I_REMOTEASSISTANCE_USERALREADYHELP,
|
|
m_EventLogInfo.bstrNoviceDomain,
|
|
m_EventLogInfo.bstrNoviceAccount,
|
|
(IsUnsolicitedHelp())? g_URAString : g_RAString,
|
|
bstrExpertAddressFromClient,
|
|
bstrExpertAddressFromTSServer,
|
|
SAFERROR_HELPEEALREADYBEINGHELPED
|
|
);
|
|
|
|
*pResolverErrCode = SAFERROR_HELPEEALREADYBEINGHELPED;
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// We assume User is going to accept help
|
|
// 1) When expert disconnect before user accept/deny request,
|
|
// our service logoff notification can find this object and invoke
|
|
// OnDisconnect() into resolver.
|
|
// 2) If another expert connect with same ticket and resolver still
|
|
// pending response from user, we can bail out right away.
|
|
//
|
|
InterlockedExchange( (LPLONG)&m_ulHelperSessionId, (LONG)HelperSessionId );
|
|
|
|
//
|
|
// Cache the SID in object
|
|
//
|
|
m_HelpSessionOwnerSid = (CComBSTR)m_pHelpSession->m_UserSID;
|
|
|
|
hRes = CoInitialize( NULL );
|
|
if( FAILED(hRes) )
|
|
{
|
|
// failed to coinitialize,
|
|
*pResolverErrCode = SAFERROR_INTERNALERROR;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Load resolver
|
|
hRes = LoadResolverFromGIT( &pIResolver );
|
|
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
CComBSTR bstrResolverBlob;
|
|
|
|
bstrResolverBlob.Attach(resolverBlob);
|
|
|
|
sessionId = (long)m_ulLogonId;
|
|
|
|
DebugPrintf(
|
|
_TEXT("User Session ID %d\n"),
|
|
m_ulLogonId
|
|
);
|
|
|
|
//
|
|
// keep a copy of blob, we need this to send to resolver on
|
|
// disconnect, note, caller can pass its blob so we need to
|
|
// keep a copy of it.
|
|
//
|
|
if( bstrResolverBlob.Length() == 0 )
|
|
{
|
|
m_ResolverConnectBlob = (CComBSTR)m_pHelpSession->m_SessResolverBlob;
|
|
}
|
|
else
|
|
{
|
|
m_ResolverConnectBlob = bstrResolverBlob;
|
|
}
|
|
|
|
hRes = pIResolver->ResolveUserSessionID(
|
|
m_ResolverConnectBlob,
|
|
(CComBSTR)m_pHelpSession->m_UserSID,
|
|
expertBlob,
|
|
(CComBSTR)m_pHelpSession->m_SessionCreateBlob,
|
|
&sessionId,
|
|
CallerProcessId,
|
|
phHelpCtr,
|
|
&resolverRetCode
|
|
);
|
|
|
|
*pResolverErrCode = resolverRetCode;
|
|
bstrResolverBlob.Detach();
|
|
pIResolver->Release();
|
|
|
|
DebugPrintf(
|
|
_TEXT("Resolver returns 0x%08x\n"),
|
|
hRes
|
|
);
|
|
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
*plUserSession = sessionId;
|
|
|
|
//
|
|
// Update session ID, take the value return from Resolver.
|
|
//
|
|
m_ulLogonId = sessionId;
|
|
|
|
//
|
|
// Add this expert to logoff monitor list, when expert session's
|
|
// rdsaddin terminates, we will inform resolver, reason for this
|
|
// is TS might not notify us of expert session disconnect because
|
|
// some system component popup a dialog in help assistant session
|
|
// and termsrv has no other way but to terminate entire session.
|
|
//
|
|
dwStatus = MonitorExpertLogoff(
|
|
CallerProcessId,
|
|
HelperSessionId,
|
|
m_bstrHelpSessionId
|
|
);
|
|
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
//
|
|
// If we can't add to resolver list, we immediate notify
|
|
// resolver and return error or we will run into 'helpee
|
|
// already been help problem
|
|
//
|
|
|
|
DebugPrintf(
|
|
_TEXT("MonitorExpertLogoff() failed with %d\n"), dwStatus
|
|
);
|
|
|
|
// directly invoke resolver here.
|
|
hRes = pIResolver->OnDisconnect(
|
|
m_ResolverConnectBlob,
|
|
m_HelpSessionOwnerSid,
|
|
m_ulLogonId
|
|
);
|
|
|
|
MYASSERT( SUCCEEDED(hRes) );
|
|
resolverRetCode = SAFERROR_UNKNOWNSESSMGRERROR;
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// It is possible for caller to close all reference counter to our object
|
|
// and cause a release of our object, if SCM notification comes in after
|
|
// our object is deleted from cache, SCM will reload from database entry
|
|
// and that does not have helper session ID and will not invoke NotifyDisconnect().
|
|
//
|
|
AddRef();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// User does not accept help from this helpassistant session,
|
|
// reset HelpAssistant session ID
|
|
//
|
|
InterlockedExchange( (LPLONG)&m_ulHelperSessionId, (LONG)UNKNOWN_LOGONID );
|
|
}
|
|
|
|
switch( resolverRetCode )
|
|
{
|
|
case SAFERROR_NOERROR :
|
|
|
|
// LOGEVENT : SESSMGR_I_REMOTEASSISTANCE_BEGIN
|
|
|
|
//
|
|
// Cache event log info so we don't have to retrieve it again.
|
|
//
|
|
m_EventLogInfo.bstrExpertIpAddressFromClient = bstrExpertAddressFromClient;
|
|
m_EventLogInfo.bstrExpertIpAddressFromServer = bstrExpertAddressFromTSServer;
|
|
dwEventLogCode = SESSMGR_I_REMOTEASSISTANCE_BEGIN;
|
|
break;
|
|
|
|
case SAFERROR_HELPEECONSIDERINGHELP:
|
|
case SAFERROR_HELPEEALREADYBEINGHELPED:
|
|
|
|
// LOGEVENT : SESSMGR_I_REMOTEASSISTANCE_USERALREADYHELP
|
|
dwEventLogCode = SESSMGR_I_REMOTEASSISTANCE_USERALREADYHELP;
|
|
break;
|
|
|
|
case SAFERROR_HELPEENOTFOUND:
|
|
|
|
// LOGEVENT : SESSMGR_I_REMOTEASSISTANCE_INACTIVEUSER
|
|
dwEventLogCode = SESSMGR_I_REMOTEASSISTANCE_INACTIVEUSER;
|
|
break;
|
|
|
|
case SAFERROR_HELPEENEVERRESPONDED:
|
|
|
|
// LOGEVENT : SESSMGR_I_REMOTEASSISTANCE_TIMEOUT
|
|
dwEventLogCode = SESSMGR_I_REMOTEASSISTANCE_TIMEOUT;
|
|
break;
|
|
|
|
case SAFERROR_HELPEESAIDNO:
|
|
|
|
// LOGEVENT : SESSMGR_I_REMOTEASSISTANCE_USERREJECT
|
|
dwEventLogCode = SESSMGR_I_REMOTEASSISTANCE_USERREJECT;
|
|
break;
|
|
|
|
default:
|
|
|
|
// LOGEVENT : SESSMGR_I_REMOTEASSISTANCE_UNKNOWNRESOLVERERRORCODE
|
|
dwEventLogCode = SESSMGR_I_REMOTEASSISTANCE_UNKNOWNRESOLVERERRORCODE;
|
|
break;
|
|
}
|
|
|
|
_Module.LogSessmgrEventLog(
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
dwEventLogCode,
|
|
m_EventLogInfo.bstrNoviceDomain,
|
|
m_EventLogInfo.bstrNoviceAccount,
|
|
(IsUnsolicitedHelp())? g_URAString : g_RAString,
|
|
bstrExpertAddressFromClient,
|
|
bstrExpertAddressFromTSServer,
|
|
resolverRetCode
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
*pResolverErrCode = SAFERROR_CANTOPENRESOLVER;
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
DebugPrintf(
|
|
_TEXT("ResolverUserSession returns 0x%08x\n"),
|
|
hRes
|
|
);
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::NotifyDisconnect()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Notify Session Resolver that client is dis-connecting to help session.
|
|
|
|
Parameters:
|
|
|
|
bstrBlob : Blob to be passed to resolver, NULL if
|
|
use ResolverBlob property.
|
|
|
|
Returns:
|
|
|
|
E_HANDLE Invalid session, database entry has been deleted but refcount > 0
|
|
E_UNEXPECTED Internal error
|
|
HRESULT_FROM_WIN32( ERROR_VC_DISCONNECTED ) Client disconnected
|
|
HRESULT_FROM_WIN32( ERROR_NO_ASSOCIATION ) No Resolver
|
|
S_FALSE No Resolver
|
|
HRESULT_FROM_WIN32( ERROR_INVALID_DATA ) Invalid Resolver ID
|
|
|
|
Error code from CoCreateInstance() and resolver's OnConnect() method.
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
ISAFRemoteDesktopCallback* pIResolver;
|
|
|
|
DebugPrintf(
|
|
_TEXT("OnDisconnect() - Helper Session ID %d\n"),
|
|
m_ulHelperSessionId
|
|
);
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
//
|
|
// If we are not been help, just bail out.
|
|
//
|
|
if( UNKNOWN_LOGONID != m_ulHelperSessionId )
|
|
{
|
|
//
|
|
// LOGEVENT : SESSMGR_I_REMOTEASSISTANCE_END
|
|
//
|
|
|
|
//
|
|
// always cache help session creator at ResolveUserSession()
|
|
// so this value can't be empty.
|
|
//
|
|
MYASSERT( m_HelpSessionOwnerSid.Length() > 0 );
|
|
MYASSERT( m_ResolverConnectBlob.Length() > 0 );
|
|
if( m_HelpSessionOwnerSid.Length() == 0 ||
|
|
m_ResolverConnectBlob.Length() == 0 )
|
|
{
|
|
MYASSERT(FALSE);
|
|
hRes = E_UNEXPECTED;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
hRes = CoInitialize( NULL );
|
|
|
|
if( FAILED(hRes) )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Load resolver
|
|
hRes = LoadResolverFromGIT( &pIResolver );
|
|
|
|
MYASSERT( SUCCEEDED(hRes) );
|
|
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
DebugPrintf(
|
|
_TEXT("OnDisconnect() - Notify Resolver, %s\n%s\n%d\n"),
|
|
m_ResolverConnectBlob,
|
|
m_HelpSessionOwnerSid,
|
|
m_ulLogonId
|
|
);
|
|
|
|
hRes = pIResolver->OnDisconnect(
|
|
m_ResolverConnectBlob,
|
|
m_HelpSessionOwnerSid,
|
|
m_ulLogonId
|
|
);
|
|
|
|
pIResolver->Release();
|
|
m_ResolverConnectBlob.Empty();
|
|
m_HelpSessionOwnerSid.Empty();
|
|
|
|
InterlockedExchange( (LPLONG)&m_ulHelperSessionId, (LONG)UNKNOWN_LOGONID );
|
|
|
|
//
|
|
// It is possible for caller to close all reference counter to our object
|
|
// and cause a release of our object, if SCM notification comes in after
|
|
// our object is deleted from cache, SCM will reload from database entry
|
|
// and that does not have helper session ID and will not invoke NotifyDisconnect().
|
|
//
|
|
Release();
|
|
|
|
_Module.LogSessmgrEventLog(
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
SESSMGR_I_REMOTEASSISTANCE_END,
|
|
m_EventLogInfo.bstrNoviceDomain,
|
|
m_EventLogInfo.bstrNoviceAccount,
|
|
(IsUnsolicitedHelp())? g_URAString : g_RAString,
|
|
m_EventLogInfo.bstrExpertIpAddressFromClient,
|
|
m_EventLogInfo.bstrExpertIpAddressFromServer,
|
|
ERROR_SUCCESS
|
|
);
|
|
}
|
|
|
|
CoUninitialize();
|
|
}
|
|
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
return hRes;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::EnableUserSessionRdsSetting(
|
|
IN BOOL bEnable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enable/restore user session shadow setting.
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else
|
|
{
|
|
if( TRUE == bEnable )
|
|
{
|
|
hRes = ActivateSessionRDSSetting();
|
|
}
|
|
else
|
|
{
|
|
hRes = ResetSessionRDSSetting();
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::ActivateSessionRDSSetting()
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
DWORD dwStatus;
|
|
REMOTE_DESKTOP_SHARING_CLASS userRDSDefault;
|
|
BOOL bAllowToGetHelp;
|
|
|
|
MYASSERT( TRUE == IsSessionValid() );
|
|
|
|
//
|
|
// check if help session user is logon
|
|
//
|
|
if( UNKNOWN_LOGONID == m_ulLogonId )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_VC_DISCONNECTED );
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Make sure user can get help, this is possible since
|
|
// policy might change after user re-logon to help session
|
|
//
|
|
hRes = get_AllowToGetHelp( &bAllowToGetHelp );
|
|
|
|
if( FAILED(hRes) )
|
|
{
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
if( FALSE == bAllowToGetHelp )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED );
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Retrieve current user session's shadow setting.
|
|
//
|
|
dwStatus = GetUserRDSLevel( m_ulLogonId, &userRDSDefault );
|
|
if( ERROR_SUCCESS != dwStatus )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( dwStatus );
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
if( NO_DESKTOP_SHARING != userRDSDefault )
|
|
{
|
|
//
|
|
// Force reset on user session shadow setting only if
|
|
// user session is allowed remote control.
|
|
//
|
|
dwStatus = ConfigUserSessionRDSLevel( m_ulLogonId, m_pHelpSession->m_SessionRdsSetting );
|
|
hRes = HRESULT_FROM_WIN32( dwStatus );
|
|
|
|
DebugPrintf(
|
|
_TEXT("ConfigUserSessionRDSLevel to %d returns 0x%08x\n"),
|
|
(DWORD)m_pHelpSession->m_SessionRdsSetting,
|
|
hRes
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// return S_FALSE and let shadow fail
|
|
hRes = S_FALSE;
|
|
|
|
DebugPrintf( _TEXT("TS User session does not remote control\n") );
|
|
}
|
|
|
|
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::ResetSessionRDSSetting()
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
MYASSERT( TRUE == IsSessionValid() );
|
|
|
|
//
|
|
// check if user is log on
|
|
//
|
|
if( UNKNOWN_LOGONID == m_ulLogonId )
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_VC_DISCONNECTED );
|
|
}
|
|
|
|
//
|
|
// We don't do anything since TermSrv will reset shadow
|
|
// config back to original value if shadower is help
|
|
// assistant.
|
|
//
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// Private Function
|
|
//
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::put_UserLogonId(
|
|
IN long newVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set user TS session for current Help Session
|
|
|
|
Parameters:
|
|
|
|
newVal : New TS user session
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
}
|
|
else if( NULL != m_pHelpSession )
|
|
{
|
|
//MYASSERT( UNKNOWN_LOGONID == m_ulLogonId );
|
|
|
|
//
|
|
// User TS session ID is not persisted to registry
|
|
//
|
|
m_ulLogonId = newVal;
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
|
|
// private routine, assert if failed
|
|
MYASSERT( SUCCEEDED(hRes) );
|
|
|
|
return hRes;
|
|
}
|
|
|
|
BOOL
|
|
CRemoteDesktopHelpSession::IsEqualSid(
|
|
IN const CComBSTR& bstrSid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare user's SID.
|
|
|
|
Parameters:
|
|
|
|
bstrSid : SID to be compared.
|
|
|
|
Returns:
|
|
|
|
TRUE/FALSE
|
|
|
|
--*/
|
|
{
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( NULL == m_pHelpSession )
|
|
{
|
|
MYASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
return (TRUE == IsSessionValid()) ? ((CComBSTR)m_pHelpSession->m_UserSID == bstrSid) : FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CRemoteDesktopHelpSession::VerifyUserSession(
|
|
IN const CComBSTR& bstrUserSid,
|
|
IN const CComBSTR& bstrSessPwd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify user help session password.
|
|
|
|
Parameters:
|
|
|
|
bstrUserSid : calling client's user SID.
|
|
bstrSessName : Help session name, not use currently.
|
|
bstrSessPwd : Help Session Password to be verified.
|
|
|
|
Returns:
|
|
|
|
TRUE/FALSE
|
|
|
|
--*/
|
|
{
|
|
DWORD dwStatus;
|
|
BOOL bReturn = FALSE;
|
|
|
|
CCriticalSectionLocker l(m_HelpSessionLock);
|
|
|
|
if( NULL == m_pHelpSession )
|
|
{
|
|
MYASSERT(FALSE);
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
|
|
#if DISABLESECURITYCHECKS
|
|
if( (CComBSTR)m_pHelpSession->m_SessionName == HELPSESSION_UNSOLICATED )
|
|
{
|
|
// use console session
|
|
m_ulLogonId = 0;
|
|
}
|
|
#endif
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
// Help Session is invalid
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::InitInstance(
|
|
IN CRemoteDesktopHelpSessionMgr* pMgr,
|
|
IN CComBSTR& bstrClientSid,
|
|
IN PHELPENTRY pHelpEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize a CRemoteDesktopHelpSession object.
|
|
|
|
Parameters:
|
|
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
if( NULL != pHelpEntry )
|
|
{
|
|
m_pSessMgr = pMgr;
|
|
m_pHelpSession = pHelpEntry;
|
|
m_bstrClientSid = bstrClientSid;
|
|
m_bstrHelpSessionId = pHelpEntry->m_SessionId;
|
|
}
|
|
else
|
|
{
|
|
hRes = HRESULT_FROM_WIN32( ERROR_INTERNAL_ERROR );
|
|
MYASSERT( SUCCEEDED(hRes) );
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::CreateInstance(
|
|
IN CRemoteDesktopHelpSessionMgr* pMgr,
|
|
IN CComBSTR& bstrClientSid,
|
|
IN PHELPENTRY pHelpEntry,
|
|
OUT RemoteDesktopHelpSessionObj** ppRemoteDesktopHelpSession
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an instance of help session.
|
|
|
|
Parameters:
|
|
|
|
pMgr : Pointer to help session manager object.
|
|
ppRemoteDesktopHelpSession : Return a pointer to help session instance.
|
|
|
|
Returns:
|
|
|
|
S_OK
|
|
E_OUTOFMEMORY
|
|
Error code in impersonating client
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
RemoteDesktopHelpSessionObj* p = NULL;
|
|
|
|
hRes = RemoteDesktopHelpSessionObj::CreateInstance( &p );
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
hRes = p->InitInstance(
|
|
pMgr,
|
|
bstrClientSid,
|
|
pHelpEntry
|
|
);
|
|
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
p->AddRef();
|
|
*ppRemoteDesktopHelpSession = p;
|
|
}
|
|
else
|
|
{
|
|
p->Release();
|
|
}
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::BeginUpdate()
|
|
{
|
|
HRESULT hRes;
|
|
|
|
MYASSERT( NULL != m_pHelpSession );
|
|
|
|
if( NULL != m_pHelpSession )
|
|
{
|
|
hRes = m_pHelpSession->BeginUpdate();
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::CommitUpdate()
|
|
{
|
|
HRESULT hRes;
|
|
|
|
//
|
|
// Update all entries.
|
|
//
|
|
MYASSERT( NULL != m_pHelpSession );
|
|
|
|
if( NULL != m_pHelpSession )
|
|
{
|
|
hRes = m_pHelpSession->CommitUpdate();
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
HRESULT
|
|
CRemoteDesktopHelpSession::AbortUpdate()
|
|
{
|
|
HRESULT hRes;
|
|
|
|
//
|
|
// Update all entries.
|
|
//
|
|
MYASSERT( NULL != m_pHelpSession );
|
|
if( NULL != m_pHelpSession )
|
|
{
|
|
hRes = m_pHelpSession->AbortUpdate();
|
|
}
|
|
else
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
}
|
|
|
|
return hRes;
|
|
}
|
|
|
|
BOOL
|
|
CRemoteDesktopHelpSession::IsHelpSessionExpired()
|
|
{
|
|
MYASSERT( NULL != m_pHelpSession );
|
|
|
|
return (NULL != m_pHelpSession) ? m_pHelpSession->IsEntryExpired() : TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CRemoteDesktopHelpSession::IsClientSessionCreator()
|
|
{
|
|
BOOL bStatus;
|
|
|
|
//
|
|
// NOTE: This function checks to make sure the caller is the user that
|
|
// created the Help Session. For Whistler, we enforce that Help
|
|
// Sessions only be created by apps running as SYSTEM. Once
|
|
// created, the creating app can pass the object to any other app
|
|
// running in any other context. This function will get in the
|
|
// way of this capability so it simply returns TRUE for now.
|
|
//
|
|
return TRUE;
|
|
|
|
if( m_pHelpSession )
|
|
{
|
|
bStatus = (/* (CComBSTR) */m_pHelpSession->m_UserSID == m_bstrClientSid);
|
|
if( FALSE == bStatus )
|
|
{
|
|
bStatus = (m_pHelpSession->m_UserSID == g_LocalSystemSID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bStatus = FALSE;
|
|
}
|
|
|
|
return bStatus;
|
|
}
|