/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: Abstract: History: --*/ #include "precomp.h" #include #include #include #include #include "rpcrecv.h" #include "rpcmsg.h" #include "rpchdr.h" #include "rpcctx.h" extern HRESULT RpcResToWmiRes( RPC_STATUS stat, HRESULT hrDefault ); IWmiMessageSendReceive* g_pRcv = NULL; PSECURITY_DESCRIPTOR g_pSD = NULL; RPC_STATUS RPC_ENTRY RpcAuthCallback( RPC_IF_HANDLE Interface, void *Context ) { RPC_STATUS stat; _DBG_ASSERT( g_pSD != NULL ); stat = RpcImpersonateClient( Context ); if ( stat == RPC_S_OK ) { HANDLE hToken; if( OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken ) ) { GENERIC_MAPPING map; ZeroMemory( &map, sizeof(GENERIC_MAPPING) ); PRIVILEGE_SET ps; DWORD dwPrivLength = sizeof(ps); BOOL bStatus; DWORD dwGranted; if ( ::AccessCheck( g_pSD, hToken, 1, &map, &ps, &dwPrivLength, &dwGranted, &bStatus ) ) { stat = bStatus ? RPC_S_OK : RPC_S_ACCESS_DENIED; } else { stat = RPC_S_ACCESS_DENIED; } CloseHandle( hToken ); } else { stat = RPC_S_ACCESS_DENIED; } RpcRevertToSelf(); } return stat; } long RcvrSendReceive( RPC_BINDING_HANDLE hClient, PBYTE pData, ULONG cData, PBYTE pAuxData, ULONG cAuxData ) { HRESULT hr; ENTER_API_CALL CBuffer HdrStrm( pAuxData, cAuxData, FALSE ); CMsgRpcHdr Hdr; hr = Hdr.Unpersist( HdrStrm ); if ( FAILED(hr) ) { return hr; } PBYTE pUserAuxData = HdrStrm.GetRawData() + HdrStrm.GetIndex(); CMsgRpcRcvrCtx Ctx( &Hdr, hClient ); hr = g_pRcv->SendReceive( pData, cData, pUserAuxData, Hdr.GetAuxDataLength(), 0, &Ctx ); EXIT_API_CALL return hr; } HRESULT CreateAuthOnlySecurityDescriptor( PSECURITY_DESCRIPTOR* ppSD ) { HRESULT hr; // // obtain the sid from the process token to use for owner and // group fields of SD. // HANDLE hProcessToken; if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hProcessToken )) { return HRESULT_FROM_WIN32( GetLastError() ); } CCloseMe cm( hProcessToken ); DWORD dwSize; GetTokenInformation( hProcessToken, TokenOwner, NULL, 0, &dwSize ); if ( GetLastError() != ERROR_MORE_DATA && GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { return HRESULT_FROM_WIN32( GetLastError() ); } TOKEN_OWNER* pOwner = (TOKEN_OWNER*) new BYTE[dwSize]; if ( pOwner == NULL ) { return WBEM_E_OUT_OF_MEMORY; } CVectorDeleteMe vdm( (BYTE*)pOwner ); if ( !GetTokenInformation( hProcessToken, TokenOwner, (BYTE*)pOwner, dwSize, &dwSize ) ) { return HRESULT_FROM_WIN32( GetLastError() ); } // // create a DACL that allows only authenticated users access. // SID AuthenticatedUsers; SID_IDENTIFIER_AUTHORITY idAuth = SECURITY_NT_AUTHORITY; InitializeSid( &AuthenticatedUsers, &idAuth, 1 ); PDWORD pdwSubAuth = GetSidSubAuthority( &AuthenticatedUsers, 0 ); *pdwSubAuth = SECURITY_AUTHENTICATED_USER_RID; _DBG_ASSERT( IsValidSid( &AuthenticatedUsers ) ); dwSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - 4 + GetLengthSid(&AuthenticatedUsers); PACL pAuthOnlyAcl = (PACL) new BYTE[dwSize]; if ( pAuthOnlyAcl == NULL ) { return WBEM_E_OUT_OF_MEMORY; } CVectorDeleteMe vdm2( (BYTE*)pAuthOnlyAcl ); InitializeAcl( pAuthOnlyAcl, dwSize, ACL_REVISION ); AddAccessAllowedAce( pAuthOnlyAcl, ACL_REVISION, 1, &AuthenticatedUsers ); // // create and initialize SD // SECURITY_DESCRIPTOR AuthOnlySD; InitializeSecurityDescriptor( &AuthOnlySD, SECURITY_DESCRIPTOR_REVISION ); SetSecurityDescriptorOwner( &AuthOnlySD, pOwner->Owner, TRUE ); SetSecurityDescriptorGroup( &AuthOnlySD, pOwner->Owner, TRUE ); SetSecurityDescriptorDacl( &AuthOnlySD, TRUE, pAuthOnlyAcl, FALSE ); dwSize = 0; MakeSelfRelativeSD( &AuthOnlySD, NULL, &dwSize ); if ( GetLastError() != ERROR_MORE_DATA && GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { return HRESULT_FROM_WIN32( GetLastError() ); } *ppSD = new BYTE[dwSize]; if ( *ppSD == NULL ) { return WBEM_E_OUT_OF_MEMORY; } if ( !MakeSelfRelativeSD( &AuthOnlySD, *ppSD, &dwSize ) ) { delete [] *ppSD; *ppSD = NULL; return HRESULT_FROM_WIN32( GetLastError() ); } return WBEM_S_NO_ERROR; } // // for now only one rpc receiver can be registered for the process. later // make the global state be the instance state for CMsgRpcReceiver. // STDMETHODIMP CMsgRpcReceiver::Open( LPCWSTR wszBinding, DWORD dwFlags, WMIMSG_RCVR_AUTH_INFOP pAuthInfo, IWmiMessageSendReceive* pRcv ) { HRESULT hr; RPC_STATUS stat; hr = Close(); if ( FAILED(hr) ) { return hr; } // // first parse the binding string. // LPWSTR wszProtSeq, wszEndpoint; stat = RpcStringBindingParse( (LPWSTR)wszBinding, NULL, &wszProtSeq, NULL, &wszEndpoint, NULL ); if ( stat != RPC_S_OK ) { return RpcResToWmiRes( stat, S_OK ); } // // init the protocol sequence // if ( *wszEndpoint == '\0' ) { stat = RpcServerUseProtseq( wszProtSeq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, NULL ); if ( stat == RPC_S_OK ) { RPC_BINDING_VECTOR* pBindingVector; stat = RpcServerInqBindings( &pBindingVector ); if ( stat == RPC_S_OK ) { stat = RpcEpRegisterNoReplace( RcvrIWmiMessageRemoteSendReceive_v1_0_s_ifspec, pBindingVector, NULL, NULL ); RpcBindingVectorFree( &pBindingVector ); } } } else { stat = RpcServerUseProtseqEp( wszProtSeq, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, wszEndpoint, NULL ); } RpcStringFree( &wszProtSeq ); RpcStringFree( &wszEndpoint ); if ( stat != RPC_S_OK ) { return RpcResToWmiRes( stat, S_OK ); } // // enable negotiate authentication service ( negotiates between NTLM // and kerberos ) // if ( pAuthInfo != NULL ) { for( int i=0; i < pAuthInfo->cwszPrincipal; i++ ) { stat = RpcServerRegisterAuthInfo( (LPWSTR)pAuthInfo->awszPrincipal[i], RPC_C_AUTHN_GSS_NEGOTIATE, NULL, NULL ); if ( stat != RPC_S_OK ) { return RpcResToWmiRes( stat, S_OK ); } } } else { LPWSTR wszPrincipal; stat = RpcServerInqDefaultPrincName( RPC_C_AUTHN_GSS_NEGOTIATE, &wszPrincipal ); if ( stat != RPC_S_OK ) { return RpcResToWmiRes( stat, S_OK ); } stat = RpcServerRegisterAuthInfo( wszPrincipal, RPC_C_AUTHN_GSS_NEGOTIATE, NULL, NULL ); RpcStringFree( &wszPrincipal ); if ( stat != RPC_S_OK ) { return RpcResToWmiRes( stat, S_OK ); } } RPC_IF_CALLBACK_FN* pAuthCallback = NULL; if ( dwFlags & WMIMSG_FLAG_RCVR_SECURE_ONLY ) { PSECURITY_DESCRIPTOR pAuthOnlySD; hr = CreateAuthOnlySecurityDescriptor( &pAuthOnlySD ); if ( FAILED(hr) ) { return hr; } _DBG_ASSERT( g_pSD == NULL ); g_pSD = pAuthOnlySD; pAuthCallback = RpcAuthCallback; } // // register the interface // DWORD dwRpcFlags = RPC_IF_AUTOLISTEN; stat = RpcServerRegisterIfEx( RcvrIWmiMessageRemoteSendReceive_v1_0_s_ifspec, NULL, NULL, dwRpcFlags, RPC_C_LISTEN_MAX_CALLS_DEFAULT, pAuthCallback ); if ( stat != RPC_S_OK ) { return RpcResToWmiRes( stat, S_OK ); } _DBG_ASSERT( g_pRcv == NULL ); pRcv->AddRef(); g_pRcv = pRcv; return WBEM_S_NO_ERROR; } STDMETHODIMP CMsgRpcReceiver::Close() { RPC_STATUS stat; stat = RpcServerUnregisterIf( RcvrIWmiMessageRemoteSendReceive_v1_0_s_ifspec, NULL, 0 ); RPC_BINDING_VECTOR* pBindingVector; stat = RpcServerInqBindings( &pBindingVector ); if ( stat == RPC_S_OK ) { stat = RpcEpUnregister( RcvrIWmiMessageRemoteSendReceive_v1_0_s_ifspec, pBindingVector, NULL ); RpcBindingVectorFree( &pBindingVector ); } if ( g_pRcv != NULL ) { g_pRcv->Release(); g_pRcv = NULL; } if ( g_pSD != NULL ) { delete [] g_pSD; g_pSD = NULL; } return WBEM_S_NO_ERROR; }