/*++ Copyright (c) 1987-1999 Microsoft Corporation Module Name: nlcommon.c Abstract: Routines shared by logonsrv\server and logonsrv\common Author: Cliff Van Dyke (cliffv) 20-July-1996 Environment: User mode only. Contains NT-specific code. Requires ANSI C extensions: slash-slash comments, long external names. Revision History: --*/ // // Common include files. // #ifndef _NETLOGON_SERVER #include #include #include #include #include // RPC_STATUS #include #include #include // General net defines #include // DsGetDcName() #include // ROUND_UP_COUNT() #include // System Error Log definitions #include // NetapipBufferAllocate #include // NetpMemoryAllcate( #include // NetpApiStatusToNtStatus(); #include // Definition of mailslot messages #include // Needed by nlcommon.h #include #if DBG #define NETLOGONDBG 1 #endif // DBG #include // NlPrint() #include // Definitions shared with netlogon #include // Definitions shared with netlogon #include // C library functions (rand, etc) #endif // _NETLOGON_SERVER // // Include nlcommon.h again allocating the actual variables // this time around. // // #define NLCOMMON_ALLOCATE // #include "nlcommon.h" // #undef NLCOMMON_ALLOCATE #ifndef WIN32_CHICAGO VOID NlForestRelocationRoutine( IN DWORD Level, IN OUT PBUFFER_DESCRIPTOR BufferDescriptor, IN PTRDIFF_T Offset ) /*++ Routine Description: Routine to relocate the pointers from the fixed portion of a NetGroupEnum enumeration buffer to the string portion of an enumeration buffer. It is called as a callback routine from NetpAllocateEnumBuffer when it re-allocates such a buffer. NetpAllocateEnumBuffer copied the fixed portion and string portion into the new buffer before calling this routine. Arguments: Level - Level of information in the buffer. BufferDescriptor - Description of the new buffer. Offset - Offset to add to each pointer in the fixed portion. Return Value: Returns the error code for the operation. --*/ { DWORD EntryCount; DWORD EntryNumber; DWORD FixedSize; // // Local macro to add a byte offset to a pointer. // #define RELOCATE_ONE( _fieldname, _offset ) \ if ( (_fieldname) != NULL ) { \ _fieldname = (PVOID) ((LPBYTE)(_fieldname) + (_offset)); \ } // // Compute the number of fixed size entries // FixedSize = sizeof(DS_DOMAIN_TRUSTSW); EntryCount = ((DWORD)(BufferDescriptor->FixedDataEnd - BufferDescriptor->Buffer)) / FixedSize; // // Loop relocating each field in each fixed size structure // for ( EntryNumber=0; EntryNumberBuffer + FixedSize * EntryNumber; RELOCATE_ONE( ((PDS_DOMAIN_TRUSTSW)TheStruct)->NetbiosDomainName, Offset ); RELOCATE_ONE( ((PDS_DOMAIN_TRUSTSW)TheStruct)->DnsDomainName, Offset ); RELOCATE_ONE( ((PDS_DOMAIN_TRUSTSW)TheStruct)->DomainSid, Offset ); } return; UNREFERENCED_PARAMETER( Level ); } NTSTATUS NlAllocateForestTrustListEntry ( IN PBUFFER_DESCRIPTOR BufferDescriptor, IN PUNICODE_STRING InNetbiosDomainName OPTIONAL, IN PUNICODE_STRING InDnsDomainName OPTIONAL, IN ULONG Flags, IN ULONG ParentIndex, IN ULONG TrustType, IN ULONG TrustAttributes, IN PSID DomainSid OPTIONAL, IN GUID *DomainGuid, OUT PULONG RetSize, OUT PDS_DOMAIN_TRUSTSW *RetTrustedDomain ) /*++ Routine Description: Add a DS_DOMAIN_TRUSTSW structure to the buffer described by BufferDescriptor. Arguments: BufferDescriptor - Buffer entry is to be added to. NetbiosDomainName, DnsDomainName, Flags, ParentIndex, TrustType, TrustAttributes, DomainSid, DomainGuid - Fields to fill into the DS_DOMAIN_TRUSTSW structure RetSize - Returns the size in bytes of the allocated entry RetTrustedDomain - Returns a pointer to the newly allocated structure Return Value: Status of the operation. --*/ { NTSTATUS Status; NET_API_STATUS NetStatus; PDS_DOMAIN_TRUSTSW TrustedDomain = NULL; UNICODE_STRING NetbiosDomainName; UNICODE_STRING DnsDomainName; ULONG Size; ULONG VariableSize; // // Initialization // if ( InNetbiosDomainName == NULL ) { RtlInitUnicodeString( &NetbiosDomainName, NULL ); } else { NetbiosDomainName = *InNetbiosDomainName; } if ( InDnsDomainName == NULL ) { RtlInitUnicodeString( &DnsDomainName, NULL ); } else { DnsDomainName = *InDnsDomainName; } // // Determine the size of this entry // Size = sizeof(DS_DOMAIN_TRUSTSW); VariableSize = 0; if ( DnsDomainName.Length != 0 ) { VariableSize += DnsDomainName.Length + sizeof(WCHAR); } if ( NetbiosDomainName.Length != 0 ) { VariableSize += NetbiosDomainName.Length + sizeof(WCHAR); } if ( DomainSid != NULL ) { VariableSize += RtlLengthSid( DomainSid ); } VariableSize = ROUND_UP_COUNT( VariableSize, ALIGN_DWORD ); *RetSize = Size + VariableSize; Size += VariableSize; Size += sizeof(DWORD); // Size is really a function of alignment of EndOfVariableData NetStatus = NetpAllocateEnumBufferEx( BufferDescriptor, FALSE, // Not a 'get' operation 0xFFFFFFFF, // PrefMaxLen, Size, NlForestRelocationRoutine, 0, 512 ); // Grow by at most 512 bytes more than Size if (NetStatus != NERR_Success) { Status = NetpApiStatusToNtStatus( NetStatus ); goto Cleanup; } // // Copy this entry into the buffer // TrustedDomain = (PDS_DOMAIN_TRUSTSW)(BufferDescriptor->FixedDataEnd); *RetTrustedDomain = TrustedDomain; BufferDescriptor->FixedDataEnd += sizeof(DS_DOMAIN_TRUSTSW); // // Copy the fixed size data // TrustedDomain->Flags = Flags; TrustedDomain->ParentIndex = ParentIndex; TrustedDomain->TrustType = TrustType; TrustedDomain->TrustAttributes = TrustAttributes; if ( DomainGuid == NULL ) { RtlZeroMemory( &TrustedDomain->DomainGuid, sizeof(GUID) ); } else { TrustedDomain->DomainGuid = *DomainGuid; } // // Copy the information into the buffer. // // // Copy the DWORD aligned data // if ( DomainSid != NULL ) { if ( !NetpCopyDataToBuffer ( (LPBYTE)DomainSid, RtlLengthSid( DomainSid ), BufferDescriptor->FixedDataEnd, &BufferDescriptor->EndOfVariableData, (LPBYTE *)&TrustedDomain->DomainSid, sizeof(DWORD) ) ) { Status = STATUS_INTERNAL_ERROR; goto Cleanup; } } else { TrustedDomain->DomainSid = NULL; } // // Copy the WCHAR aligned data. // if ( NetbiosDomainName.Length != 0 ) { if ( !NetpCopyStringToBuffer( NetbiosDomainName.Buffer, NetbiosDomainName.Length/sizeof(WCHAR), BufferDescriptor->FixedDataEnd, (LPWSTR *)&BufferDescriptor->EndOfVariableData, &TrustedDomain->NetbiosDomainName ) ) { Status = STATUS_INTERNAL_ERROR; goto Cleanup; } } else { TrustedDomain->NetbiosDomainName = NULL; } if ( DnsDomainName.Length != 0 ) { if ( !NetpCopyStringToBuffer( DnsDomainName.Buffer, DnsDomainName.Length/sizeof(WCHAR), BufferDescriptor->FixedDataEnd, (LPWSTR *)&BufferDescriptor->EndOfVariableData, &TrustedDomain->DnsDomainName ) ) { Status = STATUS_INTERNAL_ERROR; goto Cleanup; } } else { TrustedDomain->DnsDomainName = NULL; } Status = STATUS_SUCCESS; // // Cleanup: return Status; } NTSTATUS NlGetNt4TrustedDomainList ( IN LPWSTR UncDcName, IN PUNICODE_STRING InNetbiosDomainName OPTIONAL, IN PUNICODE_STRING InDnsDomainName OPTIONAL, IN PSID DomainSid OPTIONAL, IN GUID *DomainGuid OPTIONAL, OUT PDS_DOMAIN_TRUSTSW *ForestTrustList, OUT PULONG ForestTrustListSize, OUT PULONG ForestTrustListCount ) /*++ Routine Description: Get the list of trusted domains from the specified DC using NT 4 protocols. Arguments: UncDcName - Specifies the name of a DC in the domain. InNetbiosDomainName - Netbios domain of the domain Dc is in. InDnsDomainName - Dns domain of the domain Dc is in. DomainSid - Sid of the domain Dc is in. DomainGuid - Guid of the domain Dc is in. ForestTrustList - Returns a list of trusted domains. Must be freed using NetApiBufferFree ForestTrustListSize - Size (in bytes) of ForestTrustList ForestTrustListCount - Number of entries in ForestTrustList Return Value: STATUS_SUCCESS - if the trust list was successfully returned --*/ { NTSTATUS Status; NET_API_STATUS NetStatus; LSA_HANDLE LsaHandle = NULL; UNICODE_STRING UncDcNameString; OBJECT_ATTRIBUTES ObjectAttributes; LSA_ENUMERATION_HANDLE EnumerationContext; BOOLEAN AllDone = FALSE; PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo = NULL; PLSA_TRUST_INFORMATION TrustList = NULL; BUFFER_DESCRIPTOR BufferDescriptor; PDS_DOMAIN_TRUSTSW TrustedDomain; DWORD Size; // // Initialization // *ForestTrustListCount = 0; *ForestTrustListSize = 0; *ForestTrustList = NULL; BufferDescriptor.Buffer = NULL; // // Open the policy database on the DC // RtlInitUnicodeString( &UncDcNameString, UncDcName ); InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); Status = LsaOpenPolicy( &UncDcNameString, &ObjectAttributes, POLICY_VIEW_LOCAL_INFORMATION, &LsaHandle ); if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "NlGetNt4TrustedDomainList: %ws: LsaOpenPolicy failed: %lx\n", UncDcName, Status )); LsaHandle = NULL; goto Cleanup; } // // If the caller didn't specify primary domain information, // get it from the DC // if ( InNetbiosDomainName == NULL ) { // // Get the name of the primary domain from LSA // Status = LsaQueryInformationPolicy( LsaHandle, PolicyPrimaryDomainInformation, (PVOID *) &PrimaryDomainInfo ); if (! NT_SUCCESS(Status)) { NlPrint(( NL_CRITICAL, "NlGetNt4TrustedDomainList: LsaQueryInformationPolicy failed %lx\n", Status)); goto Cleanup; } // // Grab the returned information // InNetbiosDomainName = &PrimaryDomainInfo->Name; InDnsDomainName = NULL; DomainSid = PrimaryDomainInfo->Sid; DomainGuid = NULL; } // // The LsaEnumerateTrustedDomain doesn't have the PrimaryDomain in the trust list. // Add it to our list here. // Status = NlAllocateForestTrustListEntry ( &BufferDescriptor, InNetbiosDomainName, InDnsDomainName, DS_DOMAIN_PRIMARY, 0, // No ParentIndex TRUST_TYPE_DOWNLEVEL, 0, // No TrustAttributes DomainSid, DomainGuid, &Size, &TrustedDomain ); if ( !NT_SUCCESS(Status) ) { goto Cleanup; } *ForestTrustListSize += Size; (*ForestTrustListCount) ++; // // Loop getting a list of trusted domains // EnumerationContext = 0; do { ULONG i; ULONG CountReturned; // // Free any buffers from a previous iteration. // if ( TrustList != NULL ) { (VOID) LsaFreeMemory( TrustList ); } // // Get more trusted domains names // Status = LsaEnumerateTrustedDomains( LsaHandle, &EnumerationContext, (PVOID *) &TrustList, 0xFFFFFFFF, &CountReturned ); if ( Status == STATUS_NO_MORE_ENTRIES ) { AllDone = TRUE; Status = STATUS_SUCCESS; } if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "NlGetNt4TrustedDomainList: %ws: LsaEnumerateTrustedDomains failed: %lx\n", UncDcName, Status )); TrustList = NULL; goto Cleanup; } // // Handle each trusted domain. // for ( i=0; i