2368 lines
67 KiB
C++
2368 lines
67 KiB
C++
/*++
|
||
|
||
Microsoft Windows
|
||
|
||
Copyright (C) Microsoft Corporation, 1998 - 2001
|
||
|
||
Module Name:
|
||
|
||
query.c
|
||
|
||
Abstract:
|
||
|
||
Handles the various functions for the QUERY command
|
||
|
||
--*/
|
||
#include "pch.h"
|
||
#pragma hdrstop
|
||
#include <netdom.h>
|
||
|
||
#define VERIFY_QUERY_ONLY 0xFFFFFFFF
|
||
|
||
typedef enum _ND5_ACCOUNT_TYPE {
|
||
|
||
TypeWorkstation,
|
||
TypeServer,
|
||
TypeDomainController,
|
||
TypePDC,
|
||
TypeUnknown
|
||
|
||
} ND5_ACCOUNT_TYPE;
|
||
|
||
typedef enum _ND5_ACCOUNT_OPERATION {
|
||
|
||
OperationDisplay,
|
||
OperationVerify,
|
||
OperationReset
|
||
} ND5_ACCOUNT_OPERATION;
|
||
|
||
typedef struct _ND5_TRANS_TREE_NODE {
|
||
|
||
PDS_DOMAIN_TRUSTS DomainInfo;
|
||
ULONG ListIndex;
|
||
ULONG Children;
|
||
struct _ND5_TRANS_TREE_NODE *ChildList;
|
||
struct _ND5_TRANS_TREE_NODE *Parent;
|
||
|
||
} ND5_TRANS_TREE_NODE, *PND5_TRANS_TREE_NODE;
|
||
|
||
|
||
VOID
|
||
NetDompFreeBuiltTrustInfo(
|
||
IN PTRUSTED_DOMAIN_INFORMATION_EX TDInfoEx,
|
||
IN ULONG Count
|
||
)
|
||
{
|
||
ULONG i;
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
NetApiBufferFree( TDInfoEx[ i ].Name.Buffer );
|
||
}
|
||
|
||
NetApiBufferFree( TDInfoEx );
|
||
}
|
||
|
||
VOID
|
||
NetDompDumpTrustInfo(
|
||
IN PWSTR Domain,
|
||
IN PTRUSTED_DOMAIN_INFORMATION_EX TrustInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will display the specified trusted domain info
|
||
|
||
Arguments:
|
||
|
||
Domain - Domain to be dumped
|
||
|
||
TrustInfo - Trust info the domain
|
||
|
||
Return Value:
|
||
|
||
VOID
|
||
|
||
--*/
|
||
{
|
||
ULONG Message, Type;
|
||
|
||
//
|
||
// Display the direction & name
|
||
//
|
||
Type = TrustInfo->TrustDirection & TRUST_DIRECTION_BIDIRECTIONAL;
|
||
|
||
switch ( Type ) {
|
||
case TRUST_DIRECTION_BIDIRECTIONAL:
|
||
|
||
Message = MSG_TRUST_BOTH_ARROW;
|
||
break;
|
||
|
||
case TRUST_DIRECTION_INBOUND:
|
||
|
||
Message = MSG_TRUST_IN_ARROW;
|
||
break;
|
||
|
||
case TRUST_DIRECTION_OUTBOUND:
|
||
|
||
Message = MSG_TRUST_OUT_ARROW;
|
||
break;
|
||
}
|
||
|
||
NetDompDisplayMessage( Message,
|
||
TrustInfo->Name.Buffer );
|
||
|
||
//
|
||
// Then, the type
|
||
//
|
||
switch ( TrustInfo->TrustType ) {
|
||
|
||
case TRUST_TYPE_DOWNLEVEL:
|
||
case TRUST_TYPE_UPLEVEL:
|
||
|
||
Message = MSG_TRUST_TYPE_WINDOWS;
|
||
break;
|
||
|
||
case TRUST_TYPE_MIT:
|
||
|
||
Message = MSG_TRUST_TYPE_MIT;
|
||
break;
|
||
|
||
default:
|
||
|
||
Message = MSG_TRUST_TYPE_OTHER;
|
||
break;
|
||
}
|
||
|
||
NetDompDisplayMessage( Message );
|
||
|
||
printf( "\n" );
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: GetTrustInfo
|
||
//
|
||
// Synopsis: Reads the trust info from the local TDO for the named domain.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
DWORD
|
||
GetTrustInfo(PWSTR pwzDomain,
|
||
PND5_TRUST_INFO pLocalInfo,
|
||
PND5_TRUST_INFO pTrustInfo,
|
||
DWORD * pdwVerifyErr)
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PTRUSTED_DOMAIN_INFORMATION_EX pTDIEx = NULL;
|
||
UNICODE_STRING usDomainName;
|
||
LSA_HANDLE hTrust;
|
||
|
||
*pdwVerifyErr = ERROR_ACCESS_DENIED;
|
||
|
||
RtlInitUnicodeString(&usDomainName, pwzDomain);
|
||
|
||
Status = LsaOpenTrustedDomainByName(pLocalInfo->LsaHandle,
|
||
&usDomainName,
|
||
TRUSTED_READ,
|
||
&hTrust);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
*pdwVerifyErr = LsaNtStatusToWinError(Status);
|
||
return *pdwVerifyErr;
|
||
}
|
||
|
||
Status = LsaQueryInfoTrustedDomain(hTrust,
|
||
TrustedDomainInformationEx,
|
||
(PVOID*)&pTDIEx);
|
||
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
*pdwVerifyErr = LsaNtStatusToWinError(Status);
|
||
return *pdwVerifyErr;
|
||
}
|
||
|
||
pTrustInfo->TrustHandle = hTrust;
|
||
pTrustInfo->DomainName = &pTDIEx->Name;
|
||
pTrustInfo->FlatName = &pTDIEx->FlatName;
|
||
pTrustInfo->Sid = pTDIEx->Sid;
|
||
pTrustInfo->BlobToFree = pTDIEx;
|
||
|
||
if (pTDIEx->TrustType >= TRUST_TYPE_MIT)
|
||
{
|
||
pTrustInfo->Uplevel = FALSE;
|
||
pTrustInfo->Flags = NETDOM_TRUST_TYPE_MIT;
|
||
*pdwVerifyErr = ERROR_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
PDOMAIN_CONTROLLER_INFO pDcInfo = NULL;
|
||
PPOLICY_DNS_DOMAIN_INFO pPolicyDDI = NULL;
|
||
OBJECT_ATTRIBUTES OA;
|
||
UNICODE_STRING ServerU, DomainNameU;
|
||
|
||
// Get a DC name for the domain.
|
||
//
|
||
Win32Err = DsGetDcName(NULL,
|
||
pwzDomain,
|
||
NULL,
|
||
NULL,
|
||
DS_DIRECTORY_SERVICE_PREFERRED,
|
||
&pDcInfo );
|
||
|
||
if (ERROR_SUCCESS != Win32Err)
|
||
{
|
||
pTrustInfo->Flags = NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND;
|
||
*pdwVerifyErr = Win32Err;
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
// Save off the DC name.
|
||
//
|
||
Win32Err = NetApiBufferAllocate((wcslen(pDcInfo->DomainControllerName) + 1) * sizeof(WCHAR),
|
||
(PVOID*)&(pTrustInfo->Server));
|
||
|
||
if (ERROR_SUCCESS != Win32Err)
|
||
{
|
||
NetApiBufferFree(pDcInfo);
|
||
return Win32Err;
|
||
}
|
||
|
||
wcscpy(pTrustInfo->Server, pDcInfo->DomainControllerName);
|
||
|
||
NetApiBufferFree(pDcInfo);
|
||
|
||
Win32Err = NetpManageIPCConnect(pTrustInfo->Server,
|
||
L"",
|
||
L"",
|
||
NETSETUPP_NULL_SESSION_IPC);
|
||
if (ERROR_SUCCESS == Win32Err)
|
||
{
|
||
pTrustInfo->Connected = TRUE;
|
||
}
|
||
|
||
RtlInitUnicodeString(&ServerU, pTrustInfo->Server);
|
||
|
||
InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL );
|
||
|
||
Status = LsaOpenPolicy(&ServerU,
|
||
&OA,
|
||
POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES,
|
||
&(pTrustInfo->LsaHandle));
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
// Find out if this is an uplevel or downlevel domain.
|
||
//
|
||
Status = LsaQueryInformationPolicy(pTrustInfo->LsaHandle,
|
||
PolicyDnsDomainInformation,
|
||
(PVOID *)&pPolicyDDI);
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
LsaFreeMemory(pPolicyDDI);
|
||
pTrustInfo->Uplevel = TRUE;
|
||
pTrustInfo->fWasDownlevel = FALSE;
|
||
}
|
||
else
|
||
{
|
||
if (RPC_NT_PROCNUM_OUT_OF_RANGE == Status)
|
||
{
|
||
pTrustInfo->Uplevel = pTrustInfo->fWasDownlevel = FALSE;
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (ERROR_NO_SUCH_DOMAIN == (*pdwVerifyErr = RtlNtStatusToDosError(Status)) ||
|
||
RPC_S_SERVER_UNAVAILABLE == *pdwVerifyErr)
|
||
{
|
||
pTrustInfo->Flags = NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND;
|
||
}
|
||
|
||
if (*pdwVerifyErr != ERROR_SUCCESS && pTrustInfo->Connected)
|
||
{
|
||
NetpManageIPCConnect(pTrustInfo->Server,
|
||
NULL,
|
||
NULL,
|
||
NETSETUPP_DISCONNECT_IPC);
|
||
pTrustInfo->Connected = FALSE;
|
||
}
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NetDompQueryDirectTrust(
|
||
|
||
IN PWSTR Domain,
|
||
IN PND5_TRUST_INFO TrustInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will get the trustinfo for the specified domain
|
||
|
||
Arguments:
|
||
|
||
Domain - Domain to get the trust info for
|
||
|
||
TrustInfo - Trust info to be obtained
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
LSA_ENUMERATION_HANDLE EnumerationContext = 0;
|
||
PTRUSTED_DOMAIN_INFORMATION_EX TDInfoEx = NULL, TempTDIEx = NULL;
|
||
PLSA_TRUST_INFORMATION TDInfo = NULL;
|
||
ULONG Count, i, TotalCount = 0, UserCount, j;
|
||
BOOL DisplayHeader = TRUE;
|
||
LPUSER_INFO_0 UserList = NULL;
|
||
ULONG ResumeHandle = 0;
|
||
PWSTR Lop, FullServer = NULL;
|
||
|
||
//
|
||
// Handle the uplevel case differently
|
||
//
|
||
if ( TrustInfo->Uplevel ) {
|
||
|
||
do {
|
||
|
||
Status = LsaEnumerateTrustedDomainsEx( TrustInfo->LsaHandle,
|
||
&EnumerationContext,
|
||
(PVOID*)&TDInfoEx,
|
||
0x1000,
|
||
&Count );
|
||
|
||
if ( NT_SUCCESS( Status ) || Status == STATUS_NO_MORE_ENTRIES ) {
|
||
|
||
if ( DisplayHeader ) {
|
||
|
||
NetDompDisplayMessage( MSG_TRUST_DIRECT_HEADER );
|
||
DisplayHeader = FALSE;
|
||
}
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
NetDompDumpTrustInfo( TrustInfo->DomainName->Buffer,
|
||
&TDInfoEx[ i ] );
|
||
}
|
||
}
|
||
|
||
LsaFreeMemory( TDInfoEx );
|
||
TDInfoEx = NULL;
|
||
|
||
} while ( Status == STATUS_MORE_ENTRIES );
|
||
|
||
} else {
|
||
|
||
//
|
||
// 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 = LsaEnumerateTrustedDomains( TrustInfo->LsaHandle,
|
||
&EnumerationContext,
|
||
(PVOID*)&TDInfo,
|
||
0x1000,
|
||
&Count );
|
||
|
||
if ( NT_SUCCESS( Status ) || Status == STATUS_NO_MORE_ENTRIES ) {
|
||
|
||
|
||
Win32Err = NetApiBufferAllocate( ( Count + TotalCount ) *
|
||
sizeof( TRUSTED_DOMAIN_INFORMATION_EX ),
|
||
(PVOID*)&TempTDIEx );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
RtlZeroMemory( TempTDIEx, ( Count + TotalCount ) *
|
||
sizeof( TRUSTED_DOMAIN_INFORMATION_EX ) );
|
||
RtlCopyMemory( TempTDIEx,
|
||
TDInfoEx,
|
||
TotalCount * sizeof( TRUSTED_DOMAIN_INFORMATION_EX ) );
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
TempTDIEx[ TotalCount + i ].TrustType = TRUST_TYPE_DOWNLEVEL;
|
||
TempTDIEx[ TotalCount + i ].TrustDirection = TRUST_DIRECTION_OUTBOUND;
|
||
Win32Err = NetApiBufferAllocate( TDInfo[ i ].Name.MaximumLength,
|
||
(PVOID*)&( TempTDIEx[ TotalCount + i ].Name.Buffer ) );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
RtlCopyMemory( TempTDIEx[ TotalCount + i ].Name.Buffer,
|
||
TDInfo[ i ].Name.Buffer,
|
||
TDInfo[ i ].Name.MaximumLength );
|
||
TempTDIEx[ TotalCount + i ].Name.Length = TDInfo[ i ].Name.Length;
|
||
TempTDIEx[ TotalCount + i ].Name.MaximumLength =
|
||
TDInfo[ i ].Name.MaximumLength;
|
||
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
NetApiBufferFree( TDInfoEx );
|
||
|
||
TDInfoEx = TempTDIEx;
|
||
TotalCount += Count;
|
||
|
||
} else {
|
||
|
||
for ( j = 0; j < i; j++ ) {
|
||
|
||
NetApiBufferFree( TempTDIEx[ TotalCount + j ].Name.Buffer );
|
||
TempTDIEx[ TotalCount + j ].Name.Buffer = NULL;
|
||
}
|
||
NetApiBufferFree( TempTDIEx );
|
||
}
|
||
}
|
||
|
||
} while ( Status == STATUS_MORE_ENTRIES );
|
||
|
||
//
|
||
// Now, let's add in the user accounts
|
||
//
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
|
||
if ( TrustInfo->Server && *( TrustInfo->Server ) != L'\\' ) {
|
||
|
||
Win32Err = NetApiBufferAllocate( ( wcslen( TrustInfo->Server ) + 3 ) * sizeof( WCHAR ),
|
||
( PVOID * )&FullServer );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
swprintf( FullServer, L"\\\\%ws", TrustInfo->Server );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
FullServer = TrustInfo->Server;
|
||
}
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
do {
|
||
|
||
Win32Err = NetUserEnum( FullServer,
|
||
0,
|
||
FILTER_INTERDOMAIN_TRUST_ACCOUNT,
|
||
( LPBYTE * )&UserList,
|
||
MAX_PREFERRED_LENGTH,
|
||
&Count,
|
||
&UserCount,
|
||
&ResumeHandle );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS || Win32Err == ERROR_MORE_DATA ) {
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
|
||
Lop = wcsrchr( UserList[ i ].usri0_name, L'$' );
|
||
if ( Lop ) {
|
||
|
||
*Lop = UNICODE_NULL;
|
||
}
|
||
|
||
for ( j = 0; j < TotalCount; j++ ) {
|
||
|
||
if ( _wcsicmp( UserList[ i ].usri0_name,
|
||
TDInfoEx[ j ].Name.Buffer ) == 0 ) {
|
||
|
||
TDInfoEx[ j ].TrustDirection |= TRUST_DIRECTION_INBOUND;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If it wasn't found, add it...
|
||
//
|
||
if ( j == TotalCount ) {
|
||
|
||
Win32Err = NetApiBufferAllocate( ( 1 + TotalCount ) *
|
||
sizeof( TRUSTED_DOMAIN_INFORMATION_EX ),
|
||
(PVOID*)&TempTDIEx );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
RtlZeroMemory( TempTDIEx,
|
||
( 1 + TotalCount ) *
|
||
sizeof( TRUSTED_DOMAIN_INFORMATION_EX ) );
|
||
RtlCopyMemory( TempTDIEx,
|
||
TDInfoEx,
|
||
TotalCount * sizeof( TRUSTED_DOMAIN_INFORMATION_EX ) );
|
||
|
||
TempTDIEx[ TotalCount ].TrustType = TRUST_TYPE_DOWNLEVEL;
|
||
TempTDIEx[ TotalCount ].TrustDirection = TRUST_DIRECTION_INBOUND;
|
||
|
||
Win32Err = NetApiBufferAllocate(
|
||
( wcslen( UserList[ i ].usri0_name ) + 1 ) *
|
||
sizeof( WCHAR ) ,
|
||
(PVOID*)&( TempTDIEx[ TotalCount ].Name.Buffer ) );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
break;
|
||
}
|
||
|
||
|
||
wcscpy( TempTDIEx[ TotalCount ].Name.Buffer,
|
||
UserList[ i ].usri0_name );
|
||
RtlInitUnicodeString( &TempTDIEx[ TotalCount ].Name,
|
||
TempTDIEx[ TotalCount ].Name.Buffer );
|
||
|
||
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
NetApiBufferFree( TDInfoEx );
|
||
|
||
TDInfoEx = TempTDIEx;
|
||
TotalCount++;
|
||
|
||
} else {
|
||
|
||
NetApiBufferFree( TempTDIEx );
|
||
}
|
||
}
|
||
|
||
if ( Lop ) {
|
||
|
||
*Lop = L'$';
|
||
}
|
||
}
|
||
|
||
NetApiBufferFree( UserList );
|
||
}
|
||
|
||
} while ( Win32Err == ERROR_MORE_DATA );
|
||
if( FullServer != TrustInfo->Server )
|
||
NetApiBufferFree( FullServer );
|
||
}
|
||
|
||
//
|
||
// If everything worked, then dump them all
|
||
//
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
if ( TotalCount > 0 ) {
|
||
|
||
NetDompDisplayMessage( MSG_TRUST_DIRECT_HEADER );
|
||
}
|
||
|
||
for ( i = 0; i < TotalCount; i++ ) {
|
||
|
||
NetDompDumpTrustInfo( TrustInfo->DomainName->Buffer,
|
||
&TDInfoEx[ i ] );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
NetDompFreeBuiltTrustInfo( TDInfoEx, TotalCount );
|
||
|
||
} else {
|
||
|
||
Win32Err = RtlNtStatusToDosError( Status );
|
||
}
|
||
|
||
|
||
}
|
||
|
||
if ( Status == STATUS_NO_MORE_ENTRIES ) {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = RtlNtStatusToDosError( Status );
|
||
}
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NetDompFindChildrenForNode(
|
||
IN PWSTR LocalDomain,
|
||
IN ULONG DomainCount,
|
||
IN PDS_DOMAIN_TRUSTS DomainList,
|
||
IN OUT PND5_TRANS_TREE_NODE TreeNode,
|
||
IN OUT PND5_TRANS_TREE_NODE *DomainNode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This recursive function will find all of the children for a given node in the trust list
|
||
|
||
Arguments:
|
||
|
||
LocalDomain - Domain to find the children for
|
||
|
||
DomainCount - Number of domains in the list
|
||
|
||
DomainList - List of domains
|
||
|
||
TreeNode - Tree to insert into
|
||
|
||
DomainNode - Pointer to the LocalDomain's node, if encountered
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
ULONG i, Count = 0;
|
||
BOOL HandleDirect = FALSE;
|
||
|
||
//
|
||
// See how many
|
||
//
|
||
for ( i = 0; i < DomainCount; i++ ) {
|
||
|
||
if ( DomainList[ i ].ParentIndex == TreeNode->ListIndex &&
|
||
FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_IN_FOREST ) &&
|
||
!FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_TREE_ROOT)) {
|
||
|
||
Count++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we have the current node, then make sure we get the direct trusts as well
|
||
//
|
||
if ( ( TreeNode->DomainInfo->DnsDomainName &&
|
||
_wcsicmp( LocalDomain, TreeNode->DomainInfo->DnsDomainName ) == 0 ) ||
|
||
_wcsicmp( LocalDomain, TreeNode->DomainInfo->NetbiosDomainName ) == 0 ) {
|
||
|
||
HandleDirect = TRUE;
|
||
*DomainNode = TreeNode;
|
||
for ( i = 0; i < DomainCount; i++ ) {
|
||
|
||
if ( FLAG_ON( DomainList[ i ].Flags, (DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_DIRECT_INBOUND) ) &&
|
||
!FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_IN_FOREST ) &&
|
||
DomainList[ i ].ParentIndex == 0 ) {
|
||
|
||
Count++;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Add 'em to the list
|
||
//
|
||
if ( Count ) {
|
||
|
||
Win32Err = NetApiBufferAllocate( Count * sizeof( ND5_TRANS_TREE_NODE ),
|
||
(PVOID*)&( TreeNode->ChildList ) );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
RtlZeroMemory( TreeNode->ChildList, Count * sizeof( ND5_TRANS_TREE_NODE ) );
|
||
for ( i = 0; i < DomainCount && Win32Err == ERROR_SUCCESS; i++ ) {
|
||
|
||
if ( DomainList[ i ].ParentIndex == TreeNode->ListIndex &&
|
||
FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_IN_FOREST ) &&
|
||
!FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_TREE_ROOT) ) {
|
||
|
||
TreeNode->ChildList[ TreeNode->Children ].DomainInfo = &DomainList[ i ];
|
||
TreeNode->ChildList[ TreeNode->Children ].ListIndex = i;
|
||
TreeNode->ChildList[ TreeNode->Children ].Parent = TreeNode;
|
||
Win32Err = NetDompFindChildrenForNode( LocalDomain,
|
||
DomainCount,
|
||
DomainList,
|
||
&TreeNode->ChildList[ TreeNode->Children ],
|
||
DomainNode );
|
||
TreeNode->Children++;
|
||
DomainList[ i ].ParentIndex = 0xFFFFFFFF;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now, the other local entries
|
||
//
|
||
if ( Win32Err == ERROR_SUCCESS && HandleDirect ) {
|
||
|
||
for ( i = 0; i < DomainCount; i++ ) {
|
||
|
||
if ( FLAG_ON( DomainList[ i ].Flags, (DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_DIRECT_INBOUND) ) &&
|
||
!FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_IN_FOREST ) &&
|
||
DomainList[ i ].ParentIndex == 0 ) {
|
||
|
||
TreeNode->ChildList[ TreeNode->Children ].DomainInfo = &DomainList[ i ];
|
||
TreeNode->ChildList[ TreeNode->Children ].ListIndex = i;
|
||
TreeNode->Children++;
|
||
DomainList[ i ].ParentIndex = 0xFFFFFFFF;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
DWORD
|
||
NetDompBuildTransTrustTree(
|
||
IN PWSTR LocalDomain,
|
||
IN ULONG DomainCount,
|
||
IN PDS_DOMAIN_TRUSTS DomainList,
|
||
OUT PND5_TRANS_TREE_NODE *TreeRoot,
|
||
OUT PND5_TRANS_TREE_NODE *CurrentDomainNode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will build the transative trust tree for the given trust list
|
||
|
||
Arguments:
|
||
|
||
|
||
LocalDomain - Current domain
|
||
|
||
DomainCount - Number of domains in the list
|
||
|
||
DomainList - List of domains
|
||
|
||
TreeRoot - Tree root
|
||
|
||
CurrentDomainNode - Pointer to the LocalDomain's node
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PND5_TRANS_TREE_NODE Root = NULL, Temp = NULL, DomainNode = NULL;
|
||
PDS_DOMAIN_TRUSTS TDRoot = NULL;
|
||
ULONG i, Index;
|
||
|
||
//
|
||
// First, find the tree root.
|
||
//
|
||
for ( i = 0; i < DomainCount; i++ ) {
|
||
|
||
if ( DomainList[ i ].ParentIndex == 0 &&
|
||
FLAG_ON( DomainList[ i ].Flags, DS_DOMAIN_TREE_ROOT ) ) {
|
||
|
||
TDRoot = &DomainList[ i ];
|
||
Index = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ( TDRoot == NULL ) {
|
||
|
||
//
|
||
// Find ourselves, and make us the root
|
||
//
|
||
for ( i = 0; i < DomainCount; i++ ) {
|
||
|
||
if ( ( DomainList[ i ].DnsDomainName &&
|
||
_wcsicmp( LocalDomain, DomainList[ i ].DnsDomainName ) == 0 ) ||
|
||
_wcsicmp( LocalDomain, DomainList[ i ].NetbiosDomainName ) == 0 ) {
|
||
|
||
TDRoot = &DomainList[ i ];
|
||
Index = i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we still don't have one, bail...
|
||
//
|
||
if ( TDRoot == NULL) {
|
||
|
||
Win32Err = ERROR_INVALID_DOMAIN_STATE;
|
||
goto BuildTransExit;
|
||
|
||
}
|
||
|
||
Win32Err = NetApiBufferAllocate( sizeof( ND5_TRANS_TREE_NODE ), (PVOID*)&Root );
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
goto BuildTransExit;
|
||
}
|
||
|
||
RtlZeroMemory( Root, sizeof( ND5_TRANS_TREE_NODE ) );
|
||
Root->DomainInfo = TDRoot;
|
||
Root->ListIndex = Index;
|
||
TDRoot->ParentIndex = 0xFFFFFFFF;
|
||
|
||
Win32Err = NetDompFindChildrenForNode( LocalDomain,
|
||
DomainCount,
|
||
DomainList,
|
||
Root,
|
||
&DomainNode );
|
||
|
||
BuildTransExit:
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
*TreeRoot = Root;
|
||
*CurrentDomainNode = DomainNode;
|
||
}
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NetDompGetTrustDirection(
|
||
IN PND5_TRUST_INFO TrustingInfo,
|
||
IN PND5_TRUST_INFO TrustedInfo,
|
||
IN OUT PDWORD Direction
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will get the direction of the trust between the 2 specified domains
|
||
|
||
Arguments:
|
||
|
||
|
||
TrustingInfo - Domain #1
|
||
|
||
TrustedInfo - Domain #2
|
||
|
||
Direction - Where the trust direction is returned
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
NTSTATUS Status;
|
||
LSA_HANDLE TrustedDomain;
|
||
PTRUSTED_DOMAIN_INFORMATION_EX TDIEx = NULL;
|
||
PUSER_INFO_1 UI1 = NULL;
|
||
WCHAR AccountName[ UNLEN + 1 ];
|
||
|
||
|
||
if ( TrustingInfo->Uplevel ) {
|
||
|
||
Status = LsaQueryTrustedDomainInfoByName( TrustingInfo->LsaHandle,
|
||
TrustedInfo->DomainName,
|
||
TrustedDomainInformationEx,
|
||
(PVOID*)&TDIEx );
|
||
|
||
if (STATUS_OBJECT_NAME_NOT_FOUND == Status && TrustedInfo->Uplevel)
|
||
{
|
||
// Pre-existing TDOs for domains upgraded from NT4 to NT5 will continue to
|
||
// have a flat name.
|
||
//
|
||
TrustedInfo->fWasDownlevel = TRUE;
|
||
|
||
Status = LsaQueryTrustedDomainInfoByName( TrustingInfo->LsaHandle,
|
||
TrustedInfo->FlatName,
|
||
TrustedDomainInformationEx,
|
||
(PVOID*)&TDIEx );
|
||
}
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
DBG_VERBOSE(("Trust to domain %ws has direction %d\n", TrustedInfo->DomainName->Buffer,
|
||
TDIEx->TrustDirection));
|
||
*Direction = TDIEx->TrustDirection;
|
||
LsaFreeMemory( TDIEx );
|
||
}
|
||
|
||
Win32Err = RtlNtStatusToDosError( Status );
|
||
|
||
} else {
|
||
|
||
*Direction = 0;
|
||
Status = LsaOpenTrustedDomain( TrustingInfo->LsaHandle,
|
||
TrustedInfo->Sid,
|
||
MAXIMUM_ALLOWED,
|
||
&TrustedDomain );
|
||
|
||
if ( Status != STATUS_OBJECT_NAME_NOT_FOUND ) {
|
||
|
||
*Direction = TRUST_DIRECTION_OUTBOUND;
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
LsaClose( TrustedDomain );
|
||
}
|
||
|
||
if ( TrustedInfo->FlatName->Length > DNLEN * sizeof( WCHAR ) ) {
|
||
|
||
Win32Err = ERROR_INVALID_DOMAINNAME;
|
||
|
||
} else {
|
||
|
||
|
||
//
|
||
// Build the account name...
|
||
//
|
||
swprintf( AccountName, L"%ws$", TrustedInfo->FlatName->Buffer );
|
||
|
||
Win32Err = NetUserGetInfo( TrustingInfo->Server,
|
||
AccountName,
|
||
1,
|
||
( LPBYTE * )&UI1 );
|
||
|
||
if ( Win32Err != ERROR_NO_SUCH_USER ) {
|
||
|
||
*Direction |= TRUST_DIRECTION_INBOUND;
|
||
}
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
NetApiBufferFree( UI1 );
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
/*++
|
||
DWORD
|
||
NetDompFindChildNode(
|
||
IN PUNICODE_STRING ChildToFind,
|
||
IN PND5_TRANS_TREE_NODE Current,
|
||
IN PND5_TRANS_TREE_NODE Skip,
|
||
IN ULONG Display,
|
||
BOOL IncludeParent
|
||
)
|
||
|
||
Routine Description:
|
||
|
||
This function will find the child of the current node
|
||
|
||
Arguments:
|
||
|
||
|
||
ChildToFind - Child domain to find
|
||
|
||
Current - Where we are in the tree
|
||
|
||
Skip - Node to not process if we are coming from our parent
|
||
|
||
Display - Resource id of string to display
|
||
|
||
IncludeParent - If TRUE, work up the tree as well as down
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
|
||
{
|
||
DWORD Win32Err = ERROR_NOT_FOUND;
|
||
ULONG i;
|
||
UNICODE_STRING CurrentDomain;
|
||
BOOL Found = FALSE;
|
||
|
||
if ( !Current ) {
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
for ( i = 0; i < Current->Children && !Found && Win32Err == ERROR_NOT_FOUND; i++ ) {
|
||
|
||
RtlInitUnicodeString( &CurrentDomain,
|
||
Current->ChildList[ i ].DomainInfo->DnsDomainName ?
|
||
Current->ChildList[ i ].DomainInfo->DnsDomainName :
|
||
Current->ChildList[ i ].DomainInfo->NetbiosDomainName );
|
||
if ( RtlCompareUnicodeString( &CurrentDomain,
|
||
ChildToFind,
|
||
TRUE ) == 0 ) {
|
||
|
||
Found = TRUE;
|
||
break;
|
||
|
||
} else {
|
||
|
||
if ( Skip != &Current->ChildList[ i ] ) {
|
||
|
||
Win32Err = NetDompFindChildNode( ChildToFind,
|
||
&Current->ChildList[ i ],
|
||
NULL,
|
||
Display,
|
||
FALSE );
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
break;
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( Win32Err == ERROR_NOT_FOUND && IncludeParent ) {
|
||
|
||
if ( Current->Parent && !Found ) {
|
||
|
||
RtlInitUnicodeString( &CurrentDomain,
|
||
Current->Parent->DomainInfo->DnsDomainName ?
|
||
Current->Parent->DomainInfo->DnsDomainName :
|
||
Current->Parent->DomainInfo->NetbiosDomainName );
|
||
if ( RtlCompareUnicodeString( &CurrentDomain,
|
||
ChildToFind,
|
||
TRUE ) == 0 ) {
|
||
Found = TRUE;
|
||
}
|
||
}
|
||
|
||
if ( !Found ) {
|
||
|
||
Win32Err = NetDompFindChildNode( ChildToFind,
|
||
Current->Parent,
|
||
Current,
|
||
Display,
|
||
TRUE );
|
||
}
|
||
}
|
||
|
||
if ( Win32Err == ERROR_SUCCESS && Display ) {
|
||
|
||
NetDompDisplayMessage( Display,
|
||
CurrentDomain.Buffer );
|
||
}
|
||
|
||
if ( Found ) {
|
||
|
||
Win32Err = ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
return( Win32Err );
|
||
}
|
||
--*/
|
||
|
||
|
||
DWORD
|
||
NetDompDisplayTransTrustStatus(
|
||
IN PND5_TRUST_INFO TrustInfo,
|
||
IN PWSTR DomainName,
|
||
//IN PND5_TRANS_TREE_NODE CurrentDomain,
|
||
IN DWORD Direction,
|
||
IN DWORD TrustStatus
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will display the status for a trust
|
||
|
||
Arguments:
|
||
|
||
TrustInfo - Trust info to display the status for
|
||
|
||
DomainName - Name of the domain (if TrustInfo isn't available)
|
||
|
||
CurrentDomain - Current domain node pointer
|
||
|
||
Direction - Direction of the trust
|
||
|
||
TrustStatus - Status code from verifying the trust
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
ULONG Message, Type;
|
||
|
||
//
|
||
// Display the direction & name
|
||
//
|
||
Type = Direction & TRUST_DIRECTION_BIDIRECTIONAL;
|
||
|
||
switch ( Type ) {
|
||
case 0:
|
||
Message = MSG_TRUST_TRANS_NO_ARROW;
|
||
break;
|
||
|
||
case TRUST_DIRECTION_BIDIRECTIONAL:
|
||
|
||
Message = MSG_TRUST_TRANS_BOTH_ARROW;
|
||
break;
|
||
|
||
case TRUST_DIRECTION_INBOUND:
|
||
|
||
Message = MSG_TRUST_TRANS_IN_ARROW;
|
||
break;
|
||
|
||
case TRUST_DIRECTION_OUTBOUND:
|
||
|
||
Message = MSG_TRUST_TRANS_OUT_ARROW;
|
||
break;
|
||
}
|
||
|
||
NetDompDisplayMessage( Message, TrustInfo ? TrustInfo->DomainName->Buffer : DomainName );
|
||
|
||
//
|
||
// Then, the type
|
||
//
|
||
if (TrustInfo && TrustInfo->Flags & NETDOM_TRUST_TYPE_INDIRECT)
|
||
{
|
||
Message = MSG_TRUST_TYPE_INDIRECT;
|
||
}
|
||
else
|
||
{
|
||
if (TrustInfo && TrustInfo->Flags & NETDOM_TRUST_TYPE_MIT)
|
||
{
|
||
Message = MSG_TRUST_TYPE_MIT;
|
||
}
|
||
else
|
||
{
|
||
Message = MSG_TRUST_TYPE_WINDOWS;
|
||
}
|
||
}
|
||
|
||
NetDompDisplayMessage( Message );
|
||
|
||
//
|
||
// Finally, the status.
|
||
//
|
||
if (TrustInfo && TrustInfo->Flags & NETDOM_TRUST_FLAG_DOMAIN_NOT_FOUND)
|
||
{
|
||
TrustStatus = ERROR_NO_SUCH_DOMAIN;
|
||
}
|
||
|
||
switch ( TrustStatus ) {
|
||
case ERROR_SUCCESS:
|
||
NetDompDisplayMessage( MSG_TRUST_VERIFIED );
|
||
break;
|
||
|
||
case ERROR_NO_SUCH_DOMAIN:
|
||
NetDompDisplayMessage( MSG_TRUST_NO_DOMAIN );
|
||
break;
|
||
|
||
case ERROR_ACCESS_DENIED:
|
||
NetDompDisplayMessage( MSG_TRUST_ACCESS_DENIED );
|
||
break;
|
||
|
||
case VERIFY_QUERY_ONLY:
|
||
printf( "\n" );
|
||
break;
|
||
|
||
default:
|
||
NetDompDisplayMessage( MSG_TRUST_BROKEN );
|
||
break;
|
||
|
||
}
|
||
|
||
/* this doesn't work.
|
||
if ( TrustInfo ) {
|
||
|
||
Win32Err = NetDompFindChildNode( TrustInfo->DomainName,
|
||
CurrentDomain,
|
||
NULL,
|
||
MSG_TRUST_VIA,
|
||
TRUE );
|
||
} */
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NetDompQueryTrust(
|
||
IN PWSTR Domain,
|
||
IN PND5_AUTH_INFO AuthInfo,
|
||
IN PWSTR pwzServer,
|
||
IN BOOL Direct,
|
||
IN BOOL Verify
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will get the list of trusts for a domain
|
||
|
||
Arguments:
|
||
|
||
Domain - Domain to get the trust for
|
||
|
||
AuthInfo - Username and password to use to connect to the machine
|
||
|
||
pwzServer - Server specified on command line, if any
|
||
|
||
Direct - if TRUE, get only the DIRECTLY trusted domains
|
||
|
||
Verify - If TRUE, verify that the trusts are valid
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS, VerifyErr;
|
||
ND5_TRUST_INFO TrustInfo, OtherInfo;
|
||
ULONG Count = 0, i;
|
||
PDS_DOMAIN_TRUSTS rgTrustedDomains = NULL;
|
||
ULONG Message, Type, Direction;
|
||
//PND5_TRANS_TREE_NODE TreeRoot = NULL, CurrentDomainNode;
|
||
PWSTR CurrentDomain;
|
||
RtlZeroMemory( &TrustInfo, sizeof( ND5_TRUST_INFO ) );
|
||
|
||
Win32Err = NetDompTrustGetDomInfo( Domain,
|
||
pwzServer,
|
||
AuthInfo,
|
||
&TrustInfo,
|
||
FALSE,
|
||
FALSE,
|
||
FALSE);
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
if ( Direct || !TrustInfo.Uplevel ) {
|
||
|
||
Win32Err = NetDompQueryDirectTrust( Domain,
|
||
&TrustInfo );
|
||
|
||
} else {
|
||
|
||
Win32Err = DsEnumerateDomainTrusts(TrustInfo.Server,
|
||
DS_DOMAIN_IN_FOREST | DS_DOMAIN_DIRECT_OUTBOUND | DS_DOMAIN_DIRECT_INBOUND,
|
||
&rgTrustedDomains,
|
||
&Count);
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
if ( Count ) {
|
||
|
||
NetDompDisplayMessage((Verify) ? MSG_TRUST_TRANS_HEADER_VERIFY :
|
||
MSG_TRUST_TRANS_HEADER);
|
||
}
|
||
|
||
/* this doesn't work.
|
||
Win32Err = NetDompBuildTransTrustTree( Domain,
|
||
Count,
|
||
rgTrustedDomains,
|
||
&TreeRoot,
|
||
&CurrentDomainNode ); */
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
//
|
||
// Make sure we aren't connecting to ourselves...
|
||
//
|
||
CurrentDomain = rgTrustedDomains[ i ].DnsDomainName ?
|
||
rgTrustedDomains[ i ].DnsDomainName :
|
||
rgTrustedDomains[ i ].NetbiosDomainName;
|
||
if ( !_wcsicmp( CurrentDomain, TrustInfo.DomainName->Buffer ) ) {
|
||
|
||
continue;
|
||
}
|
||
|
||
RtlZeroMemory(&OtherInfo, sizeof(ND5_TRUST_INFO));
|
||
|
||
if (rgTrustedDomains[i].Flags & DS_DOMAIN_DIRECT_OUTBOUND ||
|
||
rgTrustedDomains[i].Flags & DS_DOMAIN_DIRECT_INBOUND)
|
||
{
|
||
// There is a direct trust to the domain, therefore a TDO
|
||
// exists, so read the domain data locally.
|
||
//
|
||
Win32Err = GetTrustInfo(CurrentDomain,
|
||
&TrustInfo,
|
||
&OtherInfo,
|
||
&VerifyErr);
|
||
|
||
if (ERROR_SUCCESS == Win32Err)
|
||
{
|
||
VerifyErr = NetDompGetTrustDirection(&TrustInfo,
|
||
&OtherInfo,
|
||
&Direction);
|
||
}
|
||
else
|
||
{
|
||
Direction = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Win32Err = NetDompTrustGetDomInfo(CurrentDomain,
|
||
NULL,
|
||
AuthInfo,
|
||
&OtherInfo,
|
||
FALSE,
|
||
FALSE, TRUE);
|
||
VerifyErr = Win32Err;
|
||
OtherInfo.Flags |= NETDOM_TRUST_TYPE_INDIRECT;
|
||
//
|
||
// If the trust is indirect, it must be a forest trust.
|
||
// Enterprise trusts always have a bi-di path.
|
||
//
|
||
Direction = TRUST_DIRECTION_BIDIRECTIONAL;
|
||
}
|
||
|
||
if (ERROR_SUCCESS == VerifyErr)
|
||
{
|
||
if (Verify
|
||
&& !(NETDOM_TRUST_TYPE_MIT & OtherInfo.Flags)
|
||
&& (DS_DOMAIN_DIRECT_OUTBOUND & rgTrustedDomains[i].Flags))
|
||
{
|
||
// Verify only direct, outbound, non-MIT trusts.
|
||
// Can't verify incoming without creds to the other
|
||
// domain.
|
||
//
|
||
VerifyErr = NetDompVerifyTrust(&TrustInfo,
|
||
&OtherInfo,
|
||
FALSE);
|
||
}
|
||
else
|
||
{
|
||
VerifyErr = VERIFY_QUERY_ONLY;
|
||
}
|
||
|
||
NetDompDisplayTransTrustStatus( &OtherInfo,
|
||
NULL,
|
||
//CurrentDomainNode,
|
||
Direction,
|
||
VerifyErr );
|
||
|
||
NetDompFreeDomInfo( &OtherInfo );
|
||
|
||
} else {
|
||
|
||
if ( !Verify ) {
|
||
|
||
VerifyErr = VERIFY_QUERY_ONLY;
|
||
}
|
||
|
||
NetDompDisplayTransTrustStatus( NULL,
|
||
rgTrustedDomains[ i ].DnsDomainName ?
|
||
rgTrustedDomains[ i ].DnsDomainName :
|
||
rgTrustedDomains[ i ].NetbiosDomainName,
|
||
//CurrentDomainNode,
|
||
Direction,
|
||
VerifyErr );
|
||
}
|
||
}
|
||
}
|
||
|
||
NetApiBufferFree( rgTrustedDomains );
|
||
}
|
||
}
|
||
|
||
NetDompFreeDomInfo( &TrustInfo );
|
||
}
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NetDompQueryDisplayOus(
|
||
IN PWSTR Domain,
|
||
IN PND5_AUTH_INFO AuthInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will list the OUs under which the specified user can create a computer object
|
||
|
||
Arguments:
|
||
|
||
Domain - Domain to connect to
|
||
|
||
AuthInfo - Username and password to connect to the domain with
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PWSTR *OuList;
|
||
ULONG OuCount = 0, i;
|
||
|
||
//
|
||
// Get the list and display it
|
||
//
|
||
LOG_VERBOSE(( MSG_VERBOSE_DETERMINE_OU ));
|
||
Win32Err = NetGetJoinableOUs( NULL,
|
||
Domain,
|
||
AuthInfo->User,
|
||
AuthInfo->Password,
|
||
&OuCount,
|
||
&OuList );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
NetDompDisplayMessage( MSG_OU_LIST );
|
||
for ( i = 0; i < OuCount; i++ ) {
|
||
|
||
printf( "%ws\n", OuList[ i ] );
|
||
}
|
||
NetApiBufferFree( OuList );
|
||
}
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NetDompQueryFsmo(
|
||
IN PWSTR Domain,
|
||
IN PND5_AUTH_INFO AuthInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will list the machines holding the various FSMO roles
|
||
|
||
Arguments:
|
||
|
||
Domain - Domain to connect to
|
||
|
||
AuthInfo - Username and password to connect to the domain with
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PWSTR User = NULL, Separator = NULL, pwzDomain = NULL, FsmoServer = NULL, ServerPath;
|
||
PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
|
||
HANDLE DsHandle = NULL;
|
||
RPC_AUTH_IDENTITY_HANDLE AuthHandle;
|
||
PDS_NAME_RESULT DsRoles = NULL;
|
||
PLDAP Ldap = NULL;
|
||
ULONG i;
|
||
ULONG DisplayMap[ ] = {
|
||
MSG_FSMO_SCHEMA,
|
||
MSG_FSMO_DOMAIN,
|
||
MSG_FSMO_PDC,
|
||
MSG_FSMO_RID,
|
||
MSG_FSMO_INFRASTRUCTURE
|
||
};
|
||
|
||
//
|
||
// Find a domain controller
|
||
//
|
||
LOG_VERBOSE(( MSG_VERBOSE_FIND_DC, Domain ));
|
||
Win32Err = DsGetDcName( NULL,
|
||
Domain,
|
||
NULL,
|
||
NULL,
|
||
DS_DIRECTORY_SERVICE_REQUIRED,
|
||
&DcInfo );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
if ( AuthInfo->User ) {
|
||
|
||
Separator = wcschr( AuthInfo->User, L'\\' );
|
||
|
||
if ( Separator ) {
|
||
|
||
*Separator = UNICODE_NULL;
|
||
User = Separator + 1;
|
||
|
||
if (!*User) {
|
||
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
pwzDomain = AuthInfo->User;
|
||
|
||
} else {
|
||
|
||
User = AuthInfo->User;
|
||
|
||
pwzDomain = Domain;
|
||
}
|
||
}
|
||
|
||
Win32Err = DsMakePasswordCredentials( User,
|
||
pwzDomain,
|
||
AuthInfo->Password,
|
||
&AuthHandle );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = DsBindWithCred( DcInfo->DomainControllerName,
|
||
NULL,
|
||
AuthHandle,
|
||
&DsHandle );
|
||
|
||
DsFreePasswordCredentials( AuthHandle );
|
||
}
|
||
|
||
|
||
//
|
||
// Now, start getting the info
|
||
//
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = DsListRoles( DsHandle,
|
||
&DsRoles );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
ASSERT( sizeof( DisplayMap ) / sizeof( ULONG ) == DsRoles->cItems );
|
||
for ( i = 0; i < sizeof( DisplayMap ) / sizeof( ULONG ); i++ ) {
|
||
|
||
ULONG Type = 0;
|
||
//
|
||
// Skip items that may not exist
|
||
//
|
||
if ( DsRoles->rItems[ i ].status != DS_NAME_NO_ERROR ) {
|
||
|
||
continue;
|
||
}
|
||
|
||
ServerPath = wcschr( DsRoles->rItems[ i ].pName, L',' );
|
||
if ( ServerPath ) {
|
||
|
||
ServerPath++;
|
||
|
||
} else {
|
||
|
||
ServerPath = DsRoles->rItems[ i ].pName;
|
||
}
|
||
|
||
if ( !Ldap ) {
|
||
|
||
Win32Err = NetDompLdapBind( DcInfo->DomainControllerName + 2,
|
||
User == AuthInfo->User ? NULL : AuthInfo->User,
|
||
User,
|
||
AuthInfo->Password,
|
||
LDAP_AUTH_SSPI,
|
||
&Ldap );
|
||
}
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = NetDompLdapReadOneAttribute( Ldap,
|
||
ServerPath,
|
||
L"dNSHostName",
|
||
&FsmoServer );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
NetDompDisplayMessage( DisplayMap[ i ], FsmoServer );
|
||
NetApiBufferFree( FsmoServer );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if ( DsHandle ) {
|
||
|
||
DsUnBind( &DsHandle );
|
||
}
|
||
|
||
if ( DsRoles ) {
|
||
|
||
DsFreeNameResult( DsRoles );
|
||
}
|
||
|
||
if ( Separator ) {
|
||
|
||
*Separator = L'\\';
|
||
}
|
||
|
||
NetApiBufferFree( DcInfo );
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NetDompDisplayMachineByType(
|
||
IN PWSTR AccountName,
|
||
IN PND5_AUTH_INFO AuthInfo,
|
||
IN ND5_ACCOUNT_TYPE DesiredType,
|
||
IN ND5_ACCOUNT_TYPE KnownType,
|
||
IN BOOL DisplayOnError
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function display machines of the specified type that are joined to the domain
|
||
|
||
Arguments:
|
||
|
||
AccountName - Name of the machine to get the info from
|
||
|
||
AuthInfo - Username and password to connect to the domain with
|
||
|
||
DesiredType - Type of machine to get
|
||
|
||
KnownType - Whether the machine type is known or not
|
||
|
||
DisplayOnError - If TRUE, display a message if an error is encountered
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
ERROR_UNSUPPORTED_TYPE - An unknown type was encountered
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PSERVER_INFO_101 SrvInfo = NULL;
|
||
PWSTR AccountChar;
|
||
|
||
|
||
AccountChar = wcsrchr( AccountName, L'$' );
|
||
if ( AccountChar ) {
|
||
|
||
*AccountChar = UNICODE_NULL;
|
||
}
|
||
|
||
//
|
||
// See if we have to get the type or not
|
||
//
|
||
if ( KnownType == TypeUnknown ) {
|
||
|
||
Win32Err = NetpManageIPCConnect( AccountName,
|
||
AuthInfo->User,
|
||
AuthInfo->Password,
|
||
NETSETUPP_CONNECT_IPC );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = NetServerGetInfo( AccountName,
|
||
101,
|
||
( LPBYTE * )&SrvInfo );
|
||
|
||
NetpManageIPCConnect( AccountName,
|
||
AuthInfo->User,
|
||
AuthInfo->Password,
|
||
NETSETUPP_DISCONNECT_IPC );
|
||
}
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
if ( FLAG_ON( SrvInfo->sv101_type, SV_TYPE_DOMAIN_BAKCTRL ) ) {
|
||
|
||
KnownType = TypeDomainController;
|
||
|
||
} else if ( FLAG_ON( SrvInfo->sv101_type, SV_TYPE_DOMAIN_CTRL ) ) {
|
||
|
||
if ( DesiredType == TypeDomainController ) {
|
||
|
||
KnownType = TypeDomainController;
|
||
|
||
} else {
|
||
|
||
KnownType = TypePDC;
|
||
}
|
||
|
||
} else if ( FLAG_ON( SrvInfo->sv101_type, SV_TYPE_WORKSTATION ) ) {
|
||
|
||
KnownType = TypeWorkstation;
|
||
|
||
} else {
|
||
|
||
Win32Err = ERROR_UNSUPPORTED_TYPE;
|
||
}
|
||
|
||
|
||
} else {
|
||
|
||
LOG_VERBOSE(( MSG_VERBOSE_FAIL_MACH_TYPE, AccountName ));
|
||
ERROR_VERBOSE(( Win32Err ));
|
||
|
||
if ( DisplayOnError ) {
|
||
|
||
KnownType = DesiredType;
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if ( KnownType == DesiredType && ( Win32Err == ERROR_SUCCESS || DisplayOnError ) ) {
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
NetDompDisplayMessage( MSG_WKSTA_OR_SERVER, AccountName );
|
||
Win32Err = ERROR_SUCCESS;
|
||
|
||
} else {
|
||
|
||
printf( "%ws\n", AccountName );
|
||
}
|
||
}
|
||
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
DWORD
|
||
NetDompQueryMachines(
|
||
IN ND5_ACCOUNT_OPERATION Operation,
|
||
IN PWSTR Domain,
|
||
IN PND5_AUTH_INFO AuthInfo,
|
||
IN PWSTR pwzServer,
|
||
IN ND5_ACCOUNT_TYPE AccountType,
|
||
IN ULONG MessageId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will list the machines in a domian
|
||
|
||
Arguments:
|
||
|
||
Operation - Whether to display/verify/reset the machines
|
||
|
||
Domain - Domain to connect to
|
||
|
||
AuthInfo - Username and password to connect to the domain with
|
||
|
||
pwzServer - Optional server name specified on command line, must be NULL for PDC operation.
|
||
|
||
AccountType - Type of accounts to display
|
||
|
||
MessageId - Resource ID of string to display
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The function succeeded
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS, Win32Err2;
|
||
PWSTR pwzUncServer = NULL, Lop, pwzUser = NULL, pwzDomain = NULL;
|
||
BOOL Connected = FALSE, fDsDcInfoAllocated = FALSE, fFreeServer = FALSE;
|
||
ULONG Type = 0;
|
||
PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
|
||
ULONG AccountTypeMap[] = {
|
||
FILTER_WORKSTATION_TRUST_ACCOUNT,
|
||
FILTER_WORKSTATION_TRUST_ACCOUNT,
|
||
FILTER_SERVER_TRUST_ACCOUNT,
|
||
FILTER_SERVER_TRUST_ACCOUNT,
|
||
FILTER_WORKSTATION_TRUST_ACCOUNT
|
||
};
|
||
LPUSER_INFO_0 UserList = NULL;
|
||
ULONG ResumeHandle = 0, Count = 0, TotalCount = 0, i;
|
||
ULONG DsGetDcOptions = DS_DIRECTORY_SERVICE_PREFERRED;
|
||
PDS_DOMAIN_CONTROLLER_INFO_1 pDsDcInfo;
|
||
|
||
if ( AccountType == TypeUnknown ) {
|
||
|
||
return( ERROR_INVALID_PARAMETER );
|
||
}
|
||
|
||
if (!pwzServer)
|
||
{
|
||
if ( AccountType == TypePDC ) {
|
||
|
||
DsGetDcOptions |= DS_PDC_REQUIRED;
|
||
}
|
||
|
||
LOG_VERBOSE(( MSG_VERBOSE_FIND_DC, Domain ));
|
||
Win32Err = DsGetDcName( NULL,
|
||
Domain,
|
||
NULL,
|
||
NULL,
|
||
DsGetDcOptions,
|
||
&DcInfo );
|
||
|
||
if (ERROR_SUCCESS != Win32Err)
|
||
{
|
||
return Win32Err;
|
||
}
|
||
|
||
if (AccountType == TypePDC)
|
||
{
|
||
NetDompDisplayMessage( MessageId );
|
||
NetDompDisplayMachineByType( DcInfo->DomainControllerName + 2,
|
||
AuthInfo,
|
||
TypePDC,
|
||
TypePDC,
|
||
TRUE );
|
||
goto QueryMachinesExit;
|
||
}
|
||
|
||
pwzUncServer = DcInfo->DomainControllerName;
|
||
}
|
||
else
|
||
{
|
||
// Server supplied on the command line. See if it has the needed backslashes.
|
||
//
|
||
if (L'\\' == *pwzServer)
|
||
{
|
||
if (wcslen(pwzServer) < 3 || L'\\' != pwzServer[1])
|
||
{
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
pwzUncServer = pwzServer;
|
||
}
|
||
else
|
||
{
|
||
Win32Err = NetApiBufferAllocate((wcslen(pwzServer) + 3) * sizeof(WCHAR),
|
||
(PVOID*)&pwzUncServer);
|
||
|
||
if (ERROR_SUCCESS != Win32Err)
|
||
{
|
||
return Win32Err;
|
||
}
|
||
|
||
wsprintf(pwzUncServer, L"\\\\%s", pwzServer);
|
||
|
||
fFreeServer = TRUE;
|
||
}
|
||
}
|
||
|
||
LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, pwzUncServer ));
|
||
Win32Err = NetpManageIPCConnect( pwzUncServer,
|
||
AuthInfo->User,
|
||
AuthInfo->Password,
|
||
NETSETUPP_CONNECT_IPC );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Connected = TRUE;
|
||
}
|
||
else {
|
||
|
||
goto QueryMachinesExit;
|
||
}
|
||
|
||
NetDompDisplayMessage( MessageId );
|
||
|
||
//
|
||
// Now, do the enumeration
|
||
//
|
||
|
||
if (TypeDomainController == AccountType) {
|
||
HANDLE hDS;
|
||
RPC_AUTH_IDENTITY_HANDLE hID;
|
||
|
||
if (AuthInfo->User) {
|
||
|
||
pwzUser = wcschr(AuthInfo->User, L'\\');
|
||
|
||
if (pwzUser) {
|
||
//
|
||
// backslash found, replace with NULL and point to next char.
|
||
//
|
||
*pwzUser = UNICODE_NULL;
|
||
|
||
pwzUser++;
|
||
|
||
if (!*pwzUser) {
|
||
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
pwzDomain = AuthInfo->User;
|
||
}
|
||
else {
|
||
|
||
pwzUser = AuthInfo->User;
|
||
|
||
pwzDomain = Domain;
|
||
}
|
||
}
|
||
|
||
Win32Err = DsMakePasswordCredentials( pwzUser,
|
||
pwzDomain,
|
||
AuthInfo->Password,
|
||
&hID);
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
goto QueryMachinesExit;
|
||
}
|
||
|
||
Win32Err = DsBindWithCred(pwzUncServer, NULL, hID, &hDS);
|
||
|
||
DsFreePasswordCredentials(hID);
|
||
|
||
if ( Win32Err == ERROR_SUCCESS ) {
|
||
|
||
Win32Err = DsGetDomainControllerInfo(hDS, Domain, 1, &Count, (PVOID*)&pDsDcInfo);
|
||
|
||
DsUnBind(&hDS);
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
goto QueryMachinesExit;
|
||
}
|
||
|
||
fDsDcInfoAllocated = TRUE;
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
switch ( Operation ) {
|
||
case OperationDisplay:
|
||
|
||
//
|
||
// Ignore errors from this function
|
||
//
|
||
NetDompDisplayMachineByType( pDsDcInfo[ i ].NetbiosName,
|
||
AuthInfo,
|
||
TypeDomainController,
|
||
TypeDomainController,
|
||
TRUE );
|
||
break;
|
||
|
||
case OperationVerify:
|
||
|
||
Win32Err2 = NetDompVerifyServerSC( Domain,
|
||
pDsDcInfo[ i ].NetbiosName,
|
||
AuthInfo,
|
||
MSG_QUERY_VERIFY_OK,
|
||
0 );
|
||
if ( Win32Err2 != ERROR_SUCCESS ) {
|
||
|
||
NetDompDisplayMessageAndError( MSG_QUERY_VERIFY_BAD,
|
||
Win32Err2,
|
||
pDsDcInfo[ i ].NetbiosName );
|
||
}
|
||
break;
|
||
|
||
case OperationReset:
|
||
|
||
Win32Err2 = NetDompResetServerSC( Domain,
|
||
pDsDcInfo[ i ].NetbiosName,
|
||
NULL,
|
||
AuthInfo,
|
||
MSG_QUERY_VERIFY_OK,
|
||
0 );
|
||
if ( Win32Err2 != ERROR_SUCCESS ) {
|
||
|
||
NetDompDisplayMessageAndError( MSG_QUERY_VERIFY_BAD,
|
||
Win32Err2,
|
||
pDsDcInfo[ i ].NetbiosName );
|
||
}
|
||
break;
|
||
|
||
default:
|
||
Win32Err2 = ERROR_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
}
|
||
|
||
goto QueryMachinesExit;
|
||
}
|
||
else {
|
||
// DsBind will return EPT_S_NOT_REGISTERED if a downlevel DC is targetted.
|
||
// If so, fall through to the NetUserEnum code.
|
||
//
|
||
if (EPT_S_NOT_REGISTERED != Win32Err) {
|
||
goto QueryMachinesExit;
|
||
}
|
||
}
|
||
}
|
||
|
||
do {
|
||
|
||
Win32Err = NetUserEnum( pwzUncServer,
|
||
0,
|
||
AccountTypeMap[ AccountType ],
|
||
( LPBYTE * )&UserList,
|
||
MAX_PREFERRED_LENGTH,
|
||
&Count,
|
||
&TotalCount,
|
||
&ResumeHandle );
|
||
|
||
if ( Win32Err == ERROR_SUCCESS || Win32Err == ERROR_MORE_DATA ) {
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
switch ( Operation ) {
|
||
case OperationDisplay:
|
||
|
||
//
|
||
// Ignore errors from this function
|
||
//
|
||
NetDompDisplayMachineByType( UserList[ i ].usri0_name,
|
||
AuthInfo,
|
||
AccountType,
|
||
TypeUnknown,
|
||
TRUE );
|
||
break;
|
||
|
||
case OperationVerify:
|
||
|
||
Lop = wcsrchr( UserList[ i ].usri0_name, L'$' );
|
||
if ( Lop ) {
|
||
|
||
*Lop = UNICODE_NULL;
|
||
}
|
||
Win32Err2 = NetDompVerifyServerSC( Domain,
|
||
UserList[ i ].usri0_name,
|
||
AuthInfo,
|
||
MSG_QUERY_VERIFY_OK,
|
||
0 );
|
||
if ( Win32Err2 != ERROR_SUCCESS ) {
|
||
|
||
NetDompDisplayMessageAndError( MSG_QUERY_VERIFY_BAD,
|
||
Win32Err2,
|
||
UserList[ i ].usri0_name );
|
||
}
|
||
|
||
if ( Lop ) {
|
||
|
||
*Lop = L'$';
|
||
}
|
||
break;
|
||
|
||
case OperationReset:
|
||
Lop = wcsrchr( UserList[ i ].usri0_name, L'$' );
|
||
if ( Lop ) {
|
||
|
||
*Lop = UNICODE_NULL;
|
||
}
|
||
Win32Err2 = NetDompResetServerSC( Domain,
|
||
UserList[ i ].usri0_name,
|
||
NULL,
|
||
AuthInfo,
|
||
MSG_QUERY_VERIFY_OK,
|
||
0 );
|
||
if ( Win32Err2 != ERROR_SUCCESS ) {
|
||
|
||
NetDompDisplayMessageAndError( MSG_QUERY_VERIFY_BAD,
|
||
Win32Err2,
|
||
UserList[ i ].usri0_name );
|
||
}
|
||
|
||
if ( Lop ) {
|
||
|
||
*Lop = L'$';
|
||
}
|
||
break;
|
||
|
||
default:
|
||
Win32Err2 = ERROR_INVALID_PARAMETER;
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
NetApiBufferFree( UserList );
|
||
}
|
||
|
||
} while ( Win32Err == ERROR_MORE_DATA );
|
||
|
||
QueryMachinesExit:
|
||
|
||
if ( Connected ) {
|
||
|
||
LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, pwzUncServer ));
|
||
NetpManageIPCConnect( pwzUncServer,
|
||
NULL,
|
||
NULL,
|
||
NETSETUPP_DISCONNECT_IPC );
|
||
|
||
}
|
||
|
||
if (fFreeServer)
|
||
{
|
||
NetApiBufferFree(pwzUncServer);
|
||
}
|
||
if (fDsDcInfoAllocated)
|
||
{
|
||
DsFreeDomainControllerInfo(1, Count, pDsDcInfo);
|
||
}
|
||
if (DcInfo)
|
||
{
|
||
NetApiBufferFree(DcInfo);
|
||
}
|
||
return( Win32Err );
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
NetDompHandleQuery(ARG_RECORD * rgNetDomArgs)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function will move a machine from one domain to another
|
||
|
||
Arguments:
|
||
|
||
Args - List of command line arguments
|
||
|
||
Return Value:
|
||
|
||
ERROR_INVALID_PARAMETER - No object name was supplied
|
||
|
||
--*/
|
||
{
|
||
DWORD Win32Err = ERROR_SUCCESS;
|
||
PWSTR Domain = NULL, Server = NULL;
|
||
ND5_AUTH_INFO DomainUser;
|
||
ND5_ACCOUNT_OPERATION Operation = OperationDisplay;
|
||
ULONG DisplayFlag = 0;
|
||
|
||
RtlZeroMemory( &DomainUser, sizeof( ND5_AUTH_INFO ) );
|
||
|
||
Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
|
||
eQueryPDC,
|
||
eQueryServer,
|
||
eQueryWksta,
|
||
eQueryDC,
|
||
eQueryOU,
|
||
eQueryFSMO,
|
||
eQueryTrust,
|
||
eCommDomain,
|
||
eCommUserNameD,
|
||
eCommPasswordD,
|
||
eCommServer,
|
||
eCommReset,
|
||
eQueryDirect,
|
||
eCommVerbose,
|
||
eCommVerify,
|
||
eArgEnd);
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
DisplayHelp(ePriQuery);
|
||
return Win32Err;
|
||
}
|
||
|
||
//
|
||
// Get the server name
|
||
//
|
||
Win32Err = NetDompGetArgumentString(rgNetDomArgs,
|
||
eCommServer,
|
||
&Server);
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
goto HandleQueryExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Ok, make sure that we have a specified domain...
|
||
//
|
||
Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
|
||
Server,
|
||
TRUE,
|
||
&Domain);
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
goto HandleQueryExit;
|
||
}
|
||
|
||
//
|
||
// Get the password and user if it exists
|
||
//
|
||
if ( CmdFlagOn(rgNetDomArgs, eCommUserNameD) ) {
|
||
|
||
Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
|
||
eCommUserNameD,
|
||
Domain,
|
||
&DomainUser);
|
||
|
||
if ( Win32Err != ERROR_SUCCESS ) {
|
||
|
||
goto HandleQueryExit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Find the query sub command.
|
||
//
|
||
NETDOM_ARG_ENUM eQuery = eArgNull;
|
||
|
||
for (int i = eQueryBegin; i <= eQueryEnd; i++)
|
||
{
|
||
if (CmdFlagOn(rgNetDomArgs, static_cast<NETDOM_ARG_ENUM>(i)))
|
||
{
|
||
if (eArgNull != eQuery)
|
||
{
|
||
ASSERT(rgNetDomArgs[i].strArg1);
|
||
NetDompDisplayUnexpectedParameter(rgNetDomArgs[i].strArg1);
|
||
DisplayHelp(ePriQuery);
|
||
Win32Err = ERROR_INVALID_PARAMETER;
|
||
goto HandleQueryExit;
|
||
}
|
||
eQuery = static_cast<NETDOM_ARG_ENUM>(i);
|
||
}
|
||
}
|
||
|
||
if (eArgNull == eQuery)
|
||
{
|
||
DisplayHelp(ePriQuery);
|
||
Win32Err = ERROR_INVALID_PARAMETER;
|
||
goto HandleQueryExit;
|
||
}
|
||
|
||
if ( CmdFlagOn(rgNetDomArgs, eCommVerify) ) {
|
||
|
||
Operation = OperationVerify;
|
||
DisplayFlag = MSG_QUERY_VERIFY;
|
||
|
||
}
|
||
|
||
if ( CmdFlagOn(rgNetDomArgs, eCommReset) ) {
|
||
|
||
if ( Operation == OperationVerify ) {
|
||
|
||
Win32Err = ERROR_INVALID_PARAMETER;
|
||
goto HandleQueryExit;
|
||
|
||
} else {
|
||
|
||
Operation = OperationReset;
|
||
DisplayFlag = MSG_QUERY_RESET;
|
||
}
|
||
}
|
||
|
||
switch (eQuery)
|
||
{
|
||
case eQueryOU:
|
||
|
||
Win32Err = NetDompQueryDisplayOus( Domain,
|
||
&DomainUser );
|
||
break;
|
||
|
||
case eQueryWksta:
|
||
|
||
Win32Err = NetDompQueryMachines( Operation,
|
||
Domain,
|
||
&DomainUser,
|
||
Server,
|
||
TypeWorkstation,
|
||
DisplayFlag ? DisplayFlag : MSG_WORKSTATION_LIST );
|
||
break;
|
||
|
||
case eQueryServer:
|
||
|
||
Win32Err = NetDompQueryMachines( Operation,
|
||
Domain,
|
||
&DomainUser,
|
||
Server,
|
||
TypeServer,
|
||
DisplayFlag ? DisplayFlag : MSG_SERVER_LIST );
|
||
break;
|
||
|
||
case eQueryDC:
|
||
|
||
Win32Err = NetDompQueryMachines( Operation,
|
||
Domain,
|
||
&DomainUser,
|
||
Server,
|
||
TypeDomainController,
|
||
DisplayFlag ? DisplayFlag : MSG_DC_LIST );
|
||
break;
|
||
|
||
case eQueryPDC:
|
||
|
||
Win32Err = NetDompQueryMachines( Operation,
|
||
Domain,
|
||
&DomainUser,
|
||
NULL,
|
||
TypePDC,
|
||
MSG_PDC_LIST );
|
||
break;
|
||
|
||
case eQueryFSMO:
|
||
|
||
Win32Err = NetDompQueryFsmo( Domain,
|
||
&DomainUser );
|
||
break;
|
||
|
||
case eQueryTrust:
|
||
|
||
if (CmdFlagOn(rgNetDomArgs, eQueryDirect) &&
|
||
CmdFlagOn(rgNetDomArgs, eCommVerify))
|
||
{
|
||
DisplayHelp(ePriQuery);
|
||
Win32Err = ERROR_INVALID_PARAMETER;
|
||
goto HandleQueryExit;
|
||
}
|
||
|
||
Win32Err = NetDompQueryTrust( Domain,
|
||
&DomainUser,
|
||
Server,
|
||
CmdFlagOn(rgNetDomArgs, eQueryDirect),
|
||
CmdFlagOn(rgNetDomArgs, eCommVerify));
|
||
break;
|
||
|
||
default:
|
||
Win32Err = ERROR_INVALID_PARAMETER;
|
||
break;
|
||
}
|
||
|
||
|
||
|
||
HandleQueryExit:
|
||
NetApiBufferFree( Domain );
|
||
NetApiBufferFree( Server );
|
||
NetDompFreeAuthIdent( &DomainUser );
|
||
|
||
if (NO_ERROR != Win32Err)
|
||
{
|
||
NetDompDisplayErrorMessage(Win32Err);
|
||
}
|
||
|
||
return( Win32Err );
|
||
}
|