982 lines
29 KiB
C
982 lines
29 KiB
C
//++
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1987 - 1999
|
|
//
|
|
// Module Name:
|
|
//
|
|
// browser.c
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Queries into network drivers
|
|
//
|
|
// Author:
|
|
//
|
|
// Anilth - 4-20-1998
|
|
//
|
|
// Environment:
|
|
//
|
|
// User mode only.
|
|
// Contains NT-specific code.
|
|
//
|
|
// Revision History:
|
|
//
|
|
//--
|
|
|
|
#include "precomp.h"
|
|
#include "malloc.h"
|
|
#include "nbtutil.h"
|
|
|
|
NET_API_STATUS GetBrowserTransportList(OUT PLMDR_TRANSPORT_LIST *TransportList);
|
|
//$review (nsun) there is a recursive calling of this function
|
|
NTSTATUS
|
|
NettestBrowserSendDatagram(
|
|
IN PLIST_ENTRY listNetbtTransports,
|
|
IN PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo,
|
|
IN PVOID ContextDomainInfo,
|
|
IN ULONG IpAddress,
|
|
IN LPWSTR UnicodeDestinationName,
|
|
IN DGRECEIVER_NAME_TYPE NameType,
|
|
IN LPWSTR pswzTransportName,
|
|
IN LPSTR OemMailslotName,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferSize
|
|
);
|
|
BOOL MailslotTest(NETDIAG_PARAMS* pParams,
|
|
IN LPWSTR DestinationName,
|
|
NETDIAG_RESULT* pResults);
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
BrowserTest(
|
|
NETDIAG_PARAMS* pParams,
|
|
NETDIAG_RESULT* pResults
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the machines role and membership.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE: Test suceeded.
|
|
FALSE: Test failed
|
|
|
|
--*/
|
|
{
|
|
NET_API_STATUS NetStatus;
|
|
HRESULT hrRetVal = S_OK;
|
|
|
|
BOOL BrowserIsUp = TRUE;
|
|
BOOL RedirIsUp = TRUE;
|
|
PLMDR_TRANSPORT_LIST TransportList = NULL;
|
|
PLMDR_TRANSPORT_LIST TransportEntry;
|
|
LONG NetbtTransportCount;
|
|
LONG RealNetbtTransportCount;
|
|
PNETBT_TRANSPORT NetbtTransport;
|
|
BOOL PrintIt;
|
|
PWKSTA_TRANSPORT_INFO_0 pWti0 = NULL;
|
|
DWORD EntriesRead;
|
|
DWORD TotalEntries;
|
|
DWORD i;
|
|
WCHAR DestinationName[MAX_PATH+1];
|
|
BOOL MailslotTested = FALSE;
|
|
PTESTED_DOMAIN TestedDomain;
|
|
PLIST_ENTRY ListEntry;
|
|
|
|
USES_CONVERSION;
|
|
|
|
PrintStatusMessage( pParams, 4, IDS_BROWSER_STATUS_MSG );
|
|
pResults->Browser.fPerformed = TRUE;
|
|
|
|
InitializeListHead( &pResults->Browser.lmsgOutput );
|
|
|
|
//
|
|
// Ensure the workstation service is running.
|
|
//
|
|
|
|
NetStatus = IsServiceStarted( _T("LanmanWorkstation") );
|
|
|
|
if ( NetStatus != NO_ERROR )
|
|
{
|
|
//IDS_BROWSER_13001 " [FATAL] Workstation service is not running. [%s]\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet,
|
|
IDS_BROWSER_13001, NetStatusToString(NetStatus) );
|
|
hrRetVal = S_OK;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!pResults->Global.fHasNbtEnabledInterface)
|
|
{
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Verbose,
|
|
IDS_BROWSER_NETBT_DISABLED);
|
|
pResults->Browser.fPerformed = FALSE;
|
|
hrRetVal = S_OK;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the transports bound to the Redir
|
|
//
|
|
|
|
if ( pParams->fReallyVerbose )
|
|
{
|
|
//IDS_BROWSER_13002 " List of transports currently bound to the Redir\n"
|
|
AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_ReallyVerbose, IDS_BROWSER_13002 );
|
|
}
|
|
else if ( pParams->fVerbose )
|
|
{
|
|
//IDS_BROWSER_13003 " List of NetBt transports currently bound to the Redir\n"
|
|
AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Verbose, IDS_BROWSER_13003 );
|
|
}
|
|
|
|
|
|
NetStatus = NetWkstaTransportEnum(
|
|
NULL,
|
|
0,
|
|
(LPBYTE *)&pWti0,
|
|
0xFFFFFFFF, // MaxPreferredLength
|
|
&EntriesRead,
|
|
&TotalEntries,
|
|
NULL ); // Optional resume handle
|
|
|
|
if (NetStatus != NERR_Success)
|
|
{
|
|
//IDS_BROWSER_13004 " [FATAL] Unable to retrieve transport list from Redir. [%s]\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13004, NetStatusToString(NetStatus) );
|
|
hrRetVal = S_FALSE;
|
|
RedirIsUp = FALSE;
|
|
}
|
|
else
|
|
{
|
|
NetbtTransportCount = 0;
|
|
RealNetbtTransportCount = 0;
|
|
for ( i = 0; i < EntriesRead; i++ )
|
|
{
|
|
UNICODE_STRING ustrTransportName;
|
|
LPTSTR pszTransportName;
|
|
|
|
RtlInitUnicodeString( &ustrTransportName, (LPWSTR)pWti0[i].wkti0_transport_name );
|
|
|
|
// Strip off the "\Device\" off of the beginning of
|
|
// the string
|
|
pszTransportName = W2T(MapGuidToServiceNameW(ustrTransportName.Buffer + 8));
|
|
|
|
|
|
PrintIt = FALSE;
|
|
|
|
if ( ustrTransportName.Length >= sizeof(NETBT_DEVICE_PREFIX) &&
|
|
_wcsnicmp( ustrTransportName.Buffer, NETBT_DEVICE_PREFIX, (sizeof(NETBT_DEVICE_PREFIX)/sizeof(WCHAR)-1)) == 0 )
|
|
{
|
|
|
|
//
|
|
// Determine if this Netbt transport really exists.
|
|
//
|
|
|
|
NetbtTransport = FindNetbtTransport( pResults, ustrTransportName.Buffer );
|
|
|
|
if ( NetbtTransport == NULL )
|
|
{
|
|
//IDS_BROWSER_13005 " [FATAL] Transport %s is bound to the redir but is not a configured NetbtTransport."
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13005, pszTransportName );
|
|
hrRetVal = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
if ( NetbtTransport->Flags & BOUND_TO_REDIR )
|
|
{
|
|
//IDS_BROWSER_13006 " [WARNING] Transport %s is bound to redir more than once."
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Verbose, IDS_BROWSER_13006, pszTransportName );
|
|
}
|
|
else
|
|
{
|
|
NetbtTransport->Flags |= BOUND_TO_REDIR;
|
|
RealNetbtTransportCount ++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Count the found transports.
|
|
//
|
|
NetbtTransportCount ++;
|
|
if ( pParams->fVerbose ) {
|
|
PrintIt = TRUE;
|
|
}
|
|
}
|
|
|
|
//IDS_BROWSER_13007 " %s\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, PrintIt ? Nd_Verbose : Nd_ReallyVerbose, IDS_BROWSER_13007, pszTransportName);//&ustrTransportName );
|
|
}
|
|
|
|
//
|
|
// Ensure the redir is bound to some Netbt transports.
|
|
//
|
|
if ( NetbtTransportCount == 0 )
|
|
{
|
|
//IDS_BROWSER_13008 " [FATAL] The redir isn't bound to any NetBt transports."
|
|
AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13008);
|
|
hrRetVal = S_FALSE;
|
|
RedirIsUp = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//IDS_BROWSER_13009 " The redir is bound to %ld NetBt transport%s.\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Verbose,
|
|
IDS_BROWSER_13009,
|
|
NetbtTransportCount,
|
|
NetbtTransportCount > 1 ? "s" : "" );
|
|
}
|
|
|
|
//
|
|
// Ensure the redir is bound to all of the Netbt transports.
|
|
//
|
|
|
|
if ( RealNetbtTransportCount != pResults->NetBt.cTransportCount )
|
|
{
|
|
//IDS_BROWSER_13010 " [FATAL] The redir is only bound to %ld of the %ld NetBt transports."
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet,
|
|
IDS_BROWSER_13010,
|
|
RealNetbtTransportCount,
|
|
pResults->NetBt.cTransportCount );
|
|
hrRetVal = S_FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Get the transports bound to the browser.
|
|
//
|
|
|
|
//IDS_BROWSER_13011 "\n"
|
|
AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Verbose, IDS_BROWSER_13011);
|
|
|
|
if ( pParams->fReallyVerbose )
|
|
//IDS_BROWSER_13012 " List of transports currently bound to the browser\n"
|
|
AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_ReallyVerbose, IDS_BROWSER_13012 );
|
|
else if ( pParams->fVerbose )
|
|
//IDS_BROWSER_13013 " List of NetBt transports currently bound to the browser\n"
|
|
AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Verbose, IDS_BROWSER_13013 );
|
|
|
|
|
|
NetStatus = GetBrowserTransportList(&TransportList);
|
|
|
|
if (NetStatus != NERR_Success)
|
|
{
|
|
//IDS_BROWSER_13014 " [FATAL] Unable to retrieve transport list from browser. [%s]\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13014, NetStatusToString(NetStatus) );
|
|
hrRetVal = S_FALSE;
|
|
BrowserIsUp = FALSE;
|
|
}
|
|
else
|
|
{
|
|
TransportEntry = TransportList;
|
|
|
|
NetbtTransportCount = 0;
|
|
RealNetbtTransportCount = 0;
|
|
while (TransportEntry != NULL)
|
|
{
|
|
UNICODE_STRING ustrTransportName;
|
|
LPTSTR pszTransportName;
|
|
|
|
ustrTransportName.Buffer = TransportEntry->TransportName;
|
|
ustrTransportName.Length = (USHORT)TransportEntry->TransportNameLength;
|
|
ustrTransportName.MaximumLength = (USHORT)TransportEntry->TransportNameLength;
|
|
|
|
pszTransportName = W2T(MapGuidToServiceNameW(ustrTransportName.Buffer + 8));
|
|
|
|
PrintIt = FALSE;
|
|
if ( ustrTransportName.Length >= sizeof(NETBT_DEVICE_PREFIX) &&
|
|
_wcsnicmp( ustrTransportName.Buffer, NETBT_DEVICE_PREFIX, (sizeof(NETBT_DEVICE_PREFIX)/sizeof(WCHAR)-1)) == 0 )
|
|
{
|
|
|
|
//
|
|
// Determine if this Netbt transport really exists.
|
|
//
|
|
|
|
NetbtTransport = FindNetbtTransport( pResults, ustrTransportName.Buffer );
|
|
|
|
if ( NetbtTransport == NULL )
|
|
{
|
|
//IDS_BROWSER_13015 " [FATAL] Transport %s is bound to the browser but is not a configured NetbtTransport."
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13015, pszTransportName );
|
|
hrRetVal = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
if ( NetbtTransport->Flags & BOUND_TO_BOWSER )
|
|
{
|
|
//IDS_BROWSER_13016 " [FATAL] Transport %s is bound to browser more than once."
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13016, pszTransportName );
|
|
hrRetVal = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
NetbtTransport->Flags |= BOUND_TO_BOWSER;
|
|
RealNetbtTransportCount ++;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Count the found transports.
|
|
//
|
|
NetbtTransportCount ++;
|
|
if ( pParams->fVerbose )
|
|
PrintIt = TRUE;
|
|
}
|
|
|
|
//IDS_BROWSER_13017 " %s\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput,
|
|
PrintIt ? Nd_Verbose : Nd_ReallyVerbose,
|
|
IDS_BROWSER_13017, pszTransportName );
|
|
|
|
|
|
if (TransportEntry->NextEntryOffset == 0)
|
|
{
|
|
TransportEntry = NULL;
|
|
}
|
|
else
|
|
{
|
|
TransportEntry = (PLMDR_TRANSPORT_LIST)((PCHAR)TransportEntry+TransportEntry->NextEntryOffset);
|
|
}
|
|
}
|
|
|
|
if ( NetbtTransportCount == 0 )
|
|
{
|
|
//IDS_BROWSER_13018 " [FATAL] The browser isn't bound to any NetBt transports"
|
|
AddMessageToListId( &pResults->Browser.lmsgOutput, Nd_Quiet,
|
|
IDS_BROWSER_13018 );
|
|
hrRetVal = S_FALSE;
|
|
BrowserIsUp = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//IDS_BROWSER_13019 " The browser is bound to %ld NetBt transport%s.\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Verbose,
|
|
IDS_BROWSER_13019,
|
|
NetbtTransportCount,
|
|
NetbtTransportCount > 1 ? "s" : "" );
|
|
}
|
|
|
|
//
|
|
// Ensure the browser is bound to all of the Netbt transports.
|
|
//
|
|
|
|
if ( RealNetbtTransportCount != pResults->NetBt.cTransportCount )
|
|
{
|
|
//IDS_BROWSER_13020 " [FATAL] The browser is only bound to %ld of the %ld NetBt transports."
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet,
|
|
IDS_BROWSER_13020,
|
|
RealNetbtTransportCount,
|
|
pResults->NetBt.cTransportCount );
|
|
hrRetVal = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ensure we can send mailslot messages. (DsGetDcName uses them.)
|
|
//
|
|
// Try sending to each of the tested domains.
|
|
//
|
|
|
|
for ( ListEntry = pResults->Global.listTestedDomains.Flink ;
|
|
ListEntry != &pResults->Global.listTestedDomains ;
|
|
ListEntry = ListEntry->Flink )
|
|
{
|
|
|
|
//
|
|
// Only test this domain if it is has a Netbios domain name
|
|
//
|
|
|
|
TestedDomain = CONTAINING_RECORD( ListEntry, TESTED_DOMAIN, Next );
|
|
|
|
if ( TestedDomain->NetbiosDomainName != NULL )
|
|
{
|
|
//
|
|
// Send the message to the <DomainName>[1C] name
|
|
//
|
|
wcscpy( DestinationName, TestedDomain->NetbiosDomainName );
|
|
wcscat( DestinationName, L"*" );
|
|
if ( !MailslotTest( pParams, DestinationName, pResults ) ) {
|
|
hrRetVal = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
USES_CONVERSION;
|
|
//IDS_BROWSER_13021 "Mailslot test for %s passed.\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_ReallyVerbose, IDS_BROWSER_13021, W2CT(DestinationName));
|
|
}
|
|
MailslotTested = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we still haven't tested mailslots,
|
|
// test them by sending the message to our own computername.
|
|
//
|
|
|
|
//#ifdef notdef // crashes build 1728
|
|
if ( !MailslotTested ) {
|
|
wcscpy( DestinationName, pResults->Global.swzNetBiosName );
|
|
if ( !MailslotTest( pParams, DestinationName, pResults ) ) {
|
|
hrRetVal = S_FALSE;
|
|
}
|
|
MailslotTested = TRUE;
|
|
}
|
|
//#endif // notdef // crashes build 1728
|
|
|
|
|
|
Cleanup:
|
|
if ( pWti0 )
|
|
{
|
|
NetApiBufferFree( pWti0 );
|
|
}
|
|
|
|
if ( TransportList != NULL )
|
|
{
|
|
NetApiBufferFree(TransportList);
|
|
}
|
|
|
|
if ( FHrOK(hrRetVal) )
|
|
{
|
|
PrintStatusMessage(pParams, 0, IDS_GLOBAL_PASS_NL);
|
|
}
|
|
else
|
|
{
|
|
PrintStatusMessage(pParams, 0, IDS_GLOBAL_FAIL_NL);
|
|
}
|
|
|
|
|
|
pResults->Browser.hrTestResult = hrRetVal;
|
|
|
|
return hrRetVal;
|
|
}
|
|
|
|
|
|
|
|
|
|
NET_API_STATUS
|
|
GetBrowserTransportList(
|
|
OUT PLMDR_TRANSPORT_LIST *TransportList
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the list of transports bound into the browser.
|
|
|
|
Arguments:
|
|
|
|
OUT PLMDR_TRANSPORT_LIST *TransportList - Transport list to return.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NERR_Success or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NET_API_STATUS NetStatus;
|
|
HANDLE BrowserHandle;
|
|
LMDR_REQUEST_PACKET RequestPacket;
|
|
|
|
NetStatus = OpenBrowser(&BrowserHandle);
|
|
|
|
if (NetStatus != NERR_Success) {
|
|
DebugMessage2(" [FATAL] Unable to open browser driver. [%s]\n", NetStatusToString(NetStatus) );
|
|
return NetStatus;
|
|
}
|
|
|
|
RequestPacket.Version = LMDR_REQUEST_PACKET_VERSION_DOM;
|
|
|
|
RequestPacket.Type = EnumerateXports;
|
|
|
|
RtlInitUnicodeString(&RequestPacket.TransportName, NULL);
|
|
RtlInitUnicodeString(&RequestPacket.EmulatedDomainName, NULL);
|
|
|
|
NetStatus = DeviceControlGetInfo(
|
|
BrowserHandle,
|
|
IOCTL_LMDR_ENUMERATE_TRANSPORTS,
|
|
&RequestPacket,
|
|
sizeof(RequestPacket),
|
|
(PVOID *)TransportList,
|
|
0xffffffff,
|
|
4096,
|
|
NULL);
|
|
|
|
NtClose(BrowserHandle);
|
|
|
|
return NetStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
MailslotTest(
|
|
NETDIAG_PARAMS* pParams,
|
|
IN LPWSTR DestinationName,
|
|
NETDIAG_RESULT* pResults
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ensure we can send mailslot messages.
|
|
|
|
Test both via redir and browser.
|
|
|
|
Don't test responses (since that really tests if the DC is up).
|
|
|
|
Arguments:
|
|
|
|
DestinationName - Name to send the message to
|
|
Name ends in * if destination is the [1c] name.
|
|
|
|
Return Value:
|
|
|
|
TRUE: Test suceeded.
|
|
FALSE: Test failed
|
|
|
|
--*/
|
|
{
|
|
BOOL RetVal = TRUE;
|
|
|
|
NET_API_STATUS NetStatus;
|
|
NTSTATUS Status;
|
|
HANDLE ResponseMailslotHandle = NULL;
|
|
TCHAR ResponseMailslotName[MAX_PATH+1];
|
|
WCHAR NetlogonMailslotName[MAX_PATH+1];
|
|
|
|
WCHAR BrowserDestinationName[MAX_PATH+1];
|
|
DWORD BrowserDestinationNameLen;
|
|
DGRECEIVER_NAME_TYPE NameType;
|
|
|
|
PVOID PingMessage = NULL;
|
|
ULONG PingMessageSize = 0;
|
|
|
|
//
|
|
// Open a mailslot to get ping responses on.
|
|
//
|
|
//
|
|
|
|
NetStatus = NetpLogonCreateRandomMailslot( ResponseMailslotName,
|
|
&ResponseMailslotHandle );
|
|
|
|
if (NetStatus != NO_ERROR ) {
|
|
//IDS_BROWSER_13022 " [FATAL] Cannot create temp mailslot. [%s]\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13022, NetStatusToString(NetStatus) );
|
|
RetVal = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Allocate a mailslot message to send
|
|
//
|
|
|
|
NetStatus = NetpDcBuildPing (
|
|
FALSE, // Not only PDC
|
|
0, // Retry count
|
|
pResults->Global.swzNetBiosName, //replace GlobalNetbiosComputerName,
|
|
NULL, // No Account name
|
|
ResponseMailslotName,
|
|
0, // no AllowableAccountControlBits,
|
|
NULL, // No Domain SID
|
|
0, // Not NT Version 5
|
|
&PingMessage,
|
|
&PingMessageSize );
|
|
|
|
if ( NetStatus != NO_ERROR ) {
|
|
//IDS_BROWSER_13023 " [FATAL] Cannot allocate mailslot message. [%s]\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13023,
|
|
NetStatusToString(NetStatus) );
|
|
RetVal = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Build the destination mailslot name.
|
|
//
|
|
|
|
NetlogonMailslotName[0] = '\\';
|
|
NetlogonMailslotName[1] = '\\';
|
|
wcscpy(NetlogonMailslotName + 2, DestinationName );
|
|
wcscat( NetlogonMailslotName, NETLOGON_LM_MAILSLOT_W );
|
|
|
|
//
|
|
// Send the mailslot via the redir.
|
|
//
|
|
NetStatus = NetpLogonWriteMailslot(
|
|
NetlogonMailslotName,
|
|
(PCHAR)PingMessage,
|
|
PingMessageSize );
|
|
|
|
if ( NetStatus != NO_ERROR ) {
|
|
//IDS_BROWSER_13024 " [FATAL] Cannot send mailslot message to '%ws' via redir. [%s]\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13024,
|
|
NetlogonMailslotName, NetStatusToString(NetStatus) );
|
|
RetVal = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Send the mailslot via the browser
|
|
//
|
|
// Avoid this test if this build has an old value for the IOCTL function
|
|
// code to the browser.
|
|
//
|
|
|
|
if ( _ttoi(pResults->Global.pszCurrentBuildNumber) < NTBUILD_BOWSER )
|
|
{
|
|
if ( pParams->fReallyVerbose ) {
|
|
//IDS_BROWSER_13025 " Cannot sending mailslot messages via the browser since this machine is running build %ld. [Test skipped.]\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13025, pResults->Global.pszCurrentBuildNumber );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wcscpy( BrowserDestinationName, DestinationName );
|
|
BrowserDestinationNameLen = wcslen(BrowserDestinationName);
|
|
|
|
if ( BrowserDestinationName[BrowserDestinationNameLen-1] == L'*' )
|
|
{
|
|
BrowserDestinationName[BrowserDestinationNameLen-1] = L'\0';
|
|
NameType = DomainName; // [1c] name
|
|
}
|
|
else
|
|
{
|
|
NameType = PrimaryDomain; // [00] name
|
|
}
|
|
|
|
Status = NettestBrowserSendDatagram(
|
|
&pResults->NetBt.Transports,
|
|
pResults->Global.pPrimaryDomainInfo,
|
|
NULL,
|
|
ALL_IP_TRANSPORTS,
|
|
BrowserDestinationName,
|
|
NameType,
|
|
NULL, // All transports
|
|
NETLOGON_LM_MAILSLOT_A,
|
|
PingMessage,
|
|
PingMessageSize );
|
|
|
|
if ( !NT_SUCCESS(Status) )
|
|
{
|
|
NetStatus = NetpNtStatusToApiStatus(Status);
|
|
//IDS_BROWSER_13026 " [FATAL] Cannot send mailslot message to '%ws' via browser. [%s]\n"
|
|
AddMessageToList( &pResults->Browser.lmsgOutput, Nd_Quiet, IDS_BROWSER_13026,
|
|
DestinationName, NetStatusToString(NetStatus) );
|
|
RetVal = FALSE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
if ( PingMessage != NULL ) {
|
|
NetpMemoryFree( PingMessage );
|
|
}
|
|
if ( ResponseMailslotHandle != NULL ) {
|
|
CloseHandle(ResponseMailslotHandle);
|
|
}
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NettestBrowserSendDatagram(
|
|
IN PLIST_ENTRY plistNetbtTransports,
|
|
IN PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo,
|
|
IN PVOID ContextDomainInfo,
|
|
IN ULONG IpAddress,
|
|
IN LPWSTR UnicodeDestinationName,
|
|
IN DGRECEIVER_NAME_TYPE NameType,
|
|
IN LPWSTR TransportName,
|
|
IN LPSTR OemMailslotName,
|
|
IN PVOID Buffer,
|
|
IN ULONG BufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send the specified mailslot message to the specified mailslot on the
|
|
specified server on the specified transport..
|
|
|
|
Arguments:
|
|
|
|
DomainInfo - Hosted domain sending the datagram
|
|
|
|
IpAddress - IpAddress of the machine to send the message to.
|
|
If zero, UnicodeDestinationName must be specified.
|
|
If ALL_IP_TRANSPORTS, UnicodeDestination must be specified but the datagram
|
|
will only be sent on IP transports.
|
|
|
|
UnicodeDestinationName -- Name of the server to send to.
|
|
|
|
NameType -- Type of name represented by UnicodeDestinationName.
|
|
|
|
TransportName -- Name of the transport to send on.
|
|
Use NULL to send on all transports.
|
|
|
|
OemMailslotName -- Name of the mailslot to send to.
|
|
|
|
Buffer -- Specifies a pointer to the mailslot message to send.
|
|
|
|
BufferSize -- Size in bytes of the mailslot message
|
|
|
|
Return Value:
|
|
|
|
Status of the operation.
|
|
|
|
STATUS_NETWORK_UNREACHABLE: Cannot write to network.
|
|
|
|
--*/
|
|
{
|
|
PLMDR_REQUEST_PACKET RequestPacket = NULL;
|
|
NET_API_STATUS NetStatus;
|
|
|
|
DWORD OemMailslotNameSize;
|
|
DWORD TransportNameSize;
|
|
DWORD DestinationNameSize;
|
|
WCHAR IpAddressString[NL_IP_ADDRESS_LENGTH+1];
|
|
ULONG Information;
|
|
HANDLE BrowserHandle = NULL;
|
|
|
|
NTSTATUS Status;
|
|
LPBYTE Where;
|
|
LONG test;
|
|
|
|
//
|
|
// If the transport isn't specified,
|
|
// send on all transports.
|
|
//
|
|
|
|
if ( TransportName == NULL ) {
|
|
ULONG i;
|
|
PLIST_ENTRY ListEntry;
|
|
NTSTATUS SavedStatus = STATUS_NETWORK_UNREACHABLE;
|
|
|
|
//
|
|
// Loop through the list of netbt transports finding this one.
|
|
//
|
|
|
|
for ( ListEntry = plistNetbtTransports->Flink ;
|
|
ListEntry != plistNetbtTransports ;
|
|
ListEntry = ListEntry->Flink ) {
|
|
|
|
PNETBT_TRANSPORT NetbtTransport;
|
|
|
|
//
|
|
// If the transport names match,
|
|
// return the entry
|
|
//
|
|
|
|
NetbtTransport = CONTAINING_RECORD( ListEntry, NETBT_TRANSPORT, Next );
|
|
|
|
//
|
|
// Skip deleted transports.
|
|
//
|
|
if ( (NetbtTransport->Flags & BOUND_TO_BOWSER) == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
Status = NettestBrowserSendDatagram(
|
|
plistNetbtTransports,
|
|
pPrimaryDomainInfo,
|
|
ContextDomainInfo,
|
|
IpAddress,
|
|
UnicodeDestinationName,
|
|
NameType,
|
|
NetbtTransport->pswzTransportName,
|
|
OemMailslotName,
|
|
Buffer,
|
|
BufferSize );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
// If any transport works, we've been successful
|
|
SavedStatus = STATUS_SUCCESS;
|
|
} else {
|
|
// Remember the real reason for the failure instead of the default failure status
|
|
// Remember only the first failure.
|
|
if ( SavedStatus == STATUS_NETWORK_UNREACHABLE ) {
|
|
SavedStatus = Status;
|
|
}
|
|
}
|
|
|
|
}
|
|
return SavedStatus;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Open a handle to the browser.
|
|
//
|
|
|
|
NetStatus = OpenBrowser(&BrowserHandle);
|
|
|
|
if (NetStatus != NERR_Success) {
|
|
DebugMessage2(" [FATAL] Unable to open browser driver. [%s]\n", NetStatusToString(NetStatus));
|
|
Status = NetpApiStatusToNtStatus( NetStatus );
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Allocate a request packet.
|
|
//
|
|
|
|
OemMailslotNameSize = strlen(OemMailslotName) + 1;
|
|
TransportNameSize = (wcslen(TransportName) + 1) * sizeof(WCHAR);
|
|
|
|
if ( UnicodeDestinationName == NULL ) {
|
|
return STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
DestinationNameSize = wcslen(UnicodeDestinationName) * sizeof(WCHAR);
|
|
|
|
RequestPacket = NetpMemoryAllocate(
|
|
sizeof(LMDR_REQUEST_PACKET) +
|
|
TransportNameSize +
|
|
OemMailslotNameSize +
|
|
DestinationNameSize + sizeof(WCHAR) +
|
|
(wcslen( pPrimaryDomainInfo->DomainNameFlat ) + 1) * sizeof(WCHAR) +
|
|
sizeof(WCHAR)) ; // For alignment
|
|
|
|
|
|
if (RequestPacket == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Fill in the Request Packet.
|
|
//
|
|
|
|
RequestPacket->Type = Datagram;
|
|
RequestPacket->Parameters.SendDatagram.DestinationNameType = NameType;
|
|
|
|
|
|
//
|
|
// Fill in the name of the machine to send the mailslot message to.
|
|
//
|
|
|
|
RequestPacket->Parameters.SendDatagram.NameLength = DestinationNameSize;
|
|
|
|
Where = (LPBYTE) RequestPacket->Parameters.SendDatagram.Name;
|
|
RtlCopyMemory( Where, UnicodeDestinationName, DestinationNameSize );
|
|
Where += DestinationNameSize;
|
|
|
|
|
|
//
|
|
// Fill in the name of the mailslot to send to.
|
|
//
|
|
|
|
RequestPacket->Parameters.SendDatagram.MailslotNameLength =
|
|
OemMailslotNameSize;
|
|
strcpy( Where, OemMailslotName);
|
|
Where += OemMailslotNameSize;
|
|
Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
|
|
|
|
|
|
//
|
|
// Fill in the TransportName
|
|
//
|
|
|
|
wcscpy( (LPWSTR) Where, TransportName);
|
|
RtlInitUnicodeString( &RequestPacket->TransportName, (LPWSTR) Where );
|
|
Where += TransportNameSize;
|
|
|
|
|
|
//
|
|
// Copy the hosted domain name to the request packet.
|
|
//
|
|
//If the machine doesn't belong to a domain, we shouldn't get to here
|
|
assert(pPrimaryDomainInfo->DomainNameFlat);
|
|
if (pPrimaryDomainInfo->DomainNameFlat)
|
|
{
|
|
wcscpy( (LPWSTR)Where,
|
|
pPrimaryDomainInfo->DomainNameFlat );
|
|
RtlInitUnicodeString( &RequestPacket->EmulatedDomainName,
|
|
(LPWSTR)Where );
|
|
Where += (wcslen( pPrimaryDomainInfo->DomainNameFlat ) + 1) * sizeof(WCHAR);
|
|
}
|
|
|
|
|
|
//
|
|
// Send the request to the browser.
|
|
//
|
|
|
|
NetStatus = BrDgReceiverIoControl(
|
|
BrowserHandle,
|
|
IOCTL_LMDR_WRITE_MAILSLOT,
|
|
RequestPacket,
|
|
(ULONG)(Where - (LPBYTE)RequestPacket),
|
|
Buffer,
|
|
BufferSize,
|
|
&Information );
|
|
|
|
|
|
if ( NetStatus != NO_ERROR ) {
|
|
Status = NetpApiStatusToNtStatus( NetStatus );
|
|
}
|
|
|
|
//
|
|
// Free locally used resources.
|
|
//
|
|
Cleanup:
|
|
if ( BrowserHandle != NULL ) {
|
|
NtClose(BrowserHandle);
|
|
}
|
|
|
|
if ( RequestPacket != NULL ) {
|
|
NetpMemoryFree( RequestPacket );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
void BrowserGlobalPrint(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
|
|
{
|
|
if (pParams->fVerbose || !FHrOK(pResults->Browser.hrTestResult))
|
|
{
|
|
PrintNewLine(pParams, 2);
|
|
PrintTestTitleResult(pParams,
|
|
IDS_BROWSER_LONG,
|
|
IDS_BROWSER_SHORT,
|
|
pResults->Browser.fPerformed,
|
|
pResults->Browser.hrTestResult,
|
|
0);
|
|
}
|
|
PrintMessageList(pParams, &pResults->Browser.lmsgOutput);
|
|
|
|
}
|
|
|
|
void BrowserPerInterfacePrint(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults, INTERFACE_RESULT *pInterfaceResults)
|
|
{
|
|
//no per interface results
|
|
}
|
|
|
|
void BrowserCleanup(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
|
|
{
|
|
MessageListCleanUp(&pResults->Browser.lmsgOutput);
|
|
}
|