Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1311 lines
29 KiB

/*++
Copyright (c) 2001-2001 Microsoft Corporation
Module Name:
rpc.c
Abstract:
DNS Resolver Service
RPC intialization, shutdown and utility routines.
Author:
Jim Gilroy (jamesg) April 19, 2001
Revision History:
--*/
#include "local.h"
#include <rpc.h>
#include "rpcdce.h"
#include "secobj.h"
#undef UNICODE
//
// RPC globals
//
BOOL g_fRpcInitialized = FALSE;
DWORD g_RpcProtocol = RESOLVER_RPC_USE_LPC;
PSECURITY_DESCRIPTOR g_pRpcSecurityDescriptor;
#define AUTO_BIND
//
// Resolver access control
//
PSECURITY_DESCRIPTOR g_pAccessSecurityDescriptor = NULL;
PACL g_pAccessAcl = NULL;
PSID g_pAccessOwnerSid = NULL;
GENERIC_MAPPING g_AccessGenericMapping =
{
RESOLVER_GENERIC_READ,
RESOLVER_GENERIC_WRITE,
RESOLVER_GENERIC_EXECUTE,
RESOLVER_GENERIC_ALL
};
#define SECURITY_LOCK() EnterCriticalSection( &CacheCS )
#define SECURITY_UNLOCK() LeaveCriticalSection( &CacheCS )
//
// Privileges
//
#if 0
#define RESOLVER_PRIV_READ 1
#define RESOLVER_PRIV_ENUM 2
#define RESOLVER_PRIV_FLUSH 3
#define RESOLVER_PRIV_REGISTER 4
#endif
DNS_STATUS
Rpc_InitAccessChecking(
VOID
);
VOID
Rpc_CleanupAccessChecking(
VOID
);
BOOL
Rpc_IsProtoLpcA(
IN PVOID pContext
)
/*++
Routine Description:
Check if access if over LPC
Arguments:
pContext -- client RPC context
Return Value:
TRUE if protocol is LPC
FALSE otherwise
--*/
{
DNS_STATUS status;
BOOL fisLpc = FALSE;
PSTR pbinding = NULL;
PSTR pprotoString = NULL;
DNSDBG( RPC, (
"Rpc_IsAccessOverLpc( context=%p )\n",
pContext ));
//
// get string binding
//
status = RpcBindingToStringBindingA(
pContext,
& pbinding );
if ( status != NO_ERROR )
{
goto Cleanup;
}
//
// get protocol as string
//
status = RpcStringBindingParseA(
pbinding,
NULL,
& pprotoString,
NULL,
NULL,
NULL );
if ( status != NO_ERROR )
{
goto Cleanup;
}
//
// check for LPC
//
fisLpc = ( _stricmp( pprotoString, "ncalrpc" ) == 0 );
RpcStringFreeA( &pprotoString );
Cleanup:
if ( pbinding )
{
RpcStringFreeA( &pbinding );
}
return( fisLpc );
}
BOOL
Rpc_IsProtoLpc(
IN PVOID pContext
)
/*++
Routine Description:
Check if access if over LPC
Arguments:
pContext -- client RPC context
Return Value:
TRUE if protocol is LPC
FALSE otherwise
--*/
{
DNS_STATUS status;
BOOL fisLpc = FALSE;
PWSTR pbinding = NULL;
PWSTR pprotoString = NULL;
DNSDBG( RPC, (
"Rpc_IsAccessOverLpc( context=%p )\n",
pContext ));
//
// get string binding
//
status = RpcBindingToStringBinding(
pContext,
& pbinding );
if ( status != NO_ERROR )
{
goto Cleanup;
}
//
// get protocol as string
//
status = RpcStringBindingParse(
pbinding,
NULL,
& pprotoString,
NULL,
NULL,
NULL );
if ( status != NO_ERROR )
{
goto Cleanup;
}
//
// check for LPC
//
fisLpc = ( _wcsicmp( pprotoString, L"ncalrpc" ) == 0 );
RpcStringFree( &pprotoString );
Cleanup:
if ( pbinding )
{
RpcStringFree( &pbinding );
}
return( fisLpc );
}
RPC_STATUS
RPC_ENTRY
Rpc_SecurityCallback(
IN RPC_IF_HANDLE IfHandle,
IN PVOID pContext
)
/*++
Routine Description:
RPC callback security check.
Arguments:
IfHandle -- interface handle
pContext -- client RPC context
Return Value:
NO_ERROR if security check allows access.
ErrorCode on security failure.
--*/
{
DNSDBG( RPC, (
"Rpc_SecurityCallback( context=%p )\n",
pContext ));
//
// check if connection over LPC
//
if ( !Rpc_IsProtoLpc(pContext) )
{
return ERROR_ACCESS_DENIED;
}
return NO_ERROR;
}
DNS_STATUS
Rpc_Initialize(
VOID
)
/*++
Routine Description:
Initialize server side RPC.
Arguments:
None.
Return Value:
ERROR_SUCCESS if successful.
Error status on failure.
--*/
{
RPC_STATUS status;
BOOL fusingTcpip = FALSE;
DNSDBG( RPC, (
"Rpc_Initialize()\n"
"\tIF handle = %p\n"
"\tprotocol = %d\n",
DnsResolver_ServerIfHandle,
g_RpcProtocol
));
//
// RPC disabled?
//
if ( ! g_RpcProtocol )
{
g_RpcProtocol = RESOLVER_RPC_USE_LPC;
}
#if 0
//
// Create security for RPC API
//
status = NetpCreateWellKnownSids( NULL );
if ( status != ERROR_SUCCESS )
{
DNS_PRINT(( "ERROR: Creating well known SIDs.\n" ));
return( status );
}
status = RpcUtil_CreateSecurityObjects();
if ( status != ERROR_SUCCESS )
{
DNS_PRINT(( "ERROR: Creating DNS security object.\n" ));
return( status );
}
#endif
//
// build security descriptor
//
// NULL security descriptor gives some sort of default security
// on the interface
// - owner is this service (currently "Network Service")
// - read access for everyone
//
// note: if roll your own, remember to avoid NULL DACL, this
// puts NO security on interface including the right to
// change security, so any app can hijack the ACL and
// deny access to folks; the default SD==NULL security
// doesn't give everyone WRITE_DACL
//
g_pRpcSecurityDescriptor = NULL;
//
// RPC over LPC
//
if( g_RpcProtocol & RESOLVER_RPC_USE_LPC )
{
status = RpcServerUseProtseqEpW(
L"ncalrpc", // protocol string.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // maximum concurrent calls
RESOLVER_RPC_LPC_ENDPOINT_W, // endpoint
g_pRpcSecurityDescriptor // security
);
// duplicate endpoint is ok
if ( status == RPC_S_DUPLICATE_ENDPOINT )
{
status = RPC_S_OK;
}
if ( status != RPC_S_OK )
{
DNSDBG( INIT, (
"ERROR: RpcServerUseProtseqEp() for LPC failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return( status );
}
}
#if 0 // use use LPC interface
//
// RCP over TCP/IP
//
if( g_RpcProtocol & RESOLVER_RPC_USE_TCPIP )
{
#ifdef AUTO_BIND
RPC_BINDING_VECTOR * bindingVector;
status = RpcServerUseProtseqW(
L"ncacn_ip_tcp", // protocol string.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // max concurrent calls
g_pRpcSecurityDescriptor
);
if ( status != RPC_S_OK )
{
DNSDBG( INIT, (
"ERROR: RpcServerUseProtseq() for TCP/IP failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return( status );
}
status = RpcServerInqBindings( &bindingVector );
if ( status != RPC_S_OK )
{
DNSDBG( INIT, (
"ERROR: RpcServerInqBindings failed.\n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return( status );
}
//
// register interface(s)
// since only one DNS server on a host can use
// RpcEpRegister() rather than RpcEpRegisterNoReplace()
//
status = RpcEpRegisterW(
DnsResolver_ServerIfHandle,
bindingVector,
NULL,
L"" );
if ( status != RPC_S_OK )
{
DNSDBG( ANY, (
"ERROR: RpcEpRegisterNoReplace() failed.\n"
"\tstatus = %d %p.\n",
status, status ));
return( status );
}
//
// free binding vector
//
status = RpcBindingVectorFree( &bindingVector );
ASSERT( status == RPC_S_OK );
status = RPC_S_OK;
#else // not AUTO_BIND
status = RpcServerUseProtseqEpW(
L"ncacn_ip_tcp", // protocol string.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // maximum concurrent calls
RESOLVER_RPC_SERVER_PORT_W, // endpoint
g_pRpcSecurityDescriptor // security
);
if ( status != RPC_S_OK )
{
DNSDBG( ANY, (
"ERROR: RpcServerUseProtseqEp() for TCP/IP failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return( status );
}
#endif // AUTO_BIND
fusingTcpip = TRUE;
}
//
// RPC over named pipes
//
if ( g_RpcProtocol & RESOLVER_RPC_USE_NAMED_PIPE )
{
status = RpcServerUseProtseqEpW(
L"ncacn_np", // protocol string.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // maximum concurrent calls
RESOLVER_RPC_PIPE_NAME_W, // endpoint
g_pRpcSecurityDescriptor
);
// duplicate endpoint is ok
if ( status == RPC_S_DUPLICATE_ENDPOINT )
{
status = RPC_S_OK;
}
if ( status != RPC_S_OK )
{
DNSDBG( INIT, (
"ERROR: RpcServerUseProtseqEp() for named pipe failed.]n"
"\tstatus = %d 0x%08lx.\n",
status,
status ));
return( status );
}
}
#endif // only LPC interface
//
// register DNS RPC interface(s)
//
status = RpcServerRegisterIfEx(
DnsResolver_ServerIfHandle,
NULL,
NULL,
0,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
Rpc_SecurityCallback
);
if ( status != RPC_S_OK )
{
DNSDBG( INIT, (
"ERROR: RpcServerRegisterIfEx() failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return(status);
}
#if 0
//
// for TCP/IP setup authentication
//
if ( fuseTcpip )
{
status = RpcServerRegisterAuthInfoW(
RESOLVER_RPC_SECURITY_W, // app name to security provider.
RESOLVER_RPC_SECURITY_AUTH_ID, // Auth package ID.
NULL, // Encryption function handle.
NULL ); // argment pointer to Encrypt function.
if ( status != RPC_S_OK )
{
DNSDBG( INIT, (
"ERROR: RpcServerRegisterAuthInfo() failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return( status );
}
}
#endif
//
// Listen on RPC
//
status = RpcServerListen(
1, // min threads
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // max concurrent calls
TRUE ); // return on completion
if ( status != RPC_S_OK )
{
if ( status != RPC_S_ALREADY_LISTENING )
{
DNS_PRINT((
"ERROR: RpcServerListen() failed\n"
"\tstatus = %d 0x%p\n",
status, status ));
return( status );
}
status = NO_ERROR;
}
g_fRpcInitialized = TRUE;
return( status );
} // Rpc_Initialize
VOID
Rpc_Shutdown(
VOID
)
/*++
Routine Description:
Shutdown RPC on the server.
Arguments:
None.
Return Value:
None.
--*/
{
DWORD status;
RPC_BINDING_VECTOR * bindingVector = NULL;
DNSDBG( RPC, ( "Rpc_Shutdown().\n" ));
if( ! g_fRpcInitialized )
{
DNSDBG( RPC, (
"RPC not active, no shutdown necessary.\n" ));
return;
}
#if 0
// can not stop server as another service may share this process
//
// stop server listen
// then wait for all RPC threads to go away
//
status = RpcMgmtStopServerListening(
NULL // this app
);
if ( status == RPC_S_OK )
{
status = RpcMgmtWaitServerListen();
}
#endif
//
// unbind / unregister endpoints
//
status = RpcServerInqBindings( &bindingVector );
ASSERT( status == RPC_S_OK );
if ( status == RPC_S_OK )
{
status = RpcEpUnregister(
DnsResolver_ServerIfHandle,
bindingVector,
NULL ); // Uuid vector.
if ( status != RPC_S_OK )
{
DNSDBG( ANY, (
"ERROR: RpcEpUnregister, status = %d.\n", status ));
}
}
//
// free binding vector
//
if ( bindingVector )
{
status = RpcBindingVectorFree( &bindingVector );
ASSERT( status == RPC_S_OK );
}
//
// wait for all calls to complete
//
status = RpcServerUnregisterIf(
DnsResolver_ServerIfHandle,
0,
TRUE );
ASSERT( status == ERROR_SUCCESS );
g_fRpcInitialized = FALSE;
//
// dump resolver access checking security structs
//
Rpc_CleanupAccessChecking();
DNSDBG( RPC, (
"RPC shutdown completed.\n" ));
}
//
// RPC access control
//
// The RPC interface, by design, must be open to basically every
// process for query. So the RPC interface itself uses just
// default security (above).
//
// To get more detailed call-by-call access checking for special
// operations -- enum, flush, cluster registrations -- we need
// separate access checking.
//
DNS_STATUS
Rpc_InitAccessChecking(
VOID
)
/*++
Routine Description:
Initialize resolver security.
Arguments:
None
Return Value:
NO_ERROR if successful.
ErrorCode on failure.
--*/
{
PSECURITY_DESCRIPTOR psd = NULL;
SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
PACL pacl = NULL;
PSID psidAdmin = NULL;
PSID psidPowerUser = NULL;
PSID psidLocalService = NULL;
PSID psidNetworkService = NULL;
PSID psidNetworkConfigOps = NULL;
DWORD lengthAcl;
DNS_STATUS status = NO_ERROR;
BOOL bresult;
DNSDBG( INIT, ( "Rpc_InitAccessChecking()\n" ));
//
// check if already have SD
//
// explicitly "create once" semantics; once
// created SD is read-only and not destroyed until
// shutdown
//
if ( g_pAccessSecurityDescriptor )
{
return NO_ERROR;
}
// lock and retest
SECURITY_LOCK();
if ( g_pAccessSecurityDescriptor )
{
status = NO_ERROR;
goto Unlock;
}
//
// build SIDs that will be allowed access
//
bresult = AllocateAndInitializeSid(
&authority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
& psidAdmin
);
bresult = bresult &&
AllocateAndInitializeSid(
&authority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_POWER_USERS,
0, 0, 0, 0, 0, 0,
& psidPowerUser
);
bresult = bresult &&
AllocateAndInitializeSid(
&authority,
1,
SECURITY_LOCAL_SERVICE_RID,
0,
0, 0, 0, 0, 0, 0,
&psidLocalService
);
bresult = bresult &&
AllocateAndInitializeSid(
&authority,
1,
SECURITY_NETWORK_SERVICE_RID,
0,
0, 0, 0, 0, 0, 0,
&psidNetworkService
);
bresult = bresult &&
AllocateAndInitializeSid(
&authority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS,
0, 0, 0, 0, 0, 0,
&psidNetworkConfigOps
);
if ( !bresult )
{
status = GetLastError();
if ( status == NO_ERROR )
{
status = DNS_ERROR_NO_MEMORY;
}
DNSDBG( ANY, (
"Failed building resolver ACEs!\n" ));
goto Cleanup;
}
//
// allocate ACL
//
lengthAcl = ( (ULONG)sizeof(ACL)
+ 5*((ULONG)sizeof(ACCESS_ALLOWED_ACE) - (ULONG)sizeof(ULONG)) +
+ GetLengthSid( psidAdmin )
+ GetLengthSid( psidPowerUser )
+ GetLengthSid( psidLocalService )
+ GetLengthSid( psidNetworkService )
+ GetLengthSid( psidNetworkConfigOps ) );
pacl = GENERAL_HEAP_ALLOC( lengthAcl );
if ( !pacl )
{
status = GetLastError();
goto Cleanup;
}
bresult = InitializeAcl( pacl, lengthAcl, ACL_REVISION2 );
//
// init ACLs
//
// - default to generic READ\WRITE
// - local service GENERIC_ALL to include registration
// - admin gets GENERIC_ALL on debug to test registration
//
// DCR: GENERIC_ALL on admin subject to test flag
//
// note: the masks for the individual SIDs need not be
// GENERIC bits, they can be made completely with
// with individual bits or mixed\matched with GENERIC
// bits as desired
//
bresult = bresult &&
AddAccessAllowedAce(
pacl,
ACL_REVISION2,
GENERIC_ALL,
psidLocalService );
bresult = bresult &&
AddAccessAllowedAce(
pacl,
ACL_REVISION2,
#ifdef DBG
GENERIC_ALL,
#else
GENERIC_READ | GENERIC_WRITE,
#endif
psidAdmin );
bresult = bresult &&
AddAccessAllowedAce(
pacl,
ACL_REVISION2,
GENERIC_READ | GENERIC_WRITE,
psidPowerUser );
bresult = bresult &&
AddAccessAllowedAce(
pacl,
ACL_REVISION2,
GENERIC_READ | GENERIC_WRITE,
psidNetworkService );
bresult = bresult &&
AddAccessAllowedAce(
pacl,
ACL_REVISION2,
GENERIC_READ | GENERIC_WRITE,
psidNetworkConfigOps );
if ( !bresult )
{
status = GetLastError();
DNSDBG( ANY, (
"Failed building resolver ACEs!\n" ));
goto Cleanup;
}
//
// allocate security descriptor
// then init with ACL
//
psd = GENERAL_HEAP_ALLOC( SECURITY_DESCRIPTOR_MIN_LENGTH );
if ( !psd )
{
status = DNS_ERROR_NO_MEMORY;
goto Cleanup;
}
bresult = InitializeSecurityDescriptor(
psd,
SECURITY_DESCRIPTOR_REVISION );
bresult = bresult &&
SetSecurityDescriptorDacl(
psd,
TRUE, // have DACL
pacl, // DACL
FALSE // DACL not defaulted, explicit
);
// security folks indicate need owner to do AccessCheck
bresult = bresult &&
SetSecurityDescriptorOwner(
psd,
psidNetworkService,
FALSE // owner not defaulted, explicit
);
#if 0
// adding group seemed to make it worse
bresult = bresult &&
SetSecurityDescriptorGroup(
psd,
psidNetworkService,
FALSE // group not defaulted, explicit
);
#endif
if ( !bresult )
{
status = GetLastError();
DNSDBG( ANY, (
"Failed setting security descriptor!\n" ));
goto Cleanup;
}
Cleanup:
if ( psidAdmin )
{
FreeSid( psidAdmin );
}
if ( psidPowerUser )
{
FreeSid( psidPowerUser );
}
if ( psidLocalService )
{
FreeSid( psidLocalService );
}
if ( psidNetworkConfigOps )
{
FreeSid( psidNetworkConfigOps );
}
// validate SD
if ( status == NO_ERROR )
{
if ( psd &&
IsValidSecurityDescriptor(psd) )
{
g_pAccessSecurityDescriptor = psd;
g_pAccessAcl = pacl;
g_pAccessOwnerSid = psidNetworkService;
goto Unlock;
}
status = GetLastError();
DNSDBG( RPC, (
"Invalid security descriptor\n",
status ));
ASSERT( FALSE );
}
// failed
if ( status == NO_ERROR )
{
status = DNS_ERROR_NO_MEMORY;
}
GENERAL_HEAP_FREE( psd );
GENERAL_HEAP_FREE( pacl );
if ( psidNetworkService )
{
FreeSid( psidNetworkService );
}
Unlock:
SECURITY_UNLOCK();
DNSDBG( INIT, (
"Leave Rpc_InitAccessChecking() = %d\n",
status ));
return( status );
}
VOID
Rpc_CleanupAccessChecking(
VOID
)
/*++
Routine Description:
Cleanup resolver security allocations for shutdown.
Arguments:
None
Return Value:
None
--*/
{
GENERAL_HEAP_FREE( g_pAccessSecurityDescriptor );
GENERAL_HEAP_FREE( g_pAccessAcl );
if ( g_pAccessOwnerSid )
{
FreeSid( g_pAccessOwnerSid );
g_pAccessOwnerSid = NULL;
}
g_pAccessSecurityDescriptor = NULL;
g_pAccessAcl = NULL;
}
BOOL
Rpc_AccessCheck(
IN DWORD DesiredAccess
)
/*++
Routine Description:
Access check on resolver operations.
Note, we do NOT do this on common operations -- query.
This is pointless and way too expensive. We only protect
Arguments:
DesiredAccess -- access desired
Return Value:
None
--*/
{
DNS_STATUS status;
BOOL bstatus;
HANDLE hthread = NULL;
HANDLE htoken = NULL;
BOOL fimpersonating = FALSE;
DWORD desiredAccess = DesiredAccess;
PRIVILEGE_SET privilegeSet;
DWORD grantedAccess;
DWORD privilegeSetLength;
DNSDBG( RPC, (
"Rpc_AccessCheck( priv=%08x )\n",
DesiredAccess ));
//
// create security descriptor if not created yet
//
if ( !g_pAccessSecurityDescriptor )
{
status = Rpc_InitAccessChecking();
if ( status != NO_ERROR )
{
goto Failed;
}
DNS_ASSERT( g_pAccessSecurityDescriptor );
}
if ( !IsValidSecurityDescriptor( g_pAccessSecurityDescriptor ) )
{
status = GetLastError();
DNSDBG( RPC, (
"ERROR Invalid access check SD %p => %u\n",
g_pAccessSecurityDescriptor,
status ));
goto Failed;
}
//
// impersonate and test access against mapping
//
status = RpcImpersonateClient( 0 );
if ( status != NO_ERROR )
{
DNSDBG( RPC, (
"ERROR <%u>: failed RpcImpersonateClient()\n",
status ));
DNS_ASSERT( FALSE );
goto Failed;
}
fimpersonating = TRUE;
//
// get thread token
//
hthread = GetCurrentThread();
if ( !hthread )
{
goto Failed;
}
bstatus = OpenThreadToken(
hthread,
TOKEN_QUERY,
TRUE,
&htoken );
if ( !bstatus )
{
status = GetLastError();
DNSDBG( RPC, (
"\nERROR <%lu>: failed to open thread token!\n",
status ));
ASSERT( FALSE );
goto Failed;
}
//
// map generic bits
// - we should NOT be called with generic bits
// only bits for specific resolver operations
//
if ( (desiredAccess & SPECIFIC_RIGHTS_ALL) != desiredAccess )
{
DNS_ASSERT( FALSE );
DNSDBG( RPC, (
"desiredAccess before MapGenericMask() = %p\n",
desiredAccess ));
MapGenericMask(
& desiredAccess,
& g_AccessGenericMapping );
DNSDBG( RPC, (
"desiredAccess after MapGenericMask() = %p\n",
desiredAccess ));
}
//
// do access check
//
privilegeSetLength = sizeof(privilegeSet);
if ( ! AccessCheck(
g_pAccessSecurityDescriptor,
htoken,
desiredAccess,
& g_AccessGenericMapping,
& privilegeSet,
& privilegeSetLength,
& grantedAccess,
& bstatus ) )
{
status = GetLastError();
DNSDBG( RPC, (
"AccessCheck() Failed => %u\n"
"\tsec descp = %p\n"
"\thtoken = %p\n"
"\tdesired access = %08x\n"
"\tgeneric mapping = %p\n"
"\tpriv set ptr = %p\n"
"\tpriv set length = %p\n"
"\tgranted ptr = %p\n"
"\tbstatus ptr = %p\n",
status,
g_pAccessSecurityDescriptor,
htoken,
desiredAccess,
& g_AccessGenericMapping,
& privilegeSet,
& privilegeSetLength,
& grantedAccess,
& bstatus ));
goto Failed;
}
//
// access check successful
// - access is either granted or denied
if ( bstatus )
{
DNSDBG( RPC, (
"RPC Client GRANTED access (%08x) by AccessCheck\n",
DesiredAccess ));
goto Cleanup;
}
else
{
DNSDBG( RPC, (
"Warning: Client DENIED by AccessCheck\n"
"\trequested access = %08x\n",
desiredAccess ));
goto Cleanup;
}
Failed:
//
// failure to do access check
//
// note again: NOT ACCESS_DENIED, but failure to be able to complete
// the test
//
// note: since we aren't in general protecting anything interesting,
// the we grant most access on failure --as admins may want the info
// for diagnostic purposes, the current lone exception is cluster
// registrations
//
// privilege:
// - enum => allow access
// - flush => allow access
// - cluster registration => deny access
//
DNSDBG( ANY, (
"ERROR: Failed to execute RPC access check status = %d\n",
status ));
#if 0
// DCR: FIX: can't screen REGISTER until AccessCheck() works
bstatus = !( desiredAccess & RESOLVER_ACCESS_REGISTER );
#else
bstatus = TRUE;
#endif
Cleanup:
if ( htoken )
{
CloseHandle( htoken );
}
if ( hthread )
{
CloseHandle( hthread );
}
if ( fimpersonating )
{
RpcRevertToSelf();
}
return( bstatus );
}
//
// End rpc.c
//