windows-nt/Source/XPSP1/NT/ds/netapi/svcimgs/ntrepl/frs/frsrpc.c

2960 lines
78 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}