WindowsXP-SP1/admin/display/proppage/admin/ftinfo.cxx
2020-09-30 16:53:49 +02:00

2667 lines
68 KiB
C++

//+----------------------------------------------------------------------------
//
// Windows NT Directory Service Property Pages
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2001
//
// File: ftinfo.cxx
//
// Contents: Domain trust support, forest trust name information.
//
// History: 03-Dec-00 EricB created
//
//-----------------------------------------------------------------------------
#include "pch.h"
#include <stdio.h>
#include <lmerr.h>
#include <dnsapi.h>
#include "proppage.h"
#include "trust.h"
#include "trustwiz.h"
#ifdef DSADMIN
void FormatSID(PSID Sid, CStrW & str);
//+----------------------------------------------------------------------------
//
// Class: CFTInfo
//
// Purpose: Wrap an LSA_FOREST_TRUST_INFORMATION structure.
//
//-----------------------------------------------------------------------------
CFTInfo::CFTInfo(void) :
_pFTInfo(NULL),
_pExtraInfo(NULL)
{
TRACER(CFTInfo,CFTInfo);
#ifdef _DEBUG
strcpy(szClass, "CFTInfo");
#endif
}
CFTInfo::CFTInfo(PLSA_FOREST_TRUST_INFORMATION pFTInfo) :
_pFTInfo(NULL),
_pExtraInfo(NULL)
{
TRACER(CFTInfo,CFTInfo pointer copy ctor);
#ifdef _DEBUG
strcpy(szClass, "CFTInfo");
#endif
bool fOK = SetFTInfo(pFTInfo);
dspAssert(fOK);
}
CFTInfo::CFTInfo(CFTInfo & FTInfo) :
_pFTInfo(NULL),
_pExtraInfo(NULL)
{
TRACER(CFTInfo,CFTInfo obj copy ctor);
#ifdef _DEBUG
strcpy(szClass, "CFTInfo");
#endif
bool fOK = SetFTInfo(FTInfo.GetFTInfo());
dspAssert(fOK);
}
CFTInfo::~CFTInfo(void)
{
DeleteFTInfo();
}
const CFTInfo &
CFTInfo::operator= (const PLSA_FOREST_TRUST_INFORMATION pFTInfo)
{
bool fOK = SetFTInfo(pFTInfo);
dspAssert(fOK);
return *this;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::SetFTInfo
//
// Synopsis: Copy the FTInfo data.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::SetFTInfo(PLSA_FOREST_TRUST_INFORMATION pFTInfo)
{
TRACER(CFTInfo,SetFTInfo);
dspAssert(pFTInfo);
if (!pFTInfo)
{
return false;
}
DeleteFTInfo();
_pFTInfo = new LSA_FOREST_TRUST_INFORMATION;
CHECK_NULL(_pFTInfo, return false);
ZeroMemory(_pFTInfo, sizeof(LSA_FOREST_TRUST_INFORMATION));
if (!pFTInfo->RecordCount)
{
DBG_OUT("RecordCount is zero.\n");
return true;
}
dspDebugOut((DEB_ITRACE, "RecordCount is %d\n", pFTInfo->RecordCount));
_pFTInfo->Entries = new PLSA_FOREST_TRUST_RECORD[pFTInfo->RecordCount];
CHECK_NULL(_pFTInfo->Entries, return false);
ZeroMemory(_pFTInfo->Entries, sizeof(PLSA_FOREST_TRUST_RECORD) * pFTInfo->RecordCount);
PWSTR pwz = NULL;
size_t cch = 0;
for (ULONG i = 0; i < pFTInfo->RecordCount; i++)
{
PLSA_FOREST_TRUST_RECORD pRec = pFTInfo->Entries[i], pCopyRec;
dspAssert(pRec);
_pFTInfo->Entries[i] = pCopyRec = new LSA_FOREST_TRUST_RECORD;
CHECK_NULL(pCopyRec, return false);
ZeroMemory(pCopyRec, sizeof(LSA_FOREST_TRUST_RECORD));
_pFTInfo->RecordCount++;
pCopyRec->ForestTrustType = pRec->ForestTrustType;
pCopyRec->Flags = pRec->Flags;
pCopyRec->Time = pRec->Time;
switch (pRec->ForestTrustType)
{
case ForestTrustTopLevelName:
case ForestTrustTopLevelNameEx:
cch = pRec->ForestTrustData.TopLevelName.Length / sizeof(WCHAR);
pwz = new WCHAR[cch + 1];
CHECK_NULL(pwz, return false);
wcsncpy(pwz, pRec->ForestTrustData.TopLevelName.Buffer, cch);
pwz[cch] = L'\0';
RtlInitUnicodeString(&pCopyRec->ForestTrustData.TopLevelName, pwz);
dspDebugOut((DEB_USER1, "%s: %ws, Flags 0x%x\n",
(ForestTrustTopLevelName == pCopyRec->ForestTrustType) ?
"ForestTrustTopLevelName" : "ForestTrustTopLevelNameEx",
pwz, pCopyRec->Flags));
break;
case ForestTrustDomainInfo:
cch = pRec->ForestTrustData.DomainInfo.DnsName.Length / sizeof(WCHAR);
pwz = new WCHAR[cch + 1];
CHECK_NULL(pwz, return false);
wcsncpy(pwz, pRec->ForestTrustData.DomainInfo.DnsName.Buffer, cch);
pwz[cch] = L'\0';
RtlInitUnicodeString(&pCopyRec->ForestTrustData.DomainInfo.DnsName, pwz);
dspDebugOut((DEB_USER1, "ForestTrustDomainInfo: %ws, Flags 0x%x\n",
pwz, pCopyRec->Flags));
cch = pRec->ForestTrustData.DomainInfo.NetbiosName.Length / sizeof(WCHAR);
pwz = new WCHAR[cch + 1];
CHECK_NULL(pwz, return false);
wcsncpy(pwz, pRec->ForestTrustData.DomainInfo.NetbiosName.Buffer, cch);
pwz[cch] = L'\0';
RtlInitUnicodeString(&pCopyRec->ForestTrustData.DomainInfo.NetbiosName, pwz);
pCopyRec->ForestTrustData.DomainInfo.Sid = new BYTE[GetLengthSid(pRec->ForestTrustData.DomainInfo.Sid)];
CHECK_NULL(pCopyRec->ForestTrustData.DomainInfo.Sid, return false);
CopyMemory(pCopyRec->ForestTrustData.DomainInfo.Sid,
pRec->ForestTrustData.DomainInfo.Sid,
GetLengthSid(pRec->ForestTrustData.DomainInfo.Sid));
break;
default:
pCopyRec->ForestTrustData.Data.Buffer = new UCHAR[pRec->ForestTrustData.Data.Length];
CHECK_NULL(pCopyRec->ForestTrustData.Data.Buffer, return false);
CopyMemory(pCopyRec->ForestTrustData.Data.Buffer,
pRec->ForestTrustData.Data.Buffer,
pRec->ForestTrustData.Data.Length);
dspDebugOut((DEB_USER1, "Unknown type: Flags 0x%x\n", pCopyRec->Flags));
break;
}
}
_pExtraInfo = new FT_EXTRA_INFO[pFTInfo->RecordCount];
CHECK_NULL(_pExtraInfo, return false);
SetDomainState();
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::AddNewExclusion
//
//-----------------------------------------------------------------------------
bool
CFTInfo::AddNewExclusion(PCWSTR pwzName, ULONG & NewIndex)
{
if (!_pFTInfo || !pwzName || wcslen(pwzName) < 3) // to be subordinate to something requires at least 3 chars.
{
dspAssert(FALSE);
return false;
}
dspDebugOut((DEB_ITRACE, "CFTInfo::AddNewExclusion for name %ws\n", pwzName));
PLSA_FOREST_TRUST_RECORD * rgpNewEntries;
ULONG nEntries = _pFTInfo->RecordCount;
rgpNewEntries = new PLSA_FOREST_TRUST_RECORD[nEntries + 1];
CHECK_NULL(rgpNewEntries, return false);
ZeroMemory(rgpNewEntries, sizeof(PLSA_FOREST_TRUST_RECORD) * (nEntries + 1));
CopyMemory(rgpNewEntries, _pFTInfo->Entries, nEntries * sizeof(PLSA_FOREST_TRUST_RECORD));
rgpNewEntries[nEntries] = new LSA_FOREST_TRUST_RECORD;
CHECK_NULL(rgpNewEntries[nEntries], return false);
FT_EXTRA_INFO * pNewExtraInfo = new FT_EXTRA_INFO[nEntries + 1];
CHECK_NULL(pNewExtraInfo, return false);
// Flags and Time both implicitly set to zero.
//
ZeroMemory(rgpNewEntries[nEntries], sizeof(LSA_FOREST_TRUST_RECORD));
_pFTInfo->RecordCount++;
rgpNewEntries[nEntries]->ForestTrustType = ForestTrustTopLevelNameEx;
PWSTR pwz = new WCHAR[wcslen(pwzName) + 1];
CHECK_NULL(pwz, return false);
wcscpy(pwz, pwzName);
RtlInitUnicodeString(&rgpNewEntries[nEntries]->ForestTrustData.TopLevelName,
pwz);
delete [] _pFTInfo->Entries;
_pFTInfo->Entries = rgpNewEntries;
NewIndex = nEntries;
ZeroMemory(pNewExtraInfo, (nEntries + 1) * sizeof(FT_EXTRA_INFO));
dspAssert(_pExtraInfo);
CopyMemory(pNewExtraInfo, _pExtraInfo, nEntries * sizeof(FT_EXTRA_INFO));
delete [] _pExtraInfo;
_pExtraInfo = pNewExtraInfo;
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::RemoveExclusion
//
//-----------------------------------------------------------------------------
bool
CFTInfo::RemoveExclusion(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pRec = _pFTInfo->Entries[index];
if (ForestTrustTopLevelNameEx != pRec->ForestTrustType)
{
dspAssert(FALSE);
return false;
}
delete [] pRec->ForestTrustData.TopLevelName.Buffer;
delete pRec;
for (ULONG i = index; i < _pFTInfo->RecordCount - 1; i++)
{
_pFTInfo->Entries[i] = _pFTInfo->Entries[i + 1];
}
_pFTInfo->RecordCount--;
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::DeleteFTInfo
//
//-----------------------------------------------------------------------------
void
CFTInfo::DeleteFTInfo(void)
{
if (!_pFTInfo)
{
return;
}
PLSA_FOREST_TRUST_INFORMATION pFTInfo = _pFTInfo;
_pFTInfo = NULL;
for (ULONG i = 0; i < pFTInfo->RecordCount; i++)
{
PLSA_FOREST_TRUST_RECORD pRec = pFTInfo->Entries[i];
if (!pRec)
{
return;
}
switch (pRec->ForestTrustType)
{
case ForestTrustTopLevelName:
case ForestTrustTopLevelNameEx:
if (pRec->ForestTrustData.DomainInfo.DnsName.Buffer)
{
delete [] pRec->ForestTrustData.DomainInfo.DnsName.Buffer;
}
break;
case ForestTrustDomainInfo:
if (pRec->ForestTrustData.DomainInfo.DnsName.Buffer)
{
delete [] pRec->ForestTrustData.DomainInfo.DnsName.Buffer;
}
if (pRec->ForestTrustData.DomainInfo.NetbiosName.Buffer)
{
delete [] pRec->ForestTrustData.DomainInfo.NetbiosName.Buffer;
}
if (pRec->ForestTrustData.DomainInfo.Sid)
{
delete [] pRec->ForestTrustData.DomainInfo.Sid;
}
break;
default:
if (pRec->ForestTrustData.Data.Buffer)
{
delete [] pRec->ForestTrustData.Data.Buffer;
}
break;
}
delete pRec;
}
delete [] pFTInfo->Entries;
delete pFTInfo;
if (_pExtraInfo)
{
delete [] _pExtraInfo;
_pExtraInfo = NULL;
}
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::GetIndex
//
// Synopsis: Return the index that matches the passed in name.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::GetIndex(PCWSTR pwzName, ULONG & index)
{
if (!_pFTInfo || !pwzName)
{
dspAssert(FALSE);
return false;
}
CStrW strName;
for (ULONG i = 0; i < _pFTInfo->RecordCount; i++)
{
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[i];
dspAssert(pFTRec);
switch (pFTRec->ForestTrustType)
{
case ForestTrustTopLevelName:
case ForestTrustTopLevelNameEx:
strName = pFTRec->ForestTrustData.TopLevelName;
break;
case ForestTrustDomainInfo:
strName = pFTRec->ForestTrustData.DomainInfo.DnsName;
break;
default:
dspAssert(FALSE);
break;
}
if (!strName.IsEmpty())
{
if (wcscmp(strName, pwzName) == 0)
{
index = i;
return true;
}
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::FindSID
//
// Synopsis: Return the index if the passed in string SID is found.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::FindSID(PCWSTR pwzSID, ULONG & index)
{
if (!_pFTInfo || !pwzSID)
{
dspAssert(FALSE);
return false;
}
CStrW strSID;
for (ULONG i = 0; i < _pFTInfo->RecordCount; i++)
{
PLSA_FOREST_TRUST_RECORD pRec = _pFTInfo->Entries[i];
dspAssert(pRec);
if (ForestTrustDomainInfo == pRec->ForestTrustType)
{
FormatSID(pRec->ForestTrustData.DomainInfo.Sid, strSID);
if (!strSID.IsEmpty())
{
if (strSID.CompareNoCase(pwzSID) == 0)
{
index = i;
return true;
}
}
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsDomainMatch
//
// Synopsis: Is there a domain whose name matches the passed-in TLNEx?
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsDomainMatch(ULONG index)
{
if (!_pFTInfo)
{
dspAssert(FALSE);
return false;
}
LSA_FOREST_TRUST_RECORD_TYPE type;
if (!GetType(index, type))
{
dspAssert(FALSE);
return false;
}
if (ForestTrustTopLevelNameEx != type)
{
dspAssert(FALSE);
return false;
}
CStrW strTlnEx, strDomain;
if (!GetDnsName(index, strTlnEx))
{
dspAssert(FALSE);
return false;
}
for (ULONG i = 0; i < _pFTInfo->RecordCount; i++)
{
PLSA_FOREST_TRUST_RECORD pRec = _pFTInfo->Entries[i];
dspAssert(pRec);
if (ForestTrustDomainInfo == pRec->ForestTrustType)
{
strDomain = pRec->ForestTrustData.DomainInfo.DnsName;
if (strDomain.CompareNoCase(strTlnEx) == 0)
{
return true;
}
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::GetDnsName
//
// Synopsis: Return the name for the passed in index.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::GetDnsName(ULONG index, CStrW & strName)
{
strName.Empty();
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
dspAssert(pFTRec);
switch (pFTRec->ForestTrustType)
{
case ForestTrustTopLevelName:
case ForestTrustTopLevelNameEx:
strName = pFTRec->ForestTrustData.TopLevelName;
return true;
case ForestTrustDomainInfo:
strName = pFTRec->ForestTrustData.DomainInfo.DnsName;
return true;
default:
dspAssert(FALSE);
break;
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::GetNbName
//
// Synopsis: Return the NetBIOS name for the passed in index.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::GetNbName(ULONG index, CStrW & strName)
{
strName.Empty();
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
dspAssert(pFTRec);
if (ForestTrustDomainInfo == pFTRec->ForestTrustType)
{
strName = pFTRec->ForestTrustData.DomainInfo.NetbiosName;
return true;
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::GetType
//
//-----------------------------------------------------------------------------
bool
CFTInfo::GetType(ULONG index, LSA_FOREST_TRUST_RECORD_TYPE & type)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
type = _pFTInfo->Entries[index]->ForestTrustType;
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::GetFlags
//
//-----------------------------------------------------------------------------
ULONG
CFTInfo::GetFlags(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return 0;
}
return _pFTInfo->Entries[index]->Flags;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::SetDomainState
//
// Synopsis: Set the extra-info flags to indicate status based on relation-
// ships between TLN exclusion records and domain records..
//
//-----------------------------------------------------------------------------
void
CFTInfo::SetDomainState(void)
{
if (!_pFTInfo)
{
return;
}
LSA_FOREST_TRUST_RECORD_TYPE type;
for (ULONG iTLNEx = 0; iTLNEx < _pFTInfo->RecordCount; iTLNEx++)
{
// Scan FTInfos for TLNEx records.
//
if (IsTlnExclusion(iTLNEx))
{
CStrW strTLNEx;
if (!GetDnsName(iTLNEx, strTLNEx))
{
dspAssert(FALSE);
continue;
}
// Search for a matching domain record.
//
for (ULONG jDomain = 0; jDomain < _pFTInfo->RecordCount; jDomain++)
{
if (!GetType(jDomain, type))
{
dspAssert(FALSE);
continue;
}
if (ForestTrustDomainInfo != type)
{
continue;
}
CStrW strDNS;
if (!GetDnsName(jDomain, strDNS))
{
dspAssert(FALSE);
continue;
}
if (strTLNEx == strDNS)
{
// If there is a matching domain record, mark it as
// disabled-via-matching-TLNEx in the extra info.
//
_pExtraInfo[jDomain]._Status = FT_EXTRA_INFO::STATUS::DisabledViaMatchingTLNEx;
// Set the status on the TLNEx as well.
//
_pExtraInfo[iTLNEx]._Status = FT_EXTRA_INFO::STATUS::TLNExMatchesExistingDomain;
// Search for children of the domain and mark each as
// disabled-via-parent-matching-TLNEx in the extra info.
//
for (ULONG kChild = 0; kChild < _pFTInfo->RecordCount; kChild++)
{
if (kChild == jDomain || kChild == iTLNEx)
{
continue;
}
if (IsChildDomain(jDomain, kChild))
{
_pExtraInfo[kChild]._Status = FT_EXTRA_INFO::STATUS::DisabledViaParentMatchingTLNEx;
}
}
// Only one domain record can match the exclusion.
//
break;
}
}
}
}
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsInConflict
//
// Synopsis: Are any of the FTInfo records in confict.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsInConflict(void)
{
if (!_pFTInfo)
{
return false;
}
for (ULONG i = 0; i < _pFTInfo->RecordCount; i++)
{
if (IsConflictFlagSet(i))
{
return true;
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsConflictFlagSet
//
// Synopsis: Is the FTInfo record in confict.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsConflictFlagSet(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
dspAssert(pFTRec);
switch (pFTRec->ForestTrustType)
{
case ForestTrustTopLevelName:
if (LSA_TLN_DISABLED_CONFLICT & pFTRec->Flags)
{
return true;
}
break;
case ForestTrustDomainInfo:
if (LSA_SID_DISABLED_CONFLICT & pFTRec->Flags ||
LSA_NB_DISABLED_CONFLICT & pFTRec->Flags)
{
return true;
}
break;
default:
break;
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::SetAdminDisable
//
// Synopsis: Admin-disables the name. Returns false if not a name record.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::SetAdminDisable(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
switch (pFTRec->ForestTrustType)
{
case ForestTrustTopLevelName:
pFTRec->Flags = LSA_TLN_DISABLED_ADMIN;
break;
case ForestTrustDomainInfo:
pFTRec->Flags = LSA_NB_DISABLED_ADMIN;
break;
default:
return false;
}
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::SetConflictDisable
//
// Synopsis: Sets the conflict-disabled flag. Returns false if not a name record.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::SetConflictDisable(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
switch (pFTRec->ForestTrustType)
{
case ForestTrustTopLevelName:
pFTRec->Flags = LSA_TLN_DISABLED_CONFLICT;
break;
case ForestTrustDomainInfo:
pFTRec->Flags = LSA_NB_DISABLED_CONFLICT;
break;
default:
return false;
}
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::SetSidAdminDisable
//
// Synopsis: Admin-disables the SID, returns false if not a domain record.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::SetSidAdminDisable(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
dspAssert(pFTRec);
if (!pFTRec || ForestTrustDomainInfo != pFTRec->ForestTrustType)
{
dspAssert(FALSE);
return false;
}
pFTRec->Flags = LSA_SID_DISABLED_ADMIN;
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsEnabled
//
// Synopsis:
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsEnabled(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
switch (pFTRec->ForestTrustType)
{
case ForestTrustDomainInfo:
if (FT_EXTRA_INFO::STATUS::Enabled == _pExtraInfo[index]._Status)
{
return true;
}
break;
case ForestTrustTopLevelName:
if (!(pFTRec->Flags & (LSA_TLN_DISABLED_NEW | LSA_TLN_DISABLED_ADMIN | LSA_TLN_DISABLED_CONFLICT)))
{
return true;
}
break;
default:
break;
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::DisableDomain
//
// Synopsis: Disable a domain subtree rooted at the domain named by index.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::DisableDomain(ULONG index)
{
TRACER(CFTInfo,DisableDomain);
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
if (ForestTrustDomainInfo != _pFTInfo->Entries[index]->ForestTrustType)
{
dspAssert(false);
return false;
}
CStrW strDomainName;
if (!GetDnsName(index, strDomainName))
{
dspAssert(false);
return false;
}
// Add an exclusion record for the domain's DNS name.
//
ULONG iNewTLNEx;
if (!AddNewExclusion(strDomainName, iNewTLNEx))
{
dspAssert(false);
return false;
}
_pExtraInfo[iNewTLNEx]._Status = FT_EXTRA_INFO::STATUS::TLNExMatchesExistingDomain;
// Mark the domain and all of its children as disabled.
//
_pExtraInfo[index]._Status = FT_EXTRA_INFO::STATUS::DisabledViaMatchingTLNEx;
for (ULONG j = 0; j < _pFTInfo->RecordCount; j++)
{
if (j == index || j == iNewTLNEx)
{
continue;
}
if (IsChildDomain(index, j))
{
_pExtraInfo[j]._Status = FT_EXTRA_INFO::STATUS::DisabledViaParentMatchingTLNEx;
}
}
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::EnableDomain
//
// Synopsis: Enable a domain subtree rooted at the domain named by index.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::EnableDomain(ULONG index)
{
TRACER(CFTInfo,EnableDomain);
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
if (ForestTrustDomainInfo != _pFTInfo->Entries[index]->ForestTrustType)
{
dspAssert(false);
return false;
}
// Remove the exclusion record.
//
ULONG iExclusion;
if (!FindMatchingExclusion(index, iExclusion))
{
dspAssert(false);
return false;
}
if (!RemoveExclusion(iExclusion))
{
dspAssert(false);
return false;
}
// Mark the domain and all of its children as enabled.
//
_pExtraInfo[index]._Status = FT_EXTRA_INFO::STATUS::Enabled;
for (ULONG j = 0; j < _pFTInfo->RecordCount; j++)
{
if (j == index || j == iExclusion)
{
continue;
}
if (IsChildDomain(index, j))
{
_pExtraInfo[j]._Status = FT_EXTRA_INFO::STATUS::Enabled;
}
}
return true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::SetUsedToBeInConflict
//
//-----------------------------------------------------------------------------
void
CFTInfo::SetUsedToBeInConflict(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount || !_pExtraInfo)
{
dspAssert(FALSE);
return;
}
_pExtraInfo[index]._fWasInConflict = true;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::WasInConflict
//
//-----------------------------------------------------------------------------
bool
CFTInfo::WasInConflict(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount || !_pExtraInfo)
{
dspAssert(FALSE);
return false;
}
return _pExtraInfo[index]._fWasInConflict;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::ClearAnyConflict
//
//-----------------------------------------------------------------------------
void
CFTInfo::ClearAnyConflict(void)
{
if (!_pFTInfo)
{
dspAssert(FALSE);
return;
}
for (ULONG i = 0; i < _pFTInfo->RecordCount; i++)
{
ClearConflict(i);
}
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::ClearConflict
//
//-----------------------------------------------------------------------------
void
CFTInfo::ClearConflict(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
dspAssert(pFTRec);
switch (pFTRec->ForestTrustType)
{
case ForestTrustTopLevelName:
if (LSA_TLN_DISABLED_CONFLICT & pFTRec->Flags)
{
pFTRec->Flags &= ~(LSA_TLN_DISABLED_CONFLICT);
}
break;
case ForestTrustDomainInfo:
if (LSA_SID_DISABLED_CONFLICT & pFTRec->Flags)
{
pFTRec->Flags &= ~(LSA_SID_DISABLED_CONFLICT);
}
if (LSA_NB_DISABLED_CONFLICT & pFTRec->Flags)
{
pFTRec->Flags &= ~(LSA_NB_DISABLED_CONFLICT);
}
break;
default:
break;
}
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::ClearDisableFlags
//
//-----------------------------------------------------------------------------
void
CFTInfo::ClearDisableFlags(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
pFTRec->Flags = 0;
if (_pExtraInfo)
{
_pExtraInfo[index]._fWasInConflict = false;
}
return;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::AnyChildDisabled
//
// Synopsis: Are any matching or child domain names disabled.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::AnyChildDisabled(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount ||
_pFTInfo->Entries[index]->ForestTrustType != ForestTrustTopLevelName)
{
dspAssert(FALSE);
return false;
}
CStrW strTLN, strDNS;
GetDnsName(index, strTLN);
dspAssert(!strTLN.IsEmpty());
for (ULONG i = 0; i < _pFTInfo->RecordCount; i++)
{
PLSA_FOREST_TRUST_RECORD pRec = _pFTInfo->Entries[i];
dspAssert(pRec);
strDNS.Empty();
// See if any subordinate names are disabled.
//
if (pRec->ForestTrustType == ForestTrustTopLevelName)
{
// No need to check the passed in or other TLNs.
//
continue;
}
bool fIsException = false;
switch (pRec->ForestTrustType)
{
case ForestTrustDomainInfo:
strDNS = pRec->ForestTrustData.DomainInfo.DnsName;
break;
case ForestTrustTopLevelNameEx:
strDNS = pRec->ForestTrustData.TopLevelName;
fIsException = true;
break;
default:
continue;
}
if (!strDNS.IsEmpty())
{
DNS_NAME_COMPARE_STATUS compare;
compare = DnsNameCompareEx_W(strDNS, strTLN, 0);
if ((DnsNameCompareRightParent == compare ||
DnsNameCompareEqual == compare) &&
(fIsException || pRec->Flags))
{
return true;
}
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsTlnExclusion
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsTlnExclusion(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
return _pFTInfo->Entries[index]->ForestTrustType == ForestTrustTopLevelNameEx;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::FindMatchingExclusion
//
// Synopsis: Search for an exclusion record that matches the indicated
// record. If CheckParents is true, will look for parent matches.
// CheckParents defaults to false.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::FindMatchingExclusion(ULONG index, ULONG & iExclusion, bool CheckParents)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
LSA_FOREST_TRUST_RECORD_TYPE type;
if (!GetType(index, type) || ForestTrustDomainInfo != type)
{
dspAssert(false);
return false;
}
CStrW strDomain, strExclusion;
if (!GetDnsName(index, strDomain))
{
dspAssert(false);
return false;
}
for (ULONG j = 0; j < _pFTInfo->RecordCount; j++)
{
if (!GetType(j, type))
{
dspAssert(false);
return false;
}
if (ForestTrustTopLevelNameEx != type)
{
continue;
}
if (!GetDnsName(j, strExclusion))
{
dspAssert(false);
return false;
}
if (strDomain == strExclusion)
{
iExclusion = j;
return true;
}
if (CheckParents && (DnsNameCompareEx_W(strDomain, strExclusion, 0) == DnsNameCompareRightParent))
{
iExclusion = j;
return true;
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsMatchingDomain
//
// Synopsis: Is the name of 'index' the domain with the same name as the
// top level name iTLN.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsMatchingDomain(ULONG iTLN, ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
if (iTLN == index)
{
return false;
}
if (ForestTrustTopLevelName != _pFTInfo->Entries[iTLN]->ForestTrustType ||
ForestTrustDomainInfo != _pFTInfo->Entries[index]->ForestTrustType)
{
return false;
}
CStrW strTLN, strDomain;
if (!GetDnsName(iTLN, strTLN))
{
dspAssert(FALSE);
return false;
}
if (!GetDnsName(index, strDomain))
{
dspAssert(FALSE);
return false;
}
if (strTLN == strDomain)
{
return true;
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsChildDomain
//
// Synopsis: Is the name of 'index' a child of the iParent DNS names.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsChildDomain(ULONG iParent, ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
CStrW strName;
if (!GetDnsName(index, strName))
{
return false;
}
return IsChildName(iParent, strName);
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsChildName
//
// Synopsis: Is the name pwzName a child of the iParent DNS names.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsChildName(ULONG iParent, PCWSTR pwzName)
{
if (!_pFTInfo || iParent >= _pFTInfo->RecordCount || !pwzName)
{
dspAssert(FALSE);
return false;
}
if (wcslen(pwzName) < 3)
{
return false;
}
CStrW strParent;
if (!GetDnsName(iParent, strParent))
{
return false;
}
return DnsNameCompareEx_W(strParent, pwzName, 0) == DnsNameCompareLeftParent;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsNameTLNExChild
//
// Synopsis: Is the name a child of a TLN exclusion.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsNameTLNExChild(PCWSTR pwzName)
{
if (!_pFTInfo || !pwzName || wcslen(pwzName) < 3)
{
dspAssert(FALSE);
return false;
}
CStrW strTLNEx;
for (ULONG i = 0; i < _pFTInfo->RecordCount; i++)
{
if (ForestTrustTopLevelNameEx == _pFTInfo->Entries[i]->ForestTrustType)
{
if (!GetDnsName(i, strTLNEx))
{
dspAssert(FALSE);
return false;
}
if (DnsNameCompareEx_W(strTLNEx, pwzName, 0) == DnsNameCompareLeftParent)
{
return true;
}
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::IsParentDisabled
//
//-----------------------------------------------------------------------------
bool
CFTInfo::IsParentDisabled(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
CStrW strTLN, strDNS;
GetDnsName(index, strDNS);
dspAssert(!strDNS.IsEmpty());
for (ULONG i = 0; i < _pFTInfo->RecordCount; i++)
{
PLSA_FOREST_TRUST_RECORD pRec = _pFTInfo->Entries[i];
dspAssert(pRec);
if (pRec->ForestTrustType != ForestTrustTopLevelName)
{
// Check only TLNs.
//
continue;
}
strTLN = pRec->ForestTrustData.TopLevelName;
if (DnsNameCompareEx_W(strDNS, strTLN, 0) == DnsNameCompareRightParent &&
pRec->Flags)
{
return true;
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::GetExtraStatus
//
// Synopsis: Return the extra-info status of the item.
//
//-----------------------------------------------------------------------------
FT_EXTRA_INFO::STATUS
CFTInfo::GetExtraStatus(ULONG index)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return FT_EXTRA_INFO::STATUS::Invalid;
}
return _pExtraInfo[index]._Status;
}
//+----------------------------------------------------------------------------
//
// Method: CFTInfo::GetTlnEditStatus
//
// Synopsis: Return the routing status of the item.
//
//-----------------------------------------------------------------------------
bool
CFTInfo::GetTlnEditStatus(ULONG index, TLN_EDIT_STATUS & status)
{
if (!_pFTInfo || index >= _pFTInfo->RecordCount)
{
dspAssert(FALSE);
return false;
}
PLSA_FOREST_TRUST_RECORD pFTRec = _pFTInfo->Entries[index];
dspAssert(pFTRec);
status = Enabled;
switch (pFTRec->ForestTrustType)
{
case ForestTrustTopLevelName:
if (pFTRec->Flags)
{
status = Disabled;
}
break;
case ForestTrustDomainInfo:
//
// Find the parent. If the parent is disabled, then so is this DNS name.
//
if (IsParentDisabled(index))
{
status = Disabled;
}
else
{
switch (pFTRec->Flags)
{
case LSA_SID_DISABLED_ADMIN:
case LSA_SID_DISABLED_CONFLICT:
//
// The SID is disabled but the NB name is enabled. The DNS
// name is disabled by virtue of the SID being disabled. NB
// names will still route though.
//
status = Disabled_Exceptions;
break;
case LSA_NB_DISABLED_ADMIN:
case LSA_NB_DISABLED_CONFLICT:
//
// SID enabled means DNS name enabled. Only NB names disabled.
//
status = Enabled_Exceptions;
break;
case LSA_SID_DISABLED_ADMIN | LSA_NB_DISABLED_ADMIN:
case LSA_SID_DISABLED_CONFLICT | LSA_NB_DISABLED_ADMIN:
case LSA_SID_DISABLED_ADMIN | LSA_NB_DISABLED_CONFLICT:
case LSA_SID_DISABLED_CONFLICT | LSA_NB_DISABLED_CONFLICT:
//
// If both NB and SID disabled, then no routing.
//
status = Disabled;
break;
default:
// already enabled above.
break;
}
}
break;
default:
break;
}
return true;
}
//+----------------------------------------------------------------------------
//
// Class: CFTCollisionInfo
//
// Purpose: Encapsulate the forest trust naming information.
//
//-----------------------------------------------------------------------------
CFTCollisionInfo::CFTCollisionInfo(void) :
_pFTCollisionInfo(NULL)
{
TRACER(CFTCollisionInfo,CFTCollisionInfo);
#ifdef _DEBUG
strcpy(szClass, "CFTCollisionInfo");
#endif
}
CFTCollisionInfo::CFTCollisionInfo(PLSA_FOREST_TRUST_COLLISION_INFORMATION pColInfo) :
_pFTCollisionInfo(NULL)
{
TRACER(CFTCollisionInfo,CFTCollisionInfo);
#ifdef _DEBUG
strcpy(szClass, "CFTCollisionInfo");
#endif
SetCollisionInfo(pColInfo);
}
CFTCollisionInfo::~CFTCollisionInfo(void)
{
if (_pFTCollisionInfo)
{
// The collision info is allocated by LsaSetForestTrustInformation
//
LsaFreeMemory(_pFTCollisionInfo);
}
}
const CFTCollisionInfo &
CFTCollisionInfo::operator = (const PLSA_FOREST_TRUST_COLLISION_INFORMATION pColInfo)
{
SetCollisionInfo(pColInfo);
return *this;
}
void
CFTCollisionInfo::SetCollisionInfo(PLSA_FOREST_TRUST_COLLISION_INFORMATION pColInfo)
{
TRACER(CFTCollisionInfo,SetCollisionInfo);
if (_pFTCollisionInfo)
{
// The collision info is allocated by LsaSetForestTrustInformation
//
LsaFreeMemory(_pFTCollisionInfo);
}
_pFTCollisionInfo = pColInfo;
#if DBG
if (_pFTCollisionInfo)
{
dspDebugOut((DEB_ITRACE, "pCollisionInfo->RecordCount = %d\n",
_pFTCollisionInfo->RecordCount));
}
#endif
}
//+----------------------------------------------------------------------------
//
// Method: CFTCollisionInfo::IsInCollisionInfo
//
// Synopsis: Is the FTRecord index found on a collision record?
//
//-----------------------------------------------------------------------------
bool
CFTCollisionInfo::IsInCollisionInfo(ULONG index)
{
if (!_pFTCollisionInfo)
{
return false;
}
for (ULONG i = 0; i < _pFTCollisionInfo->RecordCount; i++)
{
if (_pFTCollisionInfo->Entries[i]->Index == index)
{
return true;
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Method: CFTCollisionInfo::GetCollisionName
//
// Synopsis: Return the name of the source of the collision.
//
//-----------------------------------------------------------------------------
bool
CFTCollisionInfo::GetCollisionName(ULONG index, CStrW & strName)
{
strName.Empty();
if (!_pFTCollisionInfo)
{
return false;
}
for (ULONG i = 0; i < _pFTCollisionInfo->RecordCount; i++)
{
if (_pFTCollisionInfo->Entries[i]->Index == index)
{
strName = _pFTCollisionInfo->Entries[i]->Name;
return true;
}
}
return false;
}
//+----------------------------------------------------------------------------
//
// Function: ComposeLineTabSep
//
// Synopsis: Format a line of tab-separated-values.
//
// D&Ts Write-to-File functionality uses tabs as delimiters because
// Excel treats unicode CSV files as unknown format but it will
// nevertheless properly parse fields separated by tabs (but not commas).
//
// ulLineNum is ignored.
//
//-----------------------------------------------------------------------------
void
ComposeLineTabSep(CStrW & strOut, ULONG ulLineNum, PCWSTR pwzCol1,
PCWSTR pwzCol2, PCWSTR pwzCol3, PCWSTR pwzCol4)
{
dspAssert(pwzCol1 && pwzCol2);
strOut += pwzCol1;
strOut += L"\t";
strOut += pwzCol2;
if (pwzCol3 && *pwzCol3)
{
strOut += L"\t";
strOut += pwzCol3;
}
if (pwzCol4 && *pwzCol4)
{
strOut += L"\t";
strOut += pwzCol4;
}
strOut += g_wzCRLF;
}
//+----------------------------------------------------------------------------
//
// Function: ComposeNumberedLine
//
// Synopsis: Format a line of comma-separated-values.
//
// Used by netdom to list names to stdout.
//
//-----------------------------------------------------------------------------
void
ComposeNumberedLine(CStrW & strOut, ULONG ulLineNum, PCWSTR pwzCol1,
PCWSTR pwzCol2, PCWSTR pwzCol3, PCWSTR pwzCol4)
{
dspAssert(pwzCol1 && pwzCol2);
if (ulLineNum > 0)
{
CStrW strNumber;
strNumber.Format(L"%d. ", ulLineNum);
strOut += strNumber;
}
else
{
strOut += L" ";
}
strOut += pwzCol1;
strOut += L", ";
strOut += pwzCol2;
if (pwzCol3 && *pwzCol3)
{
strOut += L", ";
strOut += pwzCol3;
}
if (pwzCol4 && *pwzCol4)
{
strOut += L", ";
strOut += pwzCol4;
}
strOut += g_wzCRLF;
}
//+----------------------------------------------------------------------------
//
// Function: SaveFTInfoAs
//
// Synopsis: Prompt the user for a file name and then save the FTInfo as a
// CSV text file.
//
//-----------------------------------------------------------------------------
void
SaveFTInfoAs(HWND hWnd, PCWSTR pwzFlatName, PCWSTR pwzDnsName,
CFTInfo & FTInfo, CFTCollisionInfo & ColInfo)
{
TRACE_FUNCTION(SaveFTInfoAs);
if (!pwzFlatName || !pwzDnsName)
{
dspAssert(FALSE);
return;
}
OPENFILENAME ofn = {0};
WCHAR wzFilter[MAX_PATH + 1] = {0}, wzFileName[MAX_PATH + MAX_PATH + 1];
CStrW strFilter, strExt, strMsg;
wcscpy(wzFileName, pwzFlatName);
strExt.LoadString(g_hInstance, IDS_FTFILE_SUFFIX);
wcscat(wzFileName, strExt);
wcscat(wzFileName, L".");
strExt.LoadString(g_hInstance, IDS_FTFILE_CSV_EXT);
wcscat(wzFileName, strExt);
LoadString(g_hInstance, IDS_FTFILE_FILTER, wzFilter, MAX_PATH);
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = wzFileName;
ofn.nMaxFile = MAX_PATH + MAX_PATH + 1;
ofn.Flags = OFN_OVERWRITEPROMPT;
ofn.lpstrDefExt = strExt;
ofn.lpstrFilter = wzFilter;
if (GetSaveFileName(&ofn))
{
dspDebugOut((DEB_ITRACE, "Saving FTInfo to %ws\n", ofn.lpstrFile));
PWSTR pwzErr;
BOOL fSucceeded = TRUE;
HANDLE hFile = CreateFile(ofn.lpstrFile, GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
CStrW strPrefix;
strPrefix.LoadString(g_hInstance, IDS_LOG_PREFIX);
ComposeLineTabSep(strMsg, 0, strPrefix, pwzDnsName, NULL, NULL);
strMsg += g_wzCRLF;
FormatFTNames(FTInfo, ColInfo, ComposeLineTabSep, strMsg);
strMsg += g_wzCRLF;
DWORD dwWritten;
fSucceeded = WriteFile(hFile, strMsg.GetBuffer(0),
strMsg.GetLength() * sizeof(WCHAR),
&dwWritten, NULL);
CloseHandle(hFile);
}
else
{
fSucceeded = FALSE;
}
if (!fSucceeded)
{
CStrW strTitle;
strTitle.LoadString(g_hInstance, IDS_DNT_MSG_TITLE);
LoadErrorMessage(GetLastError(), 0, &pwzErr);
if (pwzErr)
{
strMsg.FormatMessage(g_hInstance, IDS_LOGFILE_CREATE_FAILED, pwzErr);
delete [] pwzErr;
}
MessageBox(hWnd, strMsg, strTitle, MB_ICONERROR);
}
}
}
//+----------------------------------------------------------------------------
//
// Function: FormatFTNames
//
//-----------------------------------------------------------------------------
void
FormatFTNames(CFTInfo & FTInfo, CFTCollisionInfo & ColInfo,
LINE_COMPOSER pLineFcn, CStrW & strMsg)
{
TRACE_FUNCTION(FormatFTNames);
PLSA_FOREST_TRUST_RECORD pRec = NULL;
CStrW strName, strType, strStatus, strNotes, strDnsName,
strAdminDisabled, strNewDisabled, strEnabled, strTlnExMatch,
strExclusion, strTypeSuffix, strTypeDnsDomain, strTypeNBDomain,
strConflict, strTypeSID, strWith, strFor, strUnknown;
strName.LoadString(g_hInstance, IDS_COL_TITLE_OBJNAME);
strType.LoadString(g_hInstance, IDS_LOG_TYPE);
strStatus.LoadString(g_hInstance, IDS_LOG_STATUS);
strNotes.LoadString(g_hInstance, IDS_LOG_NOTES);
(*pLineFcn)(strMsg, 0, strName, strType, strStatus, strNotes);
if (!FTInfo.GetCount())
{
return;
}
strTypeSuffix.LoadString(g_hInstance, IDS_LOG_NAME_SUFFIX);
strTypeDnsDomain.LoadString(g_hInstance, IDS_LOG_DOM_DNS_NAME);
strTypeNBDomain.LoadString(g_hInstance, IDS_LOG_DOM_FLAT_NAME);
strTypeSID.LoadString(g_hInstance, IDS_LOG_SID);
strEnabled.LoadString(g_hInstance, IDS_LOG_ENABLED);
strAdminDisabled.LoadString(g_hInstance, IDS_LOG_ADMIN_DISABLED);
strNewDisabled.LoadString(g_hInstance, IDS_LOG_NEW_DISABLED);
strExclusion.LoadString(g_hInstance, IDS_LOG_EXCLUSION);
strTlnExMatch.LoadString(g_hInstance, IDS_LOG_MATCHING_EXCLUSION);
strConflict.LoadString(g_hInstance, IDS_LOG_CONFLICT);
strWith.LoadString(g_hInstance, IDS_LOG_WITH);
strFor.LoadString(g_hInstance, IDS_LOG_FOR);
strUnknown.LoadString(g_hInstance, IDS_LOG_UNKNOWN);
CStrW strCollisionName;
ULONG j = 1;
for (UINT i = 0; i < FTInfo.GetCount(); i++)
{
bool fCollision = false;
bool fExcluded = false;
pRec = FTInfo.GetFTInfo()->Entries[i];
dspAssert(pRec);
if (ColInfo.IsInCollisionInfo(i))
{
fCollision = TRUE;
ColInfo.GetCollisionName(i, strCollisionName);
}
strNotes.Empty();
strStatus.Empty();
switch (pRec->ForestTrustType)
{
case ForestTrustTopLevelName:
strName = pRec->ForestTrustData.TopLevelName;
AddAsteriskPrefix(strName);
if (pRec->Flags)
{
if (LSA_TLN_DISABLED_NEW & pRec->Flags)
{
strStatus = strNewDisabled;
}
if (LSA_TLN_DISABLED_ADMIN & pRec->Flags)
{
strStatus = strAdminDisabled;
}
if (LSA_TLN_DISABLED_CONFLICT & pRec->Flags)
{
strStatus = strConflict;
}
}
else
{
strStatus = strEnabled;
}
if (fCollision)
{
strStatus = strConflict;
strNotes = strWith;
strNotes += strCollisionName;
}
(*pLineFcn)(strMsg, j++, strName, strTypeSuffix, strStatus, strNotes);
break;
case ForestTrustTopLevelNameEx:
strName = pRec->ForestTrustData.TopLevelName;
AddAsteriskPrefix(strName);
(*pLineFcn)(strMsg, j++, strName,
FTInfo.IsDomainMatch(i) ? strTlnExMatch : strExclusion,
NULL, NULL);
break;
case ForestTrustDomainInfo:
strDnsName = pRec->ForestTrustData.DomainInfo.DnsName;
strStatus = strEnabled;
ULONG iExclusion;
if (FTInfo.FindMatchingExclusion(i, iExclusion, true))
{
strStatus = strAdminDisabled;
strType.LoadString(g_hInstance, IDS_LOG_HAS_EXCLUSION);
strNotes = strType;
fExcluded = true;
}
(*pLineFcn)(strMsg, j++, strDnsName, strTypeDnsDomain, strStatus, strNotes);
strName = pRec->ForestTrustData.DomainInfo.NetbiosName;
strNotes = strFor;
strNotes += strDnsName;
if (fCollision)
{
strStatus = strConflict;
strNotes += ", ";
strNotes += strWith;
strNotes += strCollisionName;
}
if (fExcluded)
{
strStatus = strAdminDisabled;
strNotes += ", ";
strNotes += strType;
}
else
{
if (LSA_NB_DISABLED_ADMIN & pRec->Flags)
{
strStatus = strAdminDisabled;
}
else if (LSA_NB_DISABLED_CONFLICT & pRec->Flags)
{
strStatus = strConflict;
}
else
{
strStatus = strEnabled;
}
}
(*pLineFcn)(strMsg, j++, strName, strTypeNBDomain, strStatus, strNotes);
FormatSID(pRec->ForestTrustData.DomainInfo.Sid, strName);
strNotes = strFor;
strNotes += strDnsName;
if (fCollision)
{
strStatus = strConflict;
strNotes += ", ";
strNotes += strWith;
strNotes += strCollisionName;
}
if (fExcluded)
{
strStatus = strAdminDisabled;
strNotes += ", ";
strNotes += strType;
}
else
{
if (LSA_SID_DISABLED_ADMIN & pRec->Flags)
{
strStatus = strAdminDisabled;
}
else if (LSA_SID_DISABLED_CONFLICT & pRec->Flags)
{
strStatus = strConflict;
}
else
{
strStatus = strEnabled;
}
}
(*pLineFcn)(strMsg, j++, strName, strTypeSID, strStatus, strNotes);
break;
default:
(*pLineFcn)(strMsg, j++, strUnknown, L"", NULL, NULL);
break;
}
}
return;
}
//+----------------------------------------------------------------------------
//
// Function: FormatSID
//
//-----------------------------------------------------------------------------
void
FormatSID(PSID Sid, CStrW & str)
{
TRACE_FUNCTION(FormatSID);
SID_IDENTIFIER_AUTHORITY * sia;
ULONG i = 0;
CStrW strTmp;
dspAssert(Sid);
sia = RtlIdentifierAuthoritySid(Sid);
str = L"s-1-";
for (i = 0; i < 5; i++)
{
if (sia->Value[i])
{
strTmp.Format(L"%d", sia->Value[i]);
str += strTmp;
}
}
strTmp.Format(L"%d", sia->Value[5]);
str += strTmp;
for (i = 0; i < *RtlSubAuthorityCountSid(Sid); i++)
{
strTmp.Format(L"-%ld", *RtlSubAuthoritySid(Sid, i));
str += strTmp;
}
}
void AddAsteriskPrefix(CStrW & strName)
{
CStrW strTemp = L"*.";
strTemp += strName;
strName = strTemp;
}
void RemoveAsteriskPrefix(CStrW & strName)
{
CStrW strTemp;
strTemp = strName.Left(2);
if (strTemp != L"*.")
{
return;
}
strTemp = strName.Right(strName.GetLength() - 2);
strName = strTemp;
}
//+----------------------------------------------------------------------------
//
// Function: NDReadFTNames
//
// Synopsis: Reads the forest trust names claimed by the trust partner and
// stored on the TDO. No attempt is made to contact the other
// domain to refresh the names.
//
//-----------------------------------------------------------------------------
DWORD
NDReadFTNames(PCWSTR pwzLocalDc, PCWSTR pwzTrust, CFTInfo & FTInfo,
CFTCollisionInfo & ColInfo)
{
DWORD dwRet = NO_ERROR;
NTSTATUS status = STATUS_SUCCESS;
LSA_UNICODE_STRING TrustPartner = {0};
PLSA_FOREST_TRUST_INFORMATION pFTInfo = NULL;
if (!pwzLocalDc || !pwzTrust)
{
return ERROR_INVALID_PARAMETER;
}
RtlInitUnicodeString(&TrustPartner, pwzTrust);
CPolicyHandle cPolicy(pwzLocalDc);
dwRet = cPolicy.OpenNoAdmin();
if (NO_ERROR != dwRet)
{
return dwRet;
}
status = LsaQueryForestTrustInformation(cPolicy,
&TrustPartner,
&pFTInfo);
if (STATUS_NOT_FOUND == status)
{
// no FT info stored yet, which can occur on a new trust.
//
CStrW strErr;
strErr.LoadString(g_hInstance, IDS_NETDOM_NO_FTINFOS);
printf("%ws\n", strErr.GetBuffer(0));
return LsaNtStatusToWinError(status);
}
if (NO_ERROR != (dwRet = LsaNtStatusToWinError(status)))
{
if (ERROR_INVALID_DOMAIN_STATE == dwRet)
{
CStrW strMsg;
strMsg.LoadString(g_hInstance, IDS_NETDOM_NOT_FOREST);
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
if (ERROR_NO_SUCH_DOMAIN == dwRet)
{
CStrW strMsg;
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_NO_TRUST, pwzTrust);
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
return dwRet;
}
dspAssert(pFTInfo);
FTInfo = pFTInfo;
LsaFreeMemory(pFTInfo);
// Make a temp copy and clear the conflict bit before submitting to LSA.
// This will return current conflict info.
//
CFTInfo TempFTInfo(FTInfo);
TempFTInfo.ClearAnyConflict();
// Now check the data. On return from the call the pColInfo struct
// will contain current collision data.
//
PLSA_FOREST_TRUST_COLLISION_INFORMATION pColInfo = NULL;
status = LsaSetForestTrustInformation(cPolicy,
&TrustPartner,
TempFTInfo.GetFTInfo(),
TRUE, // check only, don't write to TDO
&pColInfo);
if (NO_ERROR != (dwRet = LsaNtStatusToWinError(status)))
{
if (ERROR_INVALID_DOMAIN_STATE == dwRet)
{
CStrW strMsg;
strMsg.LoadString(g_hInstance, IDS_NETDOM_NOT_FOREST);
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
return dwRet;
}
ColInfo = pColInfo;
// Look for names that used to be or are now in conflict.
//
for (ULONG i = 0; i < FTInfo.GetCount(); i++)
{
// Any names that used to be in conflict but aren't now are marked as
// admin-disabled.
//
if (FTInfo.IsConflictFlagSet(i))
{
if (!ColInfo.IsInCollisionInfo(i))
{
FTInfo.SetAdminDisable(i);
FTInfo.SetUsedToBeInConflict(i);
continue;
}
}
// If a name is in the collision info, then set the conflict flag.
//
if (ColInfo.IsInCollisionInfo(i))
{
FTInfo.SetConflictDisable(i);
}
}
return NO_ERROR;
}
//+----------------------------------------------------------------------------
//
// Function: NDWriteFTNames
//
// Synopsis: Writes the forest trust names to the TDO.
//
//-----------------------------------------------------------------------------
DWORD
NDWriteFTNames(PCWSTR pwzLocalDc, PCWSTR pwzTrust, CFTInfo & FTInfo)
{
DWORD dwRet = NO_ERROR;
NTSTATUS status = STATUS_SUCCESS;
LSA_UNICODE_STRING TrustPartner = {0};
PLSA_FOREST_TRUST_INFORMATION pFTInfo = NULL;
if (!pwzLocalDc || !pwzTrust || !FTInfo.GetCount())
{
return ERROR_INVALID_PARAMETER;
}
RtlInitUnicodeString(&TrustPartner, pwzTrust);
CPolicyHandle cPolicy(pwzLocalDc);
dwRet = cPolicy.OpenNoAdmin();
if (NO_ERROR != dwRet)
{
return dwRet;
}
PLSA_FOREST_TRUST_COLLISION_INFORMATION pColInfo = NULL;
status = LsaSetForestTrustInformation(cPolicy,
&TrustPartner,
FTInfo.GetFTInfo(),
FALSE,
&pColInfo);
if (NO_ERROR != (dwRet = LsaNtStatusToWinError(status)))
{
return dwRet;
}
if (pColInfo)
{
LsaFreeMemory(pColInfo);
}
return NO_ERROR;
}
//+----------------------------------------------------------------------------
//
// Function: DSPROP_DumpFTInfos
//
// Synopsis: Exported function that netdom can use to dump the FTInfos for a
// forest trust.
//
//-----------------------------------------------------------------------------
extern "C" INT_PTR WINAPI
DSPROP_DumpFTInfos(PCWSTR pwzLocalDc, PCWSTR pwzTrust,
PCWSTR pwzUser, PCWSTR pwzPw)
{
TRACE_FUNCTION(DSPROP_DumpFTInfos);
if (!pwzLocalDc || !pwzTrust)
{
return ERROR_INVALID_PARAMETER;
}
//
// Read the FTInfos, using the creds if needed.
//
DWORD dwRet = NO_ERROR;
CCreds Creds;
if (pwzUser && *pwzUser)
{
dwRet = Creds.SetUserAndPW(pwzUser, pwzPw, NULL);
if (ERROR_SUCCESS != dwRet)
{
return dwRet;
}
dwRet = Creds.Impersonate();
if (ERROR_SUCCESS != dwRet)
{
return dwRet;
}
}
CFTInfo FTInfo;
CFTCollisionInfo ColInfo;
dwRet = NDReadFTNames(pwzLocalDc, pwzTrust, FTInfo, ColInfo);
if (NO_ERROR != dwRet)
{
return dwRet;
}
CStrW strMsg;
FormatFTNames(FTInfo, ColInfo, ComposeNumberedLine, strMsg);
printf("%ws\n", strMsg.GetBuffer(0));
return NO_ERROR;
}
//+----------------------------------------------------------------------------
//
// Function: DSPROP_ToggleFTName
//
// Synopsis: Exported function that netdom can use to toggle the state of an
// FTInfo name for a forest trust.
//
//-----------------------------------------------------------------------------
extern "C" INT_PTR WINAPI
DSPROP_ToggleFTName(PCWSTR pwzLocalDc, PWSTR pwzTrust, ULONG iSel,
PCWSTR pwzUser, PCWSTR pwzPW)
{
dspDebugOut((DEB_ITRACE, "DSPROP_ToggleFTName, TDO: %ws, name: %d\n",
pwzTrust, iSel));
if (!pwzLocalDc || !pwzTrust)
{
return ERROR_INVALID_PARAMETER;
}
//
// Read the FTInfos, using the creds if needed.
//
DWORD dwRet = NO_ERROR;
NTSTATUS status = 0;
CCreds Creds;
if (pwzUser && *pwzUser)
{
dwRet = Creds.SetUserAndPW(pwzUser, pwzPW, NULL);
if (ERROR_SUCCESS != dwRet)
{
return dwRet;
}
dwRet = Creds.Impersonate();
if (ERROR_SUCCESS != dwRet)
{
return dwRet;
}
}
CFTInfo FTInfo;
CFTCollisionInfo ColInfo;
CStrW strMsg, strName, strCollisionName;
dwRet = NDReadFTNames(pwzLocalDc, pwzTrust, FTInfo, ColInfo);
if (NO_ERROR != dwRet)
{
return dwRet;
}
PLSA_FOREST_TRUST_RECORD pRec = NULL;
ULONG j = 1;
bool fFound = false;
for (UINT i = 0; i < FTInfo.GetCount() && !fFound; i++)
{
pRec = FTInfo.GetFTInfo()->Entries[i];
dspAssert(pRec);
bool fExcluded = false;
switch (pRec->ForestTrustType)
{
case ForestTrustTopLevelName:
if (iSel == j)
{
if (pRec->Flags)
{
if (pRec->Flags & (LSA_TLN_DISABLED_NEW | LSA_TLN_DISABLED_ADMIN))
{
pRec->Flags = 0;
}
if ((LSA_TLN_DISABLED_CONFLICT & pRec->Flags) ||
ColInfo.IsInCollisionInfo(i))
{
strName = pRec->ForestTrustData.TopLevelName;
if (ColInfo.GetCollisionName(i, strCollisionName))
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_CONFLICT_NAME,
strName.GetBuffer(0),
strCollisionName.GetBuffer(0));
}
else
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_CONFLICT,
strName.GetBuffer(0));
}
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
}
else
{
pRec->Flags = LSA_TLN_DISABLED_ADMIN;
}
fFound = true;
break;
}
j++;
break;
case ForestTrustTopLevelNameEx:
if (iSel == j)
{
strName = pRec->ForestTrustData.TopLevelName;
strMsg.FormatMessage(g_hInstance,
FTInfo.IsDomainMatch(i) ? IDS_NETDOM_MATCHING_TLNEX :
IDS_NETDOM_TLNEX,
strName.GetBuffer(0));
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
j++;
break;
case ForestTrustDomainInfo:
ULONG iExclusion;
fExcluded = FTInfo.FindMatchingExclusion(i, iExclusion, true);
if (iSel == j)
{
strName = pRec->ForestTrustData.DomainInfo.DnsName;
strMsg.FormatMessage(g_hInstance,
(fExcluded) ? IDS_NETDOM_ENABLE_DOMAIN :
IDS_NETDOM_DISABLE_DOMAIN,
strName.GetBuffer(0));
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
j++;
if (iSel == j)
{
strName = pRec->ForestTrustData.DomainInfo.NetbiosName;
if ((LSA_NB_DISABLED_CONFLICT & pRec->Flags) ||
ColInfo.IsInCollisionInfo(i))
{
if (ColInfo.GetCollisionName(i, strCollisionName))
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_CONFLICT_NAME,
strName.GetBuffer(0),
strCollisionName.GetBuffer(0));
}
else
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_CONFLICT,
strName.GetBuffer(0));
}
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
if (fExcluded)
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_EXCLUDED,
strName.GetBuffer(0));
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
if (LSA_NB_DISABLED_ADMIN & pRec->Flags)
{
pRec->Flags &= ~LSA_NB_DISABLED_ADMIN;
}
else
{
pRec->Flags |= LSA_NB_DISABLED_ADMIN;
}
fFound = true;
break;
}
j++;
if (iSel == j)
{
FormatSID(pRec->ForestTrustData.DomainInfo.Sid, strName);
if ((LSA_SID_DISABLED_CONFLICT & pRec->Flags) ||
ColInfo.IsInCollisionInfo(i))
{
if (ColInfo.GetCollisionName(i, strCollisionName))
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_SID_CONFLICT_NAME,
strName.GetBuffer(0),
strCollisionName.GetBuffer(0));
}
else
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_SID_CONFLICT,
strName.GetBuffer(0));
}
}
if (fExcluded)
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_EXCLUDED,
strName.GetBuffer(0));
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
if (LSA_SID_DISABLED_ADMIN & pRec->Flags)
{
pRec->Flags &= ~LSA_SID_DISABLED_ADMIN;
}
else
{
pRec->Flags |= LSA_SID_DISABLED_ADMIN;
}
fFound = true;
break;
}
j++;
break;
default:
if (iSel == j)
{
return ERROR_INVALID_PARAMETER;
}
j++;
break;
}
}
if (!fFound)
{
strMsg.FormatMessage(g_hInstance, IDS_NETDOM_RANGE_ERROR, --j);
printf("%ws\n", strMsg.GetBuffer(0));
return ERROR_INVALID_PARAMETER;
}
//
// Save the updated FTInfo.
//
dwRet = NDWriteFTNames(pwzLocalDc, pwzTrust, FTInfo);
if (NO_ERROR != dwRet)
{
strMsg.LoadString(g_hInstance, IDS_NETDOM_WRITE_FTINFO_FAILED);
printf("%ws\n", strMsg.GetBuffer(0));
return dwRet;
}
//
// Print out the changes for the user.
//
FormatFTNames(FTInfo, ColInfo, ComposeNumberedLine, strMsg);
printf("%ws\n", strMsg.GetBuffer(0));
return NO_ERROR;
}
#endif // DSADMIN