You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
14 KiB
390 lines
14 KiB
/*++
|
|
|
|
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;
|
|
}
|
|
|