769 lines
23 KiB
C++
769 lines
23 KiB
C++
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Windows 2000 Active Directory Service domain trust verification WMI provider
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 2000
|
||
|
//
|
||
|
// File: trust.cpp
|
||
|
//
|
||
|
// Contents: Trust class implementation
|
||
|
//
|
||
|
// Classes: CTrustInfo
|
||
|
//
|
||
|
// History: 27-Mar-00 EricB created
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#include <stdafx.h>
|
||
|
|
||
|
PCWSTR CSTR_PROP_TRUSTED_DOMAIN = L"TrustedDomain"; // String
|
||
|
PCWSTR CSTR_PROP_FLAT_NAME = L"FlatName"; // String
|
||
|
PCWSTR CSTR_PROP_SID = L"SID"; // String
|
||
|
PCWSTR CSTR_PROP_TRUST_DIRECTION = L"TrustDirection"; // uint32
|
||
|
PCWSTR CSTR_PROP_TRUST_TYPE = L"TrustType"; // uint32
|
||
|
PCWSTR CSTR_PROP_TRUST_ATTRIBUTES = L"TrustAttributes"; // uint32
|
||
|
PCWSTR CSTR_PROP_TRUST_STATUS = L"TrustStatus"; // uint32
|
||
|
PCWSTR CSTR_PROP_TRUST_STATUS_STRING = L"TrustStatusString"; // String
|
||
|
PCWSTR CSTR_PROP_TRUST_IS_OK = L"TrustIsOk"; // Boolean
|
||
|
PCWSTR CSTR_PROP_TRUSTED_DC_NAME = L"TrustedDCName"; // String
|
||
|
|
||
|
// Define NETLOGON_CONTROL_TC_VERIFY if not found so this will build for W2K.
|
||
|
// This constant is in the Whistler version of lmaccess.h
|
||
|
#if !defined(NETLOGON_CONTROL_TC_VERIFY)
|
||
|
# define NETLOGON_CONTROL_TC_VERIFY (10)
|
||
|
#endif
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CTrustInfo
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
CTrustInfo::CTrustInfo() : m_ulTrustDirection(0),
|
||
|
m_ulTrustType(0),
|
||
|
m_ulTrustAttributes(0),
|
||
|
m_trustStatus(ERROR_SUCCESS),
|
||
|
m_VerifyStatus(VerifyStatusNone),
|
||
|
m_fPwVerifySupported(TRUE)
|
||
|
{
|
||
|
m_liLastVerified.QuadPart = 0;
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTrustInfo::Verify
|
||
|
//
|
||
|
// Synopsis: Verify the status of the trust
|
||
|
//
|
||
|
// Returns: FALSE if the trust was not outbound.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL
|
||
|
CTrustInfo::Verify(TrustCheckLevel CheckLevel)
|
||
|
{
|
||
|
TRACE(L"CTrustInfo::Verify, verify level %d\n", CheckLevel);
|
||
|
NET_API_STATUS netStatus = NERR_Success;
|
||
|
NETLOGON_INFO_2 * pNetlogonInfo2 = NULL;
|
||
|
VerifyStatus Status = VerifyStatusNone;
|
||
|
PCWSTR pwzTrustedDomain = GetTrustedDomain();
|
||
|
CString strDCName, strResetTarget = GetTrustedDomain();
|
||
|
|
||
|
if (DONT_VERIFY == CheckLevel)
|
||
|
{
|
||
|
TRACE(L"\tCheck-Level set to not verify trust.\n");
|
||
|
SetTrustStatus(NERR_Success, VerifyStatusTrustNotChecked);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
TRACE(L"\tVerifying trust with %s\n", GetTrustedDomain());
|
||
|
|
||
|
if ((TRUST_TYPE_MIT == GetTrustType()) ||
|
||
|
(TRUST_TYPE_DCE == GetTrustType()))
|
||
|
{
|
||
|
// don't verify non-Windows trusts.
|
||
|
//
|
||
|
TRACE(L"\tNot a windows trust, returning.\n");
|
||
|
SetTrustStatus(NERR_Success, VerifyStatusNotWindowsTrust);
|
||
|
SetLastVerifiedTime();
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (!IsTrustOutbound())
|
||
|
{
|
||
|
// don't verify inbound-only trusts.
|
||
|
//
|
||
|
TRACE(L"\tInbound-only trust, returning.\n");
|
||
|
SetTrustStatus(NERR_Success, VerifyStatusNotOutboundTrust);
|
||
|
SetLastVerifiedTime();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// NETLOGON_CONTROL_TC_QUERY - get the status (locally) and the name of trusted DC
|
||
|
// Note that the secure channel is set up only on demand, so it is not an error if
|
||
|
// it is not set up. The SC_QUERY will return ERROR_NO_LOGON_SERVERS if this is the
|
||
|
// case.
|
||
|
//
|
||
|
|
||
|
netStatus = I_NetLogonControl2(NULL,
|
||
|
NETLOGON_CONTROL_TC_QUERY,
|
||
|
2,
|
||
|
(LPBYTE)&pwzTrustedDomain,
|
||
|
(LPBYTE *)&pNetlogonInfo2);
|
||
|
|
||
|
if (NERR_Success == netStatus)
|
||
|
{
|
||
|
ASSERT(pNetlogonInfo2);
|
||
|
|
||
|
netStatus = pNetlogonInfo2->netlog2_tc_connection_status;
|
||
|
|
||
|
if (netStatus == NERR_Success)
|
||
|
{
|
||
|
SetTrustedDCName(pNetlogonInfo2->netlog2_trusted_dc_name);
|
||
|
strDCName = pNetlogonInfo2->netlog2_trusted_dc_name;
|
||
|
#if !defined(NT4_BUILD)
|
||
|
//
|
||
|
// Compose the domain\dc string for the reset command so it will not change
|
||
|
// DCs as a result of the reset. This only works with NT5 or later NetLogon.
|
||
|
//
|
||
|
strResetTarget += L"\\";
|
||
|
strResetTarget += pNetlogonInfo2->netlog2_trusted_dc_name + 2; // skip the UNC double slashes
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ERROR_NO_LOGON_SERVERS == netStatus)
|
||
|
{
|
||
|
// This is the error returned when the SC has not yet been set up.
|
||
|
// It is also returned if no DCs are reachable. DsGetDcName is called with the
|
||
|
// force flag to discover if any DCs are reachable on the net.
|
||
|
//
|
||
|
PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
|
||
|
DWORD dwRet = NO_ERROR;
|
||
|
|
||
|
#if !defined(NT4_BUILD)
|
||
|
dwRet = DsGetDcName(NULL, pwzTrustedDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDCInfo);
|
||
|
#endif
|
||
|
if (NO_ERROR == dwRet)
|
||
|
{
|
||
|
// A DC is reachable, so it is safe to assume that the SC has not yet been
|
||
|
// set up. Treat this as success.
|
||
|
//
|
||
|
netStatus = NERR_Success;
|
||
|
TRACE(L"SC_QUERY has returned ERROR_NO_LOGON_SERVERS, SC not yet set up.\n");
|
||
|
#if !defined(NT4_BUILD)
|
||
|
SetTrustedDCName(pDCInfo->DomainControllerName);
|
||
|
NetApiBufferFree(pDCInfo);
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If there are no DCs, there is nothing to be done except return the error.
|
||
|
//
|
||
|
TRACE(L"DsGetDcName /FORCE has returned %d, DC not found.\n", dwRet);
|
||
|
// Save the error code and fixed by method
|
||
|
SetTrustStatus(dwRet, VerifyStatusBroken);
|
||
|
SetLastVerifiedTime();
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE(L"SC_QUERY has returned %d.\n", netStatus);
|
||
|
}
|
||
|
}
|
||
|
NetApiBufferFree(pNetlogonInfo2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE(L"I_NetLogonControl2 has returned %d.\n", netStatus);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Do a trust PW verification if the other domain supports it.
|
||
|
//
|
||
|
if (PW_VERIFY == CheckLevel)
|
||
|
{
|
||
|
if (m_fPwVerifySupported)
|
||
|
{
|
||
|
netStatus = I_NetLogonControl2(NULL,
|
||
|
NETLOGON_CONTROL_TC_VERIFY,
|
||
|
2,
|
||
|
(LPBYTE)&pwzTrustedDomain,
|
||
|
(LPBYTE *)&pNetlogonInfo2);
|
||
|
|
||
|
if (NERR_Success == netStatus)
|
||
|
{
|
||
|
ASSERT(pNetlogonInfo2);
|
||
|
netStatus = pNetlogonInfo2->netlog2_tc_connection_status;
|
||
|
NetApiBufferFree(pNetlogonInfo2);
|
||
|
}
|
||
|
if (NERR_Success == netStatus)
|
||
|
{
|
||
|
TRACE(L"PW Verify successful on %s\n", pwzTrustedDomain);
|
||
|
Status = VerifyStatusTrustOK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ERROR_INVALID_LEVEL == netStatus ||
|
||
|
ERROR_NOT_SUPPORTED == netStatus ||
|
||
|
RPC_S_PROCNUM_OUT_OF_RANGE == netStatus ||
|
||
|
RPC_NT_PROCNUM_OUT_OF_RANGE == netStatus)
|
||
|
{
|
||
|
TRACE(L"NETLOGON_CONTROL_TC_VERIFY is not supported on %s\n", pwzTrustedDomain);
|
||
|
m_fPwVerifySupported = FALSE;
|
||
|
Status = VerifyStatusPwCheckNotSupported;
|
||
|
netStatus = NERR_Success; // call it success since we don't know the true state
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE(L"NETLOGON_CONTROL_TC_VERIFY returned 0x%08x on %s\n", netStatus, pwzTrustedDomain);
|
||
|
Status = VerifyStatusBroken;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = VerifyStatusPwCheckNotSupported;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Try an SC Reset against the DC returned by the SC query
|
||
|
//
|
||
|
if (SC_RESET == CheckLevel)
|
||
|
{
|
||
|
PCWSTR pwzResetTarget = strResetTarget;
|
||
|
|
||
|
netStatus = I_NetLogonControl2(NULL,
|
||
|
NETLOGON_CONTROL_REDISCOVER,
|
||
|
2,
|
||
|
(LPBYTE)&pwzResetTarget,
|
||
|
(LPBYTE *)&pNetlogonInfo2);
|
||
|
|
||
|
if (NERR_Success == netStatus)
|
||
|
{
|
||
|
ASSERT(pNetlogonInfo2);
|
||
|
netStatus = pNetlogonInfo2->netlog2_tc_connection_status;
|
||
|
NetApiBufferFree(pNetlogonInfo2);
|
||
|
}
|
||
|
if (NERR_Success == netStatus)
|
||
|
{
|
||
|
TRACE(L"SC_RESET successfull on %s\n", pwzResetTarget);
|
||
|
Status = VerifyStatusRediscover;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TRACE(L"SC_RESET returned 0x%08x on %s\n", netStatus, pwzResetTarget);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef NT4_BUILD
|
||
|
//
|
||
|
// Force trust pw replication from PDC to BDCs; only works on pre-W2K.
|
||
|
//
|
||
|
if (netStatus != NERR_Success)
|
||
|
{
|
||
|
// perform only once, ignore the result
|
||
|
ForceReplication();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// If still in an error state, do an SC reset against any DC
|
||
|
//
|
||
|
if (netStatus != NERR_Success)
|
||
|
{
|
||
|
netStatus = ForceRediscover(NULL, &strDCName);
|
||
|
|
||
|
if (NERR_Success == netStatus)
|
||
|
{
|
||
|
Status = VerifyStatusRediscover;
|
||
|
|
||
|
SetTrustedDCName(const_cast<PWSTR>((PCWSTR)strDCName));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Walk through the DCs trying to establish an SC: TRCHK_RETARGET_ON_ERROR
|
||
|
//
|
||
|
if (NERR_Success != netStatus)
|
||
|
{
|
||
|
vector<LPWSTR> dcList;
|
||
|
LPBYTE pbuf = NULL;
|
||
|
|
||
|
TRACE(L"Attempting to retarget...\n");
|
||
|
|
||
|
//
|
||
|
// Enumerate all DCs in the trusted domain
|
||
|
// Attempt reconnecting to another DC.
|
||
|
//
|
||
|
// The returned value is not recorded.
|
||
|
// (if not enumerated, skip this step)
|
||
|
//
|
||
|
if( NERR_Success == GetDCList(strDCName,
|
||
|
dcList,
|
||
|
&pbuf))
|
||
|
{
|
||
|
//
|
||
|
// Try to connect to every DC until success
|
||
|
//
|
||
|
for (vector<LPWSTR>::iterator ppszDCName = dcList.begin();
|
||
|
NERR_Success != netStatus && ppszDCName != dcList.end();
|
||
|
ppszDCName++)
|
||
|
{
|
||
|
netStatus = ForceRediscover(*ppszDCName, &strDCName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NERR_Success == netStatus)
|
||
|
{
|
||
|
SetTrustedDCName(const_cast<PWSTR>((PCWSTR)strDCName));
|
||
|
Status = VerifyStatusRetarget;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Clean up the DC list
|
||
|
//
|
||
|
if (pbuf)
|
||
|
{
|
||
|
VERIFY( NERR_Success == NetApiBufferFree(pbuf));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Save the error code and Status
|
||
|
SetTrustStatus(netStatus, Status);
|
||
|
SetLastVerifiedTime();
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTrustInfo::SetLastVerifiedTime
|
||
|
//
|
||
|
// Synopsis: Record the time of verification.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void
|
||
|
CTrustInfo::SetLastVerifiedTime(void)
|
||
|
{
|
||
|
SYSTEMTIME st;
|
||
|
|
||
|
GetSystemTime(&st);
|
||
|
SystemTimeToFileTime(&st, (LPFILETIME)&m_liLastVerified);
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTrustInfo::IsVerificationStale
|
||
|
//
|
||
|
// Synopsis: Checks to see if the last verification time is older than the
|
||
|
// passed in criteria.
|
||
|
//
|
||
|
// Returns: TRUE if older.
|
||
|
//
|
||
|
// Notes: If the trust hasn't been verified (m_liLastVerified == 0),
|
||
|
// then the verification is defined to be stale.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL
|
||
|
CTrustInfo::IsVerificationStale(LARGE_INTEGER liMaxAge)
|
||
|
{
|
||
|
TRACE(L"CTrustInfo::IsVerificationStale(0x%08x), MaxAge = %d\n",
|
||
|
this, liMaxAge.QuadPart / TRUSTMON_FILETIMES_PER_MINUTE);
|
||
|
BOOL fStale = FALSE;
|
||
|
LARGE_INTEGER liCurrentTime;
|
||
|
SYSTEMTIME st;
|
||
|
|
||
|
GetSystemTime(&st);
|
||
|
SystemTimeToFileTime(&st, (LPFILETIME)&liCurrentTime);
|
||
|
|
||
|
//TRACE(L"\tlast: %I64d, cur: %I64d, max: %I64d\n", m_liLastVerified, liCurrentTime, liMaxAge);
|
||
|
|
||
|
fStale = (m_liLastVerified.QuadPart + liMaxAge.QuadPart) < liCurrentTime.QuadPart;
|
||
|
|
||
|
return fStale;
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTrustInfo::GetDCList
|
||
|
//
|
||
|
// Synopsis: Enumerate all DCs in a domain and return a list in random order.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
NET_API_STATUS
|
||
|
CTrustInfo::GetDCList(PCWSTR pszKnownServer, // OPTIONAL The server name to be placed in the end of the list
|
||
|
vector<LPWSTR> & dcList, // Vector of PCWSTRs, pointing to the DC names inside pbufptr
|
||
|
LPBYTE * pbufptr ) // This buffer must be freed with NetApiBufferFree when done.
|
||
|
{
|
||
|
TRACE(L"CTrustInfo::GetDCList\n");
|
||
|
|
||
|
ASSERT( pbufptr );
|
||
|
ASSERT( !(*pbufptr) );
|
||
|
|
||
|
NET_API_STATUS netStatus = NERR_Success;
|
||
|
DWORD dwEntriesRead = 0;
|
||
|
DWORD dwTotalEntries = 0;
|
||
|
DWORD dwResumeHandle = 0;
|
||
|
DWORD dwIndKnownServer = MAXDWORD;
|
||
|
DWORD dwInd = 0;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
// Init
|
||
|
dcList.clear();
|
||
|
|
||
|
//
|
||
|
// Enumerate all the servers belonging to the specified domain
|
||
|
//
|
||
|
netStatus = NetServerEnum( NULL,
|
||
|
100, // SERVER_INFO_100
|
||
|
pbufptr,
|
||
|
MAX_PREFERRED_LENGTH,
|
||
|
& dwEntriesRead,
|
||
|
& dwTotalEntries,
|
||
|
SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL,
|
||
|
GetTrustedDomain(),
|
||
|
& dwResumeHandle );
|
||
|
|
||
|
TRACE(L"NetServerEnum returned 0x%08x! (%d entries)\n", netStatus, dwEntriesRead);
|
||
|
|
||
|
if( netStatus == ERROR_MORE_DATA )
|
||
|
{
|
||
|
// should never happen (no enum handle)
|
||
|
ASSERT( FALSE );
|
||
|
|
||
|
// process whatever NetServerEnum returned.
|
||
|
netStatus = NERR_Success;
|
||
|
}
|
||
|
|
||
|
if( netStatus != NERR_Success ||
|
||
|
!dwEntriesRead ||
|
||
|
!(*pbufptr) )
|
||
|
{
|
||
|
TRACE(L"Failure, exiting...\n");
|
||
|
|
||
|
dcList.clear();
|
||
|
|
||
|
if( *pbufptr )
|
||
|
{
|
||
|
VERIFY( NERR_Success == NetApiBufferFree( *pbufptr ) );
|
||
|
*pbufptr = NULL;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// To simplify buffer access...
|
||
|
PSERVER_INFO_100 pServerInfo100 = PSERVER_INFO_100( *pbufptr );
|
||
|
|
||
|
// Reserve enough space for all the entries
|
||
|
dcList.reserve( dwEntriesRead );
|
||
|
|
||
|
//
|
||
|
// Create a list of Servers
|
||
|
//
|
||
|
for( dwInd = 0; dwInd < dwEntriesRead; dwInd++ )
|
||
|
{
|
||
|
if( pszKnownServer &&
|
||
|
!_wcsicmp( pszKnownServer, pServerInfo100[dwInd].sv100_name ) )
|
||
|
{
|
||
|
dwIndKnownServer = dwInd; // postpone until the end
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dcList.push_back( pServerInfo100[dwInd].sv100_name );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASSERT( dwEntriesRead );
|
||
|
|
||
|
//
|
||
|
// Known server should go to the end of the list
|
||
|
//
|
||
|
if( MAXDWORD != dwIndKnownServer )
|
||
|
{
|
||
|
TRACE(L"Server %s placed @ the end\n", pszKnownServer);
|
||
|
|
||
|
dcList.push_back( pServerInfo100[dwIndKnownServer].sv100_name );
|
||
|
|
||
|
// Shuffling should not include the last entry
|
||
|
dwEntriesRead--;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize randomizer
|
||
|
//
|
||
|
srand( (unsigned) time( NULL ) );
|
||
|
|
||
|
//
|
||
|
// Shuffle by replacing each entry with another random entry
|
||
|
//
|
||
|
for( dwInd = 0; dwInd < (int) dwEntriesRead; dwInd++ )
|
||
|
{
|
||
|
DWORD dwRandPos = DWORD( rand() % dwEntriesRead );
|
||
|
|
||
|
if( dwRandPos == dwInd )
|
||
|
continue;
|
||
|
|
||
|
// Swap!
|
||
|
LPWSTR pstrTemp = dcList[ dwRandPos ];
|
||
|
dcList[ dwRandPos ] = dcList[ dwInd ];
|
||
|
dcList[ dwInd ] = pstrTemp;
|
||
|
}
|
||
|
|
||
|
} while( FALSE );
|
||
|
|
||
|
return netStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTrustInfo::ForceRediscover
|
||
|
//
|
||
|
// Synopsis:
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
NET_API_STATUS
|
||
|
CTrustInfo::ForceRediscover(PCWSTR pstrDCName, CString * pstrDCNameRet)
|
||
|
{
|
||
|
TRACE(L"CTrustInfo::ForceRediscover\n");
|
||
|
|
||
|
NET_API_STATUS netStatus = NERR_Success;
|
||
|
NETLOGON_INFO_2 * pNetlogonInfo2 = NULL;
|
||
|
CString strTemp;
|
||
|
PCWSTR pstrDomainName = GetTrustedDomain();
|
||
|
|
||
|
if( pstrDCName )
|
||
|
{
|
||
|
//
|
||
|
// Form domain\dc request
|
||
|
//
|
||
|
strTemp = pstrDomainName;
|
||
|
strTemp += L"\\";
|
||
|
strTemp += pstrDCName;
|
||
|
|
||
|
// Retarget pstrDomainName to the new string
|
||
|
pstrDomainName = strTemp;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Attempt to re-establish trust
|
||
|
//
|
||
|
netStatus = I_NetLogonControl2( NULL,
|
||
|
NETLOGON_CONTROL_REDISCOVER,
|
||
|
2,
|
||
|
( LPBYTE ) &pstrDomainName,
|
||
|
( LPBYTE *) &pNetlogonInfo2 );
|
||
|
|
||
|
TRACE(L"I_NetLogonControl2:NETLOGON_CONTROL_REDISCOVER to %s returned 0x%08x\n",
|
||
|
pstrDomainName, netStatus);
|
||
|
//
|
||
|
// Clean-up
|
||
|
//
|
||
|
if( pNetlogonInfo2 )
|
||
|
{
|
||
|
*pstrDCNameRet = pNetlogonInfo2->netlog2_trusted_dc_name;
|
||
|
TRACE(L"netlog2_flags=0x%08x, netlog2_pdc_connection_status=0x%08x\n",
|
||
|
pNetlogonInfo2->netlog2_flags,
|
||
|
pNetlogonInfo2->netlog2_pdc_connection_status);
|
||
|
|
||
|
TRACE(L"netlog2_trusted_dc_name=%s, netlog2_tc_connection_status=0x%08x\n",
|
||
|
pNetlogonInfo2->netlog2_trusted_dc_name,
|
||
|
pNetlogonInfo2->netlog2_tc_connection_status);
|
||
|
|
||
|
NetApiBufferFree( pNetlogonInfo2 );
|
||
|
}
|
||
|
|
||
|
return netStatus;
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTrustInfo::SetTrustStatus
|
||
|
//
|
||
|
// Synopsis: Set the status string based on the netStatus value if an error
|
||
|
// else based on the VerifyStatus.
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void
|
||
|
CTrustInfo::SetTrustStatus(ULONG netStatus, VerifyStatus Status)
|
||
|
{
|
||
|
WCHAR wzBuf[512];
|
||
|
|
||
|
m_trustStatus = netStatus;
|
||
|
m_VerifyStatus = Status;
|
||
|
|
||
|
if (NERR_Success == netStatus)
|
||
|
{
|
||
|
int nStrID;
|
||
|
|
||
|
switch (Status)
|
||
|
{
|
||
|
case VerifyStatusNone:
|
||
|
//
|
||
|
// This is the default value for the Status parameter.
|
||
|
//
|
||
|
case VerifyStatusTrustOK:
|
||
|
nStrID = IDS_TRUST_STATUS_OK;
|
||
|
break;
|
||
|
|
||
|
case VerifyStatusNotWindowsTrust:
|
||
|
nStrID = IDS_MIT_TRUST_STATUS;
|
||
|
break;
|
||
|
|
||
|
case VerifyStatusNotOutboundTrust:
|
||
|
nStrID = IDS_STATUS_INBOUND_ONLY;
|
||
|
break;
|
||
|
|
||
|
case VerifyStatusTrustNotChecked:
|
||
|
nStrID = IDS_STATUS_NOT_CHECKED;
|
||
|
break;
|
||
|
|
||
|
case VerifyStatusPwCheckNotSupported:
|
||
|
nStrID = IDS_PW_VERIFY_NOT_SUPPORTED;
|
||
|
break;
|
||
|
|
||
|
case VerifyStatusRetarget:
|
||
|
nStrID = IDS_FIXED_BY_RETARGET;
|
||
|
break;
|
||
|
|
||
|
case VerifyStatusRediscover:
|
||
|
nStrID = IDS_STATUS_REDISCOVER;
|
||
|
break;
|
||
|
|
||
|
case VerifyStatusBroken:
|
||
|
ASSERT(FALSE); // shouldn't get here, fall through.
|
||
|
default:
|
||
|
nStrID = IDS_STATUS_UNKNOWN;
|
||
|
}
|
||
|
|
||
|
LoadString(_Module.GetModuleInstance(), nStrID, wzBuf, 512);
|
||
|
m_strTrustStatus = wzBuf;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PWSTR pwzMsg;
|
||
|
|
||
|
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
||
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
|
NULL,
|
||
|
netStatus,
|
||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||
|
(PWSTR)&pwzMsg,
|
||
|
0,
|
||
|
NULL))
|
||
|
{
|
||
|
PWSTR pwzSuffix = wcsstr(pwzMsg, L"\r\n");
|
||
|
if (pwzSuffix)
|
||
|
{
|
||
|
*pwzSuffix = L'\0';
|
||
|
}
|
||
|
m_strTrustStatus = pwzMsg;
|
||
|
LocalFree(pwzMsg);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LoadString(_Module.GetModuleInstance(), IDS_TRUST_STATUS_FAILED, wzBuf, 512);
|
||
|
m_strTrustStatus = wzBuf;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTrustInfo::SetTrustDirectionFromFlags
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void
|
||
|
CTrustInfo::SetTrustDirectionFromFlags(ULONG ulFlags)
|
||
|
{
|
||
|
m_ulTrustDirection = 0;
|
||
|
|
||
|
if (DS_DOMAIN_DIRECT_OUTBOUND & ulFlags)
|
||
|
{
|
||
|
m_ulTrustDirection = TRUST_DIRECTION_OUTBOUND;
|
||
|
}
|
||
|
|
||
|
if (DS_DOMAIN_DIRECT_INBOUND & ulFlags)
|
||
|
{
|
||
|
m_ulTrustDirection |= TRUST_DIRECTION_INBOUND;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CTrustInfo::SetSid
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL
|
||
|
CTrustInfo::SetSid(PSID pSid)
|
||
|
{
|
||
|
if (!pSid)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
#if !defined(NT4_BUILD)
|
||
|
PWSTR buffer;
|
||
|
|
||
|
BOOL fRet = ConvertSidToStringSid(pSid, &buffer);
|
||
|
|
||
|
if (fRet)
|
||
|
{
|
||
|
m_strSid = buffer;
|
||
|
LocalFree(buffer);
|
||
|
}
|
||
|
|
||
|
return fRet;
|
||
|
#else
|
||
|
// TODO: Code for NT4 ??
|
||
|
#pragma message("need ConvertSidToStringSid for NT4");
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef NT4_BUILD
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ForceReplication
|
||
|
//
|
||
|
// Synopsis: Force local Domain Replication -- works only for NT4 domains
|
||
|
//
|
||
|
//-----------------------------------------------------------------------------
|
||
|
NET_API_STATUS ForceReplication(void)
|
||
|
{
|
||
|
TRACE(L"ForceReplication\n");
|
||
|
|
||
|
NET_API_STATUS netStatus = NERR_Success;
|
||
|
|
||
|
LPBYTE pbInputDataPtr = NULL;
|
||
|
PNETLOGON_INFO_1 pNetlogonInfo1 = NULL;
|
||
|
|
||
|
netStatus = I_NetLogonControl2( NULL,
|
||
|
NETLOGON_CONTROL_REPLICATE,
|
||
|
1,
|
||
|
(LPBYTE ) &pbInputDataPtr,
|
||
|
(LPBYTE *) &pNetlogonInfo1 );
|
||
|
|
||
|
TRACE(L"I_NetLogonControl2:NETLOGON_CONTROL_REPLICATE returned 0x%08x\n", netStatus);
|
||
|
|
||
|
if( pNetlogonInfo1 )
|
||
|
{
|
||
|
TRACE(L"netlog1_flags=0x%08x, netlog1_pdc_connection_status=0x%08x\n",
|
||
|
pNetlogonInfo1->netlog1_flags,
|
||
|
pNetlogonInfo1->netlog1_pdc_connection_status);
|
||
|
|
||
|
NetApiBufferFree( pNetlogonInfo1 );
|
||
|
}
|
||
|
|
||
|
return netStatus;
|
||
|
}
|
||
|
|
||
|
#endif //NT4_BUILD
|