windows-nt/Source/XPSP1/NT/base/fs/rdr2/bowser/bowipx.c

391 lines
14 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
bowtdi.c
Abstract:
This module implements all of the routines that interface with the TDI
transport for NT
Author:
Larry Osterman (LarryO) 21-Jun-1990
Revision History:
21-Jun-1990 LarryO
Created
--*/
#include "precomp.h"
#include <isnkrnl.h>
#include <smbipx.h>
#pragma hdrstop
NTSTATUS
BowserHandleIpxDomainAnnouncement(
IN PTRANSPORT Transport,
IN PSMB_IPX_NAME_PACKET NamePacket,
IN PBROWSE_ANNOUNCE_PACKET_1 DomainAnnouncement,
IN DWORD RequestLength,
IN ULONG ReceiveFlags
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE4BROW, BowserHandleIpxDomainAnnouncement)
#endif
NTSTATUS
BowserIpxDatagramHandler (
IN PVOID TdiEventContext,
IN LONG SourceAddressLength,
IN PVOID SourceAddress,
IN LONG OptionsLength,
IN PVOID Options,
IN ULONG ReceiveDatagramFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
IN PVOID Tsdu,
OUT PIRP *IoRequestPacket
)
{
PVOID DatagramData;
PINTERNAL_TRANSACTION InternalTransaction = NULL;
ULONG DatagramDataSize;
PTRANSPORT Transport = TdiEventContext;
MAILSLOTTYPE Opcode;
PSMB_IPX_NAME_PACKET NamePacket = Tsdu;
PSMB_HEADER Smb = (PSMB_HEADER)(NamePacket+1);
PCHAR ComputerName;
PCHAR DomainName;
PTRANSPORT_NAME TransportName = Transport->ComputerName;
ULONG SmbLength = BytesIndicated - sizeof(SMB_IPX_NAME_PACKET);
if (BytesAvailable > Transport->DatagramSize) {
return STATUS_REQUEST_NOT_ACCEPTED;
}
if (BytesIndicated <= sizeof(SMB_IPX_NAME_PACKET)) {
return STATUS_REQUEST_NOT_ACCEPTED;
}
//
// If we're not fully initialized yet,
// simply ignore the packet.
//
if (Transport->ComputerName == NULL ) {
return STATUS_REQUEST_NOT_ACCEPTED;
}
ComputerName = ((PTA_NETBIOS_ADDRESS)(Transport->ComputerName->TransportAddress.Buffer))->Address[0].Address->NetbiosName;
DomainName = Transport->DomainInfo->DomNetbiosDomainName;
//
// It's not for us, ignore the announcement.
//
if (NamePacket->NameType == SMB_IPX_NAME_TYPE_MACHINE) {
// Mailslot messages are always sent as TYPE_MACHINE even when they're
// to the DomainName (so allow both).
if (!RtlEqualMemory(ComputerName, NamePacket->Name, SMB_IPX_NAME_LENGTH) &&
!RtlEqualMemory(DomainName, NamePacket->Name, SMB_IPX_NAME_LENGTH)) {
return STATUS_REQUEST_NOT_ACCEPTED;
}
} else if (NamePacket->NameType == SMB_IPX_NAME_TYPE_WORKKGROUP) {
if (!RtlEqualMemory(DomainName, NamePacket->Name, SMB_IPX_NAME_LENGTH)) {
return STATUS_REQUEST_NOT_ACCEPTED;
}
} else if (NamePacket->NameType != SMB_IPX_NAME_TYPE_BROWSER) {
return STATUS_REQUEST_NOT_ACCEPTED;
}
//
// Classify the incoming packet according to it's type. Depending on
// the type, either process it as:
//
// 1) A server announcement
// 2) An incoming mailslot
//
Opcode = BowserClassifyIncomingDatagram(Smb, SmbLength,
&DatagramData,
&DatagramDataSize);
if (Opcode == MailslotTransaction) {
//
// BowserHandleMailslotTransaction will always receive the indicated bytes
// expecting to find the SMB. Tell the TDI driver we've already consumed
// the IPX_NAME_PACKET to keep that assumption constant.
//
*BytesTaken = sizeof(SMB_IPX_NAME_PACKET);
return BowserHandleMailslotTransaction(
Transport->ComputerName,
NamePacket->SourceName,
0, // No IP address
sizeof(SMB_IPX_NAME_PACKET), // SMB offset into TSDU
ReceiveDatagramFlags,
BytesIndicated,
BytesAvailable,
BytesTaken,
Tsdu,
IoRequestPacket );
} else if (Opcode == Illegal) {
//
// This might be illegal because it's a short packet. In that
// case, handle it as if it were a short packet and deal with any
// other failures when we have the whole packet.
//
if (BytesAvailable != BytesIndicated) {
return BowserHandleShortBrowserPacket(Transport->ComputerName,
TdiEventContext,
SourceAddressLength,
SourceAddress,
OptionsLength,
Options,
ReceiveDatagramFlags,
BytesAvailable,
BytesTaken,
IoRequestPacket,
BowserIpxDatagramHandler
);
}
BowserLogIllegalDatagram( Transport->ComputerName,
Smb,
(USHORT)(SmbLength & 0xffff),
NamePacket->SourceName,
ReceiveDatagramFlags);
return STATUS_REQUEST_NOT_ACCEPTED;
} else {
// PTA_NETBIOS_ADDRESS NetbiosAddress = SourceAddress;
if (BowserDatagramHandlerTable[Opcode] == NULL) {
return STATUS_SUCCESS;
}
//
// If this isn't the full packet, post a receive for it and
// handle it when we finally complete the receive.
//
if (BytesIndicated != BytesAvailable) {
return BowserHandleShortBrowserPacket(Transport->ComputerName,
TdiEventContext,
SourceAddressLength,
SourceAddress,
OptionsLength,
Options,
ReceiveDatagramFlags,
BytesAvailable,
BytesTaken,
IoRequestPacket,
BowserIpxDatagramHandler
);
}
InternalTransaction = DatagramData;
//
// If this is a workgroup announcement (a server announcement for another
// workgroup), handle it specially - regardless of the opcode, it's
// really a workgroup announcement.
//
if (NamePacket->NameType == SMB_IPX_NAME_TYPE_BROWSER) {
if (Opcode == LocalMasterAnnouncement ) {
NTSTATUS status;
//
// If we're processing these announcements, then handle this
// as a domain announcement.
//
if (Transport->MasterBrowser &&
Transport->MasterBrowser->ProcessHostAnnouncements) {
status = BowserHandleIpxDomainAnnouncement(Transport,
NamePacket,
(PBROWSE_ANNOUNCE_PACKET_1)&InternalTransaction->Union.Announcement,
SmbLength-(ULONG)((PCHAR)&InternalTransaction->Union.Announcement - (PCHAR)Smb),
ReceiveDatagramFlags);
} else {
status = STATUS_REQUEST_NOT_ACCEPTED;
}
//
// If this request isn't for our domain, we're done with it, if
// it's for our domain, then we need to do some more work.
//
if (!RtlEqualMemory(DomainName, NamePacket->Name, SMB_IPX_NAME_LENGTH)) {
return status;
}
} else {
//
// This isn't a master announcement, so ignore it.
//
return STATUS_REQUEST_NOT_ACCEPTED;
}
}
//
// Figure out which transportname is appropriate for the request:
//
// There are basically 3 choices:
//
// ComputeName (The default)
// MasterBrowser (if this is a server announcement)
// PrimaryDomain (if this is a request announcement)
// Election (if this is a local master announcement)
if ((Opcode == WkGroupAnnouncement) ||
(Opcode == HostAnnouncement)) {
if (Transport->MasterBrowser == NULL ||
!Transport->MasterBrowser->ProcessHostAnnouncements) {
return STATUS_REQUEST_NOT_ACCEPTED;
} else {
TransportName = Transport->MasterBrowser;
}
} else if (Opcode == AnnouncementRequest) {
TransportName = Transport->PrimaryDomain;
} else if (Opcode == LocalMasterAnnouncement) {
if (Transport->BrowserElection != NULL) {
TransportName = Transport->BrowserElection;
} else {
return STATUS_REQUEST_NOT_ACCEPTED;
}
}
ASSERT (DatagramDataSize == (SmbLength - ((PCHAR)InternalTransaction - (PCHAR)Smb)));
ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.BrowseAnnouncement));
ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.RequestElection));
ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.BecomeBackup));
ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.GetBackupListRequest));
ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.GetBackupListResp));
ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.ResetState));
ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.MasterAnnouncement));
return BowserDatagramHandlerTable[Opcode](TransportName,
&InternalTransaction->Union.Announcement,
SmbLength-(ULONG)((PCHAR)&InternalTransaction->Union.Announcement - (PCHAR)Smb),
BytesTaken,
SourceAddress,
SourceAddressLength,
&NamePacket->SourceName,
SMB_IPX_NAME_LENGTH,
ReceiveDatagramFlags);
}
return STATUS_SUCCESS;
UNREFERENCED_PARAMETER(OptionsLength);
UNREFERENCED_PARAMETER(Options);
UNREFERENCED_PARAMETER(ReceiveDatagramFlags);
}
NTSTATUS
BowserHandleIpxDomainAnnouncement(
IN PTRANSPORT Transport,
IN PSMB_IPX_NAME_PACKET NamePacket,
IN PBROWSE_ANNOUNCE_PACKET_1 DomainAnnouncement,
IN DWORD RequestLength,
IN ULONG ReceiveFlags
)
/*++
Routine Description:
This routine will process receive datagram indication messages, and
process them as appropriate.
Arguments:
IN PTRANSPORT Transport - The transport provider for this request.
IN PSMB_IPX_NAME_PACKET NamePacket - The name packet for this request.
Return Value:
NTSTATUS - Status of operation.
--*/
{
PVIEW_BUFFER ViewBuffer;
DISCARDABLE_CODE(BowserDiscardableCodeSection);
#ifdef ENABLE_PSEUDO_BROWSER
if ( BowserData.PseudoServerLevel == BROWSER_PSEUDO ) {
// no-op for black hole server
return STATUS_SUCCESS;
}
#endif
ExInterlockedAddLargeStatistic(&BowserStatistics.NumberOfDomainAnnouncements, 1);
ViewBuffer = BowserAllocateViewBuffer();
//
// If we are unable to allocate a view buffer, ditch this datagram on
// the floor.
//
if (ViewBuffer == NULL) {
return STATUS_REQUEST_NOT_ACCEPTED;
}
BowserCopyOemComputerName(ViewBuffer->ServerName, NamePacket->Name, SMB_IPX_NAME_LENGTH, ReceiveFlags);
BowserCopyOemComputerName(ViewBuffer->ServerComment, NamePacket->SourceName, SMB_IPX_NAME_LENGTH, ReceiveFlags);
if ( DomainAnnouncement->Type & SV_TYPE_NT ) {
ViewBuffer->ServerType = SV_TYPE_DOMAIN_ENUM | SV_TYPE_NT;
} else {
ViewBuffer->ServerType = SV_TYPE_DOMAIN_ENUM;
}
ASSERT (Transport->MasterBrowser != NULL);
ViewBuffer->TransportName = Transport->MasterBrowser;
ViewBuffer->ServerVersionMajor = DomainAnnouncement->VersionMajor;
ViewBuffer->ServerVersionMinor = DomainAnnouncement->VersionMinor;
ViewBuffer->ServerPeriodicity = (USHORT)((SmbGetUlong(&DomainAnnouncement->Periodicity) + 999) / 1000);
BowserReferenceTransportName(Transport->MasterBrowser);
BowserReferenceTransport( Transport );
ExInitializeWorkItem(&ViewBuffer->Overlay.WorkHeader, BowserProcessDomainAnnouncement, ViewBuffer);
BowserQueueDelayedWorkItem( &ViewBuffer->Overlay.WorkHeader );
return STATUS_SUCCESS;
}