windows-nt/Source/XPSP1/NT/ds/dns/server/server/rpc.c
2020-09-26 16:20:57 +08:00

1363 lines
30 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1995-1999 Microsoft Corporation
Module Name:
rpc.c
Abstract:
Domain Name System (DNS) Server
RPC intialization, shutdown and utility routines.
Actual RPC callable routines are in the modules for their functional
area.
Author:
Jim Gilroy (jamesg) September, 1995
Revision History:
--*/
#include <rpc.h>
#include "dnssrv.h"
#include "rpcdce.h"
#include "secobj.h"
#include "sdutl.h"
#undef UNICODE
//
// RPC globals
//
BOOL g_bRpcInitialized = FALSE;
PSECURITY_DESCRIPTOR g_pRpcSecurityDescriptor;
#define AUTO_BIND
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 buseTcpip = FALSE;
BOOL bstatus;
DWORD len;
DNS_DEBUG( RPC, (
"Rpc_Initialize( %p ).\n",
SrvCfg_dwRpcProtocol ));
//
// RPC disabled?
//
if ( ! SrvCfg_dwRpcProtocol )
{
DNS_PRINT(( "RPC disabled -- running without RPC.\n" ));
return( ERROR_SUCCESS );
}
#if 0
//
// no RPC if test application
//
if ( fServiceStartedFromConsole )
{
return( ERROR_SUCCESS );
}
#endif
//
// 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" ));
#if !DBG
return( status ); // DBG - allow to continue
#endif
}
//
// build security descriptor
//
// security is
// - owner LocalSystem
// - read access for Everyone
//
g_pRpcSecurityDescriptor = NULL;
//
// RCP over TCP/IP
//
if( SrvCfg_dwRpcProtocol & DNS_RPC_USE_TCPIP )
{
#ifdef AUTO_BIND
RPC_BINDING_VECTOR * bindingVector;
status = RpcServerUseProtseqA(
"ncacn_ip_tcp", // protocol string.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // max concurrent calls
g_pRpcSecurityDescriptor
//NULL // security (see #301918)
);
if ( status != RPC_S_OK )
{
DNS_DEBUG( 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 )
{
DNS_DEBUG( 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 = RpcEpRegisterA(
DnsServer_ServerIfHandle,
bindingVector,
NULL,
"" );
if ( status != RPC_S_OK )
{
DNS_DEBUG( INIT, (
"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 = RpcServerUseProtseqEpA(
"ncacn_ip_tcp", // protocol string.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // maximum concurrent calls
DNS_RPC_SERVER_PORT_A, // endpoint
g_pRpcSecurityDescriptor ); // security
if ( status != RPC_S_OK )
{
DNS_DEBUG( INIT, (
"ERROR: RpcServerUseProtseqEp() for TCP/IP failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return( status );
}
#endif // AUTO_BIND
buseTcpip = TRUE;
}
//
// RPC over named pipes
//
// Named pipes RPC has a bug, don't use security descriptor with NULL DACL
// Just send NULL.
//
if ( SrvCfg_dwRpcProtocol & DNS_RPC_USE_NAMED_PIPE )
{
status = RpcServerUseProtseqEpA(
"ncacn_np", // protocol string.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // maximum concurrent calls
DNS_RPC_NAMED_PIPE_A, // endpoint
g_pRpcSecurityDescriptor
// NULL // security
);
// duplicate endpoint is ok
if ( status == RPC_S_DUPLICATE_ENDPOINT )
{
status = RPC_S_OK;
}
if ( status != RPC_S_OK )
{
DNS_DEBUG( INIT, (
"ERROR: RpcServerUseProtseqEp() for named pipe failed.]n"
"\tstatus = %d 0x%08lx.\n",
status,
status ));
return( status );
}
}
//
// RPC over LPC
//
// Need LPC
//
// 1. performance.
// 2. due to a bug in the security checking when rpc is made from
// one local system process to another local system process using
// other protocols.
//
if( SrvCfg_dwRpcProtocol & DNS_RPC_USE_LPC )
{
status = RpcServerUseProtseqEpA(
"ncalrpc", // protocol string.
RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // maximum concurrent calls
DNS_RPC_LPC_EP_A, // endpoint
g_pRpcSecurityDescriptor ); // security
// duplicate endpoint is ok
if ( status == RPC_S_DUPLICATE_ENDPOINT )
{
status = RPC_S_OK;
}
if ( status != RPC_S_OK )
{
DNS_DEBUG( INIT, (
"ERROR: RpcServerUseProtseqEp() for LPC failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return( status );
}
}
//
// register DNS RPC interface(s)
//
status = RpcServerRegisterIf(
DnsServer_ServerIfHandle,
0,
0);
if ( status != RPC_S_OK )
{
DNS_DEBUG( INIT, (
"ERROR: RpcServerRegisterIf() failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return(status);
}
//
// for TCP/IP setup authentication
//
if ( buseTcpip )
{
status = RpcServerRegisterAuthInfoA(
DNS_RPC_SECURITY, // app name to security provider.
DNS_RPC_SECURITY_AUTH_ID, // Auth package ID.
NULL, // Encryption function handle.
NULL ); // argment pointer to Encrypt function.
if ( status != RPC_S_OK )
{
DNS_DEBUG( INIT, (
"ERROR: RpcServerRegisterAuthInfo() failed.]n"
"\tstatus = %d 0x%08lx.\n",
status, status ));
return( status );
}
}
//
// 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 )
{
DNS_PRINT((
"ERROR: RpcServerListen() failed\n"
"\tstatus = %d 0x%p\n",
status, status ));
return( status );
}
g_bRpcInitialized = 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;
DNS_DEBUG( RPC, ( "Rpc_Shutdown().\n" ));
if( ! g_bRpcInitialized )
{
DNS_DEBUG( RPC, (
"RPC not active, no shutdown necessary.\n" ));
return;
}
//
// stop server listen
// then wait for all RPC threads to go away
//
status = RpcMgmtStopServerListening(
NULL // this app
);
if ( status == RPC_S_OK )
{
status = RpcMgmtWaitServerListen();
}
//
// unbind / unregister endpoints
//
status = RpcServerInqBindings( &bindingVector );
ASSERT( status == RPC_S_OK );
if ( status == RPC_S_OK )
{
status = RpcEpUnregister(
DnsServer_ServerIfHandle,
bindingVector,
NULL ); // Uuid vector.
#if DBG
if ( status != RPC_S_OK )
{
DNS_PRINT((
"ERROR: RpcEpUnregister, status = %d.\n", status ));
}
#endif
}
//
// free binding vector
//
if ( bindingVector )
{
status = RpcBindingVectorFree( &bindingVector );
ASSERT( status == RPC_S_OK );
}
//
// wait for all calls to complete
//
status = RpcServerUnregisterIf(
DnsServer_ServerIfHandle,
0,
TRUE );
ASSERT( status == ERROR_SUCCESS );
g_bRpcInitialized = FALSE;
DNS_DEBUG( RPC, (
"RPC shutdown completed.\n" ));
}
//
// RPC allocate and free routines
//
PVOID
MIDL_user_allocate(
IN size_t cBytes
)
/*++
Routine Description:
Allocate memory for use in RPC
- used by server RPC stubs to unpack arguments
- used by DNS RPC functions to allocate memory to send to client
Arguments:
cBytes -- count of bytes to allocate
Return Value:
Ptr to allocated memory, if successful.
NULL on allocation failure.
--*/
{
PVOID pMem;
pMem = ALLOC_TAGHEAP( cBytes, MEMTAG_RPC );
DNS_DEBUG( RPC, (
"RPC allocation of %d bytes at %p.\n",
cBytes,
pMem ));
return( pMem );
}
PVOID
MIDL_user_allocate_zero(
IN size_t cBytes
)
/*++
Routine Description:
Allocate zeroed memory for use in RPC
- used by DNS RPC functions to allocate memory to send to client
Arguments:
cBytes -- count of bytes to allocate
Return Value:
Ptr to allocated memory, if successful.
NULL on allocation failure.
--*/
{
PVOID pMem;
pMem = MIDL_user_allocate( cBytes );
if ( !pMem )
{
return pMem;
}
// zero
RtlZeroMemory(
pMem,
cBytes );
return( pMem );
}
VOID
MIDL_user_free(
IN OUT PVOID pMem
)
/*++
Routine Description:
Free memory used in RPC
- used by server RPC stubs to free memory sent back to client
- used by DNS RPC functions when freeing sub-structures in RPC buffers
Arguments:
pMem -- memory to free
Return Value:
None
--*/
{
DNS_DEBUG( RPC, (
"Free RPC allocation at %p.\n",
pMem ));
// allocation passed to RPC might have had another source
//FREE_TAGHEAP( pMem, 0, MEMTAG_RPC );
FREE_TAGHEAP( pMem, 0, 0 );
}
//
// RPC buffer writing utilities
//
// These are used to write allocated substructures -- IP arrays and
// strings -- to RPC buffer.
//
BOOL
RpcUtil_CopyIpArrayToRpcBuffer(
IN OUT PIP_ARRAY * paipRpcIpArray,
IN PIP_ARRAY aipLocalIpArray
)
/*++
Routine Description:
Copy local IP Array to RPC buffer.
Arguments:
paipRpcIpArray -- address in RPC buffer to place IP array; may or may
not have existing IP array
aipLocalIpArray -- local IP array
Return Value:
TRUE if successful.
FALSE on memory allocation failure.
--*/
{
if ( *paipRpcIpArray )
{
MIDL_user_free( *paipRpcIpArray );
*paipRpcIpArray = NULL;
}
if ( aipLocalIpArray )
{
*paipRpcIpArray = Dns_CreateIpArrayCopy( aipLocalIpArray );
if ( ! *paipRpcIpArray )
{
return( FALSE );
}
}
return( TRUE );
}
BOOL
RpcUtil_CopyStringToRpcBuffer(
IN OUT LPSTR * ppszRpcString,
IN LPSTR pszLocalString
)
/*++
Routine Description:
Copy local string to RPC buffer.
Arguments:
ppszRpcString -- address in RPC buffer to place string; may or may
not have existing string
pszLocalString -- local string
Return Value:
TRUE if successful.
FALSE on memory allocation failure.
--*/
{
if ( *ppszRpcString )
{
MIDL_user_free( *ppszRpcString );
*ppszRpcString = NULL;
}
if ( pszLocalString )
{
*ppszRpcString = Dns_CreateStringCopy( pszLocalString, 0 );
if ( ! *ppszRpcString )
{
return( FALSE );
}
}
return( TRUE );
}
BOOL
RpcUtil_CopyStringToRpcBufferEx(
IN OUT LPSTR * ppszRpcString,
IN LPSTR pszLocalString,
IN BOOL fUnicodeIn,
IN BOOL fUnicodeOut
)
/*++
Routine Description:
Copy local string to RPC buffer.
Arguments:
ppszRpcString -- address in RPC buffer to place string; may or may
not have existing string
pszLocalString -- local string
Return Value:
TRUE if successful.
FALSE on memory allocation failure.
--*/
{
if ( *ppszRpcString )
{
MIDL_user_free( *ppszRpcString );
*ppszRpcString = NULL;
}
if ( pszLocalString )
{
*ppszRpcString = Dns_StringCopyAllocate(
pszLocalString,
0,
fUnicodeIn ? DnsCharSetUnicode : DnsCharSetUtf8,
fUnicodeOut ? DnsCharSetUnicode : DnsCharSetUtf8
);
if ( ! *ppszRpcString )
{
return( FALSE );
}
}
return( TRUE );
}
//
// Access control for RPC API
//
//
// Access control globals
//
PSECURITY_DESCRIPTOR g_GlobalSecurityDescriptor;
GENERIC_MAPPING g_GlobalSecurityInfoMapping =
{
STANDARD_RIGHTS_READ, // generic read access
STANDARD_RIGHTS_WRITE, // generic write
STANDARD_RIGHTS_EXECUTE, // generic execute
DNS_ALL_ACCESS // generic all
};
//#define DNS_SERVICE_OBJECT_NAME TEXT("dns_Server")
#define DNS_SERVICE_OBJECT_NAME TEXT("DnsServer")
DNS_STATUS
RpcUtil_CreateSecurityObjects(
VOID
)
/*++
Routine Description:
Add security ACEs to DNS security descriptor.
Arguments:
None.
Return Value:
ERROR_SUCCESS if successful.
Error code on failure.
--*/
{
NTSTATUS status;
//
// Create ACE data for the DACL.
//
// Note, ordering matters! When access is checked it is checked
// by moving down the list until access is granted or denied.
//
// Admin -- all access
// SysOps and AcctOps -- DNS admin access
// Everyone -- view access only
//
ACE_DATA AceData[] =
{
{ACCESS_ALLOWED_ACE_TYPE, 0, 0, GENERIC_ALL, &AliasAdminsSid},
{ACCESS_ALLOWED_ACE_TYPE, 0, 0, DNS_ALL_ACCESS, &AliasSystemOpsSid},
//{ACCESS_ALLOWED_ACE_TYPE, 0, 0, DNS_ADMIN_ACCESS, &AliasAccountOpsSid},
//{ACCESS_ALLOWED_ACE_TYPE, 0, 0, DNS_VIEW_ACCESS, &AliasAccountOpsSid},
//{ACCESS_ALLOWED_ACE_TYPE, 0, 0, DNS_VIEW_ACCESS, &AliasSystemOpsSid},
};
//
// Create the security descriptor
//
status = NetpCreateSecurityObject(
AceData,
sizeof(AceData)/sizeof(AceData[0]),
LocalSystemSid,
LocalSystemSid,
&g_GlobalSecurityInfoMapping,
&g_GlobalSecurityDescriptor );
return( RtlNtStatusToDosError( status ) );
}
DNS_STATUS
RpcUtil_ApiAccessCheck(
IN ACCESS_MASK DesiredAccess
)
/*++
Routine Description:
Check caller for desired access needed for the calling API.
NOTE: Skipping test if we're ds integrated. Will use
Granular access check.
Arguments:
DesiredAccess - required access to call the API.
Return Value:
ERROR_SUCCESS if successful.
ERROR_ACCESS_DENIED if access not allowed.
--*/
{
DNS_STATUS status;
DNS_DEBUG( RPC, (
"Call: RpcUtil_ApiAccessCheck\n" ));
status = NetpAccessCheckAndAudit(
DNS_SERVICE_NAME, // Subsystem name
DNS_SERVICE_OBJECT_NAME, // Object typedef name
g_GlobalSecurityDescriptor, // Security descriptor
DesiredAccess, // Desired access
&g_GlobalSecurityInfoMapping ); // Generic mapping
if ( status != ERROR_SUCCESS )
{
DNS_DEBUG( RPC, (
"ACCESS DENIED (%lu): RpcUtil_ApiAccessCheck\n",
status ));
status = ERROR_ACCESS_DENIED;
}
#if DBG
//
// DBG: if not running as a service this will always fail.
//
if ( status == ERROR_ACCESS_DENIED && !g_RunAsService )
{
DNS_DEBUG( RPC, (
"RpcUtil_ApiAccessCheck: granting access even though check failed\n",
status ));
status = ERROR_SUCCESS;
}
#endif
DNS_DEBUG( RPC, (
"Exit (%lu): RpcUtil_ApiAccessCheck\n",
status ));
return( status );
}
DNS_STATUS
RpcUtil_CheckAdminPrivilege(
IN PZONE_INFO pZone,
IN DWORD dwPrivilege
)
/*++
Routine Description:
Check for that caller has desired privilege.
Precondition: Post RpcImpersonation!! Getting thread token.
Arguments:
pZone -- Zone if specific zone action, NULL for server actions.
dwPrivilege -- desired action (PRIVILEGE_XXX constant from dnsprocs.h)
Return Value:
ERROR_SUCCESS if successful.
ERROR_ACCESS_DENIED if access not allowed.
other NTSTATUS error code if API call failure
--*/
{
HANDLE htoken = NULL;
BOOL bstatus;
DWORD status = ERROR_SUCCESS;
PSECURITY_DESCRIPTOR psecurityDescriptor = NULL;
// AccessCheck Parameter
DWORD desiredAccess;
GENERIC_MAPPING genericMapping;
PRIVILEGE_SET privilegeSet;
DWORD privilegeSetLength;
DWORD grantedAccess;
//
// get SD for zone (if exists)
// otherwise default server SD
//
if ( pZone && pZone->pSD )
{
psecurityDescriptor = pZone->pSD;
}
else if ( g_pServerObjectSD )
{
psecurityDescriptor = g_pServerObjectSD;
}
DNS_DEBUG( RPC, (
"CheckAdminPrivilege( zone=%s, priv=%p ) against SD %p\n",
pZone ? pZone->pszZoneName : "NONE",
dwPrivilege,
psecurityDescriptor ));
//
// if no SD from DS -- then signal for old security check
//
// DEVNOTE-DCR: 455822 - old/new access?
//
if ( !psecurityDescriptor )
{
DNS_DEBUG( RPC, (
"No DS security check -- fail over to old RPC security.\n" ));
return( DNSSRV_STATUS_DS_UNAVAILABLE );
}
//
// Second level access check. See if client in DnsAdmins group
// 1. get thread token (must be an impersonating thread).
// 2. See if user has RW privilage in the zone or on the server SD
//
bstatus = OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY,
TRUE,
&htoken );
if ( !bstatus )
{
status = GetLastError();
DNS_DEBUG( RPC, (
"\nERROR <%lu>: failed to open thread token!\n",
status ));
ASSERT( FALSE );
goto Failed;
}
#if DBG
{
PSID pSid = NULL;
if ( Dbg_GetUserSidForToken( htoken, &pSid ) )
{
DNS_DEBUG( RPC, (
"CheckAdminPrivilege: impersonating: %S\n",
Dbg_DumpSid( pSid ) ));
Dbg_FreeUserSid( &pSid );
}
else
{
DNS_DEBUG( RPC, (
"CheckAdminPrivilege: GetUserSidForToken failed\n" ));
}
}
#endif
// validate SD
if ( !IsValidSecurityDescriptor(psecurityDescriptor) )
{
status = GetLastError();
DNS_DEBUG( RPC, (
"Error <%lu>: Invalid security descriptor\n",
status));
ASSERT( status != ERROR_SUCCESS );
goto Failed;
}
//
// access check against SD
//
// - generic mapping that corresponds to DS objects
// - support READ or WRITE access levels
//
// generic mapping for DS objects
genericMapping.GenericRead = DNS_DS_GENERIC_READ;
genericMapping.GenericWrite = DNS_DS_GENERIC_WRITE;
genericMapping.GenericExecute = DNS_DS_GENERIC_EXECUTE;
genericMapping.GenericAll = DNS_DS_GENERIC_ALL;
if ( PRIVILEGE_READ == dwPrivilege )
{
desiredAccess = GENERIC_READ;
// desiredAccess = GENERIC_READ | GENERIC_WRITE;
}
else
{
desiredAccess = GENERIC_READ | GENERIC_WRITE;
}
DNS_DEBUG( RPC, (
"desiredAccess before MapGenericMask() = %p\n",
desiredAccess ));
MapGenericMask(
& desiredAccess,
& genericMapping );
DNS_DEBUG( RPC, (
"desiredAccess after MapGenericMask() = %p\n",
desiredAccess ));
privilegeSetLength = sizeof(privilegeSet);
//
// do access check
//
bstatus = AccessCheck(
psecurityDescriptor,
htoken,
desiredAccess,
& genericMapping,
& privilegeSet,
& privilegeSetLength,
& grantedAccess,
& status );
if ( !bstatus )
{
status = GetLastError();
DNS_DEBUG( RPC, (
"Error <%lu>: AccessCheck Failed\n",
status));
ASSERT( status != ERROR_SUCCESS );
goto Failed;
}
if ( !status )
{
DNS_DEBUG( RPC, (
"Warning: Client DENIED by AccessCheck\n"
"\trequested access = %p\n",
desiredAccess ));
status = ERROR_ACCESS_DENIED;
goto Failed;
}
DNS_DEBUG( RPC, (
"RPC Client GRANTED access by AccessCheck\n" ));
CloseHandle( htoken );
return( ERROR_SUCCESS );
Failed:
if ( status == ERROR_SUCCESS )
{
status = ERROR_ACCESS_DENIED;
}
if ( htoken )
{
CloseHandle( htoken );
}
return( status );
}
DNS_STATUS
RpcUtil_SessionSecurityInit(
IN LPCSTR pszZoneName,
IN DWORD dwPrivilege,
IN DWORD dwFlag,
OUT PBOOL pfImpersonating,
OUT PZONE_INFO * ppZone
)
/*++
Routine Description:
RPC security init and check for session.
Impersonate client and check for that caller has desired privilege.
Arguments:
pZone -- Zone if specific zone action, NULL for server actions.
dwPrivilege -- desired action
dwFlag -- flag for action to control special zones (cache, root hints);
currently unused
pfImpersonating -- ptr to receive impersonating flag
ppZone -- resulting zone
Return Value:
ERROR_SUCCESS if successful.
ERROR_ACCESS_DENIED if access not allowed.
other NTSTATUS error code if API call failure
--*/
{
PZONE_INFO pzone = NULL;
DNS_STATUS status;
BOOL bimpersonating = FALSE;
DNS_DEBUG( RPC, (
"RpcUtil_SessionSecurityInit()\n"
"\tzone name = %s\n"
"\tprivilege = %p\n",
pszZoneName,
dwPrivilege ));
//
// if zone given -- find it
//
// psuedo-zones
// - root-hints
// - cache
// - multi-zone
// require server level security for desired access
//
if ( pszZoneName )
{
pzone = Zone_FindZoneByName( (LPSTR)pszZoneName );
if ( !pzone )
{
if ( strcmp( pszZoneName, DNS_ZONE_ROOT_HINTS ) == 0 )
{
if ( dwFlag & RPC_INIT_FIND_ALL_ZONES )
{
pzone = g_pRootHintsZone;
}
}
else if ( strcmp( pszZoneName, DNS_ZONE_CACHE ) == 0 )
{
if ( dwFlag & RPC_INIT_FIND_ALL_ZONES )
{
pzone = g_pCacheZone;
}
}
else if ( Zone_GetFilterForMultiZoneName( (LPSTR)pszZoneName ) )
{
// no-op -- if have filter, then valid multizone lookup
}
else // just bad zone name
{
DNS_DEBUG( RPC, (
"ERROR: zone name %s does not match real or pseudo zones!\n",
pszZoneName ));
status = DNS_ERROR_ZONE_DOES_NOT_EXIST;
goto Cleanup;
}
}
}
//
// impersonate -- currently do for all calls
//
// not strictly necessary for calls which don't write to DS and
// which use Net API authentication, but better to just always do
// this
//
// DEVNOTE: if always impersonate can eliminate bImpersonate flag
// and always revert on cleanup
//
bimpersonating = RpcUtil_SwitchSecurityContext( RPC_CLIENT_CONTEXT );
//
// check with new granular access
// if check fails -- still try NT4 administrator-has-access
//
// some issue about whether Admin should OVERRIDE or whether
// granular access ought to be able to defeat admin; i think
// the former is fine, we just need to get the story out
//
//
// if DS backed -- check granular access
//
// DEVNOTE: fix to make single access check for all
//
if ( g_pDefaultServerSD )
{
status = RpcUtil_CheckAdminPrivilege(
pzone,
dwPrivilege );
}
else
{
status = RpcUtil_ApiAccessCheck( DNS_ADMIN_ACCESS );
}
Cleanup:
// revert to self on failure
if ( status != ERROR_SUCCESS && bimpersonating )
{
bimpersonating = RpcUtil_SwitchSecurityContext( RPC_SERVER_CONTEXT );
}
//
// return zone and impersonation flag
//
// DEVNOTE: currently do NOT return multizone
// must lookup again
// - this is superior to returning bogus zone to folks
// - better would be to have interface include multizone return
//
if ( ppZone )
{
*ppZone = pzone;
}
if ( pfImpersonating )
{
*pfImpersonating = bimpersonating;
}
DNS_DEBUG( RPC, (
"Exit (%lu): RpcUtil_SessionSecurityInit\n",
status ));
return( status );
}
DNS_STATUS
RpcUtil_SessionComplete(
VOID
)
/*++
Routine Description:
Cleanup for ending RPC call.
Do revert to self, if impersonating.
Arguments:
None
Return Value:
None
--*/
{
//
// revert to self
//
RpcUtil_SwitchSecurityContext ( RPC_SERVER_CONTEXT );
return( ERROR_SUCCESS );
}
BOOL
RpcUtil_SwitchSecurityContext(
IN BOOL bClientContext
)
/*++
Routine Description:
Shells on RPC impersonation api's.
Provides single entry point access to changing rpc impersonation state.
Arguments:
bClientContext -- does caller request to switch to client or server context
Return Value:
resulting state : impersonated or not
--*/
{
DWORD status;
BOOL bRpcImpersonated; // note: all code paths set a value.
if ( !bClientContext )
{
//
// We're in impersonation context & reverting to self
//
status = RpcRevertToSelf();
if ( status != RPC_S_OK )
{
DNS_DEBUG( ANY, ("Error <%lu>: RpcRevertToSelf Failed\n", status ));
ASSERT ( FALSE );
//
// DEVNOTE: we're assuming that if the revert to self is a noop (we're self),
// then we'll get back an OK & only if we actually failed to revert from
// client context, we get an error. Thus, we'll set the flag to TRUE
//
bRpcImpersonated = TRUE;
goto Cleanup;
}
bRpcImpersonated = FALSE;
}
else
{
//
// We're in server context & would like to impersonate.
//
//
// impersonate -- currently do for all calls
//
// not strictly necessary for calls which don't write to DS and
// which use Net API authentication, but better to just always do
// this
//
status = RpcImpersonateClient( 0 );
if ( status != RPC_S_OK )
{
DNS_DEBUG( RPC, (
"Error <%lu>: RpcImpersonateClient Failed\n",
status ));
ASSERT (FALSE);
//
// DEVNOTE: We assume that an impersonated thread calling this we'll end up
// w/ a noop & return success. Thus we get here only if we attempt to
// impersonate from server context & we failed, thus we're not impersonating
// & the flag is FALSE.
//
bRpcImpersonated = FALSE;
goto Cleanup;
}
bRpcImpersonated = TRUE;
}
Cleanup:
return( bRpcImpersonated );
}
//
// End rpc.c
//