windows-nt/Source/XPSP1/NT/base/cluster/service/nm/connsink.cpp
2020-09-26 16:20:57 +08:00

724 lines
18 KiB
C++

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
connsink.c
Abstract:
Implements a COM sink object on which to receive connection folder
events
Author:
CharlWi (Charlie Wickham) 11/30/98 - heavily ripped off from
net\config\shell\folder\notify.cpp, originally authored by
ShaunCo (Shaun Cox)
Revision History:
--*/
#define UNICODE 1
#include "connsink.h"
#include <iaccess.h>
extern "C" {
#include "nmp.h"
VOID
ProcessNameChange(
GUID * GuidId,
LPCWSTR NewName
);
}
EXTERN_C const CLSID CLSID_ConnectionManager;
EXTERN_C const IID IID_INetConnectionNotifySink;
#define INVALID_COOKIE -1
CComModule _Module;
DWORD AdviseCookie = INVALID_COOKIE;
//static
HRESULT
CConnectionNotifySink::CreateInstance (
REFIID riid,
VOID** ppv)
{
HRESULT hr = E_OUTOFMEMORY;
// Initialize the output parameter.
//
*ppv = NULL;
CConnectionNotifySink* pObj;
pObj = new CComObject <CConnectionNotifySink>;
if (pObj)
{
// Do the standard CComCreator::CreateInstance stuff.
//
pObj->SetVoid (NULL);
pObj->InternalFinalConstructAddRef ();
hr = pObj->FinalConstruct ();
pObj->InternalFinalConstructRelease ();
if (SUCCEEDED(hr))
{
hr = pObj->QueryInterface (riid, ppv);
}
if (FAILED(hr))
{
delete pObj;
}
}
if ( FAILED( hr )) {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Unable to create Net Connection Manager advise sink "
"object, status %08X.\n",
hr);
}
return hr;
} // CConnectionNotifySink::CreateInstance
//+---------------------------------------------------------------------------
//
// Member: CConnectionNotifySink::~CConnectionNotifySink
//
// Purpose: Clean up the sink object
//
// Arguments:
// (none)
//
// Returns:
//
CConnectionNotifySink::~CConnectionNotifySink()
{
}
//
// all we really care about are renaming events hence the rest of the routines
// are stubbed out
//
HRESULT
CConnectionNotifySink::ConnectionAdded (
const NETCON_PROPERTIES_EX* pPropsEx)
{
return E_NOTIMPL;
}
HRESULT
CConnectionNotifySink::ConnectionBandWidthChange (
const GUID* pguidId)
{
return E_NOTIMPL;
}
HRESULT
CConnectionNotifySink::ConnectionDeleted (
const GUID* pguidId)
{
return E_NOTIMPL;
}
HRESULT
CConnectionNotifySink::ConnectionModified (
const NETCON_PROPERTIES_EX* pPropsEx)
{
ProcessNameChange(const_cast<GUID *>(&(pPropsEx->guidId)), pPropsEx->bstrName );
return S_OK;
}
HRESULT
CConnectionNotifySink::ConnectionRenamed (
const GUID* GuidId,
LPCWSTR NewName)
{
ProcessNameChange(( GUID *)GuidId, NewName );
return S_OK;
} // CConnectionNotifySink::ConnectionRenamed
HRESULT
CConnectionNotifySink::ConnectionStatusChange (
const GUID* pguidId,
NETCON_STATUS Status)
{
return E_NOTIMPL;
}
HRESULT
CConnectionNotifySink::RefreshAll ()
{
return E_NOTIMPL;
}
HRESULT CConnectionNotifySink::ConnectionAddressChange (
const GUID* pguidId )
{
return E_NOTIMPL;
}
HRESULT CConnectionNotifySink::ShowBalloon(
IN const GUID* pguidId,
IN const BSTR szCookie,
IN const BSTR szBalloonText)
{
return E_NOTIMPL;
}
HRESULT CConnectionNotifySink::DisableEvents(
IN const BOOL fDisable,
IN const ULONG ulDisableTimeout)
{
return E_NOTIMPL;
}
//+---------------------------------------------------------------------------
//
// Function: HrGetNotifyConPoint
//
// Purpose: Common code for getting the connection point for use in
// NotifyAdd and NotifyRemove
//
// Arguments:
// ppConPoint [out] Return ptr for IConnectionPoint
//
// Returns:
//
// Author: jeffspr 24 Aug 1998
//
// Notes:
//
HRESULT HrGetNotifyConPoint(
IConnectionPoint ** ppConPoint)
{
HRESULT hr;
IConnectionPointContainer * pContainer = NULL;
CL_ASSERT(ppConPoint);
// Get the debug interface from the connection manager
//
hr = CoCreateInstance(CLSID_ConnectionManager, NULL,
CLSCTX_LOCAL_SERVER,
IID_IConnectionPointContainer,
(LPVOID*)&pContainer);
if (SUCCEEDED(hr)) {
IConnectionPoint * pConPoint = NULL;
// Get the connection point itself and fill in the return param
// on success
//
hr = pContainer->FindConnectionPoint(
IID_INetConnectionNotifySink,
&pConPoint);
if (SUCCEEDED(hr)) {
//
// set up a proxy on the connection point interface that will
// identify ourselves as ourselves.
//
hr = CoSetProxyBlanket(pConPoint,
RPC_C_AUTHN_WINNT, // use NT default security
RPC_C_AUTHZ_NONE, // use NT default authentication
NULL, // must be null if default
RPC_C_AUTHN_LEVEL_CALL, // call
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, // use process token
EOAC_NONE);
if (SUCCEEDED(hr)) {
*ppConPoint = pConPoint;
} else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Couldn't set proxy blanket on Net Connection "
"point, status %1!08X!.\n",
hr);
pConPoint->Release();
}
} else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Couldn't find notify sink connection point on Net Connection "
"Manager, status %1!08X!.\n",
hr);
}
pContainer->Release();
} else {
ClRtlLogPrint(LOG_CRITICAL,
"[NM] Couldn't establish connection point with Net Connection "
"Manager, status %1!08X!.\n",
hr);
}
return hr;
}
EXTERN_C {
HRESULT
NmpGrantAccessToNotifySink(
VOID
)
/*++
Routine Description:
allow localsystem and cluster service account access to make callbacks
into the service.
stolen from private\admin\snapin\netsnap\remrras\server\remrras.cpp and
code reviewed by SajiA
Arguments:
None
Return Value:
ERROR_SUCCESS if everything went ok.
--*/
{
IAccessControl* pAccessControl = NULL;
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
PSID pSystemSid = NULL;
HANDLE processToken = NULL;
ULONG tokenUserSize;
PTOKEN_USER processTokenUser = NULL;
DWORD status;
HRESULT hr = CoCreateInstance(CLSID_DCOMAccessControl,
NULL,
CLSCTX_INPROC_SERVER,
IID_IAccessControl,
(void**)&pAccessControl);
if(FAILED(hr)) {
goto Error;
}
//
// Setup the property list. We use the NULL property because we are trying
// to adjust the security of the object itself
//
ACTRL_ACCESSW access;
ACTRL_PROPERTY_ENTRYW propEntry;
access.cEntries = 1;
access.pPropertyAccessList = &propEntry;
ACTRL_ACCESS_ENTRY_LISTW entryList;
propEntry.lpProperty = NULL;
propEntry.pAccessEntryList = &entryList;
propEntry.fListFlags = 0;
//
// Setup the access control list for the default property
//
ACTRL_ACCESS_ENTRYW entry[2];
entryList.cEntries = 2;
entryList.pAccessList = entry;
//
// Setup the access control entry for localsystem
//
entry[0].fAccessFlags = ACTRL_ACCESS_ALLOWED;
entry[0].Access = COM_RIGHTS_EXECUTE;
entry[0].ProvSpecificAccess = 0;
entry[0].Inheritance = NO_INHERITANCE;
entry[0].lpInheritProperty = NULL;
// NT requires the system account to have access (for launching)
entry[0].Trustee.pMultipleTrustee = NULL;
entry[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
entry[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
entry[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
//
// allocate and init the SYSTEM sid
//
if ( !AllocateAndInitializeSid( &siaNtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&pSystemSid ) ) {
status = GetLastError();
goto Error;
}
entry[0].Trustee.ptstrName = (PWCHAR)pSystemSid;;
//
// Setup the access control entry for cluster service account
//
entry[1].fAccessFlags = ACTRL_ACCESS_ALLOWED;
entry[1].Access = COM_RIGHTS_EXECUTE;
entry[1].ProvSpecificAccess = 0;
entry[1].Inheritance = NO_INHERITANCE;
entry[1].lpInheritProperty = NULL;
entry[1].Trustee.pMultipleTrustee = NULL;
entry[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
entry[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
entry[1].Trustee.TrusteeType = TRUSTEE_IS_USER;
status = NtOpenProcessToken(
NtCurrentProcess(),
TOKEN_QUERY,
&processToken
);
if (!NT_SUCCESS(status)) {
goto Error;
}
//
// find out the size of token, allocate and requery to get info
//
status = NtQueryInformationToken(
processToken,
TokenUser,
NULL,
0,
&tokenUserSize
);
CL_ASSERT( status == STATUS_BUFFER_TOO_SMALL );
if ( status != STATUS_BUFFER_TOO_SMALL ) {
goto Error;
}
processTokenUser = (PTOKEN_USER) LocalAlloc( 0, tokenUserSize );
if (( processToken == NULL ) || ( processTokenUser == NULL )) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Error;
}
status = NtQueryInformationToken(
processToken,
TokenUser,
processTokenUser,
tokenUserSize,
&tokenUserSize
);
if (!NT_SUCCESS(status)) {
goto Error;
}
entry[1].Trustee.ptstrName = (PWCHAR)processTokenUser->User.Sid;
//
// grant access to this mess
//
hr = pAccessControl->GrantAccessRights(&access);
if( SUCCEEDED(hr))
{
hr = CoInitializeSecurity(pAccessControl,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_CONNECT,
RPC_C_IMP_LEVEL_IDENTIFY,
NULL,
EOAC_ACCESS_CONTROL,
NULL);
}
Error:
if(pAccessControl) {
pAccessControl->Release();
}
if (processTokenUser != NULL) {
LocalFree( processTokenUser );
}
if (processToken != NULL) {
NtClose(processToken);
}
return hr;
}
HRESULT
NmpInitializeConnectoidAdviseSink(
VOID
)
/*++
Routine Description:
Get an instance pointer to the conn mgr's connection point object and hook
up our advice sink so we can catch connectoid rename events
Arguments:
None
Return Value:
ERROR_SUCCESS if everything worked...
--*/
{
HRESULT hr = S_OK; // Not returned, but used for debugging
IConnectionPoint * pConPoint = NULL;
INetConnectionNotifySink * pSink = NULL;
PSECURITY_DESCRIPTOR sinkSD;
hr = NmpGrantAccessToNotifySink();
if ( SUCCEEDED( hr )) {
hr = HrGetNotifyConPoint(&pConPoint);
if (SUCCEEDED(hr)) {
// Create the notify sink
//
hr = CConnectionNotifySink::CreateInstance(
IID_INetConnectionNotifySink,
(LPVOID*)&pSink);
if (SUCCEEDED(hr)) {
CL_ASSERT(pSink);
hr = pConPoint->Advise(pSink, &AdviseCookie);
if ( !SUCCEEDED( hr )) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Couldn't initialize Net Connection Manager advise "
"sink, status %1!08X!\n",
hr);
}
pSink->Release();
} else {
hr = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Couldn't create sink instance, status %1!08X!\n",
hr);
}
pConPoint->Release();
}
} else {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] CoInitializeSecurity failed, status %1!08X!\n",
hr);
}
if ( FAILED( hr )) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Couldn't initialize Net Connection Manager advise "
"sink, status %1!08X!\n",
hr);
AdviseCookie = INVALID_COOKIE;
}
return hr;
} // NmpInitializeConnectoidAdviseSink
VOID
NmCloseConnectoidAdviseSink(
VOID
)
/*++
Routine Description:
close down the conn mgr event sink. this routine is public since it is
called prior to CoUninitialize in ClusterShutdown()
Arguments:
None
Return Value:
None
--*/
{
HRESULT hr = S_OK;
IConnectionPoint * pConPoint = NULL;
if ( AdviseCookie != INVALID_COOKIE ) {
hr = HrGetNotifyConPoint(&pConPoint);
if (SUCCEEDED(hr)) {
// Unadvise
//
hr = pConPoint->Unadvise(AdviseCookie);
AdviseCookie = INVALID_COOKIE;
pConPoint->Release();
}
if ( FAILED( hr )) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Couldn't close Net Connection Manager advise sink, status %1!08X!\n",
hr);
}
}
} // NmCloseConnectoidAdviseSink
VOID
ProcessNameChange(
GUID * GuidId,
LPCWSTR NewName
)
/*++
Routine Description:
wrapper that enums the net interfaces
Arguments:
GuidId - pointer to connectoid that changed
NewName - pointer to new name of connectoid
Return Value:
None
--*/
{
RPC_STATUS rpcStatus;
LPWSTR connectoidId = NULL;
CL_ASSERT(GuidId);
CL_ASSERT(NewName);
rpcStatus = UuidToString( (GUID *) GuidId, &connectoidId);
if ( rpcStatus == RPC_S_OK ) {
PNM_INTERFACE netInterface;
DWORD status;
PLIST_ENTRY entry;
ClRtlLogPrint(LOG_NOISE,
"[NM] Received notification that name for connectoid %1!ws! was changed "
"to '%2!ws!'\n",
connectoidId,
NewName);
NmpAcquireLock();
//
// enum the interfaces, looking for the connectoid GUID as the
// adapter ID
//
for (entry = NmpInterfaceList.Flink;
entry != &NmpInterfaceList;
entry = entry->Flink
)
{
netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, Linkage);
if ( lstrcmpiW( connectoidId , netInterface->AdapterId ) == 0 ) {
PNM_NETWORK network = netInterface->Network;
LPWSTR networkName = (LPWSTR) OmObjectName( network );
if ( lstrcmpW( networkName, NewName ) != 0 ) {
NM_NETWORK_INFO netInfo;
//
// For some reason, OmReferenceObject causes a compiler
// error here. Likely a header ordering problem. The
// function has been wrappered as a workaround.
//
NmpReferenceNetwork(network);
NmpReleaseLock();
netInfo.Id = (LPWSTR) OmObjectId( network );
netInfo.Name = (LPWSTR) NewName;
status = NmpSetNetworkName( &netInfo );
if ( status != ERROR_SUCCESS ) {
ClRtlLogPrint( LOG_UNUSUAL,
"[NM] Couldn't rename network '%1!ws!' to '%2!ws!', status %3!u!\n",
networkName,
NewName,
status
);
//If the error condition is due to the object
//already existing revert back to the old name.
if(status == ERROR_OBJECT_ALREADY_EXISTS) {
DWORD tempStatus = ERROR_SUCCESS;
INetConnection *connectoid;
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Reverting back network name to '%1!ws!', from '%2!ws!\n",
networkName,
NewName
);
connectoid = ClRtlFindConnectoidByGuid(connectoidId);
if(connectoid != NULL){
tempStatus = ClRtlSetConnectoidName(
connectoid,
networkName);
}
if((tempStatus != ERROR_SUCCESS) ||
(connectoid == NULL)) {
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Failed to set name of network connection"
"%1!ws!, status %2!u!\n",
networkName,
tempStatus);
}
}
}
NmpDereferenceNetwork(network);
}
else {
NmpReleaseLock();
}
break;
}
}
if ( entry == &NmpInterfaceList ) {
NmpReleaseLock();
ClRtlLogPrint(LOG_UNUSUAL,
"[NM] Couldn't find net interface for connectoid '%1!ws!'\n",
connectoidId
);
}
RpcStringFree( &connectoidId );
}
return;
} // ProcessNameChange
} // EXTERN_C