//+---------------------------------------------------------------------------- // // Windows 2000 Active Directory Service domain trust verification WMI provider // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 2000 // // File: domain.cpp // // Contents: domain class implementation // // Classes: CDomainInfo // // History: 27-Mar-00 EricB created // //----------------------------------------------------------------------------- #include PCWSTR CSTR_PROP_LOCAL_DNS_NAME = L"DNSname"; // String PCWSTR CSTR_PROP_LOCAL_FLAT_NAME = L"FlatName"; // String PCWSTR CSTR_PROP_LOCAL_SID = L"SID"; // String PCWSTR CSTR_PROP_LOCAL_TREE_NAME = L"TreeName"; // String PCWSTR CSTR_PROP_LOCAL_DC_NAME = L"DCname"; // String // TODO: string property listing the FSMOs owned by this DC? //Implementaion of CDomainInfo class //+---------------------------------------------------------------------------- // // Class: CDomainInfo // //----------------------------------------------------------------------------- CDomainInfo::CDomainInfo() { TRACE(L"CDomainInfo::CDomainInfo\n"); m_liLastEnumed.QuadPart = 0; } CDomainInfo::~CDomainInfo() { TRACE(L"CDomainInfo::~CDomainInfo\n"); Reset(); } //+---------------------------------------------------------------------------- // // Method: CDomainInfo::Init // // Synopsis: Initializes the CDomainInfo object. // //----------------------------------------------------------------------------- HRESULT CDomainInfo::Init(IWbemClassObject * pClassDef) { TRACE(L"CDomainInfo::Init\n"); NTSTATUS Status = STATUS_SUCCESS; OBJECT_ATTRIBUTES objectAttributes; CSmartPolicyHandle chPolicy; m_sipClassDefLocalDomain = pClassDef; InitializeObjectAttributes(&objectAttributes, NULL, 0L, NULL, NULL); // Get Local policy Status = LsaOpenPolicy(NULL, // Local server &objectAttributes, MAXIMUM_ALLOWED, // Needed for Rediscover &chPolicy); if (!NT_SUCCESS(Status)) { TRACE(L"LsaOpenPolicy failed with error %d\n", Status); return HRESULT_FROM_WIN32(LsaNtStatusToWinError(Status)); } PPOLICY_DNS_DOMAIN_INFO pDnsDomainInfo; Status = LsaQueryInformationPolicy(chPolicy, PolicyDnsDomainInformation, (PVOID *)&pDnsDomainInfo); if (!NT_SUCCESS(Status)) { TRACE(L"LsaQueryInformationPolicy failed with error %d\n", Status); return HRESULT_FROM_WIN32(LsaNtStatusToWinError(Status)); } m_strDomainFlatName = pDnsDomainInfo->Name.Buffer; m_strDomainDnsName = pDnsDomainInfo->DnsDomainName.Buffer; m_strForestName = pDnsDomainInfo->DnsForestName.Buffer; if (!SetSid(pDnsDomainInfo->Sid)) { ASSERT(false); LsaFreeMemory(pDnsDomainInfo); return E_OUTOFMEMORY; } LsaFreeMemory(pDnsDomainInfo); DWORD dwBufSize = MAX_COMPUTERNAME_LENGTH + 1; if (!GetComputerName(m_strDcName.GetBuffer(dwBufSize), &dwBufSize)) { DWORD dwErr = GetLastError(); TRACE(L"GetComputerName failed with error %d\n", dwErr); return HRESULT_FROM_WIN32(dwErr); } m_strDcName.ReleaseBuffer(); return S_OK; } //+---------------------------------------------------------------------------- // // Method: CDomainInfo::Reset // // Synopsis: Free the contents of the trust array and re-initialize it. // //----------------------------------------------------------------------------- void CDomainInfo::Reset(void) { TRACE(L"CDomainInfo::Reset\n"); CTrustInfo * pTrustInfo = NULL; if (IsEnumerated()) { // Empty cache for (UINT i = 0; i < m_vectTrustInfo.size(); ++i) { pTrustInfo = m_vectTrustInfo[i]; if (pTrustInfo) delete pTrustInfo; } m_vectTrustInfo.clear(); } } //+---------------------------------------------------------------------------- // // Method: CDomainInfo::SetSid // //----------------------------------------------------------------------------- BOOL CDomainInfo::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 ?? #endif } //+---------------------------------------------------------------------------- // // Method: CDomainInfo::EnumerateTrusts // // Synopsis: List the trusts for this domain. // //----------------------------------------------------------------------------- #if !defined(NT4_BUILD) HRESULT CDomainInfo::EnumerateTrusts(void) { TRACE(L"CDomainInfo::EnumerateTrusts\n"); DWORD dwRet = ERROR_SUCCESS; CTrustInfo * pTrustInfo = NULL; PDS_DOMAIN_TRUSTS rgTrusts = NULL; ULONG nTrustCount = 0; Reset(); dwRet = DsEnumerateDomainTrusts(NULL, DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_DIRECT_INBOUND, &rgTrusts, &nTrustCount); if (ERROR_SUCCESS != dwRet) { TRACE(L"DsEnumerateDomainTrusts failed with error %d\n", dwRet); return HRESULT_FROM_WIN32(dwRet); } for (ULONG i = 0; i < nTrustCount; i++) { pTrustInfo = new CTrustInfo(); BREAK_ON_NULL(pTrustInfo); if (rgTrusts[i].DnsDomainName) { // Downlevel domains don't have a DNS name. // pTrustInfo->SetTrustedDomain(rgTrusts[i].DnsDomainName); } else { // So use the flat name instead. // pTrustInfo->SetTrustedDomain(rgTrusts[i].NetbiosDomainName); } pTrustInfo->SetFlatName(rgTrusts[i].NetbiosDomainName); BREAK_ON_NULL(pTrustInfo->SetSid(rgTrusts[i].DomainSid)); pTrustInfo->SetTrustType(rgTrusts[i].TrustType); pTrustInfo->SetTrustDirectionFromFlags(rgTrusts[i].Flags); pTrustInfo->SetTrustAttributes(rgTrusts[i].TrustAttributes); pTrustInfo->SetFlags(rgTrusts[i].Flags); m_vectTrustInfo.push_back(pTrustInfo); pTrustInfo = NULL; } if (rgTrusts) { NetApiBufferFree(rgTrusts); } if (ERROR_SUCCESS == dwRet) { SYSTEMTIME st; GetSystemTime(&st); SystemTimeToFileTime(&st, (LPFILETIME)&m_liLastEnumed); } return HRESULT_FROM_WIN32(dwRet); } #else // NT4_BUILD HRESULT CDomainInfo::EnumerateTrusts(void) { TRACE(L"CDomainInfo::EnumerateTrusts\n"); NTSTATUS Status = STATUS_SUCCESS; DWORD dwErr = ERROR_SUCCESS; ULONG i = 0; CTrustInfo * pTrustInfo = NULL; Reset(); LSA_ENUMERATION_HANDLE hEnumContext = NULL; ULONG nTrustCount = 0; ULONG nTotalCount = 0; ULONG j = 0; PLSA_TRUST_INFORMATION pTrustDomainInfo = NULL; DWORD hResumeHandle = 0; LPUSER_INFO_0 pUserList = NULL; CTrustInfo * pTempTrustInfo = NULL; LPWSTR Lop = NULL; CSmartPolicyHandle chPolicy; OBJECT_ATTRIBUTES objectAttributes; InitializeObjectAttributes(&objectAttributes, NULL, 0L, NULL, NULL); // // We'll have to do this the old fashioned way. That means that we'll enumerate all of // the trust directly, save them off in a list, and then go through and enumerate all // of the interdomain trust accounts and merge those into the list. // do { Status = LsaOpenPolicy(NULL, // Local server &objectAttributes, MAXIMUM_ALLOWED, // Needed for Rediscover &chPolicy); Status = LsaEnumerateTrustedDomains(chPolicy, &hEnumContext, (void**)&pTrustDomainInfo, ULONG_MAX, &nTrustCount ); if (NT_SUCCESS(Status) || Status == STATUS_MORE_ENTRIES) { dwErr = ERROR_SUCCESS; for ( i = 0; i < nTrustCount; i++ ) { pTrustInfo = new CTrustInfo(); CHECK_NULL( pTrustInfo, CLEAN_RETURN ); pTrustInfo->SetTrustedDomain( pTrustDomainInfo[i].Name.Buffer ); pTrustInfo->SetFlatName( pTrustDomainInfo[i].Name.Buffer ); pTrustInfo->SetSid( pTrustDomainInfo[i].Sid ); pTrustInfo->SetTrustType( TRUST_TYPE_DOWNLEVEL ); pTrustInfo->SetTrustDirection( TRUST_DIRECTION_OUTBOUND ); m_vectTrustInfo.push_back( pTrustInfo ); pTrustInfo = NULL; } LsaFreeMemory( pTrustDomainInfo ); pTrustDomainInfo = NULL; } else dwErr = LsaNtStatusToWinError(Status); } while (Status == STATUS_MORE_ENTRIES); if( Status == STATUS_NO_MORE_ENTRIES ) dwErr = ERROR_SUCCESS; // // Now, let's add in the user accounts // if ( dwErr == ERROR_SUCCESS ) { do { nTrustCount = 0; nTotalCount = 0; dwErr = NetUserEnum(NULL, 0, FILTER_INTERDOMAIN_TRUST_ACCOUNT, (LPBYTE *)&pUserList, MAX_PREFERRED_LENGTH, &nTrustCount, &nTotalCount, &hResumeHandle); if ( dwErr == ERROR_SUCCESS || dwErr == ERROR_MORE_DATA ) { dwErr = ERROR_SUCCESS; for ( i = 0; i < nTrustCount; i++ ) { Lop = wcsrchr( pUserList[ i ].usri0_name, L'$' ); if ( Lop ) { *Lop = UNICODE_NULL; } for ( j = 0; j < m_vectTrustInfo.size(); j++ ) { pTempTrustInfo = m_vectTrustInfo[j]; if ( _wcsicmp( pUserList[ i ].usri0_name, pTempTrustInfo->GetTrustedDomain() ) == 0 ) { pTempTrustInfo->SetTrustDirection( TRUST_DIRECTION_INBOUND | TRUST_DIRECTION_OUTBOUND ); break; } } // If it wasn't found, add it... if ( j == m_vectTrustInfo.size() ) { pTrustInfo = new CTrustInfo(); CHECK_NULL( pTrustInfo, CLEAN_RETURN ); pTrustInfo->SetTrustedDomain( pUserList[ i ].usri0_name ); pTrustInfo->SetFlatName( pUserList[ i ].usri0_name ); pTrustInfo->SetTrustType( TRUST_TYPE_DOWNLEVEL ); pTrustInfo->SetTrustDirection( TRUST_DIRECTION_INBOUND ); m_vectTrustInfo.push_back( pTrustInfo ); pTrustInfo = NULL; } if ( Lop ) { *Lop = L'$'; } } NetApiBufferFree( pUserList ); pUserList = NULL; } } while ( dwErr == ERROR_MORE_DATA ); } CLEAN_RETURN: if( pUserList ) NetApiBufferFree( pUserList ); if( pTrustDomainInfo ) LsaFreeMemory( pTrustDomainInfo ); if (ERROR_SUCCESS == dwErr) { SYSTEMTIME st; GetSystemTime(&st); SystemTimeToFileTime(&st, (LPFILETIME)&m_liLastEnumed); } return HRESULT_FROM_WIN32(dwErr); } #endif // NT4_BUILD //+---------------------------------------------------------------------------- // // Method: CDomainInfo::FindTrust // // Synopsis: Find a trust by trusted Domain Name // //----------------------------------------------------------------------------- CTrustInfo * CDomainInfo::FindTrust(PCWSTR pwzTrust) { TRACE(L"CDomainInfo::FindTrust\n"); TRACE(L"\nlooking for domain %s\n", pwzTrust); ASSERT(IsEnumerated()); ULONG i = 0; for( i = 0; i < m_vectTrustInfo.size(); ++i ) { int nStrComp = CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, (m_vectTrustInfo[i])->GetTrustedDomain(), -1, pwzTrust, -1 ); ASSERT( nStrComp ); if( CSTR_EQUAL == nStrComp ) { TRACE(L"Trust found!\n"); return m_vectTrustInfo[i]; } } return NULL; // Not Found } //+---------------------------------------------------------------------------- // // Method: CDomainInfo::GetTrustByIndex // // Synopsis: Get trust info by Index // //----------------------------------------------------------------------------- CTrustInfo * CDomainInfo::GetTrustByIndex(size_t index) { ASSERT(IsEnumerated()); if (index < Size()) { return m_vectTrustInfo[index]; } else { ASSERT(FALSE); return NULL; } } //+---------------------------------------------------------------------------- // // Method: CDomainInfo::IsTrustListStale // // Synopsis: Checks to see if the last emumeration time is older than the // passed in criteria. // // Returns: TRUE if older. // // Notes: If the trusts haven't been enumerated (m_liLastEnumed == 0), // then the enumeration is defined to be stale. // //----------------------------------------------------------------------------- BOOL CDomainInfo::IsTrustListStale(LARGE_INTEGER liMaxAge) { TRACE(L"CDomainInfo::IsTrustListStale(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); fStale = (m_liLastEnumed.QuadPart + liMaxAge.QuadPart) < liCurrentTime.QuadPart; return fStale; } //+---------------------------------------------------------------------------- // // Method: CDomainInfo::CreateAndSendInst // // Synopsis: Returns a copy of the current instance back to WMI // //----------------------------------------------------------------------------- HRESULT CDomainInfo::CreateAndSendInst(IWbemObjectSink * pResponseHandler) { TRACE(L"CDomainInfo::CreateAndSendInst\n"); HRESULT hr = WBEM_S_NO_ERROR; do { CComPtr ipNewInst; CComVariant var; // // Create a new instance of the WMI class object // hr = m_sipClassDefLocalDomain->SpawnInstance(0, &ipNewInst); BREAK_ON_FAIL; // Set the DNS property value var = GetDnsName(); hr = ipNewInst->Put(CSTR_PROP_LOCAL_DNS_NAME, 0, &var, 0); TRACE(L"\tCreating instance %s\n", var.bstrVal); BREAK_ON_FAIL; // Set the flat name property value var = GetFlatName(); hr = ipNewInst->Put(CSTR_PROP_LOCAL_FLAT_NAME, 0, &var, 0); TRACE(L"\twith flat name %s\n", var.bstrVal); BREAK_ON_FAIL; // Set the SID property value var = GetSid(); hr = ipNewInst->Put(CSTR_PROP_LOCAL_SID, 0, &var, 0); TRACE(L"\twith SID %s\n", var.bstrVal); BREAK_ON_FAIL; // Set the forest name property value var = GetForestName(); hr = ipNewInst->Put(CSTR_PROP_LOCAL_TREE_NAME, 0, &var, 0); TRACE(L"\twith forest name %s\n", var.bstrVal); BREAK_ON_FAIL; // Set the DC name property value var = GetDcName(); hr = ipNewInst->Put(CSTR_PROP_LOCAL_DC_NAME, 0, &var, 0); TRACE(L"\ton DC %s\n", var.bstrVal); BREAK_ON_FAIL; // // Send the object to the caller // // [In] param, no need to addref. IWbemClassObject * pNewInstance = ipNewInst; hr = pResponseHandler->Indicate(1, &pNewInstance); BREAK_ON_FAIL; } while(FALSE); return hr; }