WindowsXP-SP1/ds/netapi/netdom/query.cxx
2020-09-30 16:53:49 +02:00

2368 lines
69 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 );
}