Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

686 lines
18 KiB

/*++
Copyright (c) 1991-1992 Microsoft Corporation
Module Name:
brdevice.c
Abstract:
This module contains the support routines for the APIs that call
into the browser or the datagram receiver.
Author:
Rita Wong (ritaw) 20-Feb-1991
Larry Osterman (larryo) 23-Mar-1992
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//-------------------------------------------------------------------//
// //
// Local Function Prototypes //
// //
//-------------------------------------------------------------------//
//-------------------------------------------------------------------//
// //
// Global variables //
// //
//-------------------------------------------------------------------//
//
// Handle to the Datagram Receiver DD
//
HANDLE BrDgReceiverDeviceHandle = NULL;
VOID
CompleteAsyncBrowserIoControl(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved
);
NET_API_STATUS
BrOpenDgReceiver (
VOID
)
/*++
Routine Description:
This routine opens the NT LAN Man Datagram Receiver driver.
Arguments:
None.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/
{
NTSTATUS ntstatus;
UNICODE_STRING DeviceName;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
//
// Open the redirector device.
//
RtlInitUnicodeString(&DeviceName, DD_BROWSER_DEVICE_NAME_U);
InitializeObjectAttributes(
&ObjectAttributes,
&DeviceName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
ntstatus = NtOpenFile(
&BrDgReceiverDeviceHandle,
SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
0,
0
);
if (NT_SUCCESS(ntstatus)) {
ntstatus = IoStatusBlock.Status;
}
if (! NT_SUCCESS(ntstatus)) {
KdPrint(("[Browser] NtOpenFile browser driver failed: 0x%08lx\n",
ntstatus));
}
return NetpNtStatusToApiStatus(ntstatus);
}
VOID
BrShutdownDgReceiver(
VOID
)
/*++
Routine Description:
This routine close the LAN Man Redirector device.
Arguments:
None.
Return Value:
None.
--*/
{
IO_STATUS_BLOCK IoSb;
//
// Cancel the I/O operations outstanding on the browser.
//
NtCancelIoFile(BrDgReceiverDeviceHandle, &IoSb);
}
//
// Retreive the list of bound transports from the bowser driver.
//
NET_API_STATUS
BrGetTransportList(
OUT PLMDR_TRANSPORT_LIST *TransportList
)
{
NET_API_STATUS Status;
LMDR_REQUEST_PACKET RequestPacket;
//
// If we have a previous buffer that was too small, free it up.
//
RequestPacket.Version = LMDR_REQUEST_PACKET_VERSION;
RequestPacket.Type = EnumerateXports;
RtlInitUnicodeString(&RequestPacket.TransportName, NULL);
Status = DeviceControlGetInfo(
BrDgReceiverDeviceHandle,
IOCTL_LMDR_ENUMERATE_TRANSPORTS,
&RequestPacket,
sizeof(RequestPacket),
(LPVOID *)TransportList,
0xffffffff,
4096,
NULL
);
return Status;
}
NET_API_STATUS
BrAnnounceDomain(
IN PNETWORK Network,
IN ULONG Periodicity
)
{
NET_API_STATUS Status;
UCHAR AnnounceBuffer[sizeof(BROWSE_ANNOUNCE_PACKET)+LM20_CNLEN+1];
PBROWSE_ANNOUNCE_PACKET Announcement = (PBROWSE_ANNOUNCE_PACKET )AnnounceBuffer;
CHAR ADomainName[CNLEN+1];
ULONG ADomainNameLength;
CHAR AMasterName[CNLEN+1];
ULONG AMasterNameLength;
//
// We don't announce domains on direct host IPX.
//
if (Network->Flags & NETWORK_IPX) {
return NERR_Success;
}
Status = RtlAcquireResourceShared(&BrInfo.ConfigResource, TRUE);
if (!Status) {
KdPrint(("Browser: Unable to lock config database: %lx\n", Status));
return Status;
}
Status = RtlUpcaseUnicodeToOemN(ADomainName,
sizeof(ADomainName),
&ADomainNameLength,
BrInfo.BrPrimaryDomainName,
BrInfo.BrPrimaryDomainNameLength*sizeof(TCHAR));
if (!NT_SUCCESS(Status)) {
KdPrint(("Browser: Unable to convert primary domain name to OEM\n"));
return Status;
}
ADomainName[ADomainNameLength] = '\0';
Status = RtlUpcaseUnicodeToOemN(AMasterName,
sizeof(AMasterName),
&AMasterNameLength,
BrInfo.BrComputerName,
BrInfo.BrComputerNameLength*sizeof(TCHAR));
if (!NT_SUCCESS(Status)) {
KdPrint(("Browser: Unable to convert computer name to OEM\n"));
return Status;
}
AMasterName[AMasterNameLength] = '\0';
RtlReleaseResource(&BrInfo.ConfigResource);
Announcement->BrowseType = WkGroupAnnouncement;
Announcement->BrowseAnnouncement.Periodicity = Periodicity;
Announcement->BrowseAnnouncement.UpdateCount = 0;
Announcement->BrowseAnnouncement.VersionMajor = BROWSER_CONFIG_VERSION_MAJOR;
Announcement->BrowseAnnouncement.VersionMinor = BROWSER_CONFIG_VERSION_MINOR;
Announcement->BrowseAnnouncement.Type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_NT;
if (BrInfo.IsPrimaryDomainController) {
Announcement->BrowseAnnouncement.Type |= SV_TYPE_DOMAIN_CTRL;
}
strcpy(Announcement->BrowseAnnouncement.ServerName, ADomainName);
strcpy(Announcement->BrowseAnnouncement.Comment, AMasterName);
Status = SendDatagram(BrDgReceiverDeviceHandle,
&Network->NetworkName,
BrInfo.BrPrimaryDomainName,
DomainAnnouncement,
Announcement,
FIELD_OFFSET(BROWSE_ANNOUNCE_PACKET, BrowseAnnouncement.Comment)+
AMasterNameLength+sizeof(UCHAR)
);
if (Status != NERR_Success) {
KdPrint(("Browser: Unable to announce domain for network %wZ: %X\n", &Network->NetworkName, Status));
}
return Status;
}
NET_API_STATUS
BrUpdateBrowserStatus (
IN PNETWORK Network,
IN DWORD ServiceStatus
)
{
NET_API_STATUS Status;
UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION;
RequestPacket->TransportName = Network->NetworkName;
RequestPacket->Parameters.UpdateStatus.NewStatus = ServiceStatus;
RequestPacket->Parameters.UpdateStatus.IsLanmanNt = BrInfo.IsLanmanNt;
RequestPacket->Parameters.UpdateStatus.IsMemberDomain = BrInfo.IsDomainMember;
RequestPacket->Parameters.UpdateStatus.IsPrimaryDomainController = BrInfo.IsPrimaryDomainController;
RequestPacket->Parameters.UpdateStatus.IsDomainMaster = BrInfo.IsDomainMasterBrowser;
RequestPacket->Parameters.UpdateStatus.MaintainServerList = (BrInfo.MaintainServerList == 1);
//
// Tell the bowser the number of servers in the server table.
//
RequestPacket->Parameters.UpdateStatus.NumberOfServersInTable =
NumberInterimServerListElements(&Network->BrowseTable) +
NumberInterimServerListElements(&Network->DomainList) +
Network->TotalBackupServerListEntries +
Network->TotalBackupDomainListEntries;
//
// This is a simple IoControl - It just updates the status.
//
Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
IOCTL_LMDR_UPDATE_STATUS,
RequestPacket,
sizeof(LMDR_REQUEST_PACKET),
NULL,
0,
NULL);
return Status;
}
NET_API_STATUS
BrIssueAsyncBrowserIoControl(
IN PNETWORK Network,
IN ULONG ControlCode,
IN PBROWSER_WORKER_ROUTINE CompletionRoutine
)
{
ULONG PacketSize;
PLMDR_REQUEST_PACKET RequestPacket = NULL;
NTSTATUS NtStatus;
PBROWSERASYNCCONTEXT Context = NULL;
PacketSize = sizeof(LMDR_REQUEST_PACKET) +
MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR) +
Network->NetworkName.MaximumLength;
RequestPacket = MIDL_user_allocate(PacketSize);
if (RequestPacket == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
Context = MIDL_user_allocate(sizeof(BROWSERASYNCCONTEXT));
if (Context == NULL) {
MIDL_user_free(RequestPacket);
return(ERROR_NOT_ENOUGH_MEMORY);
}
RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION;
//
// Set level to FALSE to indicate that find master should not initiate
// a findmaster request, simply complete when a new master announces
// itself.
//
RequestPacket->Level = 0;
//
// Stick the name of the transport associated with this request at the
// end of the request packet.
//
RequestPacket->TransportName.MaximumLength = Network->NetworkName.MaximumLength;
RequestPacket->TransportName.Buffer = (PWSTR)((PCHAR)RequestPacket+sizeof(LMDR_REQUEST_PACKET)+(MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)));
RtlCopyUnicodeString(&RequestPacket->TransportName, &Network->NetworkName);
BrInitializeWorkItem(&Context->WorkItem, CompletionRoutine, Context);
Context->Network = Network;
Context->RequestPacket = RequestPacket;
NtStatus = NtDeviceIoControlFile(BrDgReceiverDeviceHandle,
NULL,
CompleteAsyncBrowserIoControl,
Context,
&Context->IoStatusBlock,
ControlCode,
RequestPacket,
PacketSize,
RequestPacket,
sizeof(LMDR_REQUEST_PACKET)+MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)
);
if (!NT_SUCCESS(NtStatus)) {
KdPrint(("Browser: Unable to issue browser IoControl: %X\n", NtStatus));
MIDL_user_free(RequestPacket);
MIDL_user_free(Context);
return(BrMapStatus(NtStatus));
}
return NERR_Success;
}
VOID
CompleteAsyncBrowserIoControl(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved
)
{
PBROWSERASYNCCONTEXT Context = ApcContext;
//
// If this request was canceled, we're stopping the browser, so we
// want to clean up our allocated pool. In addition, don't bother
// calling into the routine - the threads are gone by now.
//
if (IoStatusBlock->Status == STATUS_CANCELLED) {
MIDL_user_free(Context->RequestPacket);
MIDL_user_free(Context);
return;
}
//
// Timestamp when this request was completed. This allows us to tell
// where a request spent its time.
//
NtQueryPerformanceCounter(&Context->TimeCompleted, NULL);
BrQueueWorkItem(&Context->WorkItem);
}
NET_API_STATUS
BrGetLocalBrowseList(
IN PNETWORK Network,
IN LPWSTR DomainName OPTIONAL,
IN ULONG Level,
IN ULONG ServerType,
OUT PVOID *ServerList,
OUT PULONG EntriesRead,
OUT PULONG TotalEntries
)
{
NET_API_STATUS status;
PLMDR_REQUEST_PACKET Drp; // Datagram receiver request packet
ULONG DrpSize;
//
// Allocate the request packet large enough to hold the variable length
// domain name.
//
DrpSize = sizeof(LMDR_REQUEST_PACKET) +
(ARGUMENT_PRESENT(DomainName) ? (wcslen(DomainName) + 1) * sizeof(WCHAR) : 0) +
Network->NetworkName.MaximumLength;
if ((Drp = MIDL_user_allocate(DrpSize)) == NULL) {
return GetLastError();
}
//
// Set up request packet. Output buffer structure is of enumerate
// servers type.
//
Drp->Version = LMDR_REQUEST_PACKET_VERSION;
Drp->Type = EnumerateServers;
Drp->Level = Level;
Drp->Parameters.EnumerateServers.ServerType = ServerType;
Drp->Parameters.EnumerateServers.ResumeHandle = 0;
Drp->TransportName.Buffer = (PWSTR)((PCHAR)Drp+sizeof(LMDR_REQUEST_PACKET) +
(ARGUMENT_PRESENT(DomainName) ? (wcslen(DomainName) + 1) * sizeof(WCHAR) : 0));
Drp->TransportName.MaximumLength = Network->NetworkName.MaximumLength;
RtlCopyUnicodeString(&Drp->TransportName, &Network->NetworkName);
if (ARGUMENT_PRESENT(DomainName)) {
Drp->Parameters.EnumerateServers.DomainNameLength = wcslen(DomainName)*sizeof(WCHAR);
wcscpy(Drp->Parameters.EnumerateServers.DomainName, DomainName);
} else {
Drp->Parameters.EnumerateServers.DomainNameLength = 0;
Drp->Parameters.EnumerateServers.DomainName[0] = '\0';
}
//
// Ask the datagram receiver to enumerate the servers
//
status = DeviceControlGetInfo(
BrDgReceiverDeviceHandle,
IOCTL_LMDR_ENUMERATE_SERVERS,
Drp,
DrpSize,
ServerList,
0xffffffff,
4096,
NULL
);
*EntriesRead = Drp->Parameters.EnumerateServers.EntriesRead;
*TotalEntries = Drp->Parameters.EnumerateServers.TotalEntries;
(void) MIDL_user_free(Drp);
return status;
}
NET_API_STATUS
BrRemoveOtherDomain(
IN PNETWORK Network,
IN LPTSTR ServerName
)
{
NET_API_STATUS Status;
UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION;
RequestPacket->TransportName = Network->NetworkName;
RequestPacket->Parameters.AddDelName.DgReceiverNameLength = STRLEN(ServerName)*sizeof(TCHAR);
RequestPacket->Parameters.AddDelName.Type = OtherDomain;
STRCPY(RequestPacket->Parameters.AddDelName.Name,ServerName);
//
// This is a simple IoControl - It just updates the status.
//
Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
IOCTL_LMDR_DELETE_NAME,
RequestPacket,
sizeof(LMDR_REQUEST_PACKET),
NULL,
0,
NULL);
return Status;
}
NET_API_STATUS
BrAddOtherDomain(
IN PNETWORK Network,
IN LPTSTR ServerName
)
{
NET_API_STATUS Status;
UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(LM20_CNLEN+1)*sizeof(WCHAR)];
PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION;
RequestPacket->TransportName = Network->NetworkName;
RequestPacket->Parameters.AddDelName.DgReceiverNameLength = STRLEN(ServerName)*sizeof(TCHAR);
RequestPacket->Parameters.AddDelName.Type = OtherDomain;
STRCPY(RequestPacket->Parameters.AddDelName.Name,ServerName);
//
// This is a simple IoControl - It just updates the status.
//
Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
IOCTL_LMDR_ADD_NAME,
RequestPacket,
sizeof(LMDR_REQUEST_PACKET),
NULL,
0,
NULL);
return Status;
}
NET_API_STATUS
BrBindToTransport(
IN LPTSTR TransportName
)
{
NET_API_STATUS Status;
UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(MAXIMUM_FILENAME_LENGTH+1)*sizeof(WCHAR)];
PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION;
RequestPacket->TransportName.Length = 0;
RequestPacket->TransportName.MaximumLength = 0;
RequestPacket->Parameters.Bind.TransportNameLength = STRLEN(TransportName)*sizeof(TCHAR);
STRCPY(RequestPacket->Parameters.Bind.TransportName, TransportName);
//
// This is a simple IoControl - It just updates the status.
//
Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
IOCTL_LMDR_BIND_TO_TRANSPORT,
RequestPacket,
FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.Bind.TransportName) +
RequestPacket->Parameters.Bind.TransportNameLength,
NULL,
0,
NULL);
return Status;
}
NET_API_STATUS
BrUnbindFromTransport(
IN LPTSTR TransportName
)
{
NET_API_STATUS Status;
UCHAR PacketBuffer[sizeof(LMDR_REQUEST_PACKET)+(MAXIMUM_FILENAME_LENGTH+1)*sizeof(WCHAR)];
PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET)PacketBuffer;
RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION;
RequestPacket->TransportName.Length = 0;
RequestPacket->TransportName.MaximumLength = 0;
RequestPacket->Parameters.Unbind.TransportNameLength = STRLEN(TransportName)*sizeof(TCHAR);
STRCPY(RequestPacket->Parameters.Unbind.TransportName, TransportName);
KdPrint(("Browser: unbind from IPX transport %ws\n", TransportName));
//
// This is a simple IoControl - It just updates the status.
//
Status = BrDgReceiverIoControl(BrDgReceiverDeviceHandle,
IOCTL_LMDR_UNBIND_FROM_TRANSPORT,
RequestPacket,
FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.Bind.TransportName) +
RequestPacket->Parameters.Bind.TransportNameLength,
NULL,
0,
NULL);
if (Status != NERR_Success) {
KdPrint(("Browser: unbind from IPX transport %ws: %ld\n", TransportName, Status));
}
return Status;
}