/*++ 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 #pragma hdrstop #include #include #include #include #include #include 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; }