/*-- Copyright (c) 1987-1993 Microsoft Corporation Module Name: mailslot.c Abstract: Routines for doing I/O on the netlogon service's mailslots. Author: 03-Nov-1993 (cliffv) Environment: User mode only. Contains NT-specific code. Requires ANSI C extensions: slash-slash comments, long external names. Revision History: --*/ // // Common include files. // #include // Include files common to entire service // // Include files specific to this module #include // LARGE_INTEGER definition #include // ALIGN_WCHAR #include // System Error Log definitions #include // SERVICE_UIC codes are defined here #include // Interface to browser driver #include // max() ///////////////////////////////////////////////////////////////////////////// // // Structure describing one of the primary mailslots the netlogon service // will read messages from. // // This structure is used only by netlogon's main thread and therefore needs // no synchronization. // ///////////////////////////////////////////////////////////////////////////// // // Define maximum buffer size returned from the browser. // // Header returned by browser + actual mailslot message size + name of // mailslot + name of transport. // #define MAILSLOT_MESSAGE_SIZE \ (sizeof(NETLOGON_MAILSLOT)+ \ NETLOGON_MAX_MS_SIZE + \ (NETLOGON_LM_MAILSLOT_LEN+1) * sizeof(WCHAR) + \ (MAXIMUM_FILENAME_LENGTH+1) * sizeof(WCHAR)) typedef struct _NETLOGON_MAILSLOT_DESC { HANDLE BrowserHandle; // Handle to the browser device driver HANDLE BrowserReadEvent;// Handle to wait on for overlapped I/O OVERLAPPED Overlapped; // Governs overlapped I/O BOOL ReadPending; // True if a read operation is pending BOOL NameAdded; // True if Domain<1B> name has been added BOOL AddNameEventLogged;// True if Domain<1B> name add failed at least once LPBYTE CurrentMessage; // Pointer to Message1 or Message2 below LPBYTE PreviousMessage; // Previous value of CurrentMessage // // Buffer containing message from browser // // The buffers are alternated allowing us to compare if an incoming // message is identical to the previous message. // // Leave room so the actual used portion of each buffer is properly aligned. // The NETLOGON_MAILSLOT struct begins with a LARGE_INTEGER which must be // aligned. BYTE Message1[ MAILSLOT_MESSAGE_SIZE + ALIGN_WORST ]; BYTE Message2[ MAILSLOT_MESSAGE_SIZE + ALIGN_WORST ]; } NETLOGON_MAILSLOT_DESC, *PNETLOGON_MAILSLOT_DESC; PNETLOGON_MAILSLOT_DESC NlGlobalMailslotDesc; HANDLE NlBrowserCreateEvent( VOID ) /*++ Routine Description: Creates an event to be used in a DeviceIoControl to the browser. ?? Consider caching one or two events to reduce the number of create events Arguments: None Return Value: Handle to an event or NULL if the event couldn't be allocated. --*/ { HANDLE EventHandle; // // Create a completion event // EventHandle = CreateEvent( NULL, // No security ettibutes TRUE, // Manual reset FALSE, // Initially not signaled NULL); // No Name if ( EventHandle == NULL ) { NlPrint((NL_CRITICAL, "Cannot create Browser read event %ld\n", GetLastError() )); } return EventHandle; } VOID NlBrowserCloseEvent( IN HANDLE EventHandle ) /*++ Routine Description: Closes an event used in a DeviceIoControl to the browser. Arguments: EventHandle - Handle of the event to close Return Value: None. --*/ { (VOID) CloseHandle( EventHandle ); } VOID NlBrowserClose( VOID ); NTSTATUS NlBrowserDeviceIoControl( IN DWORD FunctionCode, IN PLMDR_REQUEST_PACKET RequestPacket, IN DWORD RequestPacketSize, IN LPBYTE Buffer, IN DWORD BufferSize ) /*++ Routine Description: Send a DeviceIoControl syncrhonously to the browser. Arguments: FunctionCode - DeviceIoControl function code RequestPacket - The request packet to send. RequestPacketSize - Size (in bytes) of the request packet. Buffer - Additional buffer to pass to the browser BufferSize - Size (in bytes) of Buffer Return Value: Status of the operation. --*/ { NTSTATUS Status; DWORD WinStatus; OVERLAPPED Overlapped; DWORD BytesReturned; // // Initialization // if ( NlGlobalMailslotDesc == NULL || NlGlobalMailslotDesc->BrowserHandle == NULL ) { return ERROR_NOT_SUPPORTED; } RequestPacket->Version = LMDR_REQUEST_PACKET_VERSION; // // Get a completion event // Overlapped.hEvent = NlBrowserCreateEvent(); if ( Overlapped.hEvent == NULL ) { return GetLastError(); } // // Send the request to the Datagram Receiver device driver. // if ( !DeviceIoControl( NlGlobalMailslotDesc->BrowserHandle, FunctionCode, RequestPacket, RequestPacketSize, Buffer, BufferSize, &BytesReturned, &Overlapped )) { WinStatus = GetLastError(); if ( WinStatus == ERROR_IO_PENDING ) { if ( !GetOverlappedResult( NlGlobalMailslotDesc->BrowserHandle, &Overlapped, &BytesReturned, TRUE )) { WinStatus = GetLastError(); } else { WinStatus = NO_ERROR; } } } else { WinStatus = NO_ERROR; } // // Delete the completion event // NlBrowserCloseEvent( Overlapped.hEvent ); if ( WinStatus ) { NlPrint((NL_CRITICAL,"ioctl to Browser returns %ld\n", WinStatus)); Status = NetpApiStatusToNtStatus( WinStatus ); } else { Status = STATUS_SUCCESS; } return Status; } VOID NlBrowserAddName( VOID ) /*++ Routine Description: Add the Domain<1B> name. The is the name NetGetDcName uses to identify the PDC. Arguments: None. Return Value: None. --*/ { NTSTATUS Status; BYTE Buffer[sizeof(LMDR_REQUEST_PACKET) + (max(CNLEN, DNLEN) + 1) * sizeof(WCHAR)]; PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET) Buffer; // // Add the 0x1B name. // // This is the name NetGetDcName uses to identify the PDC. // if ( NlGlobalRole == RolePrimary && !NlGlobalMailslotDesc->NameAdded ) { RequestPacket->TransportName.Length = 0; RequestPacket->TransportName.Buffer = NULL; RequestPacket->Parameters.AddDelName.Type = PrimaryDomainBrowser; RequestPacket->Parameters.AddDelName.DgReceiverNameLength = NlGlobalUnicodeDomainNameString.Length; wcscpy( RequestPacket->Parameters.AddDelName.Name, NlGlobalUnicodeDomainNameString.Buffer ); Status = NlBrowserDeviceIoControl( IOCTL_LMDR_ADD_NAME, RequestPacket, sizeof(LMDR_REQUEST_PACKET) + NlGlobalUnicodeDomainNameString.Length + sizeof(WCHAR), NULL, 0 ); if (NT_SUCCESS(Status)) { NlGlobalMailslotDesc->NameAdded = TRUE; } else { if ( !NlGlobalMailslotDesc->AddNameEventLogged ) { LPWSTR MsgStrings[2]; MsgStrings[0] = NlGlobalUnicodeDomainName; MsgStrings[1] = (LPWSTR) Status; NlpWriteEventlog( NELOG_NetlogonAddNameFailure, EVENTLOG_WARNING_TYPE, (LPBYTE)&Status, sizeof(Status), MsgStrings, 2 | LAST_MESSAGE_IS_NTSTATUS ); NlGlobalMailslotDesc->AddNameEventLogged = TRUE; } NlPrint((NL_CRITICAL,"Can't add the 0x1B name: 0x%lx\n", Status)); } } return; } BOOL NlBrowserOpen( VOID ) /*++ Routine Description: This routine opens the NT LAN Man Datagram Receiver driver and prepares for reading mailslot messages from it. Arguments: None. Return Value: TRUE -- iff initialization is successful. if false, NlExit will already have been called. --*/ { NTSTATUS Status; BOOL ReturnValue; UNICODE_STRING DeviceName; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; BYTE Buffer[sizeof(LMDR_REQUEST_PACKET) + (max(CNLEN, DNLEN) + 1) * sizeof(WCHAR)]; PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET) Buffer; // // Allocate the mailslot descriptor for this mailslot // NlGlobalMailslotDesc = NetpMemoryAllocate( sizeof(NETLOGON_MAILSLOT_DESC) ); if ( NlGlobalMailslotDesc == NULL ) { NlExit( SERVICE_UIC_RESOURCE, ERROR_NOT_ENOUGH_MEMORY, LogError, NULL); return FALSE; } RtlZeroMemory( NlGlobalMailslotDesc, sizeof(NETLOGON_MAILSLOT_DESC) ); NlGlobalMailslotDesc->CurrentMessage = ROUND_UP_POINTER( NlGlobalMailslotDesc->Message1, ALIGN_WORST); // // Open the browser device. // RtlInitUnicodeString(&DeviceName, DD_BROWSER_DEVICE_NAME_U); InitializeObjectAttributes( &ObjectAttributes, &DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = NtOpenFile( &NlGlobalMailslotDesc->BrowserHandle, SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, 0 ); if (NT_SUCCESS(Status)) { Status = IoStatusBlock.Status; } if (! NT_SUCCESS(Status)) { NlPrint((NL_CRITICAL,"NtOpenFile browser driver failed: 0x%lx\n", Status)); ReturnValue = FALSE; goto Cleanup; } // // Create a completion event // NlGlobalMailslotHandle = NlGlobalMailslotDesc->BrowserReadEvent = NlBrowserCreateEvent(); if ( NlGlobalMailslotDesc->BrowserReadEvent == NULL ) { Status = NetpApiStatusToNtStatus( GetLastError() ); ReturnValue = FALSE; goto Cleanup; } // // Set the maximum number of messages to be queued // RequestPacket->TransportName.Length = 0; RequestPacket->TransportName.Buffer = NULL; RequestPacket->Parameters.NetlogonMailslotEnable.MaxMessageCount = NlGlobalMaximumMailslotMessagesParameter; Status = NlBrowserDeviceIoControl( IOCTL_LMDR_NETLOGON_MAILSLOT_ENABLE, RequestPacket, sizeof(LMDR_REQUEST_PACKET), NULL, 0 ); if (! NT_SUCCESS(Status)) { NlPrint((NL_CRITICAL,"Can't set browser max message count: 0x%lx\n", Status)); ReturnValue = FALSE; goto Cleanup; } // // Add the Domain<1B> name. // NlBrowserAddName(); ReturnValue = TRUE; Cleanup: if ( !ReturnValue ) { NlExit( NELOG_NetlogonBrowserDriver, Status, LogErrorAndNtStatus, NULL); NlBrowserClose(); } return ReturnValue; } VOID NlBrowserClose( VOID ) /*++ Routine Description: This routine cleans up after a NlBrowserInitialize() Arguments: None. Return Value: None. --*/ { IO_STATUS_BLOCK IoSb; NTSTATUS Status; BYTE Buffer[sizeof(LMDR_REQUEST_PACKET) + (max(CNLEN, DNLEN) + 1) * sizeof(WCHAR)]; PLMDR_REQUEST_PACKET RequestPacket = (PLMDR_REQUEST_PACKET) Buffer; if ( NlGlobalMailslotDesc == NULL) { return; } // // If we've opened the browser, clean up. // if ( NlGlobalMailslotDesc->BrowserHandle != NULL ) { // // Tell the browser to stop queueing messages // RequestPacket->TransportName.Length = 0; RequestPacket->TransportName.Buffer = NULL; RequestPacket->Parameters.NetlogonMailslotEnable.MaxMessageCount = 0; Status = NlBrowserDeviceIoControl( IOCTL_LMDR_NETLOGON_MAILSLOT_ENABLE, RequestPacket, sizeof(LMDR_REQUEST_PACKET), NULL, 0 ); if (! NT_SUCCESS(Status)) { NlPrint((NL_CRITICAL,"Can't reset browser max message count: 0x%lx\n", Status)); } // // Delete the 0x1B name. // if ( NlGlobalRole == RolePrimary ) { RequestPacket->TransportName.Length = 0; RequestPacket->TransportName.Buffer = NULL; RequestPacket->Parameters.AddDelName.Type = PrimaryDomainBrowser; RequestPacket->Parameters.AddDelName.DgReceiverNameLength = NlGlobalUnicodeDomainNameString.Length; wcscpy( RequestPacket->Parameters.AddDelName.Name, NlGlobalUnicodeDomainNameString.Buffer ); Status = NlBrowserDeviceIoControl( IOCTL_LMDR_DELETE_NAME, RequestPacket, sizeof(LMDR_REQUEST_PACKET) + NlGlobalUnicodeDomainNameString.Length + sizeof(WCHAR), NULL, 0 ); if (! NT_SUCCESS(Status)) { NlPrint((NL_CRITICAL,"Can't remove the 0x1B name: 0x%lx\n", Status)); } } // // Cancel the I/O operations outstanding on the browser. // NtCancelIoFile(NlGlobalMailslotDesc->BrowserHandle, &IoSb); // // Close the handle to the browser // NtClose(NlGlobalMailslotDesc->BrowserHandle); NlGlobalMailslotDesc->BrowserHandle = NULL; } // // Close the global browser read event // if ( NlGlobalMailslotDesc->BrowserReadEvent != NULL ) { NlBrowserCloseEvent(NlGlobalMailslotDesc->BrowserReadEvent); } NlGlobalMailslotHandle = NULL; // // Free the descriptor describing the browser // NetpMemoryFree( NlGlobalMailslotDesc ); NlGlobalMailslotDesc = NULL; } NTSTATUS NlBrowserSendDatagram( IN LPSTR OemServerName, 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: OemServerName -- Name of the server to send to. 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. --*/ { PLMDR_REQUEST_PACKET RequestPacket = NULL; UNICODE_STRING ServerNameString; OEM_STRING TempOemString; DWORD OemMailslotNameSize; DWORD TransportNameSize; NTSTATUS Status; LPBYTE Where; // // If the transport isn't specified, // send on all transports. // if ( TransportName == NULL ) { CHAR FullMailslotName[(UNCLEN+2) + NETLOGON_LM_MAILSLOT_LEN]; // // Build the mailslot name. // (VOID) lstrcpyA(FullMailslotName, "\\\\" ); (VOID) lstrcatA(FullMailslotName, OemServerName ); (VOID) lstrcatA(FullMailslotName, OemMailslotName ); Status = NlpWriteMailslotA( FullMailslotName, Buffer, BufferSize ); return Status; } // // Ensure we've initialized. // ServerNameString.Buffer = NULL; // // Convert the server name to uppercase. // RtlInitString( &TempOemString, OemServerName ); Status = RtlOemStringToUnicodeString( &ServerNameString, &TempOemString, TRUE ); // Allocate buffer if ( !NT_SUCCESS(Status) ) { NlPrint((NL_CRITICAL, "NlBrowserSendDatagram: Cannot convert server name %08lx\n", Status)); goto Cleanup; } // // Allocate a request packet. // OemMailslotNameSize = lstrlenA(OemMailslotName) + 1; TransportNameSize = (wcslen(TransportName) + 1) * sizeof(WCHAR); RequestPacket = NetpMemoryAllocate( sizeof(LMDR_REQUEST_PACKET) + TransportNameSize + OemMailslotNameSize + ServerNameString.Length + 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 = ComputerName; // // Fill in the name of the machine to send the mailslot message to. // RequestPacket->Parameters.SendDatagram.NameLength = ServerNameString.Length; Where = (LPBYTE) RequestPacket->Parameters.SendDatagram.Name; RtlMoveMemory( Where, ServerNameString.Buffer, ServerNameString.Length ); Where += ServerNameString.Length; // // 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; // // Send the request to the browser. // Status = NlBrowserDeviceIoControl( IOCTL_LMDR_WRITE_MAILSLOT, RequestPacket, Where - (LPBYTE)RequestPacket, Buffer, BufferSize ); // // Free locally used resources. // Cleanup: if ( RequestPacket != NULL ) { NetpMemoryFree( RequestPacket ); } if ( ServerNameString.Buffer != NULL ) { RtlFreeUnicodeString( &ServerNameString ); } NlPrint((NL_MAILSLOT_TEXT, "Sent out message to %s%s on transport " FORMAT_LPWSTR ".\n", OemServerName, OemMailslotName, TransportName )); #if DBG NlpDumpBuffer( NL_MAILSLOT_TEXT, Buffer, BufferSize ); #endif // DBG return Status; } VOID NlMailslotPostRead( IN BOOLEAN IgnoreDuplicatesOfPreviousMessage ) /*++ Routine Description: Post a read on the mailslot if one isn't already posted. Arguments: IgnoreDuplicatesOfPreviousMessage - TRUE to indicate that the next message read should be ignored if it is a duplicate of the previous message. Return Value: TRUE -- iff successful. --*/ { NET_API_STATUS WinStatus; ULONG LocalBytesRead; // // If a read is already pending, // immediately return to caller. // if ( NlGlobalMailslotDesc->ReadPending ) { return; } // // Decide which buffer to read into. // // Switch back and forth so we always have the current buffer and the // previous buffer. // if ( IgnoreDuplicatesOfPreviousMessage ) { NlGlobalMailslotDesc->PreviousMessage = NlGlobalMailslotDesc->CurrentMessage; if ( NlGlobalMailslotDesc->CurrentMessage >= NlGlobalMailslotDesc->Message2 ) { NlGlobalMailslotDesc->CurrentMessage = ROUND_UP_POINTER( NlGlobalMailslotDesc->Message1, ALIGN_WORST); } else { NlGlobalMailslotDesc->CurrentMessage = ROUND_UP_POINTER( NlGlobalMailslotDesc->Message2, ALIGN_WORST); } // // If duplicates of the previous message need not be ignored, // indicate so. // Don't bother switching the buffer pointers. // } else { NlGlobalMailslotDesc->PreviousMessage = NULL; } // // Post an overlapped read to the mailslot. // RtlZeroMemory( &NlGlobalMailslotDesc->Overlapped, sizeof(NlGlobalMailslotDesc->Overlapped) ); NlGlobalMailslotDesc->Overlapped.hEvent = NlGlobalMailslotDesc->BrowserReadEvent; if ( !DeviceIoControl( NlGlobalMailslotDesc->BrowserHandle, IOCTL_LMDR_NETLOGON_MAILSLOT_READ, NULL, 0, NlGlobalMailslotDesc->CurrentMessage, MAILSLOT_MESSAGE_SIZE, &LocalBytesRead, &NlGlobalMailslotDesc->Overlapped )) { WinStatus = GetLastError(); // // On error, wait a second before returning. This ensures we don't // consume the system in an infinite loop. We don't shutdown netlogon // because the error might be a temporary low memory condition. // if( WinStatus != ERROR_IO_PENDING ) { LPWSTR MsgStrings[1]; NlPrint((NL_CRITICAL, "Error in reading mailslot message from browser" ". WinStatus = %ld\n", WinStatus )); MsgStrings[0] = (LPWSTR) WinStatus; NlpWriteEventlog( NELOG_NetlogonFailedToReadMailslot, EVENTLOG_WARNING_TYPE, (LPBYTE)&WinStatus, sizeof(WinStatus), MsgStrings, 1 | LAST_MESSAGE_IS_NETSTATUS ); Sleep( 1000 ); } else { NlGlobalMailslotDesc->ReadPending = TRUE; } } else { NlGlobalMailslotDesc->ReadPending = TRUE; } return; } BOOL NlMailslotOverlappedResult( OUT LPBYTE *Message, OUT PULONG BytesRead, OUT LPWSTR *Transport, OUT PBOOLEAN IgnoreDuplicatesOfPreviousMessage ) /*++ Routine Description: Get the overlapped result of a previous mailslot read. Arguments: Message - Returns a pointer to the buffer containing the message BytesRead - Returns the number of bytes read into the buffer Transport - Returns a pointer to the name of the transport the message was received on. IgnoreDuplicatesOfPreviousMessage - Indicates that duplicates of the previous message are to be ignored. Return Value: TRUE -- iff successful. --*/ { NET_API_STATUS WinStatus; ULONG LocalBytesRead; LARGE_INTEGER TimeNow; PNETLOGON_MAILSLOT NetlogonMailslot; // // Default to not ignoring duplicate messages. // (Only ignore duplicates if a message has been properly processed.) *IgnoreDuplicatesOfPreviousMessage = FALSE; // // Always post another read regardless of the success or failure of // GetOverlappedResult. // We don't know the failure mode of GetOverlappedResult, so we don't // know in the failure case if we're discarding a mailslot message. // But we do know that there is no read pending, so make sure we // issue another one. // NlGlobalMailslotDesc->ReadPending = FALSE; // no read pending anymore // // Get the result of the last read // if( !GetOverlappedResult( NlGlobalMailslotDesc->BrowserHandle, &NlGlobalMailslotDesc->Overlapped, &LocalBytesRead, TRUE) ) { // wait for the read to complete. LPWSTR MsgStrings[1]; // On error, wait a second before returning. This ensures we don't // consume the system in an infinite loop. We don't shutdown netlogon // because the error might be a temporary low memory condition. // WinStatus = GetLastError(); NlPrint((NL_CRITICAL, "Error in GetOverlappedResult on mailslot read" ". WinStatus = %ld\n", WinStatus )); MsgStrings[0] = (LPWSTR) WinStatus; NlpWriteEventlog( NELOG_NetlogonFailedToReadMailslot, EVENTLOG_WARNING_TYPE, (LPBYTE)&WinStatus, sizeof(WinStatus), MsgStrings, 1 | LAST_MESSAGE_IS_NETSTATUS ); Sleep( 1000 ); return FALSE; } // // On success, // Return the mailslot message to the caller. NetlogonMailslot = (PNETLOGON_MAILSLOT) NlGlobalMailslotDesc->CurrentMessage; // // Return pointers into the buffer returned by the browser // *Message = &NlGlobalMailslotDesc->CurrentMessage[ NetlogonMailslot->MailslotMessageOffset]; *BytesRead = NetlogonMailslot->MailslotMessageSize; *Transport = (LPWSTR) &NlGlobalMailslotDesc->CurrentMessage[ NetlogonMailslot->TransportNameOffset]; NlPrint(( NL_MAILSLOT, "Received mailslot opcode 0x%x on transport: " FORMAT_LPWSTR, ((PNETLOGON_LOGON_QUERY)*Message)->Opcode, *Transport )); // // Determine if we can discard an ancient or duplicate message // // Only discard messages that are either expensive to process on this // machine or generate excessive traffic to respond to. Don't discard // messages that we've worked hard to get (e.g., discovery responses). // switch ( ((PNETLOGON_LOGON_QUERY)*Message)->Opcode) { case LOGON_REQUEST: case LOGON_SAM_LOGON_REQUEST: case LOGON_PRIMARY_QUERY: // // If the message is too old, // discard it. // (VOID) NtQuerySystemTime( &TimeNow ); if ( NetlogonMailslot->TimeReceived.QuadPart + NlGlobalMailslotMessageTimeout.QuadPart < TimeNow.QuadPart ) { NlPrint((NL_MAILSLOT, " (Discarded as too old.)\n" )); return FALSE; } // // If the previous message was recent, // and this message is identical to it, // discard the current message. // if ( NlGlobalMailslotDesc->PreviousMessage != NULL ) { PNETLOGON_MAILSLOT PreviousNetlogonMailslot; PreviousNetlogonMailslot = (PNETLOGON_MAILSLOT) NlGlobalMailslotDesc->PreviousMessage; if ( (PreviousNetlogonMailslot->TimeReceived.QuadPart + NlGlobalMailslotDuplicateTimeout.QuadPart > NetlogonMailslot->TimeReceived.QuadPart) && (PreviousNetlogonMailslot->MailslotMessageSize == NetlogonMailslot->MailslotMessageSize) && RtlCompareMemory( &NlGlobalMailslotDesc->CurrentMessage[ NetlogonMailslot->MailslotMessageOffset], &NlGlobalMailslotDesc->PreviousMessage[ PreviousNetlogonMailslot->MailslotMessageOffset], NetlogonMailslot->MailslotMessageSize ) == NetlogonMailslot->MailslotMessageSize ) { // // Ensure the next comparison is to the timestamp of the // message we actually responded to. // NetlogonMailslot->TimeReceived = PreviousNetlogonMailslot->TimeReceived; NlPrint((NL_MAILSLOT, " (Discarded as duplicate of previous.)\n" )); *IgnoreDuplicatesOfPreviousMessage = TRUE; return FALSE; } } } NlPrint(( NL_MAILSLOT, "\n" )); NlpDumpBuffer(NL_MAILSLOT_TEXT, *Message, *BytesRead); return TRUE; } NTSTATUS NlpWriteMailslot( IN LPWSTR MailslotName, IN LPVOID Buffer, IN DWORD BufferSize ) /*++ Routine Description: Write a message to a named mailslot Arguments: MailslotName - Unicode name of the mailslot to write to. Buffer - Data to write to the mailslot. BufferSize - Number of bytes to write to the mailslot. Return Value: NT status code for the operation --*/ { NTSTATUS Status; NET_API_STATUS NetStatus; // // Write the mailslot message. // NetStatus = NetpLogonWriteMailslot( MailslotName, Buffer, BufferSize ); if ( NetStatus != NERR_Success ) { Status = NetpApiStatusToNtStatus( NetStatus ); NlPrint((NL_CRITICAL, "NetpLogonWriteMailslot failed %lx\n", Status)); return Status; } NlPrint((NL_MAILSLOT_TEXT, "Sent out message to " FORMAT_LPWSTR " on all transports.\n", MailslotName)); #if DBG NlpDumpBuffer( NL_MAILSLOT_TEXT, Buffer, BufferSize ); #endif // DBG return STATUS_SUCCESS; } NTSTATUS NlpWriteMailslotA( IN LPSTR MailslotName, IN LPVOID Buffer, IN DWORD BufferSize ) /*++ Routine Description: Write a message to a named mailslot Arguments: MailslotName - ANSI Name of the mailslot to write to. Buffer - Data to write to the mailslot. BufferSize - Number of bytes to write to the mailslot. Return Value: NT status code for the operation. --*/ { NTSTATUS Status; LPWSTR UnicodeMailslotName; // // Convert mailslot name to unicode and call common routine. // UnicodeMailslotName = NetpLogonOemToUnicode( MailslotName ); if ( UnicodeMailslotName == NULL ) { return STATUS_NO_MEMORY; } Status = NlpWriteMailslot( UnicodeMailslotName, Buffer, BufferSize ); NetpMemoryFree( UnicodeMailslotName ); return Status; }