/*++ 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 #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(i))) { if (eArgNull != eQuery) { ASSERT(rgNetDomArgs[i].strArg1); NetDompDisplayUnexpectedParameter(rgNetDomArgs[i].strArg1); DisplayHelp(ePriQuery); Win32Err = ERROR_INVALID_PARAMETER; goto HandleQueryExit; } eQuery = static_cast(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 ); }