From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/bowser/bowipx.c | 383 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 private/ntos/bowser/bowipx.c (limited to 'private/ntos/bowser/bowipx.c') diff --git a/private/ntos/bowser/bowipx.c b/private/ntos/bowser/bowipx.c new file mode 100644 index 000000000..b2841c353 --- /dev/null +++ b/private/ntos/bowser/bowipx.c @@ -0,0 +1,383 @@ +/*++ + +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 +#include +#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 || + Transport->PrimaryDomain == NULL ) { + return STATUS_REQUEST_NOT_ACCEPTED; + } + + + ComputerName = ((PTA_NETBIOS_ADDRESS)(Transport->ComputerName->TransportAddress.Buffer))->Address[0].Address->NetbiosName; + DomainName = ((PTA_NETBIOS_ADDRESS)(Transport->PrimaryDomain->TransportAddress.Buffer))->Address[0].Address->NetbiosName; + + // + // 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, + 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-((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-((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); + + 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); + + ExQueueWorkItem(&ViewBuffer->Overlay.WorkHeader, DelayedWorkQueue); + + return STATUS_SUCCESS; +} + -- cgit v1.2.3