2960 lines
78 KiB
C
2960 lines
78 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
frsrpc.c
|
||
|
||
Abstract:
|
||
Setup the server and client side of authenticated RPC.
|
||
|
||
Author:
|
||
Billy J. Fuller 20-Mar-1997 (From Jim McNelis)
|
||
|
||
Environment
|
||
User mode winnt
|
||
|
||
--*/
|
||
|
||
#include <ntreppch.h>
|
||
#pragma hdrstop
|
||
|
||
#include <frs.h>
|
||
#include <ntfrsapi.h>
|
||
#include <dsrole.h>
|
||
#include <info.h>
|
||
#include <perffrs.h>
|
||
#include <perrepsr.h>
|
||
|
||
extern HANDLE PerfmonProcessSemaphore;
|
||
extern BOOL MutualAuthenticationIsEnabled;
|
||
|
||
//
|
||
// KERBEROS is not available on a server that isn't a member of
|
||
// a domain. It is possible for the non-member server to be a
|
||
// client of a KERBEROS RPC server but that doesn't help NtFrs;
|
||
// NtFrs requires server-to-server RPC.
|
||
//
|
||
BOOL KerberosIsNotAvailable;
|
||
|
||
ULONG MaxRpcServerThreads; // Maximum number of concurrent server RPC calls
|
||
|
||
//
|
||
// Binding Stats
|
||
//
|
||
ULONG RpcBinds;
|
||
ULONG RpcUnBinds;
|
||
ULONG RpcAgedBinds;
|
||
LONG RpcMaxBinds;
|
||
|
||
//
|
||
// Table of sysvols being created
|
||
//
|
||
PGEN_TABLE SysVolsBeingCreated;
|
||
|
||
|
||
//
|
||
// This table translates the FRS API access check code number to registry key table
|
||
// code for the enable/disable registry key check and the rights registry key check.
|
||
// The FRS_API_ACCESS_CHECKS enum in config.h defines the indices for the
|
||
// this table. The order of the entries here must match the order of the entries
|
||
// in the ENUM.
|
||
//
|
||
typedef struct _RPC_API_KEYS_ {
|
||
FRS_REG_KEY_CODE Enable; // FRS Registry Key Code for the Access Check enable string
|
||
FRS_REG_KEY_CODE Rights; // FRS Registry Key Code for the Access Check rights string
|
||
PWCHAR KeyName; // Key name for the API.
|
||
} RPC_API_KEYS, *PRPC_API_KEYS;
|
||
|
||
RPC_API_KEYS RpcApiKeys[ACX_MAX] = {
|
||
|
||
{FKC_ACCCHK_STARTDS_POLL_ENABLE, FKC_ACCCHK_STARTDS_POLL_RIGHTS, ACK_START_DS_POLL},
|
||
{FKC_ACCCHK_SETDS_POLL_ENABLE, FKC_ACCCHK_SETDS_POLL_RIGHTS, ACK_SET_DS_POLL},
|
||
{FKC_ACCCHK_GETDS_POLL_ENABLE, FKC_ACCCHK_GETDS_POLL_RIGHTS, ACK_GET_DS_POLL},
|
||
{FKC_ACCCHK_GET_INFO_ENABLE, FKC_ACCCHK_GET_INFO_RIGHTS, ACK_INTERNAL_INFO},
|
||
{FKC_ACCCHK_PERFMON_ENABLE, FKC_ACCCHK_PERFMON_RIGHTS, ACK_COLLECT_PERFMON_DATA},
|
||
{FKC_ACCESS_CHK_DCPROMO_ENABLE, FKC_ACCESS_CHK_DCPROMO_RIGHTS, ACK_DCPROMO}
|
||
|
||
};
|
||
|
||
|
||
|
||
//
|
||
// Used by all calls to RpcBindingSetAuthInfoEx()
|
||
//
|
||
// Version set to value indicated by docs
|
||
// Mutual authentication
|
||
// Client doesn't change credentials
|
||
// Impersonation but not delegation
|
||
//
|
||
RPC_SECURITY_QOS RpcSecurityQos = {
|
||
RPC_C_SECURITY_QOS_VERSION, // static version
|
||
RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH, // requires mutual auth
|
||
RPC_C_QOS_IDENTITY_STATIC, // client credentials don't change
|
||
RPC_C_IMP_LEVEL_IMPERSONATE // server cannot delegate
|
||
};
|
||
|
||
#define DPRINT_USER_NAME(Sev) DPrintUserName(Sev)
|
||
|
||
ULONG
|
||
RcsSubmitCommPktToRcsQueue(
|
||
IN handle_t ServerHandle,
|
||
IN PCOMM_PACKET CommPkt,
|
||
IN PWCHAR AuthClient,
|
||
IN PWCHAR AuthName,
|
||
IN DWORD AuthLevel,
|
||
IN DWORD AuthN,
|
||
IN DWORD AuthZ
|
||
);
|
||
|
||
|
||
DWORD
|
||
FrsDsIsPartnerADc(
|
||
IN PWCHAR PartnerName
|
||
);
|
||
|
||
DWORD
|
||
FrsDsVerifyPromotionParent(
|
||
IN PWCHAR ReplicaSetName,
|
||
IN PWCHAR ReplicaSetType
|
||
);
|
||
|
||
DWORD
|
||
FrsDsStartPromotionSeeding(
|
||
IN BOOL Inbound,
|
||
IN PWCHAR ReplicaSetName,
|
||
IN PWCHAR ReplicaSetType,
|
||
IN PWCHAR CxtionName,
|
||
IN PWCHAR PartnerName,
|
||
IN PWCHAR PartnerPrincName,
|
||
IN ULONG PartnerAuthLevel,
|
||
IN ULONG GuidSize,
|
||
IN UCHAR *CxtionGuid,
|
||
IN UCHAR *PartnerGuid,
|
||
OUT UCHAR *ParentGuid
|
||
);
|
||
|
||
VOID
|
||
FrsPrintRpcStats(
|
||
IN ULONG Severity,
|
||
IN PNTFRSAPI_INFO Info, OPTIONAL
|
||
IN DWORD Tabs
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Print the rpc stats into the info buffer or using DPRINT (Info == NULL).
|
||
|
||
Arguments:
|
||
Severity - for DPRINT
|
||
Info - for IPRINT (use DPRINT if NULL)
|
||
Tabs - indentation for prettyprint
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsPrintRpcStats:"
|
||
WCHAR TabW[MAX_TAB_WCHARS + 1];
|
||
|
||
InfoTabs(Tabs, TabW);
|
||
|
||
IDPRINT0(Severity, Info, "\n");
|
||
IDPRINT1(Severity, Info, ":S: %wsNTFRS RPC BINDS:\n", TabW);
|
||
IDPRINT2(Severity, Info, ":S: %ws Binds : %6d\n", TabW, RpcBinds);
|
||
IDPRINT3(Severity, Info, ":S: %ws UnBinds : %6d (%d aged)\n",
|
||
TabW, RpcUnBinds, RpcAgedBinds);
|
||
IDPRINT2(Severity, Info, ":S: %ws Max Binds : %6d\n", TabW, RpcMaxBinds);
|
||
IDPRINT0(Severity, Info, "\n");
|
||
}
|
||
|
||
|
||
|
||
PVOID
|
||
MIDL_user_allocate(
|
||
IN size_t Bytes
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Allocate memory for RPC.
|
||
XXX This should be using davidor's routines.
|
||
|
||
Arguments:
|
||
Bytes - Number of bytes to allocate.
|
||
|
||
Return Value:
|
||
NULL - memory could not be allocated.
|
||
!NULL - address of allocated memory.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "MIDL_user_allocate:"
|
||
PVOID VA;
|
||
|
||
//
|
||
// Need to check if Bytes == 0 as FrsAlloc asserts if called with 0 as the first parameter (prefix fix).
|
||
//
|
||
|
||
if (Bytes == 0) {
|
||
return NULL;
|
||
}
|
||
|
||
VA = FrsAlloc(Bytes);
|
||
return VA;
|
||
}
|
||
|
||
|
||
VOID
|
||
MIDL_user_free(
|
||
IN PVOID Buffer
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Free memory for RPC.
|
||
XXX This should be using davidor's routines.
|
||
|
||
Arguments:
|
||
Buffer - Address of memory allocated with MIDL_user_allocate().
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "MIDL_user_free:"
|
||
FrsFree(Buffer);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
VOID
|
||
DPrintUserName(
|
||
IN DWORD Sev
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Print our user name
|
||
|
||
Arguments:
|
||
Sev
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "DPrintUserName:"
|
||
WCHAR Uname[MAX_PATH + 1];
|
||
ULONG Unamesize = MAX_PATH + 1;
|
||
|
||
if (GetUserName(Uname, &Unamesize)) {
|
||
DPRINT1(Sev, "++ User name is %ws\n", Uname);
|
||
} else {
|
||
DPRINT_WS(0, "++ ERROR - Getting user name;", GetLastError());
|
||
}
|
||
}
|
||
|
||
|
||
RPC_STATUS
|
||
DummyRpcCallback (
|
||
IN RPC_IF_ID *Interface,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Dummy callback routine. By registering this routine, RPC will automatically
|
||
refuse requests from clients that don't include authentication info.
|
||
|
||
WARN: Disabled for now because frs needs to run in dcpromo environments
|
||
that do not have any form of authentication.
|
||
|
||
Arguments:
|
||
Ignored
|
||
|
||
Return Value:
|
||
RPC_S_OK
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "DummyRpcCallback:"
|
||
return RPC_S_OK;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsNOP(
|
||
handle_t Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
The frsrpc interface includes a NOP function for pinging
|
||
the server.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsNOP:"
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsRpcSendCommPkt(
|
||
handle_t Handle,
|
||
PCOMM_PACKET CommPkt
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Receiving a command packet
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
ERROR_SUCCESS - everything was okay
|
||
Anything else - the error code says it all
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsRpcSendCommPkt:"
|
||
DWORD WStatus = 0;
|
||
DWORD AuthLevel = 0;
|
||
DWORD AuthN = 0;
|
||
DWORD AuthZ = 0;
|
||
PWCHAR AuthName = NULL;
|
||
PWCHAR AuthClient = NULL;
|
||
|
||
//
|
||
// Don't send or receive during shutdown
|
||
//
|
||
if (FrsIsShuttingDown) {
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
try {
|
||
if (!CommCheckPkt(CommPkt)) {
|
||
WStatus = ERROR_NOT_SUPPORTED;
|
||
COMMAND_RCV_AUTH_TRACE(0, CommPkt, WStatus, 0, 0,
|
||
NULL, NULL, "RcvFailAuth - bad packet");
|
||
//
|
||
// Increment the Packets Received in Error Counter
|
||
//
|
||
PM_INC_CTR_SERVICE(PMTotalInst, PacketsRcvdError, 1);
|
||
goto CLEANUP;
|
||
}
|
||
|
||
if (!ServerGuid) {
|
||
WStatus = RpcBindingInqAuthClient(Handle,
|
||
&AuthClient,
|
||
&AuthName,
|
||
&AuthLevel,
|
||
&AuthN,
|
||
&AuthZ);
|
||
DPRINT_WS(4, "++ IGNORED - RpcBindingInqAuthClient;", WStatus);
|
||
|
||
COMMAND_RCV_AUTH_TRACE(4, CommPkt, WStatus, AuthLevel, AuthN,
|
||
AuthClient, AuthName, "RcvAuth");
|
||
} else {
|
||
//
|
||
// For hardwired -- Eventually DS Free configs.
|
||
//
|
||
COMMAND_RCV_AUTH_TRACE(4, CommPkt, WStatus, 0, 0,
|
||
NULL, NULL, "RcvAuth - hardwired)");
|
||
}
|
||
|
||
//
|
||
// Increment the Packets Received and
|
||
// Packets Received in bytes counters
|
||
//
|
||
PM_INC_CTR_SERVICE(PMTotalInst, PacketsRcvd, 1);
|
||
PM_INC_CTR_SERVICE(PMTotalInst, PacketsRcvdBytes, CommPkt->PktLen);
|
||
|
||
switch(CommPkt->CsId) {
|
||
|
||
case CS_RS:
|
||
|
||
WStatus = RcsSubmitCommPktToRcsQueue(Handle,
|
||
CommPkt,
|
||
AuthClient,
|
||
AuthName,
|
||
AuthLevel,
|
||
AuthN,
|
||
AuthZ);
|
||
break;
|
||
default:
|
||
WStatus = ERROR_INVALID_OPERATION;
|
||
COMMAND_RCV_AUTH_TRACE(0, CommPkt, WStatus, 0, 0,
|
||
NULL, NULL, "RcvFailAuth - bad csid");
|
||
}
|
||
|
||
CLEANUP:;
|
||
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
COMMAND_RCV_AUTH_TRACE(0, CommPkt, WStatus, 0, 0,
|
||
NULL, NULL, "RcvFailAuth - exception");
|
||
}
|
||
try {
|
||
if (AuthName) {
|
||
RpcStringFree(&AuthName);
|
||
}
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
COMMAND_RCV_AUTH_TRACE(0, CommPkt, WStatus, 0, 0,
|
||
NULL, NULL, "RcvFailAuth - cleanup exception");
|
||
}
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsEnumerateReplicaPathnames(
|
||
handle_t Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
NOT IMPLEMENTED - Enumerate the replica sets
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsEnumerateReplicaPathnames:"
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsFreeReplicaPathnames(
|
||
handle_t Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
NOT IMPLEMENTED - Just a placeholder, it won't really be part of
|
||
the RPC interface but rather a function in the client-side dll.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsFreeReplicaPathnames:"
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsPrepareForBackup(
|
||
handle_t Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
NOT IMPLEMENTED - Prepare for backup
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsPrepareForBackup:"
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsBackupComplete(
|
||
handle_t Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
NOT IMPLEMENTED - backup is complete; reset state
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsBackupComplete:"
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsPrepareForRestore(
|
||
handle_t Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
NOT IMPLEMENTED - Prepare for restore
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsPrepareForRestore:"
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsRestoreComplete(
|
||
handle_t Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
NOT IMPLEMENTED - restore is complete; reset state
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsRestoreComplete:"
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
DWORD
|
||
FrsRpcAccessChecks(
|
||
IN HANDLE ServerHandle,
|
||
IN DWORD RpcApiIndex
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
Check if the caller has access to this rpc api call.
|
||
|
||
Arguments:
|
||
|
||
ServerHandle - From the rpc runtime
|
||
|
||
RpcApiIndex - identifies key in registry
|
||
|
||
Return Value:
|
||
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcAccessChecks:"
|
||
DWORD WStatus;
|
||
PWCHAR WStr = NULL, TrimStr;
|
||
FRS_REG_KEY_CODE EnableKey, RightsKey;
|
||
|
||
DWORD ValueSize;
|
||
BOOL RequireRead;
|
||
BOOL Impersonated = FALSE;
|
||
HKEY HRpcApiKey = 0;
|
||
PWCHAR ApiName;
|
||
WCHAR ValueBuf[MAX_PATH + 1];
|
||
|
||
|
||
|
||
if (RpcApiIndex >= ACX_MAX) {
|
||
DPRINT1(0, "++ ERROR - ApiIndex out of range. (%d)\n", RpcApiIndex);
|
||
FRS_ASSERT(!"RpcApiIndexout of range");
|
||
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
|
||
EnableKey = RpcApiKeys[RpcApiIndex].Enable;
|
||
RightsKey = RpcApiKeys[RpcApiIndex].Rights;
|
||
ApiName = RpcApiKeys[RpcApiIndex].KeyName;
|
||
|
||
//
|
||
// First go fetch the enable/disable string.
|
||
//
|
||
WStatus = CfgRegReadString(EnableKey, NULL, 0, &WStr);
|
||
if (WStr == NULL) {
|
||
DPRINT1_WS(0, "++ ERROR - API Access enable check for API (%ws) failed.", ApiName, WStatus);
|
||
WStatus = ERROR_NO_TOKEN;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// If access checks are disabled then we're done.
|
||
//
|
||
TrimStr = FrsWcsTrim(WStr, L' ');
|
||
if (WSTR_EQ(TrimStr, ACCESS_CHECKS_ARE_DISABLED) ||
|
||
WSTR_EQ(TrimStr, ACCESS_CHECKS_ARE_DEFAULT_DISABLED)) {
|
||
WStatus = ERROR_SUCCESS;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
if (WSTR_NE(TrimStr, ACCESS_CHECKS_ARE_ENABLED) &&
|
||
WSTR_NE(TrimStr, ACCESS_CHECKS_ARE_DEFAULT_ENABLED)) {
|
||
DPRINT2(0, "++ ERROR - Invalid parameter API Access enable check for API (%ws) :%ws\n",
|
||
ApiName, TrimStr );
|
||
WStatus = ERROR_CANTREAD;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Fetch the access rights string that tells us if we need to check for
|
||
// read or write access.
|
||
//
|
||
WStr = FrsFree(WStr);
|
||
WStatus = CfgRegReadString(RightsKey, NULL, 0, &WStr);
|
||
if (WStr == NULL) {
|
||
DPRINT1_WS(0, "++ ERROR - API Access rights check for API (%ws) failed.", ApiName, WStatus);
|
||
WStatus = ERROR_NO_TOKEN;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
|
||
TrimStr = FrsWcsTrim(WStr, L' ');
|
||
if (WSTR_EQ(TrimStr, ACCESS_CHECKS_REQUIRE_READ) ||
|
||
WSTR_EQ(TrimStr, ACCESS_CHECKS_REQUIRE_DEFAULT_READ)) {
|
||
RequireRead = TRUE;
|
||
} else
|
||
if (WSTR_EQ(TrimStr, ACCESS_CHECKS_REQUIRE_WRITE) ||
|
||
WSTR_EQ(TrimStr, ACCESS_CHECKS_REQUIRE_DEFAULT_WRITE)) {
|
||
RequireRead = FALSE;
|
||
} else {
|
||
DPRINT2(0, "++ ERROR - Invalid parameter API Access rights check for API (%ws) :%ws\n",
|
||
ApiName, TrimStr );
|
||
WStatus = ERROR_CANTREAD;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Impersonate the caller
|
||
//
|
||
if (ServerHandle != NULL) {
|
||
WStatus = RpcImpersonateClient(ServerHandle);
|
||
CLEANUP1_WS(0, "++ ERROR - Can't impersonate caller for API Access check for API (%ws).",
|
||
ApiName, WStatus, CLEANUP);
|
||
Impersonated = TRUE;
|
||
}
|
||
|
||
//
|
||
// Open the key, with the selected access so the system can check if the
|
||
// ACL on the key (presumably set by the admin) gives this user sufficient
|
||
// rights. If the test succeeds then we allow API call to proceed.
|
||
//
|
||
WStatus = CfgRegOpenKey(RightsKey,
|
||
NULL,
|
||
(RequireRead) ? FRS_RKF_KEY_ACCCHK_READ :
|
||
FRS_RKF_KEY_ACCCHK_WRITE,
|
||
&HRpcApiKey);
|
||
|
||
CLEANUP2_WS(0, "++ ERROR - API Access check failed for API (%ws) :%ws",
|
||
ApiName, TrimStr, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Access is allowed.
|
||
//
|
||
DPRINT2(4, "++ Access Check Okay: %s access for API (%ws)\n",
|
||
(RequireRead) ? "read" : "write", ApiName);
|
||
WStatus = ERROR_SUCCESS;
|
||
|
||
|
||
CLEANUP:
|
||
|
||
if (HANDLE_IS_VALID(HRpcApiKey)) {
|
||
RegCloseKey(HRpcApiKey);
|
||
}
|
||
//
|
||
// Access checks failed, register event
|
||
//
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
WStatus = FRS_ERR_INSUFFICIENT_PRIV;
|
||
//
|
||
// Include user name if impersonation succeeded
|
||
//
|
||
if (Impersonated) {
|
||
|
||
ValueSize = MAX_PATH;
|
||
if (GetUserName(ValueBuf, &ValueSize)) {
|
||
EPRINT3(EVENT_FRS_ACCESS_CHECKS_FAILED_USER,
|
||
ApiName, ACCESS_CHECKS_ARE, ValueBuf);
|
||
} else {
|
||
EPRINT2(EVENT_FRS_ACCESS_CHECKS_FAILED_UNKNOWN,
|
||
ApiName, ACCESS_CHECKS_ARE);
|
||
}
|
||
} else {
|
||
EPRINT2(EVENT_FRS_ACCESS_CHECKS_FAILED_UNKNOWN,
|
||
ApiName, ACCESS_CHECKS_ARE);
|
||
}
|
||
}
|
||
|
||
if (Impersonated) {
|
||
RpcRevertToSelf();
|
||
}
|
||
|
||
FrsFree(WStr);
|
||
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
CheckAuth(
|
||
IN HANDLE ServerHandle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Check if the caller has the correct authentication
|
||
|
||
Arguments:
|
||
ServerHandle
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "CheckAuth:"
|
||
DWORD WStatus;
|
||
DWORD AuthLevel;
|
||
DWORD AuthN;
|
||
|
||
WStatus = RpcBindingInqAuthClient(ServerHandle, NULL, NULL, &AuthLevel,
|
||
&AuthN, NULL);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
DPRINT_WS(0, "++ ERROR - RpcBindingInqAuthClient", WStatus);
|
||
return WStatus;
|
||
}
|
||
//
|
||
// Encrypted packet
|
||
//
|
||
if (AuthLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY) {
|
||
DPRINT1(4, "++ Authlevel is %d; not RPC_C_AUTHN_LEVEL_PKT_PRIVACE\n", AuthLevel);
|
||
return ERROR_NOT_AUTHENTICATED;
|
||
}
|
||
//
|
||
// KERBEROS
|
||
//
|
||
if (AuthN != RPC_C_AUTHN_GSS_KERBEROS &&
|
||
AuthN != RPC_C_AUTHN_GSS_NEGOTIATE) {
|
||
DPRINT1(4, "++ AuthN is %d; not RPC_C_AUTHN_GSS_KERBEROS/NEGOTIATE\n", AuthN);
|
||
return ERROR_NOT_AUTHENTICATED;
|
||
}
|
||
//
|
||
// SUCCESS; RPC is authenticated, encrypted kerberos
|
||
//
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_Bind(
|
||
IN PWCHAR MachineName,
|
||
OUT PWCHAR *OutPrincName,
|
||
OUT handle_t *OutHandle,
|
||
OUT ULONG *OutParentAuthLevel
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Bind to the NtFrs service on MachineName (this machine if NULL)
|
||
using an unauthencated, un-encrypted binding.
|
||
|
||
Arguments:
|
||
MachineName - Bind to the service on this computer. The computer
|
||
name can be any RPC-bindable name. Usually, the
|
||
NetBIOS or DNS name works just fine. The NetBIOS
|
||
name can be found with GetComputerName() or
|
||
hostname. The DNS name can be found with
|
||
gethostbyname() or ipconfig /all. If NULL, the
|
||
service on this computer is contacted. The service
|
||
is contacted using Secure RPC.
|
||
|
||
OutPrincName - Principle name for MachineName
|
||
|
||
OutHandle - Bound, resolved, authenticated handle
|
||
|
||
OutParentAuthLevel - Authentication type and level
|
||
(Always CXTION_AUTH_NONE)
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_Bind:"
|
||
DWORD WStatus, WStatus1;
|
||
handle_t Handle = NULL;
|
||
PWCHAR BindingString = NULL;
|
||
|
||
try {
|
||
//
|
||
// Return value
|
||
//
|
||
*OutHandle = NULL;
|
||
*OutPrincName = NULL;
|
||
*OutParentAuthLevel = CXTION_AUTH_NONE;
|
||
|
||
//
|
||
// Create a binding string to NtFrs on some machine. Trim leading \\
|
||
//
|
||
FRS_TRIM_LEADING_2SLASH(MachineName);
|
||
|
||
WStatus = RpcStringBindingCompose(NULL, PROTSEQ_TCP_IP, MachineName,
|
||
NULL, NULL, &BindingString);
|
||
CLEANUP1_WS(0, "++ ERROR - Composing binding to %ws;",
|
||
MachineName, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Store the binding in the handle
|
||
//
|
||
WStatus = RpcBindingFromStringBinding(BindingString, &Handle);
|
||
CLEANUP1_WS(0, "++ ERROR - From binding for %ws;", MachineName, WStatus, CLEANUP);
|
||
//
|
||
// Resolve the binding to the dynamic endpoint
|
||
//
|
||
WStatus = RpcEpResolveBinding(Handle, frsrpc_ClientIfHandle);
|
||
CLEANUP1_WS(0, "++ ERROR - Resolving binding for %ws;",
|
||
MachineName, WStatus, CLEANUP);
|
||
|
||
//
|
||
// SUCCESS
|
||
//
|
||
*OutHandle = Handle;
|
||
*OutPrincName = FrsWcsDup(MachineName);
|
||
Handle = NULL;
|
||
WStatus = ERROR_SUCCESS;
|
||
DPRINT3(4, "++ NtFrsApi Bound to %ws (PrincName: %ws) Auth %d\n",
|
||
MachineName, *OutPrincName, *OutParentAuthLevel);
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Exception -", WStatus);
|
||
}
|
||
|
||
//
|
||
// Clean up any handles, events, memory, ...
|
||
//
|
||
try {
|
||
if (BindingString) {
|
||
WStatus1 = RpcStringFreeW(&BindingString);
|
||
DPRINT_WS(0, "++ WARN - RpcStringFreeW;", WStatus1);
|
||
}
|
||
if (Handle) {
|
||
WStatus1 = RpcBindingFree(&Handle);
|
||
DPRINT_WS(0, "++ WARN - RpcBindingFree;", WStatus1);
|
||
}
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Cleanup Exception.", WStatus);
|
||
}
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_BindEx(
|
||
IN PWCHAR MachineName,
|
||
OUT PWCHAR *OutPrincName,
|
||
OUT handle_t *OutHandle,
|
||
OUT ULONG *OutParentAuthLevel
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Bind to the NtFrs service on MachineName (this machine if NULL)
|
||
using an authenticated, encrypted binding.
|
||
|
||
Arguments:
|
||
MachineName - Bind to the service on this computer. The computer
|
||
name can be any RPC-bindable name. Usually, the
|
||
NetBIOS or DNS name works just fine. The NetBIOS
|
||
name can be found with GetComputerName() or
|
||
hostname. The DNS name can be found with
|
||
gethostbyname() or ipconfig /all. If NULL, the
|
||
service on this computer is contacted. The service
|
||
is contacted using Secure RPC.
|
||
|
||
OutPrincName - Principle name for MachineName
|
||
|
||
OutHandle - Bound, resolved, authenticated handle
|
||
|
||
OutParentAuthLevel - Authentication type and level
|
||
(Always CXTION_AUTH_KERBEROS_FULL)
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_BindEx:"
|
||
DWORD WStatus, WStatus1;
|
||
PWCHAR InqPrincName = NULL;
|
||
handle_t Handle = NULL;
|
||
PWCHAR PrincName = NULL;
|
||
PWCHAR BindingString = NULL;
|
||
|
||
try {
|
||
//
|
||
// Return value
|
||
//
|
||
*OutHandle = NULL;
|
||
*OutPrincName = NULL;
|
||
*OutParentAuthLevel = CXTION_AUTH_KERBEROS_FULL;
|
||
|
||
//
|
||
// Create a binding string to NtFrs on some machine. Trim leading \\
|
||
//
|
||
FRS_TRIM_LEADING_2SLASH(MachineName);
|
||
|
||
WStatus = RpcStringBindingCompose(NULL, PROTSEQ_TCP_IP, MachineName,
|
||
NULL, NULL, &BindingString);
|
||
CLEANUP1_WS(0, "++ ERROR - Composing binding to %ws;",
|
||
MachineName, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Store the binding in the handle
|
||
//
|
||
WStatus = RpcBindingFromStringBinding(BindingString, &Handle);
|
||
CLEANUP1_WS(0, "++ ERROR - From binding for %ws;", MachineName, WStatus, CLEANUP);
|
||
//
|
||
// Resolve the binding to the dynamic endpoint
|
||
//
|
||
WStatus = RpcEpResolveBinding(Handle, frsrpc_ClientIfHandle);
|
||
CLEANUP1_WS(0, "++ ERROR - Resolving binding for %ws;",
|
||
MachineName, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Find the principle name
|
||
//
|
||
WStatus = RpcMgmtInqServerPrincName(Handle,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
&InqPrincName);
|
||
CLEANUP1_WS(0, "++ ERROR - Inq PrincName for %ws;", MachineName, WStatus, CLEANUP);
|
||
|
||
PrincName = FrsWcsDup(InqPrincName);
|
||
RpcStringFree(&InqPrincName);
|
||
InqPrincName = NULL;
|
||
//
|
||
// Set authentication info
|
||
//
|
||
if (MutualAuthenticationIsEnabled) {
|
||
WStatus = RpcBindingSetAuthInfoEx(Handle,
|
||
PrincName,
|
||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
NULL,
|
||
RPC_C_AUTHZ_NONE,
|
||
&RpcSecurityQos);
|
||
DPRINT2_WS(1, "++ WARN - RpcBindingSetAuthInfoEx(%ws, %ws);",
|
||
MachineName, PrincName, WStatus);
|
||
} else {
|
||
WStatus = ERROR_NOT_SUPPORTED;
|
||
}
|
||
//
|
||
// Fall back to manual mutual authentication
|
||
//
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
WStatus = RpcBindingSetAuthInfo(Handle,
|
||
PrincName,
|
||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
NULL,
|
||
RPC_C_AUTHZ_NONE);
|
||
}
|
||
|
||
CLEANUP1_WS(0, "++ ERROR - RpcBindingSetAuthInfo(%ws);",
|
||
MachineName, WStatus, CLEANUP);
|
||
|
||
//
|
||
// SUCCESS
|
||
//
|
||
*OutHandle = Handle;
|
||
*OutPrincName = PrincName;
|
||
Handle = NULL;
|
||
PrincName = NULL;
|
||
WStatus = ERROR_SUCCESS;
|
||
DPRINT3(4, "++ NtFrsApi Bound to %ws (PrincName: %ws) Auth %d\n",
|
||
MachineName, *OutPrincName, *OutParentAuthLevel);
|
||
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ Error - Exception.", WStatus);
|
||
}
|
||
|
||
//
|
||
// Clean up any handles, events, memory, ...
|
||
//
|
||
try {
|
||
if (BindingString) {
|
||
WStatus1 = RpcStringFreeW(&BindingString);
|
||
DPRINT_WS(0, "++ WARN - RpcStringFreeW;", WStatus1);
|
||
}
|
||
if (PrincName) {
|
||
PrincName = FrsFree(PrincName);
|
||
}
|
||
if (Handle) {
|
||
WStatus1 = RpcBindingFree(&Handle);
|
||
DPRINT_WS(0, "++ WARN - RpcBindingFree;", WStatus1);
|
||
}
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ Error - Cleanup Exception.", WStatus);
|
||
}
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
GUID DummyGuid;
|
||
BOOL CommitDemotionInProgress;
|
||
DWORD
|
||
NtFrsApi_Rpc_StartDemotionW(
|
||
IN handle_t Handle,
|
||
IN PWCHAR ReplicaSetName
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Start demoting the sysvol. Basically, tombstone the replica set.
|
||
|
||
Arguments:
|
||
Handle
|
||
ReplicaSetName - Replica set name
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_StartDemotionW:"
|
||
DWORD WStatus;
|
||
PWCHAR SysVolName;
|
||
BOOL UnLockGenTable = FALSE;
|
||
BOOL DeleteFromGenTable = FALSE;
|
||
|
||
try {
|
||
//
|
||
// Display params
|
||
//
|
||
DPRINT1(0, ":S: Start Demotion: %ws\n", ReplicaSetName);
|
||
|
||
//
|
||
// Check parameters
|
||
//
|
||
if (!ReplicaSetName) {
|
||
DPRINT(0, "++ ERROR - Parameter is NULL\n");
|
||
WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
WStatus = FrsRpcAccessChecks(Handle, ACX_DCPROMO);
|
||
CLEANUP1_WS(0, "++ ERROR - FrsRpcAccessChecks(%ws);",
|
||
ReplicaSetName, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Can't promote/demote the same sysvol at the same time!
|
||
//
|
||
UnLockGenTable = TRUE;
|
||
GTabLockTable(SysVolsBeingCreated);
|
||
SysVolName = GTabLookupNoLock(SysVolsBeingCreated, &DummyGuid, ReplicaSetName);
|
||
|
||
if (SysVolName) {
|
||
DPRINT1(0, "++ ERROR - Promoting/Demoting %ws twice\n", ReplicaSetName);
|
||
WStatus = FRS_ERR_SYSVOL_IS_BUSY;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
if (CommitDemotionInProgress) {
|
||
DPRINT(0, "++ ERROR - Commit demotion in progress.\n");
|
||
WStatus = FRS_ERR_SYSVOL_IS_BUSY;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
DeleteFromGenTable = TRUE;
|
||
GTabInsertEntryNoLock(SysVolsBeingCreated,
|
||
ReplicaSetName,
|
||
&DummyGuid,
|
||
ReplicaSetName);
|
||
UnLockGenTable = FALSE;
|
||
GTabUnLockTable(SysVolsBeingCreated);
|
||
|
||
//
|
||
// Delete the replica set
|
||
//
|
||
WStatus = FrsDsStartDemotion(ReplicaSetName);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
DPRINT_WS(0, "++ ERROR - demoting;", WStatus);
|
||
WStatus = FRS_ERR_SYSVOL_DEMOTE;
|
||
goto CLEANUP;
|
||
}
|
||
//
|
||
// SUCCESS
|
||
//
|
||
WStatus = ERROR_SUCCESS;
|
||
DPRINT2(0, ":S: Success demoting %ws from %ws\n", ReplicaSetName, ComputerName);
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Exception.", WStatus);
|
||
}
|
||
try {
|
||
if (UnLockGenTable) {
|
||
GTabUnLockTable(SysVolsBeingCreated);
|
||
}
|
||
if (DeleteFromGenTable) {
|
||
GTabDelete(SysVolsBeingCreated, &DummyGuid, ReplicaSetName, NULL);
|
||
}
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Cleanup Exception.", WStatus);
|
||
}
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_CommitDemotionW(
|
||
IN handle_t Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
The sysvols have been demoted. Mark them as "do not animate."
|
||
|
||
Arguments:
|
||
Handle
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_CommitDemotionW:"
|
||
DWORD WStatus;
|
||
PWCHAR SysVolName;
|
||
PVOID Key;
|
||
BOOL UnLockGenTable = FALSE;
|
||
|
||
try {
|
||
//
|
||
// Display params
|
||
//
|
||
DPRINT(0, ":S: Commit Demotion:\n");
|
||
|
||
WStatus = FrsRpcAccessChecks(Handle, ACX_DCPROMO);
|
||
CLEANUP_WS(0, "++ ERROR - FrsRpcAccessChecks();", WStatus, CLEANUP);
|
||
|
||
//
|
||
// Can't promote/demote the same sysvol at the same time!
|
||
//
|
||
Key = NULL;
|
||
UnLockGenTable = TRUE;
|
||
GTabLockTable(SysVolsBeingCreated);
|
||
SysVolName = GTabNextDatumNoLock(SysVolsBeingCreated, &Key);
|
||
if (SysVolName) {
|
||
DPRINT(0, "++ ERROR - Promoting/Demoting during commit\n");
|
||
WStatus = FRS_ERR_SYSVOL_IS_BUSY;
|
||
goto CLEANUP;
|
||
}
|
||
CommitDemotionInProgress = TRUE;
|
||
UnLockGenTable = FALSE;
|
||
GTabUnLockTable(SysVolsBeingCreated);
|
||
|
||
//
|
||
// Create the replica set
|
||
//
|
||
WStatus = FrsDsCommitDemotion();
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
DPRINT_WS(0, "++ ERROR - Commit demotion;", WStatus);
|
||
WStatus = FRS_ERR_SYSVOL_DEMOTE;
|
||
goto CLEANUP;
|
||
}
|
||
//
|
||
// SUCCESS
|
||
//
|
||
WStatus = ERROR_SUCCESS;
|
||
DPRINT1(0, ":S: Success commit demotion on %ws.\n", ComputerName);
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Exception.", WStatus);
|
||
}
|
||
try {
|
||
CommitDemotionInProgress = FALSE;
|
||
if (UnLockGenTable) {
|
||
GTabUnLockTable(SysVolsBeingCreated);
|
||
}
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Cleanup Exception.", WStatus);
|
||
}
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsRpcVerifyPromotionParent(
|
||
IN handle_t Handle,
|
||
IN PWCHAR ParentAccount,
|
||
IN PWCHAR ParentPassword,
|
||
IN PWCHAR ReplicaSetName,
|
||
IN PWCHAR ReplicaSetType,
|
||
IN ULONG ParentAuthLevel,
|
||
IN ULONG GuidSize
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
OBSOLETE API
|
||
|
||
Verify the account on the parent computer. The parent computer
|
||
supplies the initial copy of the indicated sysvol.
|
||
|
||
Arguments:
|
||
Handle
|
||
ParentAccount - Valid account on ParentComputer
|
||
ParentPassword - Valid password for ParentAccount
|
||
ReplicaSetName - Replica set name
|
||
ReplicaSetType - Replica set type
|
||
ParentAuthLevel - Authentication type and level
|
||
GuidSize - sizeof(GUID)
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsRpcVerifyPromotionParent:"
|
||
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsRpcVerifyPromotionParentEx(
|
||
IN handle_t Handle,
|
||
IN PWCHAR ParentAccount,
|
||
IN PWCHAR ParentPassword,
|
||
IN PWCHAR ReplicaSetName,
|
||
IN PWCHAR ReplicaSetType,
|
||
IN PWCHAR CxtionName,
|
||
IN PWCHAR PartnerName,
|
||
IN PWCHAR PartnerPrincName,
|
||
IN PWCHAR ParentPrincName,
|
||
IN ULONG PartnerAuthLevel,
|
||
IN ULONG GuidSize
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
OBSOLETE API
|
||
|
||
Verify as much of the comm paths and parameters as possible so
|
||
that dcpromo fails early.
|
||
|
||
Arguments:
|
||
Handle
|
||
ParentAccount - Valid account on ParentComputer
|
||
ParentPassword - Valid password for ParentAccount
|
||
ReplicaSetName - Replica set name
|
||
ReplicaSetType - Replica set type
|
||
CxtionName - printable name for cxtion
|
||
PartnerName - RPC bindable name
|
||
PartnerPrincName - Server principle name for kerberos
|
||
ParentPrincName - Principle name used to bind to this computer
|
||
PartnerAuthLevel - Authentication type and level
|
||
GuidSize - sizeof array addressed by Guid
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsRpcVerifyPromotionParentEx:"
|
||
DWORD WStatus, WStatus1;
|
||
GNAME GName;
|
||
handle_t PartnerHandle = NULL;
|
||
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
|
||
DWORD
|
||
LOCAL_FrsRpcVerifyPromotionParent(
|
||
IN handle_t Handle,
|
||
IN PWCHAR ParentAccount,
|
||
IN PWCHAR ParentPassword,
|
||
IN PWCHAR ReplicaSetName,
|
||
IN PWCHAR ReplicaSetType,
|
||
IN ULONG ParentAuthLevel,
|
||
IN ULONG GuidSize
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Verify the account on the parent computer. The parent computer
|
||
supplies the initial copy of the indicated sysvol.
|
||
|
||
Arguments:
|
||
Handle
|
||
ParentAccount - Valid account on ParentComputer
|
||
ParentPassword - Valid password for ParentAccount
|
||
ReplicaSetName - Replica set name
|
||
ReplicaSetType - Replica set type
|
||
ParentAuthLevel - Authentication type and level
|
||
GuidSize - sizeof(GUID)
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "LOCAL_FrsRpcVerifyPromotionParent:"
|
||
DWORD WStatus;
|
||
|
||
try {
|
||
//
|
||
// Display params
|
||
//
|
||
DPRINT(0, ":S: SERVER Verify Promotion Parent:\n");
|
||
DPRINT1(0, ":S: \tAccount : %ws\n", ParentAccount);
|
||
DPRINT1(0, ":S: \tSetName : %ws\n", ReplicaSetName);
|
||
DPRINT1(0, ":S: \tSetType : %ws\n", ReplicaSetType);
|
||
DPRINT1(0, ":S: \tAuthLevel: %d\n", ParentAuthLevel);
|
||
|
||
//
|
||
// Check Authentication
|
||
//
|
||
if (ParentAuthLevel == CXTION_AUTH_KERBEROS_FULL) {
|
||
//
|
||
// Parent must be a DC
|
||
//
|
||
if (!IsADc) {
|
||
DPRINT(0, "++ ERROR - Parent is not a DC\n");
|
||
goto ERR_PARENT_AUTHENTICATION;
|
||
}
|
||
|
||
//
|
||
// Must be encrypted
|
||
//
|
||
WStatus = CheckAuth(Handle);
|
||
CLEANUP_WS(0, "++ ERROR - auth;", WStatus, ERR_PARENT_AUTHENTICATION);
|
||
|
||
} else {
|
||
goto ERR_INVALID_SERVICE_PARAMETER;
|
||
}
|
||
//
|
||
// Guid
|
||
//
|
||
if (GuidSize != sizeof(GUID)) {
|
||
DPRINT3(0, "++ ERROR - %ws: GuidSize is %d, not %d\n",
|
||
ReplicaSetName, GuidSize, sizeof(GUID));
|
||
goto ERR_INVALID_SERVICE_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Check parameters
|
||
//
|
||
if (!ReplicaSetName || !ReplicaSetType) {
|
||
DPRINT(0, "++ ERROR - Parameter is NULL\n");
|
||
goto ERR_INVALID_SERVICE_PARAMETER;
|
||
}
|
||
if (_wcsicmp(ReplicaSetType, NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE) &&
|
||
_wcsicmp(ReplicaSetType, NTFRSAPI_REPLICA_SET_TYPE_DOMAIN)) {
|
||
DPRINT1(0, "++ ERROR - ReplicaSetType is %ws\n", ReplicaSetType);
|
||
goto ERR_INVALID_SERVICE_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Verify the replica set
|
||
//
|
||
WStatus = FrsDsVerifyPromotionParent(ReplicaSetName, ReplicaSetType);
|
||
CLEANUP2_WS(0, "++ ERROR - verifying set %ws on parent %ws;",
|
||
ReplicaSetName, ComputerName, WStatus, ERR_SYSVOL_POPULATE);
|
||
|
||
//
|
||
// SUCCESS
|
||
//
|
||
DPRINT3(0, ":S: Success Verifying promotion parent %ws %ws %ws\n",
|
||
ParentAccount, ReplicaSetName, ReplicaSetType);
|
||
WStatus = ERROR_SUCCESS;
|
||
goto CLEANUP;
|
||
|
||
|
||
ERR_INVALID_SERVICE_PARAMETER:
|
||
WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
|
||
goto CLEANUP;
|
||
|
||
ERR_PARENT_AUTHENTICATION:
|
||
WStatus = FRS_ERR_PARENT_AUTHENTICATION;
|
||
goto CLEANUP;
|
||
|
||
ERR_SYSVOL_POPULATE:
|
||
WStatus = FRS_ERR_SYSVOL_POPULATE;
|
||
|
||
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Exception.", WStatus);
|
||
}
|
||
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
SERVER_FrsRpcStartPromotionParent(
|
||
IN handle_t Handle,
|
||
IN PWCHAR ParentAccount,
|
||
IN PWCHAR ParentPassword,
|
||
IN PWCHAR ReplicaSetName,
|
||
IN PWCHAR ReplicaSetType,
|
||
IN PWCHAR CxtionName,
|
||
IN PWCHAR PartnerName,
|
||
IN PWCHAR PartnerPrincName,
|
||
IN ULONG PartnerAuthLevel,
|
||
IN ULONG GuidSize,
|
||
IN UCHAR *CxtionGuid,
|
||
IN UCHAR *PartnerGuid,
|
||
OUT UCHAR *ParentGuid
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
|
||
Setup a volatile cxtion on the parent for seeding the indicated
|
||
sysvol on the caller.
|
||
|
||
Arguments:
|
||
Handle
|
||
ParentAccount - Valid account on ParentComputer
|
||
ParentPassword - Valid password for ParentAccount
|
||
ReplicaSetName - Replica set name
|
||
ReplicaSetType - Replica set type
|
||
CxtionName - printable name for cxtion
|
||
PartnerName - RPC bindable name
|
||
PartnerPrincName - Server principle name for kerberos
|
||
PartnerAuthLevel - Authentication type and level
|
||
GuidSize - sizeof array addressed by Guid
|
||
CxtionGuid - temporary: used for volatile cxtion
|
||
PartnerGuid - temporary: used to find set on partner
|
||
ParentGuid - Used as partner guid on inbound cxtion
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "SERVER_FrsRpcStartPromotionParent:"
|
||
DWORD WStatus;
|
||
try {
|
||
//
|
||
// Display params
|
||
//
|
||
DPRINT(0, ":S: SERVER Start Promotion Parent:\n");
|
||
DPRINT1(0, ":S: \tPartner : %ws\n", PartnerName);
|
||
DPRINT1(0, ":S: \tPartnerPrinc : %ws\n", PartnerPrincName);
|
||
DPRINT1(0, ":S: \tAuthLevel : %d\n", PartnerAuthLevel);
|
||
DPRINT1(0, ":S: \tAccount : %ws\n", ParentAccount);
|
||
DPRINT1(0, ":S: \tSetName : %ws\n", ReplicaSetName);
|
||
DPRINT1(0, ":S: \tSetType : %ws\n", ReplicaSetType);
|
||
DPRINT1(0, ":S: \tCxtionName : %ws\n", CxtionName);
|
||
|
||
//
|
||
// Verify parameters
|
||
//
|
||
WStatus = LOCAL_FrsRpcVerifyPromotionParent(Handle,
|
||
ParentAccount,
|
||
ParentPassword,
|
||
ReplicaSetName,
|
||
ReplicaSetType,
|
||
PartnerAuthLevel,
|
||
GuidSize);
|
||
CLEANUP_WS(0, "++ ERROR - verify;", WStatus, CLEANUP);
|
||
|
||
//
|
||
// Check Authentication
|
||
//
|
||
if (PartnerAuthLevel == CXTION_AUTH_KERBEROS_FULL) {
|
||
//
|
||
// Parent must be a DC
|
||
//
|
||
if (!IsADc) {
|
||
DPRINT(0, "++ ERROR - Parent is not a DC\n");
|
||
WStatus = ERROR_NO_SUCH_DOMAIN;
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// Our partner's computer object (or user object) should
|
||
// have the "I am a DC" flag set.
|
||
//
|
||
if (!FrsDsIsPartnerADc(PartnerName)) {
|
||
DPRINT(0, "++ ERROR - Partner is not a DC\n");
|
||
WStatus = ERROR_TRUSTED_DOMAIN_FAILURE;
|
||
goto CLEANUP;
|
||
}
|
||
} else {
|
||
WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
|
||
goto CLEANUP;
|
||
}
|
||
//
|
||
// Setup the outbound cxtion
|
||
//
|
||
WStatus = FrsDsStartPromotionSeeding(FALSE,
|
||
ReplicaSetName,
|
||
ReplicaSetType,
|
||
CxtionName,
|
||
PartnerName,
|
||
PartnerPrincName,
|
||
PartnerAuthLevel,
|
||
GuidSize,
|
||
CxtionGuid,
|
||
PartnerGuid,
|
||
ParentGuid);
|
||
CLEANUP_WS(0, "++ ERROR - ds start;", WStatus, CLEANUP);
|
||
|
||
//
|
||
// SUCCESS
|
||
//
|
||
DPRINT3(0, ":S: Success starting promotion parent %ws %ws %ws\n",
|
||
ParentAccount, ReplicaSetName, ReplicaSetType);
|
||
WStatus = ERROR_SUCCESS;
|
||
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// Exception (may be RPC)
|
||
//
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Exception.", WStatus);
|
||
}
|
||
|
||
return WStatus;
|
||
|
||
}
|
||
|
||
|
||
BOOL
|
||
IsFacilityFrs(
|
||
IN DWORD WStatus
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Is this an FRS specific error status
|
||
|
||
Arguments:
|
||
WStatus - Win32 Error Status
|
||
|
||
Return Value:
|
||
TRUE - Is an FRS specific error status
|
||
FALSE -
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "IsFacilityFrs:"
|
||
// TODO: replace these constants with symbollic values from winerror.h
|
||
return ( (WStatus >= 8000) && (WStatus < 8200) );
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_StartPromotionW(
|
||
IN handle_t Handle,
|
||
IN PWCHAR ParentComputer,
|
||
IN PWCHAR ParentAccount,
|
||
IN PWCHAR ParentPassword,
|
||
IN PWCHAR ReplicaSetName,
|
||
IN PWCHAR ReplicaSetType,
|
||
IN ULONG ReplicaSetPrimary,
|
||
IN PWCHAR ReplicaSetStage,
|
||
IN PWCHAR ReplicaSetRoot
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
OBSOLETE API
|
||
|
||
Start the promotion process by seeding the indicated sysvol.
|
||
|
||
Arguments:
|
||
Handle
|
||
ParentComputer - DNS or NetBIOS name of the parent supplying the sysvol
|
||
ParentAccount - Valid account on ParentComputer
|
||
ParentPassword - Valid password for ParentAccount
|
||
ReplicaSetName - Replica set name
|
||
ReplicaSetType - Type of set (Enterprise or Domain)
|
||
ReplicaSetPrimary - 1=Primary; 0=not
|
||
ReplicaSetStage - Staging path
|
||
ReplicaSetRoot - Root path
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_StartPromotionW:"
|
||
DWORD WStatus, WStatus1;
|
||
GUID PlaceHolderGuid;
|
||
GUID ParentGuid;
|
||
PWCHAR SysVolName;
|
||
ULONG ParentAuthLevel;
|
||
PWCHAR ParentPrincName = NULL;
|
||
handle_t ParentHandle = NULL;
|
||
BOOL DeleteFromGenTable = FALSE;
|
||
BOOL UnLockGenTable = FALSE;
|
||
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_VerifyPromotionW(
|
||
IN handle_t Handle,
|
||
IN PWCHAR ParentComputer,
|
||
IN PWCHAR ParentAccount,
|
||
IN PWCHAR ParentPassword,
|
||
IN PWCHAR ReplicaSetName,
|
||
IN PWCHAR ReplicaSetType,
|
||
IN ULONG ReplicaSetPrimary,
|
||
IN PWCHAR ReplicaSetStage,
|
||
IN PWCHAR ReplicaSetRoot
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
OBSOLETE API
|
||
|
||
Verify that sysvol promotion is likely.
|
||
|
||
Arguments:
|
||
Handle
|
||
ParentComputer - DNS or NetBIOS name of the parent supplying the sysvol
|
||
ParentAccount - Valid account on ParentComputer
|
||
ParentPassword - Valid password for ParentAccount
|
||
ReplicaSetName - Replica set name
|
||
ReplicaSetType - Type of set (Enterprise or Domain)
|
||
ReplicaSetPrimary - 1=Primary; 0=not
|
||
ReplicaSetStage - Staging path
|
||
ReplicaSetRoot - Root path
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_VerifyPromotionW:"
|
||
DWORD WStatus, WStatus1;
|
||
ULONG ParentAuthLevel;
|
||
PWCHAR ParentPrincName = NULL;
|
||
handle_t ParentHandle = NULL;
|
||
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_PromotionStatusW(
|
||
IN handle_t Handle,
|
||
IN PWCHAR ReplicaSetName,
|
||
OUT ULONG *ServiceState,
|
||
OUT ULONG *ServiceWStatus,
|
||
OUT PWCHAR *ServiceDisplay OPTIONAL
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
OBSOLETE API
|
||
|
||
Status of the seeding of the indicated sysvol
|
||
|
||
Arguments:
|
||
Handle
|
||
ReplicaSetName - Replica set name
|
||
ServiceState - State of the service
|
||
ServiceWStatus - Win32 Status if state is NTFRSAPI_SERVICE_ERROR
|
||
ServiceDisplay - Display string if state is NTFRSAPI_SERVICE_PROMOTING
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_PromotionStatusW:"
|
||
DWORD WStatus;
|
||
PREPLICA Replica;
|
||
|
||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_Get_DsPollingIntervalW(
|
||
IN handle_t Handle,
|
||
OUT ULONG *Interval,
|
||
OUT ULONG *LongInterval,
|
||
OUT ULONG *ShortInterval
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Get the current polling intervals in minutes.
|
||
|
||
Arguments:
|
||
Handle
|
||
Interval - Current interval in minutes
|
||
LongInterval - Long interval in minutes
|
||
ShortInterval - Short interval in minutes
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_Get_DsPollingIntervalW"
|
||
DWORD WStatus;
|
||
|
||
try {
|
||
WStatus = FrsRpcAccessChecks(Handle, ACX_GET_DS_POLL);
|
||
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
WStatus = FrsDsGetDsPollingInterval(Interval, LongInterval, ShortInterval);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
//
|
||
// SUCCESS
|
||
//
|
||
WStatus = ERROR_SUCCESS;
|
||
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Exception.", WStatus);
|
||
}
|
||
//
|
||
// Cleanup memory, handles, ...
|
||
//
|
||
try {
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Cleanup Exception.", WStatus);
|
||
}
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_Set_DsPollingIntervalW(
|
||
IN handle_t Handle,
|
||
IN ULONG UseShortInterval,
|
||
IN ULONG LongInterval,
|
||
IN ULONG ShortInterval
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Adjust the polling interval and kick off a new polling cycle.
|
||
The kick is ignored if a polling cycle is in progress.
|
||
The intervals are given in minutes.
|
||
|
||
Arguments:
|
||
Handle
|
||
UseShortInterval - If non-zero, use short interval. Otherwise, long.
|
||
LongInterval - Long interval in minutes
|
||
ShortInterval - Short interval in minutes
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_Set_DsPollingIntervalW"
|
||
DWORD WStatus;
|
||
|
||
try {
|
||
WStatus = FrsRpcAccessChecks(Handle,
|
||
(!LongInterval && !ShortInterval) ?
|
||
ACX_START_DS_POLL:
|
||
ACX_SET_DS_POLL);
|
||
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
WStatus = FrsDsSetDsPollingInterval(UseShortInterval,
|
||
LongInterval,
|
||
ShortInterval);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
goto CLEANUP;
|
||
}
|
||
//
|
||
// SUCCESS
|
||
//
|
||
WStatus = ERROR_SUCCESS;
|
||
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Exception.", WStatus);
|
||
}
|
||
//
|
||
// Cleanup memory, handles, ...
|
||
//
|
||
try {
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Cleanup Exception.", WStatus);
|
||
}
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NtFrsApi_Rpc_InfoW(
|
||
IN handle_t Handle,
|
||
IN ULONG BlobSize,
|
||
IN OUT PBYTE Blob
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Return internal info (see private\net\inc\ntfrsapi.h).
|
||
|
||
Arguments:
|
||
Handle
|
||
BlobSize - total bytes of Blob
|
||
Blob - details desired info and provides buffer for info
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "NtFrsApi_Rpc_InfoW:"
|
||
DWORD WStatus;
|
||
|
||
try {
|
||
WStatus = FrsRpcAccessChecks(Handle, ACX_INTERNAL_INFO);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
goto CLEANUP;
|
||
}
|
||
|
||
WStatus = Info(BlobSize, Blob);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
goto CLEANUP;
|
||
}
|
||
//
|
||
// SUCCESS
|
||
//
|
||
WStatus = ERROR_SUCCESS;
|
||
|
||
CLEANUP:;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Exception.", WStatus);
|
||
}
|
||
//
|
||
// Cleanup memory, handles, ...
|
||
//
|
||
try {
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
GET_EXCEPTION_CODE(WStatus);
|
||
DPRINT_WS(0, "++ ERROR - Cleanup Exception.", WStatus);
|
||
}
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
VOID
|
||
RegisterRpcProtseqs(
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Register the RPC protocol sequences and the authentication
|
||
that FRS supports. Currently, this is only TCP/IP authenticated
|
||
with kerberos.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "RegisterRpcProtseqs:"
|
||
DWORD WStatus;
|
||
RPC_STATUS Status;
|
||
PWCHAR InqPrincName = NULL;
|
||
|
||
//
|
||
// Register TCP/IP Protocol Sequence
|
||
//
|
||
Status = RpcServerUseProtseq(PROTSEQ_TCP_IP, MaxRpcServerThreads, NULL);
|
||
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT1_WS(0, "++ ERROR - RpcServerUseProtSeq(%ws);", PROTSEQ_TCP_IP, Status);
|
||
FrsRaiseException(FRS_ERROR_PROTSEQ, Status);
|
||
}
|
||
|
||
//
|
||
// Register named pipe Protocol Sequence
|
||
//
|
||
Status = RpcServerUseProtseq(PROTSEQ_NAMED_PIPE, MaxRpcServerThreads, NULL);
|
||
|
||
DPRINT1_WS(0, "++ WARN - RpcServerUseProtSeq(%ws);", PROTSEQ_NAMED_PIPE, Status);
|
||
|
||
//
|
||
// For hardwired -- Eventually DS Free configs.
|
||
// Don't bother with kerberos if emulating multiple machines
|
||
//
|
||
if (ServerGuid) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Get our principle name
|
||
//
|
||
if (ServerPrincName) {
|
||
ServerPrincName = FrsFree(ServerPrincName);
|
||
}
|
||
Status = RpcServerInqDefaultPrincName(RPC_C_AUTHN_GSS_NEGOTIATE, &InqPrincName);
|
||
DPRINT1_WS(4, ":S: RpcServerInqDefaultPrincname(%d);", RPC_C_AUTHN_GSS_NEGOTIATE, Status);
|
||
|
||
//
|
||
// No principle name; KERBEROS may not be available
|
||
//
|
||
if (!RPC_SUCCESS(Status)) {
|
||
//
|
||
// Don't use any authentication if this server is not part of a domain.
|
||
//
|
||
DSROLE_PRIMARY_DOMAIN_INFO_BASIC *DsRole;
|
||
|
||
//
|
||
// Is this a member server?
|
||
//
|
||
WStatus = DsRoleGetPrimaryDomainInformation(NULL,
|
||
DsRolePrimaryDomainInfoBasic,
|
||
(PBYTE *)&DsRole);
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
DPRINT_WS(0, "++ ERROR - Can't get Ds role info;", WStatus);
|
||
FrsRaiseException(FRS_ERROR_PROTSEQ, Status);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Standalone server; ignore authentication for now
|
||
// Hmmm, it seems we become a member server early
|
||
// in the dcpromo process. Oh, well...
|
||
//
|
||
// Hmmm, it seems that a NT4 to NT5 PDC doesn't
|
||
// have kerberos during dcpromo. This is getting
|
||
// old...
|
||
//
|
||
// if (DsRole->MachineRole == DsRole_RoleStandaloneServer ||
|
||
// DsRole->MachineRole == DsRole_RoleMemberServer) {
|
||
DsRoleFreeMemory(DsRole);
|
||
ServerPrincName = FrsWcsDup(ComputerName);
|
||
KerberosIsNotAvailable = TRUE;
|
||
DPRINT(0, ":S: WARN - KERBEROS IS NOT ENABLED!\n");
|
||
DPRINT1(4, ":S: Server Principal Name (no kerberos) is %ws\n",
|
||
ServerPrincName);
|
||
return;
|
||
// }
|
||
DsRoleFreeMemory(DsRole);
|
||
DPRINT1_WS(0, ":S: ERROR - RpcServerInqDefaultPrincName(%ws) failed;", ComputerName, Status);
|
||
FrsRaiseException(FRS_ERROR_PROTSEQ, Status);
|
||
} else {
|
||
DPRINT2(4, ":S: RpcServerInqDefaultPrincname(%d, %ws) success\n",
|
||
RPC_C_AUTHN_GSS_NEGOTIATE, InqPrincName);
|
||
|
||
ServerPrincName = FrsWcsDup(InqPrincName);
|
||
RpcStringFree(&InqPrincName);
|
||
InqPrincName = NULL;
|
||
}
|
||
//
|
||
// Register with the KERBEROS authentication service
|
||
//
|
||
//
|
||
// Enable GSS_KERBEROS for pre-Beta3 compatability. When can we remove??
|
||
//
|
||
KerberosIsNotAvailable = FALSE;
|
||
DPRINT1(4, ":S: Server Principal Name is %ws\n", ServerPrincName);
|
||
Status = RpcServerRegisterAuthInfo(ServerPrincName,
|
||
RPC_C_AUTHN_GSS_KERBEROS,
|
||
NULL,
|
||
NULL);
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT1_WS(0, "++ ERROR - RpcServerRegisterAuthInfo(KERBEROS, %ws) failed;",
|
||
ComputerName, Status);
|
||
FrsRaiseException(FRS_ERROR_PROTSEQ, Status);
|
||
} else {
|
||
DPRINT2(4, ":S: RpcServerRegisterAuthInfo(%ws, %d) success\n",
|
||
ServerPrincName, RPC_C_AUTHN_GSS_KERBEROS);
|
||
}
|
||
|
||
//
|
||
// Enable GSS_NEGOTIATE for future usage
|
||
//
|
||
Status = RpcServerRegisterAuthInfo(ServerPrincName,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
NULL,
|
||
NULL);
|
||
DPRINT2_WS(4, ":S: RpcServerRegisterAuthInfo(%ws, %d);",
|
||
ServerPrincName, RPC_C_AUTHN_GSS_NEGOTIATE, Status);
|
||
|
||
DPRINT1_WS(0, "++ WARN - RpcServerRegisterAuthInfo(NEGOTIATE, %ws) failed;",
|
||
ComputerName, Status);
|
||
}
|
||
|
||
|
||
VOID
|
||
RegisterRpcInterface(
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Register the frsrpc interface for the RPC protocol sequences
|
||
previously registered.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "RegisterRpcInterface:"
|
||
RPC_STATUS Status;
|
||
|
||
//
|
||
// Service RPC
|
||
//
|
||
Status = RpcServerRegisterIfEx(SERVER_frsrpc_ServerIfHandle,
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
MaxRpcServerThreads,
|
||
NULL);
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT_WS(0, "++ ERROR - Can't register NtFrs Service;", Status);
|
||
FrsRaiseException(FRS_ERROR_REGISTERIF, Status);
|
||
}
|
||
|
||
//
|
||
// API RPC
|
||
//
|
||
Status = RpcServerRegisterIfEx(NtFrsApi_ServerIfHandle,
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
MaxRpcServerThreads,
|
||
NULL);
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT_WS(0, "++ ERROR - Can't register NtFrs API;", Status);
|
||
FrsRaiseException(FRS_ERROR_REGISTERIF, Status);
|
||
}
|
||
|
||
if (HANDLE_IS_VALID(PerfmonProcessSemaphore)) {
|
||
//
|
||
// PERFMON RPC
|
||
//
|
||
Status = RpcServerRegisterIfEx(PerfFrs_ServerIfHandle,
|
||
NULL,
|
||
NULL,
|
||
0,
|
||
MaxRpcServerThreads,
|
||
NULL);
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT_WS(0, "++ ERROR - Can't register PERFMON SERVICE;", Status);
|
||
FrsRaiseException(FRS_ERROR_REGISTERIF, Status);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
StartServerRpc(
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Register the endpoints for each of the protocol sequences that
|
||
the frsrpc interface supports and then listen for client requests.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "StartServerRpc:"
|
||
RPC_STATUS Status, Status1;
|
||
UUID_VECTOR Uuids;
|
||
UUID_VECTOR *pUuids = NULL;
|
||
RPC_BINDING_VECTOR *BindingVector = NULL;
|
||
|
||
//
|
||
// The protocol sequences that frsrpc is registered for
|
||
//
|
||
Status = RpcServerInqBindings(&BindingVector);
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT_WS(0, "++ ERROR - Can't get binding vector;", Status);
|
||
FrsRaiseException(FRS_ERROR_INQ_BINDINGS, Status);
|
||
}
|
||
|
||
//
|
||
// Register endpoints with the endpoint mapper (RPCSS)
|
||
//
|
||
if (ServerGuid) {
|
||
//
|
||
// For hardwired -- Eventually DS Free configs.
|
||
//
|
||
Uuids.Count = 1;
|
||
Uuids.Uuid[0] = ServerGuid;
|
||
pUuids = &Uuids;
|
||
}
|
||
|
||
//
|
||
// Service RPC
|
||
//
|
||
Status = RpcEpRegister(SERVER_frsrpc_ServerIfHandle,
|
||
BindingVector,
|
||
pUuids,
|
||
L"NtFrs Service");
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT_WS(0, "++ ERROR - Can't register NtFrs Service Ep;", Status);
|
||
FrsRaiseException(FRS_ERROR_REGISTEREP, Status);
|
||
}
|
||
|
||
//
|
||
// API RPC
|
||
//
|
||
Status = RpcEpRegister(NtFrsApi_ServerIfHandle,
|
||
BindingVector,
|
||
NULL,
|
||
L"NtFrs API");
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT_WS(0, "++ ERROR - Can't register NtFrs API Ep;", Status);
|
||
FrsRaiseException(FRS_ERROR_REGISTEREP, Status);
|
||
}
|
||
|
||
if (HANDLE_IS_VALID(PerfmonProcessSemaphore)) {
|
||
//
|
||
// PERFMON RPC
|
||
//
|
||
Status = RpcEpRegister(PerfFrs_ServerIfHandle,
|
||
BindingVector,
|
||
NULL,
|
||
L"PERFMON SERVICE");
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT1(0, "++ ERROR - Can't register PERFMON SERVICE Ep; RStatus %d\n",
|
||
Status);
|
||
FrsRaiseException(FRS_ERROR_REGISTEREP, Status);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Listen for client requests
|
||
//
|
||
Status = RpcServerListen(1, MaxRpcServerThreads, TRUE);
|
||
if (!RPC_SUCCESS(Status)) {
|
||
DPRINT_WS(0, "++ ERROR - Can't listen;", Status);
|
||
FrsRaiseException(FRS_ERROR_LISTEN, Status);
|
||
}
|
||
|
||
Status1 = RpcBindingVectorFree(&BindingVector);
|
||
DPRINT_WS(0, "++ WARN - RpcBindingVectorFree;", Status1);
|
||
}
|
||
|
||
|
||
PWCHAR
|
||
FrsRpcDns2Machine(
|
||
IN PWCHAR DnsName
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Convert a DNS name(machine....) into a computer name.
|
||
|
||
Arguments:
|
||
DnsName
|
||
|
||
Return Value:
|
||
Computer name
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcDns2Machine:"
|
||
PWCHAR Machine;
|
||
ULONG Period;
|
||
|
||
//
|
||
// Find the period
|
||
//
|
||
if (DnsName) {
|
||
Period = wcscspn(DnsName, L".");
|
||
} else {
|
||
return FrsWcsDup(DnsName);
|
||
}
|
||
if (DnsName[Period] != L'.') {
|
||
return FrsWcsDup(DnsName);
|
||
}
|
||
|
||
Machine = FrsAlloc((Period + 1) * sizeof(WCHAR));
|
||
CopyMemory(Machine, DnsName, Period * sizeof(WCHAR));
|
||
Machine[Period] = L'\0';
|
||
|
||
DPRINT2(4, ":S: Dns %ws to Machine %ws\n", DnsName, Machine);
|
||
|
||
return Machine;
|
||
}
|
||
|
||
|
||
DWORD
|
||
FrsRpcBindToServerGuid(
|
||
IN PGNAME Name,
|
||
OUT handle_t *Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Set up the bindings to our inbound/outbound partner.
|
||
|
||
Arguments:
|
||
Name
|
||
Handle
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcBindToServerGuid:"
|
||
DWORD WStatus;
|
||
LONG DeltaBinds;
|
||
PWCHAR GuidStr = NULL;
|
||
PWCHAR BindingString = NULL;
|
||
PWCHAR MachineName;
|
||
|
||
FRS_ASSERT(RPC_S_OK == ERROR_SUCCESS);
|
||
FRS_ASSERT(ServerGuid);
|
||
|
||
//
|
||
// Emulating multiple machines with hardwired config
|
||
//
|
||
if (Name->Guid != NULL) {
|
||
WStatus = UuidToString(Name->Guid, &GuidStr);
|
||
CLEANUP_WS(0, "++ ERROR - Translating Guid to string;", WStatus, CLEANUP);
|
||
}
|
||
//
|
||
// Basically, bind to the server's RPC name on this machine. Trim leading \\
|
||
//
|
||
MachineName = Name->Name;
|
||
FRS_TRIM_LEADING_2SLASH(MachineName);
|
||
|
||
WStatus = RpcStringBindingCompose(GuidStr, PROTSEQ_TCP_IP, MachineName,
|
||
NULL, NULL, &BindingString);
|
||
CLEANUP1_WS(0, "++ ERROR - Composing for %ws;", Name->Name, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Store the binding in the handle
|
||
//
|
||
WStatus = RpcBindingFromStringBinding(BindingString, Handle);
|
||
CLEANUP1_WS(0, "++ ERROR - Storing binding for %ws;", Name->Name, WStatus, CLEANUP);
|
||
|
||
DPRINT1(4, ":S: Bound to %ws\n", Name->Name);
|
||
|
||
//
|
||
// Some simple stats for debugging
|
||
//
|
||
DeltaBinds = ++RpcBinds - RpcUnBinds;
|
||
if (DeltaBinds > RpcMaxBinds) {
|
||
RpcMaxBinds = DeltaBinds;
|
||
}
|
||
// Fall through
|
||
|
||
CLEANUP:
|
||
if (BindingString) {
|
||
RpcStringFreeW(&BindingString);
|
||
}
|
||
if (GuidStr) {
|
||
RpcStringFree(&GuidStr);
|
||
}
|
||
//
|
||
// We are now ready to talk to the server using the frsrpc interfaces
|
||
//
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
FrsRpcBindToServerNotService(
|
||
IN PGNAME Name,
|
||
IN PWCHAR PrincName,
|
||
IN ULONG AuthLevel,
|
||
OUT handle_t *Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Set up the bindings to our inbound/outbound partner.
|
||
|
||
Arguments:
|
||
Name
|
||
PrincName
|
||
AuthLevel
|
||
Handle
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcBindToServerNotSevice:"
|
||
DWORD WStatus;
|
||
LONG DeltaBinds;
|
||
PWCHAR InqPrincName = NULL;
|
||
PWCHAR BindingString = NULL;
|
||
PWCHAR MachineName;
|
||
|
||
//
|
||
// Basically, bind to the server's RPC name on this machine. Trim leading \\
|
||
//
|
||
MachineName = Name->Name;
|
||
FRS_TRIM_LEADING_2SLASH(MachineName);
|
||
|
||
WStatus = RpcStringBindingCompose(NULL, PROTSEQ_TCP_IP, MachineName,
|
||
NULL, NULL, &BindingString);
|
||
CLEANUP1_WS(0, "++ ERROR - Composing for %ws;", Name->Name, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Store the binding in the handle
|
||
//
|
||
WStatus = RpcBindingFromStringBinding(BindingString, Handle);
|
||
CLEANUP1_WS(0, "++ ERROR - Storing binding for %ws;", Name->Name, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Not authenticating
|
||
//
|
||
if (KerberosIsNotAvailable ||
|
||
AuthLevel == CXTION_AUTH_NONE) {
|
||
goto done;
|
||
}
|
||
|
||
//
|
||
// When not running as a service, we can't predict our
|
||
// principle name so simply resolve the binding.
|
||
//
|
||
WStatus = RpcEpResolveBinding(*Handle, frsrpc_ClientIfHandle);
|
||
CLEANUP_WS(4, "++ ERROR: resolving binding;", WStatus, CLEANUP);
|
||
|
||
WStatus = RpcMgmtInqServerPrincName(*Handle,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
&InqPrincName);
|
||
CLEANUP_WS(0, "++ ERROR: resolving PrincName;", WStatus, CLEANUP);
|
||
|
||
DPRINT1(4, ":S: Inq PrincName is %ws\n", InqPrincName);
|
||
|
||
//
|
||
// Put our authentication info into the handle
|
||
//
|
||
if (MutualAuthenticationIsEnabled) {
|
||
WStatus = RpcBindingSetAuthInfoEx(*Handle,
|
||
InqPrincName,
|
||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
NULL,
|
||
RPC_C_AUTHZ_NONE,
|
||
&RpcSecurityQos);
|
||
DPRINT2_WS(1, "++ WARN - RpcBindingSetAuthInfoEx(%ws, %ws);",
|
||
Name->Name, InqPrincName, WStatus);
|
||
} else {
|
||
WStatus = ERROR_NOT_SUPPORTED;
|
||
}
|
||
//
|
||
// Fall back to manual mutual authentication
|
||
//
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
WStatus = RpcBindingSetAuthInfo(*Handle,
|
||
InqPrincName,
|
||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
NULL,
|
||
RPC_C_AUTHZ_NONE);
|
||
}
|
||
CLEANUP2_WS(0, "++ ERROR - RpcBindingSetAuthInfo(%ws, %ws);",
|
||
Name->Name, InqPrincName, WStatus, CLEANUP);
|
||
|
||
//
|
||
// SUCCESS
|
||
//
|
||
WStatus = ERROR_SUCCESS;
|
||
|
||
done:
|
||
DPRINT1(4, ":S: Bound to %ws\n", Name->Name);
|
||
|
||
//
|
||
// Some simple stats for debugging
|
||
//
|
||
DeltaBinds = ++RpcBinds - RpcUnBinds;
|
||
if (DeltaBinds > RpcMaxBinds) {
|
||
RpcMaxBinds = DeltaBinds;
|
||
}
|
||
// Fall through
|
||
|
||
CLEANUP:
|
||
if (BindingString) {
|
||
RpcStringFreeW(&BindingString);
|
||
}
|
||
if (InqPrincName) {
|
||
RpcStringFree(&InqPrincName);
|
||
}
|
||
//
|
||
// We are now ready to talk to the server using the frsrpc interfaces
|
||
//
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
DWORD
|
||
FrsRpcBindToServer(
|
||
IN PGNAME Name,
|
||
IN PWCHAR PrincName,
|
||
IN ULONG AuthLevel,
|
||
OUT handle_t *Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Set up the bindings to our inbound/outbound partner.
|
||
|
||
Arguments:
|
||
Name
|
||
PrincName
|
||
AuthLevel
|
||
Handle
|
||
|
||
Return Value:
|
||
Win32 Status
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcBindToServer:"
|
||
DWORD WStatus;
|
||
LONG DeltaBinds;
|
||
PWCHAR BindingString = NULL;
|
||
PWCHAR MachineName;
|
||
|
||
FRS_ASSERT(RPC_S_OK == ERROR_SUCCESS);
|
||
|
||
//
|
||
// Emulating multiple machines with hardwired config
|
||
// For hardwired -- Eventually DS Free configs.
|
||
//
|
||
if (ServerGuid) {
|
||
return (FrsRpcBindToServerGuid(Name, Handle));
|
||
}
|
||
|
||
//
|
||
// Not running as a service; relax binding constraints
|
||
//
|
||
if (!RunningAsAService) {
|
||
return (FrsRpcBindToServerNotService(Name, PrincName, AuthLevel, Handle));
|
||
}
|
||
//
|
||
// Basically, bind to the NtFrs running on Name. Trim leading \\
|
||
//
|
||
MachineName = Name->Name;
|
||
FRS_TRIM_LEADING_2SLASH(MachineName);
|
||
|
||
WStatus = RpcStringBindingCompose(NULL, PROTSEQ_TCP_IP, MachineName,
|
||
NULL, NULL, &BindingString);
|
||
CLEANUP1_WS(0, "++ ERROR - Composing for %ws;", Name->Name, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Store the binding in the handle
|
||
//
|
||
WStatus = RpcBindingFromStringBinding(BindingString, Handle);
|
||
CLEANUP1_WS(0, "++ ERROR - Storing binding for %ws;", Name->Name, WStatus, CLEANUP);
|
||
|
||
//
|
||
// Not authenticating
|
||
//
|
||
if (KerberosIsNotAvailable ||
|
||
AuthLevel == CXTION_AUTH_NONE) {
|
||
goto done;
|
||
}
|
||
|
||
//
|
||
// Put our authentication info into the handle
|
||
//
|
||
if (MutualAuthenticationIsEnabled) {
|
||
WStatus = RpcBindingSetAuthInfoEx(*Handle,
|
||
PrincName,
|
||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
NULL,
|
||
RPC_C_AUTHZ_NONE,
|
||
&RpcSecurityQos);
|
||
DPRINT2_WS(1, "++ WARN - RpcBindingSetAuthInfoEx(%ws, %ws);",
|
||
Name->Name, PrincName, WStatus);
|
||
} else {
|
||
WStatus = ERROR_NOT_SUPPORTED;
|
||
}
|
||
//
|
||
// Fall back to manual mutual authentication
|
||
//
|
||
if (!WIN_SUCCESS(WStatus)) {
|
||
WStatus = RpcBindingSetAuthInfo(*Handle,
|
||
PrincName,
|
||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
||
RPC_C_AUTHN_GSS_NEGOTIATE,
|
||
NULL,
|
||
RPC_C_AUTHZ_NONE);
|
||
}
|
||
CLEANUP2_WS(0, "++ ERROR - RpcBindingSetAuthInfo(%ws, %ws);",
|
||
Name->Name, PrincName, WStatus, CLEANUP);
|
||
|
||
//
|
||
// SUCCESS
|
||
//
|
||
WStatus = ERROR_SUCCESS;
|
||
|
||
done:
|
||
DPRINT1(4, ":S: Bound to %ws\n", Name->Name);
|
||
|
||
//
|
||
// Some simple stats for debugging
|
||
//
|
||
DeltaBinds = ++RpcBinds - RpcUnBinds;
|
||
if (DeltaBinds > RpcMaxBinds) {
|
||
RpcMaxBinds = DeltaBinds;
|
||
}
|
||
// Fall through
|
||
|
||
CLEANUP:
|
||
if (BindingString) {
|
||
RpcStringFreeW(&BindingString);
|
||
}
|
||
//
|
||
// We are now ready to talk to the server using the frsrpc interfaces
|
||
//
|
||
return WStatus;
|
||
}
|
||
|
||
|
||
VOID
|
||
FrsRpcUnBindFromServer(
|
||
handle_t *Handle
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Unbind from the server.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcUnBindFromServer:"
|
||
DWORD WStatus;
|
||
//
|
||
// Simple stats for debugging
|
||
//
|
||
++RpcUnBinds;
|
||
try {
|
||
if (Handle) {
|
||
WStatus = RpcBindingFree(Handle);
|
||
DPRINT_WS(0, "++ WARN - RpcBindingFree;", WStatus);
|
||
}
|
||
*Handle = NULL;
|
||
} except (FrsException(GetExceptionInformation())) {
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
FrsRpcInitializeAccessChecks(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
Create the registry keys that are used to check for access to
|
||
the RPC calls that are exported for applications. The access checks
|
||
have no affect on the RPC calls used for replication.
|
||
|
||
The access checks for a given RPC call can be enabled or disabled
|
||
by setting a registry value. If enabled, the RPC call impersonates
|
||
the caller and attempts to open the registry key with the access
|
||
required for that RPC call. The required access is a registry value.
|
||
For example, the following registry hierarchy shows that the
|
||
"Set Ds Polling Interval" has access checks enabled and requires
|
||
write access while "Get Ds Polling Interval" has no access checks.
|
||
NtFrs\Parameters\Access Checks\Set Ds Polling Interval
|
||
Access checks are [enabled | disabled] REG_SZ enabled
|
||
Access checks require [read | write] REG_SZ write
|
||
|
||
NtFrs\Parameters\Access Checks\Get Ds Polling Interval
|
||
Access checks are [enabled | disabled] REG_SZ disabled
|
||
|
||
|
||
The initial set of RPC calls are: (see key context entries in config.c)
|
||
dcpromo - enabled, write
|
||
Set Ds Polling Interval - enabled, write
|
||
Start Ds Polling - enabled, read
|
||
Get Ds Polling Interval - enabled, read
|
||
Get Internal Information - enabled, write
|
||
Get Perfmon Data - enabled, read
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcInitializeAccessChecks:"
|
||
DWORD WStatus;
|
||
DWORD i;
|
||
PWCHAR AccessChecksAre = NULL;
|
||
PWCHAR AccessChecksRequire = NULL;
|
||
FRS_REG_KEY_CODE FrsRkc;
|
||
PWCHAR ApiName;
|
||
|
||
|
||
|
||
for (i = 0; i < ACX_MAX; ++i) {
|
||
|
||
FrsRkc = RpcApiKeys[i].Enable;
|
||
ApiName = RpcApiKeys[i].KeyName;
|
||
|
||
//
|
||
// Read the current string Access Check Enable string.
|
||
//
|
||
CfgRegReadString(FrsRkc, NULL, 0, &AccessChecksAre);
|
||
if ((AccessChecksAre == NULL) ||
|
||
WSTR_EQ(AccessChecksAre, ACCESS_CHECKS_ARE_DEFAULT_DISABLED)||
|
||
WSTR_EQ(AccessChecksAre, ACCESS_CHECKS_ARE_DEFAULT_ENABLED)) {
|
||
//
|
||
// The key is in the default state so we can clobber it with a
|
||
// new default.
|
||
//
|
||
WStatus = CfgRegWriteString(FrsRkc, NULL, FRS_RKF_FORCE_DEFAULT_VALUE, NULL);
|
||
DPRINT1_WS(0, "++ WARN - Cannot create Enable key for %ws;", ApiName, WStatus);
|
||
|
||
AccessChecksAre = FrsFree(AccessChecksAre);
|
||
|
||
//
|
||
// Now reread the key for the new default.
|
||
//
|
||
WStatus = CfgRegReadString(FrsRkc, NULL, 0, &AccessChecksAre);
|
||
}
|
||
|
||
DPRINT4(4, ":S: AccessChecks: ...\\%ws\\%ws\\%ws = %ws\n",
|
||
ACCESS_CHECKS_KEY, ApiName, ACCESS_CHECKS_ARE, AccessChecksAre);
|
||
|
||
if (AccessChecksAre &&
|
||
(WSTR_EQ(AccessChecksAre, ACCESS_CHECKS_ARE_DEFAULT_DISABLED) ||
|
||
WSTR_EQ(AccessChecksAre, ACCESS_CHECKS_ARE_DISABLED))) {
|
||
//
|
||
// Put a notice in the event log that the access check is disabled.
|
||
//
|
||
EPRINT2(EVENT_FRS_ACCESS_CHECKS_DISABLED, ApiName, ACCESS_CHECKS_ARE);
|
||
}
|
||
AccessChecksAre = FrsFree(AccessChecksAre);
|
||
|
||
|
||
//
|
||
// Create the Access Rights value. This determines what rights the caller
|
||
// must have in order to use the API. These rights are used when we
|
||
// open the API key after impersonating the RPC caller. If the key
|
||
// open works then the API call can proceed else we return insufficient
|
||
// privilege status (FRS_ERR_INSUFFICENT_PRIV).
|
||
//
|
||
|
||
FrsRkc = RpcApiKeys[i].Rights;
|
||
|
||
CfgRegReadString(FrsRkc, NULL, 0, &AccessChecksRequire);
|
||
|
||
if ((AccessChecksRequire == NULL)||
|
||
WSTR_EQ(AccessChecksRequire, ACCESS_CHECKS_REQUIRE_DEFAULT_READ)||
|
||
WSTR_EQ(AccessChecksRequire, ACCESS_CHECKS_REQUIRE_DEFAULT_WRITE)) {
|
||
|
||
//
|
||
// The key is in the default state so we can clobber it with a
|
||
// new default.
|
||
//
|
||
WStatus = CfgRegWriteString(FrsRkc, NULL, FRS_RKF_FORCE_DEFAULT_VALUE, NULL);
|
||
DPRINT1_WS(0, "++ WARN - Cannot set access rights key for %ws;", ApiName, WStatus);
|
||
|
||
AccessChecksRequire = FrsFree(AccessChecksRequire);
|
||
|
||
//
|
||
// Now reread the key for the new default.
|
||
//
|
||
CfgRegReadString(FrsRkc, NULL, 0, &AccessChecksRequire);
|
||
}
|
||
|
||
DPRINT4(4, ":S: AccessChecks: ...\\%ws\\%ws\\%ws = %ws\n",
|
||
ACCESS_CHECKS_KEY, ApiName, ACCESS_CHECKS_REQUIRE, AccessChecksRequire);
|
||
|
||
AccessChecksRequire = FrsFree(AccessChecksRequire);
|
||
|
||
} // end for
|
||
|
||
|
||
FrsFree(AccessChecksAre);
|
||
FrsFree(AccessChecksRequire);
|
||
}
|
||
|
||
|
||
VOID
|
||
ShutDownRpc(
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Shutdown the client and server side of RPC.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "ShutDownRpc:"
|
||
RPC_STATUS WStatus;
|
||
RPC_BINDING_VECTOR *BindingVector = NULL;
|
||
|
||
//
|
||
// Server side
|
||
//
|
||
// Stop listening for new calls
|
||
//
|
||
try {
|
||
WStatus = RpcMgmtStopServerListening(0) ;
|
||
DPRINT_WS(0, "++ WARN - RpcMgmtStopServerListening;", WStatus);
|
||
|
||
} except (FrsException(GetExceptionInformation())) {
|
||
}
|
||
|
||
try {
|
||
//
|
||
// Get our registered interfaces
|
||
//
|
||
WStatus = RpcServerInqBindings(&BindingVector);
|
||
DPRINT_WS(0, "++ WARN - RpcServerInqBindings;", WStatus);
|
||
if (RPC_SUCCESS(WStatus)) {
|
||
//
|
||
// And unexport the interfaces together with their dynamic endpoints
|
||
//
|
||
WStatus = RpcEpUnregister(SERVER_frsrpc_ServerIfHandle, BindingVector, 0);
|
||
DPRINT_WS(0, "++ WARN - RpcEpUnregister SERVER_frsrpc_ServerIfHandle;", WStatus);
|
||
|
||
WStatus = RpcEpUnregister(NtFrsApi_ServerIfHandle, BindingVector, 0);
|
||
DPRINT_WS(0, "++ WARN - RpcEpUnregister NtFrsApi_ServerIfHandle;", WStatus);
|
||
|
||
if (HANDLE_IS_VALID(PerfmonProcessSemaphore)) {
|
||
//
|
||
// PERFMON RPC
|
||
//
|
||
WStatus = RpcEpUnregister(PerfFrs_ServerIfHandle, BindingVector, 0);
|
||
DPRINT_WS(0, "++ WARN - RpcEpUnregister PerfFrs_ServerIfHandle;", WStatus);
|
||
}
|
||
|
||
WStatus = RpcBindingVectorFree(&BindingVector);
|
||
DPRINT_WS(0, "++ WARN - RpcBindingVectorFree;", WStatus);
|
||
}
|
||
//
|
||
// Wait for any outstanding RPCs to finish.
|
||
//
|
||
WStatus = RpcMgmtWaitServerListen();
|
||
DPRINT_WS(0, "++ WARN - RpcMgmtWaitServerListen;", WStatus);
|
||
|
||
} except (FrsException(GetExceptionInformation())) {
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
FrsRpcUnInitialize(
|
||
VOID
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Free up memory once all of the threads in the system have been
|
||
shut down.
|
||
|
||
Arguments:
|
||
None.
|
||
|
||
Return Value:
|
||
None.
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcUnInitialize:"
|
||
DPRINT(4, ":S: Free sysvol name table.\n");
|
||
DEBUG_FLUSH();
|
||
SysVolsBeingCreated = GTabFreeTable(SysVolsBeingCreated, NULL);
|
||
if (ServerPrincName) {
|
||
if (KerberosIsNotAvailable) {
|
||
|
||
DPRINT(4, ":S: Free ServerPrincName (no kerberos).\n");
|
||
DEBUG_FLUSH();
|
||
ServerPrincName = FrsFree(ServerPrincName);
|
||
|
||
} else {
|
||
|
||
DPRINT(4, ":S: Free ServerPrincName (kerberos).\n");
|
||
DEBUG_FLUSH();
|
||
ServerPrincName = FrsFree(ServerPrincName);
|
||
}
|
||
}
|
||
DPRINT(4, ":S: Done uninitializing RPC.\n");
|
||
DEBUG_FLUSH();
|
||
}
|
||
|
||
|
||
BOOL
|
||
FrsRpcInitialize(
|
||
VOID
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
Initializting This thread is kicked off by the main thread. This thread sets up
|
||
the server and client side of RPC for the frsrpc interface.
|
||
|
||
Arguments:
|
||
Arg - Needed to set status for our parent.
|
||
|
||
Return Value:
|
||
TRUE - RPC has started
|
||
FALSE - RPC could not be started
|
||
--*/
|
||
{
|
||
#undef DEBSUB
|
||
#define DEBSUB "FrsRpcInitialize:"
|
||
BOOL StartedOK = FALSE;
|
||
|
||
try {
|
||
|
||
|
||
//
|
||
// Get the maximum number of concurrent RPC calls out of registry.
|
||
//
|
||
CfgRegReadDWord(FKC_MAX_RPC_SERVER_THREADS, NULL, 0, &MaxRpcServerThreads);
|
||
DPRINT1(0,":S: Max RPC threads is %d\n", MaxRpcServerThreads);
|
||
|
||
//
|
||
// Register protocol sequences
|
||
//
|
||
RegisterRpcProtseqs();
|
||
DPRINT(0, ":S: FRS RPC protocol sequences registered\n");
|
||
|
||
//
|
||
// Register frsrpc interface
|
||
//
|
||
RegisterRpcInterface();
|
||
DPRINT(0, ":S: FRS RPC interface registered\n");
|
||
|
||
//
|
||
// Start listening for clients
|
||
//
|
||
StartServerRpc();
|
||
DPRINT(0, ":S: FRS RPC server interface installed\n");
|
||
|
||
//
|
||
// Table of sysvols being created
|
||
//
|
||
if (!SysVolsBeingCreated) {
|
||
SysVolsBeingCreated = GTabAllocTable();
|
||
}
|
||
|
||
StartedOK = TRUE;
|
||
|
||
} except (FrsException(GetExceptionInformation())) {
|
||
DPRINT(0, ":S: Can't start RPC\n");
|
||
}
|
||
//
|
||
// Cleanup
|
||
//
|
||
try {
|
||
if (!StartedOK) {
|
||
ShutDownRpc();
|
||
}
|
||
} except (FrsException(GetExceptionInformation())) {
|
||
DPRINT(0, ":S: Can't shutdown RPC\n");
|
||
}
|
||
|
||
//
|
||
// DONE
|
||
//
|
||
|
||
//
|
||
// Free up the rpc initialization memory
|
||
//
|
||
SetProcessWorkingSetSize(ProcessHandle, (SIZE_T)-1, (SIZE_T)-1);
|
||
return StartedOK;
|
||
}
|