//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: srvreg.hxx
//
// Contents: Classes used for keeping track of end points for a given
// class.
//
// Classes: SClsSrvHandle
//
// History: 03-Jan-94 Ricksa Created
// 01-Feb-96 BruceMa Support psid checking
//
//--------------------------------------------------------------------------
#include <headers.cxx>
#pragma hdrstop
#include "scm.hxx"
#include "port.hxx"
#include "srvreg.hxx"
#include "or.hxx"
#ifdef _CHICAGO_
BOOL NotifyToInitializeRpc(HWND hwnd);
DWORD GetOleNotificationWnd();
CStaticPortableMutex CSrvRegList::s_mxsOnlyOne; // mutex semaphore
#endif
// Mutex to protect multithreaded access to class data
CStaticPortableMutex CSrvRegList::s_mxsSyncAccess;
BOOL CSrvRegList::s_fForcedScmShutdown = FALSE;
//+-------------------------------------------------------------------------
//
// Member: SSrvRegistration::Free
//
// Synopsis: Clean up array entry
//
// Algorithm: Loop through any handle that exists and close the
// RPC binding on that handle.
//
// History: 03-Jan-94 Ricksa Created
//
//--------------------------------------------------------------------------
void SSrvRegistration::Free(void)
{
if (_hRpc != NULL)
{
#ifndef _CHICAGO_
if ( _dwHandleCount == 0 )
{
RpcBindingFree(&_hRpc);
_hRpc = (RPC_COOKIE) NULL;
if (_hRpcAnonymous)
{
RpcBindingFree(&_hRpcAnonymous);
_hRpcAnonymous = 0;
}
}
#else
ScmMemFree(_hRpc);
_hRpc = (RPC_COOKIE) NULL;
#endif
}
_dwFlags = SRV_REG_INVALID;
#ifndef _CHICAGO_
PrivMemFree (_psid);
_psid = NULL;
PrivMemFree (_pwszWinstaDesktop);
_pwszWinstaDesktop = NULL;
#endif
}
//+-------------------------------------------------------------------------
//
// Member: CSrvRegList::~CSrvRegList
//
// Synopsis: Clean up a handle object
//
// Algorithm: Loop through any handle that exists and close the
// RPC binding on that handle.
//
// History: 03-Jan-94 Ricksa Created
//
// Notes: This should only be used by the update thread so it
// doesn't need to be locked
//
// BillMo: add assertion to ensure we're never removing
// registrations that a client may need.
// I have added a flag so that we can force the close of
// RPC handles during a forced scm shutdown.
//
//--------------------------------------------------------------------------
CSrvRegList::~CSrvRegList(void)
{
#ifdef _CHICAGO_
Win4Assert(!InUse());
#else
if (!s_fForcedScmShutdown)
{
Win4Assert(!InUse());
}
else
// Search for all open RPC handles.
if (GetSize() > 0)
{
// Get pointer to the base of the array
SSrvRegistration *pssrvreg = (SSrvRegistration *) GetAt(0);
// Loop through array
for (int i = 0; i < GetSize(); i++, pssrvreg++)
{
// Tell RPC we no longer need the handle
if (pssrvreg->_hRpc != NULL)
{
pssrvreg->Free();
}
}
}
#endif
}
//+-------------------------------------------------------------------------
//
// Member: CSrvRegList::Insert
//
// Synopsis: Insert a new registration into the list
//
// Arguments: [ssrvreg] - an entry for the table
//
// Returns: 0 - Error occurred and we could not register the handle
// ~0 - Handle registered successfully
//
// Algorithm: Create a handle to an RPC bind. Then search the table for
// a place to put the binding. Stick the bind in the first
// available spot.
//
// History: 03-Jan-94 Ricksa Created
//
//--------------------------------------------------------------------------
DWORD CSrvRegList::Insert(
IFSECURITY(PSID psid)
WCHAR *pwszWinstaDesktop,
#ifdef DCOM
PHPROCESS phProcess,
OXID oxid,
IPID ipid,
#else
WCHAR *pwszEndpoint,
#endif
DWORD dwFlags)
{
// Protect from multiple updates
CStaticPortableLock lck(s_mxsSyncAccess);
int iNew = 0;
DWORD dwReg = 0;
// Create an RPC bind
SSrvRegistration ssrvregNew;
ssrvregNew._dwFlags = (dwFlags == REGCLS_SURROGATE) ?
REGCLS_MULTIPLEUSE : dwFlags;
ssrvregNew._fSurrogate = (dwFlags == REGCLS_SURROGATE);
SSrvRegistration *pssrvreg;
#ifndef _CHICAGO_
RPC_STATUS status;
// Get the string binding information from the process object.
ssrvregNew._hRpc = ((CProcess *)phProcess)->GetBindingHandle();
if (ssrvregNew._hRpc == 0)
return 0;
status = I_RpcBindingSetAsync(ssrvregNew._hRpc, 0);
if (status != RPC_S_OK)
return 0;
ssrvregNew._oxid = oxid;
ssrvregNew._ipid = ipid;
status = RpcBindingSetObject( ssrvregNew._hRpc, (GUID *) &ipid );
if (status != ERROR_SUCCESS)
{
return 0;
}
ssrvregNew._dwHandleCount = 0;
ssrvregNew._hRpcAnonymous = 0;
#else // _CHICAGO_
ssrvregNew._hRpc = (WCHAR *)ScmMemAlloc(sizeof(WCHAR) * (lstrlenW(pwszEndpoint)+1));
ssrvregNew._ulWnd = GetOleNotificationWnd();
if (ssrvregNew._hRpc == NULL)
{
return(0);
}
lstrcpyW(ssrvregNew._hRpc, pwszEndpoint);
#endif // _CHICAGO_
#ifndef _CHICAGO_
ULONG ulLength;
NTSTATUS NtStatus;
ulLength = RtlLengthSid (psid);
ssrvregNew._psid = PrivMemAlloc (ulLength);
if (ssrvregNew._psid == NULL)
{
goto errRet;
}
NtStatus = RtlCopySid (ulLength, ssrvregNew._psid, psid);
Win4Assert (NT_SUCCESS(NtStatus) && "CSrvRegList::Insert");
if (!NT_SUCCESS(NtStatus))
{
goto errRet;
}
#endif // CHICAGO
if (pwszWinstaDesktop != NULL)
{
#ifdef _CHICAGO_
Win4Assert(FALSE);
#endif
ssrvregNew._pwszWinstaDesktop =
(WCHAR *) PrivMemAlloc((lstrlenW(pwszWinstaDesktop) + 1) * sizeof(WCHAR));
if (ssrvregNew._pwszWinstaDesktop == NULL)
{
goto errRet;
}
lstrcpyW (ssrvregNew._pwszWinstaDesktop, pwszWinstaDesktop);
}
else
{
ssrvregNew._pwszWinstaDesktop = NULL;
}
// Put bind in our table
// Search for first empty bucket that we have
if (GetSize() > 0)
{
pssrvreg = (SSrvRegistration *) GetAt(0);
for ( ; iNew < GetSize(); iNew++, pssrvreg++)
{
if (pssrvreg->_hRpc == 0)
{
// Found an empty bucket
break;
}
}
}
if (iNew < GetSize())
{
memcpy(pssrvreg, &ssrvregNew, sizeof(ssrvregNew));
}
else if (!InsertAt(iNew, &ssrvregNew))
{
goto errRet;
}
CairoleDebugOut((DEB_ITRACE,
"CSrvRegList::Insert() -> %08X\n",
ssrvregNew._hRpc));
return (DWORD) ssrvregNew._hRpc;
errRet:
ssrvregNew.Free();
return(0);
};
//+-------------------------------------------------------------------------
//
// Member: CSrvRegList::Delete
//
// Synopsis: Delete an end point from the list of registered end points
//
// Arguments: [dwReg] - value used for registration
//
// Returns: TRUE - LAST registration deleted
// FALSE - other registrations still exist
//
// Algorithm: Convert the registration to the RPC handle and then
// loop through the table of registrations to see if the
// we can find it. If we do, tell RPC to dump the handle.
//
// History: 03-Jan-94 Ricksa Created
//
//--------------------------------------------------------------------------
BOOL CSrvRegList::Delete(RPC_COOKIE hRpc)
{
BOOL fLast = TRUE;
if (hRpc != (RPC_COOKIE)NULL)
{
// Protect from multiple updates
CStaticPortableLock lck(s_mxsSyncAccess);
// For Daytona, Registration is actually the RPC handle
// For Chicago, Registration is the strings address
// Search for matching entry in table
SSrvRegistration *pssrvreg = (SSrvRegistration *) GetAt(0);
for (int i = 0; i < GetSize(); i++, pssrvreg++)
{
if (pssrvreg->_hRpc == NULL)
{
continue;
}
else if (pssrvreg->_hRpc == hRpc)
{
pssrvreg->Free();
}
else
{
fLast = FALSE;
}
}
}
else
{
fLast = FALSE;
}
return fLast;
}
//+-------------------------------------------------------------------------
//
// Member: CSrvRegList::GetHandle
//
// Synopsis: Get a handle from the list of handles for the class
//
// Arguments: [psid] -- security id of client process
// [pwszWinstaDesktop]
// [rh] -- binding handle
// [fSurrogate] -- flag indicating that we want to find a
// surrogate process
//
// Returns: NULL - could not find a valid registration
// ~NULL - handle to a running RPC server.
//
// Algorithm: Loop through the list searching for the first non-null
// entry that we can use as a handle to an object server.
//
// History: 03-Jan-94 Ricksa Created
//
//--------------------------------------------------------------------------
BOOL CSrvRegList::GetHandle(IFSECURITY(PSID psid)
WCHAR * pwszWinstaDesktop,
CPortableRpcHandle &rh,
BOOL fSurrogate)
{
SSrvRegistration *pssrvreg = 0;
HWND hWnd;
do
{
#ifdef _CHICAGO_
CStaticPortableLock lckOnlyOne(s_mxsOnlyOne);
#endif
CairoleDebugOut((DEB_ITRACE,
"CSrvRegList::GetHandle(%x) called (%x)\n",
this,pssrvreg));
{ // begin mutex block
hWnd = 0;
// bracket for mutex
// Protect from multiple updates
CStaticPortableLock lck(s_mxsSyncAccess);
// Search for first non-empty bucket that we have
pssrvreg = (SSrvRegistration *) GetAt(0);
for (int i = 0; i < GetSize(); i++, pssrvreg++)
{
if ( (pssrvreg->_hRpc != NULL) &&
(pssrvreg->_dwFlags != SRV_REG_INVALID) )
{
// if we're looking for a surrogate...
if(fSurrogate)
{
if(!(pssrvreg->_fSurrogate))
{
continue;
}
}
#ifndef _CHICAGO_
//
// Client's SID param is null when connecting to services
// or RunAs servers. In those instances we just take the
// first binding handle we find. Only a server running in
// the correct security context could register a handle.
//
// For connecting to "activate as activator" server, both
// the SID and, for local activations, the winsta\desktop
// must match the server's.
//
if ( psid != NULL )
{
if ( ! RtlEqualSid(pssrvreg->_psid, psid) )
continue;
if ( (pwszWinstaDesktop != NULL) &&
(lstrcmpW(pwszWinstaDesktop, pssrvreg->_pwszWinstaDesktop) != 0) )
continue;
}
#endif
//
// On Chicago there are no SIDs nor desktops, so you get
// the first handle in the list.
//
rh.SetRpcCookie( pssrvreg->_hRpc,
pssrvreg->_dwFlags == REGCLS_SINGLEUSE,
pssrvreg->_ipid );
#ifndef _CHICAGO_
pssrvreg->_dwHandleCount++;
#endif
// Is this a single use registration?
if (pssrvreg->_dwFlags == REGCLS_SINGLEUSE)
{
CairoleDebugOut((DEB_ITRACE,
"CSrvRegList::GetHandle(%x) REGCLS_SINGLEUSE. Nulling handle pssrvreg(%x)\n",
this,pssrvreg));
// For the single use class, the call owns the handle now.
// So, we clear it and then try to free any other data
// associated with the entry.
#ifdef _CHICAGO_
if (pssrvreg->_ulWnd == 0)
#endif // _CHICAGO_
{
pssrvreg->_hRpc = NULL;
pssrvreg->Free();
}
}
#ifdef _CHICAGO_
if(pssrvreg->_ulWnd)
{
// notify the server once to launch rpc
// has to be done outside of the mutex
hWnd = (HWND)pssrvreg->_ulWnd;
pssrvreg->_ulWnd = 0;
CairoleDebugOut((DEB_ITRACE,
"CSrvRegList::GetHandle(%x) found with hWnd(%d)\n",
this, hWnd));
// fall out of loop and notify the server
// outside of the mutex
break;
}
#endif // _CHICAGO_
CairoleDebugOut((DEB_ITRACE,
"CSrvRegList::GetHandle(%x) called (%x) done TRUE\n",
this,pssrvreg));
return(TRUE);
}
}
} // end mutex block
#ifdef _CHICAGO_
if(hWnd)
{
// notify the server once to launch rpc
NotifyToInitializeRpc(hWnd);
// find the class again; since we released the
// mutex the server might have disappeared
}
else
#endif // _CHICAGO_
break;
} while (TRUE);
CairoleDebugOut((DEB_ITRACE,
"CSrvRegList::GetHandle(%x) called (%x) done FALSE\n",
this,pssrvreg));
return(FALSE);
}
//+-------------------------------------------------------------------------
//
// Member: CSrvRegList::FindCompatibleSurrogate
//
// Synopsis: Finds a server for an existing surrogate process
// with the desired attributes
//
// Arguments: [psid] -- security id of client process
// [rh] -- binding handle
//
// Returns: TRUE - it found a server with the desired
// attributes -- the rh reference or ppIObjServer
// is set to that of the appropriate server
// FALSE - no appropriate server
//
// Algorithm: Ask GetHandle or GetProxy
// to search for a surrogate for us with the
// desired attributes
//
// 21-JUN-96 t-adame created
//
//--------------------------------------------------------------------------
BOOL CSrvRegList::FindCompatibleSurrogate(IFSECURITY(PSID psid)
WCHAR* pwszWinstaDesktop,
CPortableRpcHandle &rh)
{
// we set the fSurrogate parameter of GetHandle to TRUE to let
// GetHandle know that we need a binding handle for a surrogate
// process
return GetHandle(IFSECURITY(psid) pwszWinstaDesktop,rh,TRUE);
}
//+-------------------------------------------------------------------------
//
// Member: CSrvRegList::InUse
//
// Synopsis: See whether there is anything current registration
//
// Returns: TRUE - server is currently registered
// FALSE - server is not currently registered
//
// Algorithm: Loop through the list searching for the first non-null
// entry. If we find one return NULL.
//
// History: 04-Jan-94 Ricksa Created
//
// Notes: This should only be used by the update thread so it
// doesn't need to be locked
//
//--------------------------------------------------------------------------
BOOL CSrvRegList::InUse(void)
{
// Protect from multiple updates
CStaticPortableLock lck(s_mxsSyncAccess);
// Assume there are no current registrations.
BOOL fResult = FALSE;
// Search for first non-empty bucket that we have
SSrvRegistration *pssrvreg = (SSrvRegistration *) GetAt(0);
for (int i = 0; i < GetSize(); i++, pssrvreg++)
{
if (pssrvreg->_hRpc != NULL)
{
fResult = TRUE;
break;
}
}
return fResult;
}
//+-------------------------------------------------------------------------
//
// Member: CSrvRegList::VerifyHandle
//
// Synopsis: Whether this is a valid handle to an object server
//
// Returns: TRUE - this is still a valid handle to an object server
// FALSE - this is no longer a valid handle to an object server
//
// History: 11-May-94 DonnaLi Created
//
// Notes: This should only be used to assist the retry logic.
//
//--------------------------------------------------------------------------
BOOL CSrvRegList::VerifyHandle(RPC_COOKIE hRpc)
{
if (hRpc == (RPC_COOKIE)NULL)
return FALSE;
// Protect from multiple updates
CStaticPortableLock lck(s_mxsSyncAccess);
// Search for first non-empty bucket that we have
SSrvRegistration *pssrvreg = (SSrvRegistration *) GetAt(0);
for (int i = 0; i < GetSize(); i++, pssrvreg++)
{
if ( pssrvreg->_hRpc == hRpc
#ifndef _CHICAG0_
&& pssrvreg->_dwFlags != SRV_REG_INVALID
#endif
)
{
return TRUE;
}
}
return FALSE;
}
//+-------------------------------------------------------------------------
//
// Member: CSrvRegList::InvalidateHandle
//
// Synopsis: Invalidate a handle in the list of handles for the class
// Caller of GetHandle concluded it is no longer valid
//
// Arguments: [hRpc] -- handle to invalidate
//
// Returns: None
//
// Algorithm: Loop through the list searching for match on handle or
// list is exhausted
//
// History: 20-Sep-95 MurthyS Created
//
//--------------------------------------------------------------------------
VOID CSrvRegList::InvalidateHandle(
RPC_COOKIE hRpc
)
{
if (hRpc == (RPC_COOKIE)NULL)
{
return;
}
// Protect from multiple updates
CStaticPortableLock lck(s_mxsSyncAccess);
// Search for first non-empty bucket that we have
SSrvRegistration *pssrvreg = (SSrvRegistration *) GetAt(0);
for (int i = 0; i < GetSize(); i++, pssrvreg++)
{
if (pssrvreg->_hRpc == hRpc)
{
//
// At least try to free it. Its remotely possible that another
// thread will still have a reference which will cause us to
// orphan this handle.
//
// But we have to NULL it now so that InUse() will work right,
// so that the retry logic for launching a server will work right.
// This is all very gross and nasty and needs to be redone from
// scratch.
//
// Fix it in NT 5.0.
//
pssrvreg->Free();
pssrvreg->_hRpc == NULL;
return;
}
}
}
void CSrvRegList::GetAnonymousHandle(
CPortableRpcHandle &rh,
handle_t * phRpcAnonymous )
{
RPC_STATUS RpcStatus;
RPC_SECURITY_QOS Qos;
BOOL bMatch;
*phRpcAnonymous = 0;
bMatch = FALSE;
// Protect from multiple updates
CStaticPortableLock lck(s_mxsSyncAccess);
// Search for first non-empty bucket that we have
SSrvRegistration *pssrvreg = (SSrvRegistration *) GetAt(0);
for (int i = 0; i < GetSize(); i++, pssrvreg++)
{
if ( (pssrvreg->_hRpc == rh.GetHandle()) &&
(pssrvreg->_dwFlags != SRV_REG_INVALID) )
{
Win4Assert( pssrvreg->_dwHandleCount );
if ( pssrvreg->_hRpcAnonymous )
{
*phRpcAnonymous = pssrvreg->_hRpcAnonymous;
return;
}
bMatch = TRUE;
break;
}
}
//
// We continue if we don't find the handle in the table if its a single
// use handle because it is removed from the table in GetHandle in that
// case.
//
if ( ! bMatch && ! rh.fSingleUse() )
return;
IPID ipid;
ipid = bMatch ? pssrvreg->_ipid : rh.Ipid();
//
// Note that we indicate impersonation level of identify because
// anonymous is not supported. However specifing no authentication
// in SetAuthInfo will keep the server from impersonating us.
//
Qos.Version = RPC_C_SECURITY_QOS_VERSION;
Qos.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT;
Qos.ImpersonationType = RPC_C_IMP_LEVEL_IDENTIFY;
Qos.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC;
RpcStatus = RpcBindingCopy(
rh.GetHandle(),
phRpcAnonymous );
if ( RpcStatus != RPC_S_OK )
return;
RpcStatus = I_RpcBindingSetAsync( *phRpcAnonymous, 0 );
if ( RpcStatus != RPC_S_OK )
goto GetAnonymousHandleExit;
RpcStatus = RpcBindingSetObject( *phRpcAnonymous, (GUID *) &ipid );
if ( RpcStatus != RPC_S_OK )
goto GetAnonymousHandleExit;
RpcStatus = RpcBindingSetAuthInfoEx(
*phRpcAnonymous,
NULL,
RPC_C_AUTHN_LEVEL_NONE,
RPC_C_AUTHN_WINNT,
NULL,
0,
&Qos );
GetAnonymousHandleExit:
if ( (RpcStatus == RPC_S_OK) && bMatch )
pssrvreg->_hRpcAnonymous = *phRpcAnonymous;
if ( (RpcStatus != RPC_S_OK) && *phRpcAnonymous )
{
RpcBindingFree( phRpcAnonymous );
*phRpcAnonymous = 0;
}
}
#ifndef _CHICAGO_
VOID CSrvRegList::DecHandleCount(
RPC_COOKIE hRpc
)
{
if ( hRpc == (RPC_COOKIE)NULL )
return;
// Protect from multiple updates
CStaticPortableLock lck(s_mxsSyncAccess);
// Search for first non-empty bucket that we have
SSrvRegistration *pssrvreg = (SSrvRegistration *) GetAt(0);
for (int i = 0; i < GetSize(); i++, pssrvreg++)
{
if (pssrvreg->_hRpc == hRpc)
{
if ( pssrvreg->_dwHandleCount > 0 )
pssrvreg->_dwHandleCount--;
if ( (pssrvreg->_dwHandleCount == 0) &&
(pssrvreg->_dwFlags == SRV_REG_INVALID) &&
(pssrvreg->_hRpc != 0) )
{
RpcBindingFree( &pssrvreg->_hRpc );
pssrvreg->_hRpc == NULL;
if ( pssrvreg->_hRpcAnonymous )
{
RpcBindingFree( &pssrvreg->_hRpcAnonymous );
pssrvreg->_hRpcAnonymous == NULL;
}
}
return;
}
}
}
#endif