815 lines
21 KiB
C
815 lines
21 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
apiinit.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Initialization for Cluster API component (CLUSAPI) of the
|
|||
|
NT Cluster Service
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
John Vert (jvert) 7-Feb-1996
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
#include "apip.h"
|
|||
|
#include "aclapi.h"
|
|||
|
#include "stdio.h"
|
|||
|
#include <psapi.h>
|
|||
|
|
|||
|
|
|||
|
extern LPWSTR g_pszServicesPath;
|
|||
|
extern DWORD g_dwServicesPid;
|
|||
|
|
|||
|
API_INIT_STATE ApiState=ApiStateUninitialized;
|
|||
|
|
|||
|
const DWORD NO_USER_SID = 0;
|
|||
|
const DWORD USER_SID_GRANTED = 1;
|
|||
|
const DWORD USER_SID_DENIED = 2;
|
|||
|
|
|||
|
//forward declarations
|
|||
|
DWORD
|
|||
|
ApipGetLocalCallerInfo(
|
|||
|
IN handle_t hIDL,
|
|||
|
IN OUT OPTIONAL LPDWORD pdwCheckPid,
|
|||
|
IN OPTIONAL LPCWSTR pszModuleName,
|
|||
|
OUT BOOL *pbLocal,
|
|||
|
OUT OPTIONAL BOOL *pbMatchedPid,
|
|||
|
OUT OPTIONAL BOOL *pbMatchedModule,
|
|||
|
OUT OPTIONAL BOOL *pbLocalSystemAccount
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS
|
|||
|
ApipConnectCallback(
|
|||
|
IN RPC_IF_ID * Interface,
|
|||
|
IN void * Context
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
RPC callback for authenticating connecting clients of CLUSAPI
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Interface - Supplies the UUID and version of the interface.
|
|||
|
|
|||
|
Context - Supplies a server binding handle representing the client
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
RPC_S_OK if the user is granted permission.
|
|||
|
RPC_S_ACCESS_DENIED if the user is denied permission.
|
|||
|
|
|||
|
Win32 error code otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|||
|
DWORD BufferSize=0;
|
|||
|
DWORD Size=0;
|
|||
|
DWORD Status;
|
|||
|
HANDLE ClientToken = NULL;
|
|||
|
PRIVILEGE_SET psPrivileges;
|
|||
|
DWORD PrivSize = sizeof(psPrivileges);
|
|||
|
DWORD GrantedAccess;
|
|||
|
DWORD AccessStatus;
|
|||
|
DWORD dwMask = CLUSAPI_ALL_ACCESS;
|
|||
|
GENERIC_MAPPING gmMap;
|
|||
|
DWORD dwStatus = 0;
|
|||
|
BOOL bReturn = FALSE;
|
|||
|
BOOL bACRtn = FALSE;
|
|||
|
DWORD dwUserPermStatus;
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
BOOL bRevertToSelfRequired = FALSE;
|
|||
|
BOOL bLocal, bMatchedPid, bMatchedModule, bLocalSystemAccount;
|
|||
|
|
|||
|
|
|||
|
//check if services is calling the cluster service for
|
|||
|
//services calls the interface only for eventlog propagation
|
|||
|
//if so, avoid the security checks
|
|||
|
// Get the process id
|
|||
|
Status = ApipGetLocalCallerInfo(Context,
|
|||
|
&g_dwServicesPid,
|
|||
|
g_dwServicesPid ? NULL : g_pszServicesPath, //perform the module name match the first time
|
|||
|
&bLocal,
|
|||
|
&bMatchedPid,
|
|||
|
&bMatchedModule,
|
|||
|
g_dwServicesPid ? &bLocalSystemAccount : NULL);//perform the local system account check if it is the first time
|
|||
|
if (Status != ERROR_SUCCESS)
|
|||
|
{
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] ApipGetLocalCallerInfo failed with %1!u!.\n",
|
|||
|
Status);
|
|||
|
return RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
if (Status == ERROR_SUCCESS)
|
|||
|
{
|
|||
|
//if the caller is local and if it matches the pid or if it matches
|
|||
|
//the module and is in local system account, allow access
|
|||
|
if ((bLocal) &&
|
|||
|
(bMatchedPid || (bMatchedModule && bLocalSystemAccount)))
|
|||
|
{
|
|||
|
return(RPC_S_OK);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The authentication we do here is to retrieve the Security value
|
|||
|
// from the cluster registry, impersonate the client, and call
|
|||
|
// AccessCheck.
|
|||
|
//
|
|||
|
|
|||
|
Status = DmQueryString(DmClusterParametersKey,
|
|||
|
CLUSREG_NAME_CLUS_SD,
|
|||
|
REG_BINARY,
|
|||
|
(LPWSTR *) &pSD,
|
|||
|
&BufferSize,
|
|||
|
&Size);
|
|||
|
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
|
|||
|
PSECURITY_DESCRIPTOR psd4;
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Did not find Security Descriptor key in the cluster DB.\n");
|
|||
|
Status = DmQueryString(DmClusterParametersKey,
|
|||
|
CLUSREG_NAME_CLUS_SECURITY,
|
|||
|
REG_BINARY,
|
|||
|
(LPWSTR *) &psd4,
|
|||
|
&BufferSize,
|
|||
|
&Size);
|
|||
|
|
|||
|
if (Status == ERROR_SUCCESS) {
|
|||
|
pSD = ClRtlConvertClusterSDToNT5Format(psd4);
|
|||
|
LocalFree(psd4);
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
DWORD dwSDLen;
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Did not find Security key in the cluster DB.\n");
|
|||
|
Status = ClRtlBuildDefaultClusterSD(NULL, &pSD, &dwSDLen);
|
|||
|
if (SUCCEEDED(Status)) {
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Successfully built default cluster SD.\n");
|
|||
|
}
|
|||
|
else {
|
|||
|
ClRtlLogPrint(LOG_NOISE,
|
|||
|
"[API] Did not successfully build default cluster SD. Error = 0x%1!.8x!\n",
|
|||
|
Status);
|
|||
|
Status = RPC_S_ACCESS_DENIED;
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!IsValidSecurityDescriptor(pSD)) {
|
|||
|
ClRtlLogPrint(LOG_ERROR, "[API] SD is not valid!\n");
|
|||
|
ClRtlExamineSD(pSD, "[API]");
|
|||
|
Status = RPC_S_ACCESS_DENIED;
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
RpcStatus = RpcImpersonateClient(Context);
|
|||
|
if (RpcStatus != RPC_S_OK) {
|
|||
|
Status = RpcStatus;
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] RpcImpersonateClient() failed. Status = 0x%1!.8x!\n", Status);
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
bRevertToSelfRequired = TRUE;
|
|||
|
|
|||
|
if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE, &ClientToken)) {
|
|||
|
Status = GetLastError();
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] OpenThreadToken() failed. Status = 0x%1!.8x!\n", Status);
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
gmMap.GenericRead = CLUSAPI_READ_ACCESS;
|
|||
|
gmMap.GenericWrite = CLUSAPI_CHANGE_ACCESS;
|
|||
|
gmMap.GenericExecute = CLUSAPI_READ_ACCESS | CLUSAPI_CHANGE_ACCESS;
|
|||
|
gmMap.GenericAll = CLUSAPI_ALL_ACCESS;
|
|||
|
|
|||
|
MapGenericMask(&dwMask, &gmMap);
|
|||
|
|
|||
|
bACRtn = AccessCheck(pSD, ClientToken, dwMask, &gmMap, &psPrivileges, &PrivSize, &dwStatus, &bReturn);
|
|||
|
if (bACRtn && bReturn) {
|
|||
|
Status = RPC_S_OK;
|
|||
|
} else {
|
|||
|
|
|||
|
DWORD dwSDLen;
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE,
|
|||
|
"[API] User denied access. GetLastError() = 0x%1!.8x!; dwStatus = 0x%2!.8x!. Trying the default SD...\n",
|
|||
|
GetLastError(),
|
|||
|
dwStatus);
|
|||
|
Status = RPC_S_ACCESS_DENIED;
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Dump access mask.\n");
|
|||
|
ClRtlExamineMask(dwMask, "[API]");
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Dump the SD that failed...\n" );
|
|||
|
ClRtlExamineSD(pSD, "[API]");
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Dump the ClientToken that failed...\n" );
|
|||
|
ClRtlExamineClientToken(ClientToken, "[API]");
|
|||
|
|
|||
|
if (pSD) {
|
|||
|
LocalFree(pSD);
|
|||
|
pSD = NULL;
|
|||
|
}
|
|||
|
|
|||
|
Status = ClRtlBuildDefaultClusterSD(NULL, &pSD, &dwSDLen);
|
|||
|
if (SUCCEEDED(Status)) {
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Successfully built default cluster SD.\n");
|
|||
|
bACRtn = AccessCheck(pSD, ClientToken, dwMask, &gmMap, &psPrivileges, &PrivSize, &dwStatus, &bReturn);
|
|||
|
if (bACRtn && bReturn) {
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] User granted access using default cluster SD.\n");
|
|||
|
Status = RPC_S_OK;
|
|||
|
} else {
|
|||
|
ClRtlLogPrint(LOG_NOISE,
|
|||
|
"[API] User denied access using default cluster SD. GetLastError() = 0x%1!.8x!; dwStatus = 0x%2!.8x!.\n",
|
|||
|
GetLastError(),
|
|||
|
dwStatus);
|
|||
|
Status = RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
ClRtlLogPrint(LOG_NOISE,
|
|||
|
"[API] Did not successfully build default cluster SD. Error = 0x%1!.8x!\n",
|
|||
|
Status);
|
|||
|
Status = RPC_S_ACCESS_DENIED;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
FnExit:
|
|||
|
if (bRevertToSelfRequired) {
|
|||
|
RpcRevertToSelf();
|
|||
|
}
|
|||
|
|
|||
|
if (ClientToken) {
|
|||
|
CloseHandle(ClientToken);
|
|||
|
}
|
|||
|
|
|||
|
if (pSD) {
|
|||
|
LocalFree(pSD);
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ApiInitialize(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Performs one-time initialization of the API data structures.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if successful
|
|||
|
|
|||
|
Win32 error code otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Initializing\n");
|
|||
|
|
|||
|
CL_ASSERT(ApiState == ApiStateUninitialized);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize global data.
|
|||
|
//
|
|||
|
InitializeListHead(&NotifyListHead);
|
|||
|
InitializeCriticalSection(&NotifyListLock);
|
|||
|
|
|||
|
ApiState = ApiStateOffline;
|
|||
|
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ApiOnlineReadOnly(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Brings up a limited set of APIs - currently OpenResource/read-only
|
|||
|
registry APIs. Only LPC connections are enabled.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if successful
|
|||
|
|
|||
|
Win32 error code otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Status;
|
|||
|
|
|||
|
|
|||
|
if (ApiState == ApiStateOffline) {
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Online read only\n");
|
|||
|
|
|||
|
//
|
|||
|
// Register the clusapi RPC server interface so resources can use
|
|||
|
// the API when they are created by the FM. Note that we won't receive
|
|||
|
// any calls from remote clients yet because we haven't registered
|
|||
|
// the dynamic UDP endpoint. That will happnen in ApiOnline().
|
|||
|
//
|
|||
|
Status = RpcServerRegisterIfEx(s_clusapi_v2_0_s_ifspec,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
|||
|
CsUseAuthenticatedRPC ? ApipConnectCallback : NULL
|
|||
|
);
|
|||
|
|
|||
|
if (Status != RPC_S_OK) {
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[API] Failed to register clusapi RPC interface, status %1!u!.\n",
|
|||
|
Status
|
|||
|
);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
ApiState = ApiStateReadOnly;
|
|||
|
}
|
|||
|
else {
|
|||
|
//CL_ASSERT(ApiState == ApiStateOffline);
|
|||
|
}
|
|||
|
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
ApiOnline(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Enables the rest of the API set and starts listening for remote
|
|||
|
connections.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS if successful.
|
|||
|
|
|||
|
Win32 error code otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Status;
|
|||
|
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Online\n");
|
|||
|
|
|||
|
if (ApiState == ApiStateReadOnly) {
|
|||
|
//
|
|||
|
// Register for all events
|
|||
|
//
|
|||
|
Status = EpRegisterEventHandler(CLUSTER_EVENT_ALL,ApipEventHandler);
|
|||
|
if (Status != ERROR_SUCCESS) {
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Register the dynamic UDP endpoint for the clusapi interface.
|
|||
|
// This will enable remote clients to begin calling us. We do this
|
|||
|
// here to minimize the chances that we will service an external
|
|||
|
// call before we are ready. If we ever have to rollback after
|
|||
|
// this point, we will still be listening externally. Nothing we can
|
|||
|
// do about that.
|
|||
|
//
|
|||
|
CL_ASSERT(CsRpcBindingVector != NULL);
|
|||
|
|
|||
|
Status = RpcEpRegister(s_clusapi_v2_0_s_ifspec,
|
|||
|
CsRpcBindingVector,
|
|||
|
NULL,
|
|||
|
L"Microsoft Cluster Server API");
|
|||
|
|
|||
|
if (Status != RPC_S_OK) {
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[API] Failed to register endpoint for clusapi RPC interface, status %1!u!.\n",
|
|||
|
Status
|
|||
|
);
|
|||
|
NmDumpRpcExtErrorInfo(Status);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
ApiState = ApiStateOnline;
|
|||
|
}
|
|||
|
else {
|
|||
|
CL_ASSERT(ApiState == ApiStateReadOnly);
|
|||
|
}
|
|||
|
|
|||
|
return(ERROR_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ApiOffline(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Takes the Cluster Api offline.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Status;
|
|||
|
|
|||
|
|
|||
|
if (ApiState == ApiStateOnline) {
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Offline\n");
|
|||
|
|
|||
|
//
|
|||
|
// Deregister the Clusapi RPC endpoint
|
|||
|
//
|
|||
|
CL_ASSERT(CsRpcBindingVector != NULL);
|
|||
|
|
|||
|
Status = RpcEpUnregister(
|
|||
|
s_clusapi_v2_0_s_ifspec,
|
|||
|
CsRpcBindingVector,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ((Status != RPC_S_OK) && (Status != EPT_S_NOT_REGISTERED)) {
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[API] Failed to deregister endpoint for clusapi RPC interface, status %1!u!.\n",
|
|||
|
Status
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
ApiState = ApiStateReadOnly;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// KB - We can't deregister the interface because we can't wait for
|
|||
|
// pending calls to complete - pending notifies never complete.
|
|||
|
// If we deregistered the interface after a failed join without
|
|||
|
// a complete shutdown, the subsequent form would fail. As a
|
|||
|
// result, the API won't go offline until service shutdown.
|
|||
|
//
|
|||
|
#if 0
|
|||
|
|
|||
|
if (ApiState == ApiStateReadOnly) {
|
|||
|
|
|||
|
//
|
|||
|
// Deregister the Clusapi RPC interface
|
|||
|
//
|
|||
|
|
|||
|
Status = RpcServerUnregisterIf(
|
|||
|
s_clusapi_v2_0_s_ifspec,
|
|||
|
NULL,
|
|||
|
1 // Wait for outstanding calls to complete
|
|||
|
);
|
|||
|
|
|||
|
if ((Status != RPC_S_OK) && (Status != RPC_S_UNKNOWN_IF)) {
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[INIT] Unable to deregister the clusapi RPC interface, Status %1!u!.\n",
|
|||
|
Status
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
ApiState = ApiStateOffline;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
ApiShutdown(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Shuts down the Cluster Api
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD Status;
|
|||
|
|
|||
|
|
|||
|
if (ApiState > ApiStateOffline) {
|
|||
|
ApiOffline();
|
|||
|
|
|||
|
//
|
|||
|
// KB - We do this here because shutdown of the Clusapi RPC
|
|||
|
// interface is broken due to pending notifies.
|
|||
|
//
|
|||
|
Status = RpcServerUnregisterIf(
|
|||
|
s_clusapi_v2_0_s_ifspec,
|
|||
|
NULL,
|
|||
|
0 // Don't wait for calls to complete
|
|||
|
);
|
|||
|
|
|||
|
if ((Status != RPC_S_OK) && (Status != RPC_S_UNKNOWN_IF)) {
|
|||
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|||
|
"[INIT] Unable to deregister the clusapi RPC interface, Status %1!u!.\n",
|
|||
|
Status
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
ApiState = ApiStateOffline;
|
|||
|
}
|
|||
|
|
|||
|
if (ApiState == ApiStateOffline) {
|
|||
|
|
|||
|
ClRtlLogPrint(LOG_NOISE, "[API] Shutdown\n");
|
|||
|
|
|||
|
//
|
|||
|
// KB
|
|||
|
//
|
|||
|
// Because we cannot shutdown the RPC server and cannot
|
|||
|
// unregister our event handler, it is not safe to delete
|
|||
|
// the critical section.
|
|||
|
//
|
|||
|
// DeleteCriticalSection(&NotifyListLock);
|
|||
|
// ApiState = ApiStateUninitialized;
|
|||
|
|
|||
|
//
|
|||
|
// TODO?
|
|||
|
//
|
|||
|
// SS: free notify list head
|
|||
|
// SS: how do we deregister with the event handler
|
|||
|
//
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
ApipGetLocalCallerInfo(
|
|||
|
IN handle_t hIDL,
|
|||
|
IN OUT OPTIONAL LPDWORD pdwCheckPid,
|
|||
|
IN OPTIONAL LPCWSTR pszModuleName,
|
|||
|
OUT BOOL *pbLocal,
|
|||
|
OUT OPTIONAL BOOL *pbMatchedPid,
|
|||
|
OUT OPTIONAL BOOL *pbMatchedModule,
|
|||
|
OUT OPTIONAL BOOL *pbLocalSystemAccount
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function checks whether the caller's account is the local system
|
|||
|
account.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hIDL - The handle to the binding context
|
|||
|
|
|||
|
pdwCheckPid - if the value passed in is NULL, the pid of the calling process is returned. If
|
|||
|
is returned.
|
|||
|
|
|||
|
pszModuleName - If non null, the call performs the check to compare
|
|||
|
the module name of the caller against pszModuleName. If they
|
|||
|
match, *pbMatchedPid is set to TRUE.
|
|||
|
|
|||
|
pbLocal - TRUE is returned if the caller initiated this call using
|
|||
|
lrpc. If this is FALSE, all other output values will be FALSE.
|
|||
|
|
|||
|
pbMatchedModule - TRUE is returned, if the caller matches the module
|
|||
|
name specified by lpszModuleName. This pointer can be NULL.
|
|||
|
|
|||
|
pbMatchedPid - if *pdwCheckPid is non NULL, and it matched the pid of the
|
|||
|
caller, then this is set to TRUE. Else, this is set to FALSE.
|
|||
|
|
|||
|
pbLocalSystemAccount - If this is NON NULL, the call performs a check
|
|||
|
to see if the the caller is running in LocalSystemAccount. If it is
|
|||
|
then TRUE is returned, else FALSE is returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR_SUCCESS on success.
|
|||
|
|
|||
|
Win32 error code on failure.
|
|||
|
|
|||
|
Remarks:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD Pid;
|
|||
|
HANDLE hProcess = NULL;
|
|||
|
DWORD dwNumChar;
|
|||
|
DWORD dwLen;
|
|||
|
WCHAR wCallerPath[MAX_PATH + 1];
|
|||
|
RPC_STATUS RpcStatus;
|
|||
|
DWORD dwStatus = ERROR_SUCCESS;
|
|||
|
BOOLEAN bWasEnabled;
|
|||
|
|
|||
|
if (pbMatchedModule)
|
|||
|
*pbMatchedModule = FALSE;
|
|||
|
if (pbMatchedPid)
|
|||
|
*pbMatchedPid = FALSE;
|
|||
|
if (pbLocalSystemAccount)
|
|||
|
*pbLocalSystemAccount = FALSE;
|
|||
|
|
|||
|
|
|||
|
//assume the caller is local
|
|||
|
*pbLocal = TRUE;
|
|||
|
|
|||
|
RpcStatus = I_RpcBindingInqLocalClientPID(NULL, &Pid );
|
|||
|
if (RpcStatus == RPC_S_INVALID_BINDING)
|
|||
|
{
|
|||
|
*pbLocal = FALSE;
|
|||
|
RpcStatus = RPC_S_OK;
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
dwStatus = I_RpcMapWin32Status(RpcStatus);
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS)
|
|||
|
{
|
|||
|
ClRtlLogPrint( LOG_CRITICAL,
|
|||
|
"[API] ApipGetLocalCallerInfo: Error %1!u! calling RpcBindingInqLocalClientPID.\n",
|
|||
|
dwStatus
|
|||
|
);
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
dwStatus = ClRtlEnableThreadPrivilege(SE_DEBUG_PRIVILEGE, &bWasEnabled);
|
|||
|
if ( dwStatus != ERROR_SUCCESS )
|
|||
|
{
|
|||
|
if (dwStatus == STATUS_PRIVILEGE_NOT_HELD)
|
|||
|
{
|
|||
|
ClRtlLogPrint(LOG_CRITICAL,
|
|||
|
"[API] ApipGetLocalCallerInfo: Debug privilege not held by cluster service\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ClRtlLogPrint(LOG_CRITICAL,
|
|||
|
"[API] ApipGetLocalCallerInfo: Attempt to enable debug privilege failed %1!lx!\n",
|
|||
|
dwStatus);
|
|||
|
}
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Get the process
|
|||
|
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, Pid);
|
|||
|
|
|||
|
//restore the thread privilege, now that we have a process handle with the right access
|
|||
|
ClRtlRestoreThreadPrivilege(SE_DEBUG_PRIVILEGE,
|
|||
|
bWasEnabled);
|
|||
|
|
|||
|
if(hProcess == NULL)
|
|||
|
{
|
|||
|
dwStatus = GetLastError();
|
|||
|
ClRtlLogPrint( LOG_CRITICAL,
|
|||
|
"[API] ApipGetLocalCallerInfo: Error %1!u! calling OpenProcess %2!u!.\n",
|
|||
|
dwStatus,
|
|||
|
Pid
|
|||
|
);
|
|||
|
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//if a process id has been specified, see if it matches that one
|
|||
|
if (pdwCheckPid)
|
|||
|
{
|
|||
|
if ((*pdwCheckPid) && (*pdwCheckPid == Pid))
|
|||
|
{
|
|||
|
*pbMatchedPid = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (pszModuleName && pbMatchedModule)
|
|||
|
{
|
|||
|
// Get the module name of whoever is calling us.
|
|||
|
|
|||
|
dwNumChar = GetModuleFileNameExW(hProcess, NULL, wCallerPath, MAX_PATH);
|
|||
|
if(dwNumChar == 0)
|
|||
|
{
|
|||
|
dwStatus = GetLastError();
|
|||
|
ClRtlLogPrint( LOG_CRITICAL,
|
|||
|
"[API] ApipGetLocalCallerInfo: Error %1!u! calling GetModuleFileNameExW.\n",
|
|||
|
dwStatus
|
|||
|
);
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
if(!lstrcmpiW(wCallerPath, pszModuleName))
|
|||
|
{
|
|||
|
*pbMatchedModule = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//check if it is the local system account, if requested
|
|||
|
if (pbLocalSystemAccount && hIDL)
|
|||
|
{
|
|||
|
// Impersonate the client.
|
|||
|
if ( ( RpcStatus = RpcImpersonateClient( hIDL ) ) != RPC_S_OK )
|
|||
|
{
|
|||
|
dwStatus = I_RpcMapWin32Status(RpcStatus);
|
|||
|
ClRtlLogPrint( LOG_CRITICAL,
|
|||
|
"[API] ApipGetLocalCallerInfo: Error %1!u! trying to impersonate caller...\n",
|
|||
|
dwStatus
|
|||
|
);
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// Check that the caller's account is local system account
|
|||
|
dwStatus = ClRtlIsCallerAccountLocalSystemAccount(pbLocalSystemAccount );
|
|||
|
|
|||
|
RpcRevertToSelf();
|
|||
|
|
|||
|
if (dwStatus != ERROR_SUCCESS )
|
|||
|
{
|
|||
|
ClRtlLogPrint( LOG_CRITICAL,
|
|||
|
"[API] ApipGetLocalCallerInfo : Error %1!u! trying to check caller's account...\n",
|
|||
|
dwStatus);
|
|||
|
goto FnExit;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//return the pid if the pid passed in is NULL and the pid passes
|
|||
|
//the criteria - matches pszModuleName if specified and is in
|
|||
|
//local system account
|
|||
|
if (pdwCheckPid && !(*pdwCheckPid))
|
|||
|
{
|
|||
|
//if we need to check for local system, the process must be in local system account
|
|||
|
//if the module name needs to be checked
|
|||
|
if (((pbLocalSystemAccount && *pbLocalSystemAccount) || (!pbLocalSystemAccount))
|
|||
|
&& ((pszModuleName && pbMatchedModule && *pbMatchedModule) || (!pbMatchedModule)))
|
|||
|
{
|
|||
|
ClRtlLogPrint( LOG_NOISE,
|
|||
|
"[API] ApipGetLocalCallerInfo : Returning Pid %1!u!\n",
|
|||
|
Pid);
|
|||
|
*pdwCheckPid = Pid;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
FnExit:
|
|||
|
if (hProcess)
|
|||
|
CloseHandle(hProcess);
|
|||
|
return(dwStatus);
|
|||
|
|
|||
|
}
|
|||
|
|