windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/logonsrv/idl/nlcommon.c

764 lines
18 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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 <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <rpc.h> // RPC_STATUS
#include <windef.h>
#include <winsock2.h>
#include <lmcons.h> // General net defines
#include <dsgetdc.h> // DsGetDcName()
#include <align.h> // ROUND_UP_COUNT()
#include <lmerr.h> // System Error Log definitions
#include <lmapibuf.h> // NetapipBufferAllocate
#include <netlib.h> // NetpMemoryAllcate(
#include <netlibnt.h> // NetpApiStatusToNtStatus();
#include <netlogon.h> // Definition of mailslot messages
#include <ntddbrow.h> // Needed by nlcommon.h
#include <ntrpcp.h>
#if DBG
#define NETLOGONDBG 1
#endif // DBG
#include <nldebug.h> // NlPrint()
#include <nlbind.h> // Definitions shared with netlogon
#include <nlcommon.h> // Definitions shared with netlogon
#include <stdlib.h> // 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; EntryNumber<EntryCount; EntryNumber++ ) {
LPBYTE TheStruct = BufferDescriptor->Buffer + 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<CountReturned; i++ ) {
Status = NlAllocateForestTrustListEntry (
&BufferDescriptor,
&TrustList[i].Name,
NULL, // No DNS domain name
DS_DOMAIN_DIRECT_OUTBOUND,
0, // No ParentIndex
TRUST_TYPE_DOWNLEVEL,
0, // No TrustAttributes
TrustList[i].Sid,
NULL, // No DomainGuid
&Size,
&TrustedDomain );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
//
// Account for the newly allocated entry
//
*ForestTrustListSize += Size;
(*ForestTrustListCount) ++;
}
} while ( !AllDone );
*ForestTrustList = (PDS_DOMAIN_TRUSTSW) BufferDescriptor.Buffer;
BufferDescriptor.Buffer = NULL;
Status = STATUS_SUCCESS;
//
// Free any locally used resources.
//
Cleanup:
if ( LsaHandle != NULL ) {
(VOID) LsaClose( LsaHandle );
}
if ( TrustList != NULL ) {
(VOID) LsaFreeMemory( TrustList );
}
if ( BufferDescriptor.Buffer != NULL ) {
NetApiBufferFree( BufferDescriptor.Buffer );
}
if ( PrimaryDomainInfo != NULL ) {
(void) LsaFreeMemory( PrimaryDomainInfo );
}
return Status;
}
NTSTATUS
NlRpcpBindRpc(
IN LPWSTR ServerName,
IN LPWSTR ServiceName,
IN LPWSTR NetworkOptions,
IN NL_RPC_BINDING RpcBindingType,
OUT RPC_BINDING_HANDLE *pBindingHandle
)
/*++
Routine Description:
Binds to the RPC server if possible.
Arguments:
ServerName - Name of server to bind with.
ServiceName - Name of service to bind with.
RpcBindingType - Determines whether to use unauthenticated TCP/IP transport instead of
a named pipe.
pBindingHandle - Location where binding handle is to be placed
Return Value:
STATUS_SUCCESS - The binding has been successfully completed.
STATUS_INVALID_COMPUTER_NAME - The ServerName syntax is invalid.
STATUS_NO_MEMORY - There is not sufficient memory available to the
caller to perform the binding.
--*/
{
RPC_STATUS RpcStatus;
LPWSTR StringBinding;
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
LPWSTR NewServerName = NULL;
DWORD bufLen = MAX_COMPUTERNAME_LENGTH + 1;
//
// If we're supposed to use named pipes,
// call the standard routine.
//
if ( RpcBindingType == UseNamedPipe ) {
return RpcpBindRpc( ServerName, ServiceName, NetworkOptions, pBindingHandle );
}
//
// Otherwise, use TCP/IP directly.
//
*pBindingHandle = NULL;
if (ServerName != NULL) {
if (GetComputerNameW(ComputerName,&bufLen)) {
if ((_wcsicmp(ComputerName,ServerName) == 0) ||
((ServerName[0] == '\\') &&
(ServerName[1] == '\\') &&
(_wcsicmp(ComputerName,&(ServerName[2]))==0))) {
NewServerName = NULL;
}
else {
NewServerName = ServerName;
}
}
}
//
// Ditch the \\
//
if ( NewServerName != NULL &&
NewServerName[0] == '\\' &&
NewServerName[1] == '\\' ) {
NewServerName += 2;
}
//
// Enpoint isn't known.
// Rpc will contact the endpoint mapper for it.
//
RpcStatus = RpcStringBindingComposeW(0, L"ncacn_ip_tcp", NewServerName,
NULL, NetworkOptions, &StringBinding);
if ( RpcStatus != RPC_S_OK ) {
return( STATUS_NO_MEMORY );
}
RpcStatus = RpcBindingFromStringBindingW(StringBinding, pBindingHandle);
RpcStringFreeW(&StringBinding);
if ( RpcStatus != RPC_S_OK ) {
*pBindingHandle = NULL;
if ( RpcStatus == RPC_S_INVALID_ENDPOINT_FORMAT ||
RpcStatus == RPC_S_INVALID_NET_ADDR ) {
return( STATUS_INVALID_COMPUTER_NAME );
}
if ( RpcStatus == RPC_S_PROTSEQ_NOT_SUPPORTED ) {
return RPC_NT_PROTSEQ_NOT_SUPPORTED;
}
return(STATUS_NO_MEMORY);
}
return(STATUS_SUCCESS);
}
BOOLEAN
NlDoingSetup(
VOID
)
/*++
Routine Description:
Returns TRUE if we're running setup.
Arguments:
NONE.
Return Status:
TRUE - We're currently running setup
FALSE - We're not running setup or aren't sure.
--*/
{
DWORD Value;
if ( !NlReadDwordHklmRegValue( "SYSTEM\\Setup",
"SystemSetupInProgress",
&Value ) ) {
return FALSE;
}
if ( Value != 1 ) {
// NlPrint(( 0, "NlDoingSetup: not doing setup\n" ));
return FALSE;
}
NlPrint(( 0, "NlDoingSetup: doing setup\n" ));
return TRUE;
}
#endif // WIN32_CHICAGO