You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2650 lines
65 KiB
2650 lines
65 KiB
/*++
|
|
|
|
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>
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 )
|
|
{
|
|
//
|
|
// DeleteHelp() will free m_pHelpSession but in the case that RA is in
|
|
// progress, it only set m_bDeleted to TRUE so we assert here if
|
|
// ticket is deleted.
|
|
//
|
|
MYASSERT( FALSE == m_bDeleted );
|
|
|
|
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;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
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;
|
|
DWORD dwICSPort = 0;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker ObjLock(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
hRes = E_HANDLE;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Sync. access from OpenPort() to FetchAllAddress().
|
|
//
|
|
{
|
|
CCriticalSectionLocker ICSLock(g_ICSLibLock);
|
|
|
|
//
|
|
// Open ICS port.
|
|
//
|
|
dwICSPort = OpenPort( TERMSRV_TCPPORT );
|
|
|
|
//
|
|
// 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 );
|
|
if( dwNumChars <= dwBufferRequire )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( NULL == pszAddress || dwRetry >= MAX_FETCHIPADDRESSRETRY )
|
|
{
|
|
hRes = E_UNEXPECTED;
|
|
MYASSERT( FALSE );
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Get an exclusive lock
|
|
//
|
|
ObjLock.ConvertToExclusiveLock();
|
|
|
|
//
|
|
// We hold the exclusive lock and if we call put_ICSPort(), it will
|
|
// deadlock since put_ICSPort() try to get an exclusive lock again.
|
|
//
|
|
m_pHelpSession->m_ICSPort.EnableImmediateUpdate(TRUE);
|
|
m_pHelpSession->m_ICSPort = dwICSPort;
|
|
|
|
//
|
|
// Store the IP address
|
|
//
|
|
m_pHelpSession->m_IpAddress.EnableImmediateUpdate(TRUE);
|
|
m_pHelpSession->m_IpAddress = pszAddress;
|
|
|
|
ObjLock.ConvertToShareLock();
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
{
|
|
// MTA so we need to lock g_TSSecurityBlob.
|
|
CCriticalSectionLocker l(g_GlobalLock);
|
|
|
|
MYASSERT( g_TSSecurityBlob.Length() > 0 );
|
|
|
|
#ifndef USE_WEBLINK_PARMSTRING_FORMAT
|
|
|
|
*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
|
|
);
|
|
#else
|
|
|
|
*bstrConnectParms = CreateConnectParmsString(
|
|
REMOTEDESKTOP_TSRDP_PROTOCOL,
|
|
CComBSTR(pszAddress),
|
|
bstrSessId,
|
|
g_TSSecurityBlob
|
|
);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#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;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
|
|
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;
|
|
|
|
//
|
|
// mktime() return values in local time not UTC time
|
|
// all time uses in sessmgr is UTC time, time(), so
|
|
// return in UTC time, note that no XP client bug since
|
|
// this property is not exposed.
|
|
//
|
|
if((*pTimeout = mktime(&gmTime)) == (time_t)-1)
|
|
{
|
|
*pTimeout = INT_MAX;
|
|
}
|
|
else
|
|
{
|
|
// we don't need to substract daylight saving time (dst)
|
|
// since when calling mktime, we set isdst to 0 in
|
|
// gmTime.
|
|
struct _timeb timebuffer;
|
|
_ftime( &timebuffer );
|
|
(*pTimeout) -= (timebuffer.timezone * 60);
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
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;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
|
|
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;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
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_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;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
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;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
|
|
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;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
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;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
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;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
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;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
|
|
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;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
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;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
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::IsUserOwnerOfTicket(
|
|
/*[in]*/ BSTR bstrSID,
|
|
/* [out, retval] */ VARIANT_BOOL* pbUserIsOwner
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Check if user is the owner of this ticket
|
|
|
|
Parameter:
|
|
|
|
SID : User sid to verify.
|
|
pbUserIsOwner : VARIANT_TRUE if user is the owner, VARIANT_FALSE otherwise
|
|
|
|
Return:
|
|
|
|
S_OK or error code
|
|
|
|
--*/
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
|
|
if( pbUserIsOwner == NULL )
|
|
{
|
|
hr = E_POINTER;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
if( bstrSID == NULL || 0 == SysStringLen(bstrSID) )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
*pbUserIsOwner = ( IsEqualSid(CComBSTR(bstrSID)) ) ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
return hr;
|
|
}
|
|
|
|
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;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
|
|
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,
|
|
(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;
|
|
LPTSTR eventString[2];
|
|
BSTR pszNoviceDomain = NULL;
|
|
BSTR pszNoviceName = NULL;
|
|
HRESULT hr;
|
|
|
|
|
|
CRemoteDesktopHelpSessionMgr::LockIDToSessionMapCache();
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
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();
|
|
|
|
//
|
|
// Log the event indicate that ticket was deleted, non-critical
|
|
// since we can still continue to run.
|
|
//
|
|
hr = ConvertSidToAccountName(
|
|
(CComBSTR) m_pHelpSession->m_UserSID,
|
|
&pszNoviceDomain,
|
|
&pszNoviceName
|
|
);
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
eventString[0] = pszNoviceDomain;
|
|
eventString[1] = pszNoviceName;
|
|
|
|
LogRemoteAssistanceEventString(
|
|
EVENTLOG_INFORMATION_TYPE,
|
|
SESSMGR_I_REMOTEASSISTANCE_DELETEDTICKET,
|
|
2,
|
|
eventString
|
|
);
|
|
}
|
|
//
|
|
// 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 )
|
|
{
|
|
CCriticalSectionLocker ICSLock(g_ICSLibLock);
|
|
|
|
//
|
|
// 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();
|
|
|
|
|
|
if( pszNoviceDomain )
|
|
{
|
|
SysFreeString( pszNoviceDomain );
|
|
}
|
|
|
|
if( pszNoviceName )
|
|
{
|
|
SysFreeString( pszNoviceName );
|
|
}
|
|
|
|
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;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker lock(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
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;
|
|
|
|
//
|
|
// Load resolver
|
|
hRes = LoadSessionResolver( &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;
|
|
}
|
|
|
|
//
|
|
// We don't need to hold exclusive lock while waiting for resolver to
|
|
// return
|
|
//
|
|
lock.ConvertToShareLock();
|
|
|
|
hRes = pIResolver->ResolveUserSessionID(
|
|
m_ResolverConnectBlob,
|
|
(CComBSTR)m_pHelpSession->m_UserSID,
|
|
expertBlob,
|
|
(CComBSTR)m_pHelpSession->m_SessionCreateBlob,
|
|
(ULONG_PTR)g_hServiceShutdown,
|
|
&sessionId,
|
|
CallerProcessId,
|
|
phHelpCtr,
|
|
&resolverRetCode
|
|
);
|
|
|
|
//
|
|
// Get an exclusive lock since we are modifying internal data
|
|
//
|
|
lock.ConvertToExclusiveLock();
|
|
|
|
*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;
|
|
|
|
// SECURITY: Return error code or RA connection will continue on.
|
|
*pResolverErrCode = resolverRetCode;
|
|
InterlockedExchange( (LPLONG)&m_ulHelperSessionId, (LONG)UNKNOWN_LOGONID );
|
|
}
|
|
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;
|
|
|
|
//
|
|
// We havn't inform resolver yet so mark ticket not been help.
|
|
//
|
|
InterlockedExchange( (LPLONG)&m_ulHelperSessionId, (LONG)UNKNOWN_LOGONID );
|
|
}
|
|
|
|
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
|
|
);
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker lock(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// Load resolver
|
|
hRes = LoadSessionResolver( &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
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
return hRes;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CRemoteDesktopHelpSession::EnableUserSessionRdsSetting(
|
|
IN BOOL bEnable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enable/restore user session shadow setting.
|
|
|
|
|
|
|
|
--*/
|
|
{
|
|
HRESULT hRes = S_OK;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// DCR 681451 - Shadow is disabled by default on console session.
|
|
// Change functionality, if we enforce no shadow, RA won't work on console session.
|
|
//
|
|
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
|
|
);
|
|
|
|
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;
|
|
|
|
//
|
|
// Exclusive lock on helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker lock(m_HelpSessionLock, RESOURCELOCK_EXCLUSIVE);
|
|
|
|
|
|
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
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
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
|
|
|
|
--*/
|
|
{
|
|
LPWSTR bstrDecodePwd = NULL;
|
|
DWORD dwStatus;
|
|
BOOL bReturn = FALSE;
|
|
|
|
//
|
|
// Acquire share access to helpsession object, CResourceLocker constructor
|
|
// will wait indefinately for the resource and will release resource
|
|
// at destructor time.
|
|
//
|
|
CResourceLocker l(m_HelpSessionLock, RESOURCELOCK_SHARE);
|
|
|
|
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
|
|
|
|
//
|
|
// Object can only exists when helpsessionmgr object can create us
|
|
// via loading from registry or create a new one, so we only need to
|
|
// verify if ticket has been deleted.
|
|
//
|
|
|
|
//
|
|
// Whistler server B3, no more checking on help session password,
|
|
// help session ID is the only security check.
|
|
//
|
|
|
|
if( FALSE == IsSessionValid() )
|
|
{
|
|
// Help Session is invalid
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
bReturn = TRUE;
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if( NULL != bstrDecodePwd )
|
|
{
|
|
LocalFree( bstrDecodePwd );
|
|
}
|
|
|
|
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;
|
|
|
|
try
|
|
{
|
|
hRes = RemoteDesktopHelpSessionObj::CreateInstance( &p );
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
hRes = p->InitInstance(
|
|
pMgr,
|
|
bstrClientSid,
|
|
pHelpEntry
|
|
);
|
|
|
|
if( SUCCEEDED(hRes) )
|
|
{
|
|
p->AddRef();
|
|
*ppRemoteDesktopHelpSession = p;
|
|
}
|
|
else
|
|
{
|
|
p->Release();
|
|
}
|
|
}
|
|
}
|
|
catch( ... )
|
|
{
|
|
hRes = E_OUTOFMEMORY;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|