/********************************************************************/ /** Microsoft LAN Manager **/ /** Copyright(c) Microsoft Corp., 1987-1992 **/ /********************************************************************/ /* ** Routines to log messages ** ** If message logging is off, all messages are buffered. Further, ** even if messages are being logged, multi-block messages must ** be buffered since they must be spooled to the logging file or ** device. Since there is only one message buffer in which to ** buffer all messages, this buffer must be managed as a heap. ** Also, messages are logged in a first-in-first-out manner, ** so messages in the buffer must be kept in a queue. In order ** to meet these goals, the following message blocks are defined: ** ** SBM - single-block message ** ** length - length of entire block (2 bytes) ** code - identifies block as single-block message (1 byte) ** link - link to next message in message queue (2 bytes) ** date - date message received (2 bytes) ** time - time message received (2 bytes) ** from - name of sender (null-terminated string) ** to - name of recipient (null-terminated string) ** text - text of message (remainder of block) ** ** MBB - multi-block message header ** ** length - length of entire block (2 bytes) ** code - identifies block as multi-block message header (1 byte) ** link - link to next message in message queue (2 bytes) ** date - date message received (2 bytes) ** time - time message received (2 bytes) ** btext - link to last text block (2 bytes) ** ftext - link to first text block (2 bytes) ** error - error flag (1 byte) ** from - name of sender (null-terminated string) ** to - name of recipient (null-terminated string) ** ** MBT - multi-block message text block ** ** length - length of entire block (2 bytes) ** code - identifies block a multi-block message text (1 byte) ** link - link to next text block (2 bytes) ** text - text of message (remainder of block) **/ // // Includes // #include "msrv.h" #include // memcpy #include // Unicode string macros #include // NetpAssert #include // Alert stuff #include // UNUSED macro #include // NetpNtStatusToApiStatus #include // needed for smb.h #include // Server Message Block definitions #include // NELOG_ messages #include // SMB field manipulation macros #include // MessageBox #include // Windows sockets #include "msgdbg.h" // MSG_LOG #include "msgdata.h" // // Defines for Hex Dump Function // #ifndef MIN #define MIN(a,b) ( ( (a) < (b) ) ? (a) : (b) ) #endif #define DWORDS_PER_LINE 4 #define BYTES_PER_LINE (DWORDS_PER_LINE * sizeof(DWORD)) #define SPACE_BETWEEN_BYTES NetpKdPrint((" ")) #define SPACE_BETWEEN_DWORDS NetpKdPrint((" ")) // // Local Functions // NET_API_STATUS MsgOutputMsg ( USHORT AlertLength, LPSTR AlertBuffer, ULONG SessionId, SYSTEMTIME BigTime ); // // Data // PSTD_ALERT alert_buf_ptr; // Pointer to DosAlloc'ed alert buffer USHORT alert_len; // Currently used length of alert buffer // // Defines // #define ERROR_LOG_SIZE 1024 /* ** Msglogmbb - log a multi-block message header ** ** This function is called to log a multi-block message header. ** The message header is placed in the message buffer which resides ** in the shared data area. ** ** This function stores the from and to information in the shared data ** buffer and initializes the multi-block message header. Then it puts ** a pointer to the multi-block header into the shared data pointer ** location for that net index and name index. ** ** logmbb (from, to, net, ncbi) ** ** ENTRY ** from - sender name ** to - recipient name ** net - network index ** ncbi - Network Control Block index ** ** RETURN ** zero if successful, non-zero if unable to buffer the message header ** ** SIDE EFFECTS ** ** Calls heapalloc() to obtain buffer space. **/ DWORD Msglogmbb( LPSTR from, // Name of sender LPSTR to, // Name of recipient DWORD net, // Which network ? DWORD ncbi // Network Control Block index ) { DWORD i; // Heap index LPSTR fcp; // Far character pointer LONG ipAddress; struct hostent *pHostEntry; // // Synchronize with Pnp configuration routine // MsgConfigurationLock(MSG_GET_SHARED,"Msglogmbb"); // // Block until the shared database is free // MsgDatabaseLock(MSG_GET_EXCLUSIVE,"logmbb"); // // Check whether the recipient name needs to be formatted // ipAddress = inet_addr( to ); if (ipAddress != INADDR_NONE) { pHostEntry = gethostbyaddr( (char *)&ipAddress,sizeof( LONG ),AF_INET); if (pHostEntry) { to = pHostEntry->h_name; } else { MSG_LOG2(ERROR,"Msglogmbb: could not lookup addr %s, error %d\n", to, WSAGetLastError()); } } // // Allocate space for header // i = Msgheapalloc(sizeof(MBB) + strlen(from) + strlen(to) + 2); if(i == INULL) { // If no buffer space // // Unlock the shared database // MsgDatabaseLock(MSG_RELEASE,"logmbb"); MsgConfigurationLock(MSG_RELEASE,"Msglogmbb"); return((int) i); // Log fails } // // Multi-block message // MBB_CODE(*MBBPTR(i)) = SMB_COM_SEND_START_MB_MESSAGE; MBB_NEXT(*MBBPTR(i)) = INULL; // Last message in buffer GetLocalTime(&MBB_BIGTIME(*MBBPTR(i))); // Time of message MBB_BTEXT(*MBBPTR(i)) = INULL; // No text yet MBB_FTEXT(*MBBPTR(i)) = INULL; // No text yet MBB_STATE(*MBBPTR(i)) = MESCONT; // Message in progress fcp = CPTR(i + sizeof(MBB)); // Get far pointer into buffer strcpy(fcp, from); // Copy the sender name fcp += strlen(from) + 1; // Increment pointer strcpy(fcp, to); // Copy the recipient name SD_MESPTR(net,ncbi) = i; // Save index to this record // // Unlock the shared database // MsgDatabaseLock(MSG_RELEASE,"logmbb"); MsgConfigurationLock(MSG_RELEASE,"Msglogmbb"); return(0); // Message logged successfully } /* ** Msglogmbe - log end of a multi-block message ** ** This function is called to log a multi-block message end. ** The message is marked as finished, and if logging is enabled, ** an attempt is made to write the message to the log file. If ** this attempt fails, or if logging is disabled, then the message ** is placed in the message queue in the message buffer. ** ** The message is gathered up and placed in the alert buffer and an alert ** is raised. ** ** logmbe (state, net,ncbi) ** ** ENTRY ** state - final state of message ** net - Network index ** ncbi - Network Control Block index ** ** RETURN ** int - BUFFERED if the message is left in the buffer ** int - LOGGED if the message is written to the log file ** ** FOR NT: ** SMB_ERR_SUCCESS - success in alerting ** SMB_ERR_... - an error occured ** ** ** ** SIDE EFFECTS ** ** Calls mbmprint() to print the message if logging is enabled. Calls ** mbmfree() to free the message if logging succeeds. **/ UCHAR Msglogmbe( DWORD state, // Final state of message DWORD net, // Which network? DWORD ncbi // Network Control Block index ) { DWORD i; // Heap index DWORD error; // Error code DWORD meslog; // Message logging status DWORD alert_flag; // Alert buffer allocated flag DWORD status; // Dos error for error log DWORD bufSize; // Buffer Size SYSTEMTIME bigtime; // Date and time of message PMSG_SESSION_ID_ITEM pItem; PLIST_ENTRY pHead; PLIST_ENTRY pList; // // Synchronize with Pnp configuration routine // MsgConfigurationLock(MSG_GET_SHARED,"Msglogmbe"); // // Block until the shared database is free // MsgDatabaseLock(MSG_GET_EXCLUSIVE,"logmbe"); pHead = &(SD_SIDLIST(net,ncbi)); pList = pHead; // // First get a buffer for an alert // bufSize = sizeof( STD_ALERT) + ALERT_MAX_DISPLAYED_MSG_SIZE + (2*TXTMAX) + 2; alert_buf_ptr = (PSTD_ALERT)LocalAlloc(LMEM_ZEROINIT, bufSize); if (alert_buf_ptr == NULL) { MSG_LOG(ERROR,"logmbe:Local Alloc failed\n",0); alert_flag = 0xffffffff; // No alerting if Alloc failed } else { alert_flag = 0; // File and alerting alert_len = 0; } error = 0; // Assume no error i = SD_MESPTR(net,ncbi); // Get index to message header MBB_STATE(*MBBPTR(i)) = state; // Record final state // // If logging now disabled ... // if(!SD_MESLOG()) { if( alert_flag == 0) { // // Format the message and put it in the alert buffer. // // Alert only. alert_flag is only modified if Msgmbmprint // returns success and we should skip the message (i.e., // it's a print notification from a pre-Whistler machine). // if (Msgmbmprint(1,i,0, &alert_flag)) { alert_flag = 0xffffffff; } } } // // Add message to buffer queue if logging is off, // or if the attempt to log the message failed. // meslog = SD_MESLOG(); // Get logging status if(!meslog) { // If logging disabled Msgmbmfree(i); } if(error != 0) { // // We should never get here // NetpAssert(error == 0); } // // Now alert and free up alert buffer if it was successfully allocated // if( alert_flag == 0) { // // There is an alert buffer, output it. // GetLocalTime(&bigtime); // Get the time if (g_IsTerminalServer) { // // Output the message for all the sessions sharing that name // while (pList->Flink != pHead) // loop all over the list { pList = pList->Flink; pItem = CONTAINING_RECORD(pList, MSG_SESSION_ID_ITEM, List); MsgOutputMsg(alert_len, (LPSTR)alert_buf_ptr, pItem->SessionId, bigtime); } } else // regular NT { MsgOutputMsg(alert_len, (LPSTR)alert_buf_ptr, 0, bigtime); } } LocalFree(alert_buf_ptr); // // Unlock the shared database // MsgDatabaseLock(MSG_RELEASE,"logmbe"); MsgConfigurationLock(MSG_RELEASE,"Msglogmbe"); return(SMB_ERR_SUCCESS); // Message arrived } /* ** Msglogmbt - log a multi-block message text block ** ** This function is called to log a multi-block message text block. ** The text block is placed in the message buffer which resides ** in the shared data area. If there is insufficient room in the ** buffer, logmbt() removes the header and any previous blocks of ** the message from the buffer. ** ** This function gets the current message from the message pointer in ** the shared data (for that net & name index). It looks in the header ** to see if there are any text blocks already there. If so, it adds ** this new one to the list and fixes the last block pointer to point to ** it. ** ** logmbt (text, net, ncbi) ** ** ENTRY ** text - text header ** net - Network index ** ncbi - Network Control Block index ** ** RETURN ** zero if successful, non-zero if unable to buffer the message header ** ** SIDE EFFECTS ** ** Calls heapalloc() to obtain buffer space. Calls mbmfree() if a call to ** heapalloc() fails. **/ DWORD Msglogmbt( LPSTR text, // Text of message DWORD net, // Which network? DWORD ncbi // Network Control Block index ) { DWORD i; // Heap index DWORD j; // Heap index DWORD k; // Heap index USHORT length; // Length of text // // Synchronize with Pnp configuration routine // MsgConfigurationLock(MSG_GET_SHARED,"Msglogmbt"); // *ALIGNMENT* length = SmbGetUshort( (PUSHORT)text); // Get length of text block // length = *((PSHORT) text); // Get length of text block text += sizeof(short); // Skip over length word // // Block until the shared database is free // MsgDatabaseLock(MSG_GET_EXCLUSIVE,"logmbt"); i = Msgheapalloc(sizeof(MBT) + length); // Allocate space for block // // If buffer space is available // if(i != INULL) { // // Multi-block message text // MBT_CODE(*MBTPTR(i)) = SMB_COM_SEND_TEXT_MB_MESSAGE; MBT_NEXT(*MBTPTR(i)) = INULL; // Last text block so far MBT_COUNT(*MBTPTR(i)) = (DWORD)length; // *ALIGNMENT2* memcpy(CPTR(i + sizeof(MBT)), text, length); // Copy text into buffer j = SD_MESPTR(net, ncbi); // Get index to current message if(MBB_FTEXT(*MBBPTR(j)) != INULL) { // // If there is text already, Get pointer to last block and // add new block // k = MBB_BTEXT(*MBBPTR(j)); // Get pointer to last block MBT_NEXT(*MBTPTR(k)) = i; // Add new block } else { MBB_FTEXT(*MBBPTR(j)) = i; // Else set front pointer } MBB_BTEXT(*MBBPTR(j)) = i; // Set back pointer i = 0; // Success } else { Msgmbmfree(SD_MESPTR(net,ncbi)); // Else deallocate the message } // // Unlock the shared database // MsgDatabaseLock(MSG_RELEASE,"logmbt"); MsgConfigurationLock(MSG_RELEASE,"Msglogmbt"); return((int) i); // Return status } /* ** Msglogsbm - log a single-block message ** ** This function is called to log a single-block message. If ** logging is enabled, the message is written directly to the ** logging file or device. If logging is disabled or if the ** attempt to log the message fails, the message is placed in ** the message buffer which resides in the shared data area. ** ** logsbm (from, to, text) ** ** ENTRY ** from - sender name ** to - recipient name ** text - text of message ** ** RETURN ** zero if successful, non-zero if unable to log the message ** ** SIDE EFFECTS ** ** Calls hdrprint(), txtprint(), and endprint() to print the message if ** logging is enabled. Calls heapalloc() to obtain buffer space if ** the message must be buffered. **/ DWORD Msglogsbm( LPSTR from, // Name of sender LPSTR to, // Name of recipient LPSTR text, // Text of message ULONG SessionId // Session Id ) { DWORD i; // Heap index DWORD error; // Error code SHORT length; // Length of text DWORD meslog; // Message logging status DWORD alert_flag; // Alert buffer allocated flag DWORD status; // DOS error from mespeint functions SYSTEMTIME bigtime; // Date and time of message DWORD bufSize; // Buffer Size // // Synchronize with Pnp configuration routine // MsgConfigurationLock(MSG_GET_SHARED,"Msglogsbm"); // // Block until the shared database is free // MsgDatabaseLock(MSG_GET_EXCLUSIVE,"logsbm"); // // First get a buffer for an alert // bufSize = sizeof( STD_ALERT) + ALERT_MAX_DISPLAYED_MSG_SIZE + (2*TXTMAX) + 2; alert_buf_ptr = (PSTD_ALERT)LocalAlloc(LMEM_ZEROINIT, bufSize); if (alert_buf_ptr == NULL) { MSG_LOG(ERROR,"Msglogsbm:Local Alloc failed\n",0); alert_flag = 0xffffffff; // No alerting if Alloc failed } else { alert_flag = 0; // File and alerting alert_len = 0; } // *ALIGNMENT* length = SmbGetUshort( (PUSHORT)text); // Get length of text block text += sizeof(short); // Skip over length word error = 0; // Assume no errors // // Hack to drop messages sent by pre-Whistler Spoolers. As of // Whistler, print notifications are done as shell balloon tips // so don't display print alerts sent from the server as well. // // This check is also made in Msgmbmprint to catch multi-block messages. // if ((g_lpAlertSuccessMessage && _strnicmp(text, g_lpAlertSuccessMessage, g_dwAlertSuccessLen) == 0) || (g_lpAlertFailureMessage && _strnicmp(text, g_lpAlertFailureMessage, g_dwAlertFailureLen) == 0)) { MsgDatabaseLock(MSG_RELEASE,"logsbm"); MsgConfigurationLock(MSG_RELEASE,"Msglogsbm"); return 0; } GetLocalTime(&bigtime); // Get the time if (!SD_MESLOG()) // If logging disabled { if( alert_flag == 0) // If alert buf is valid { if (!Msghdrprint(1,from, to, bigtime,0)) { if (Msgtxtprint(1, text,length,0)) { alert_flag = 0xffffffff; } } else { alert_flag = 0xffffffff; } } } meslog = SD_MESLOG(); // Get logging status i = 0; // No way to fail if not logging if(error != 0) { DbgPrint("meslog.c:logsbm(before ErrorLogWrite): We should never get here\n"); NetpAssert(0); } // Now alert and free up alert buffer if it was successfully allocated if( alert_flag == 0) { // There is an alert buffer // // There is an alert buffer, output it. // MsgOutputMsg(alert_len, (LPSTR)alert_buf_ptr, SessionId, bigtime); } LocalFree(alert_buf_ptr); // // Unlock the shared database // MsgDatabaseLock(MSG_RELEASE,"logsbm"); MsgConfigurationLock(MSG_RELEASE,"Msglogsbm"); return((int) i); // Return status } NET_API_STATUS MsgOutputMsg ( USHORT AlertLength, LPSTR AlertBuffer, ULONG SessionId, SYSTEMTIME BigTime ) /*++ Routine Description: This function translates the alert buffer from an Ansi String to a Unicode String and outputs the buffer to whereever it is to go. Currently this just becomes a DbgPrint. Arguments: AlertLength - The number of bytes in the AlertBuffer. AlertBuffer - This is a pointer to the buffer that contains the message that is to be output. The buffer is expected to contain a NUL Terminated Ansi String. BigTime - The SYSTEMTIME that indicates the time the end of the messsage was received. Return Value: --*/ { UNICODE_STRING unicodeString; OEM_STRING ansiString; NTSTATUS ntStatus; // // NUL Terminate the message. // Translate the Ansi message to a Unicode Message. // AlertBuffer[AlertLength++] = '\0'; ansiString.Length = AlertLength; ansiString.MaximumLength = AlertLength; ansiString.Buffer = AlertBuffer; ntStatus = RtlOemStringToUnicodeString( &unicodeString, // Destination &ansiString, // Source TRUE); // Allocate the destination. if (!NT_SUCCESS(ntStatus)) { MSG_LOG(ERROR, "MsgOutputMsg:RtlOemStringToUnicodeString Failed rc=%X\n", ntStatus); // // EXPLANATION OF WHY IT RETURNS SUCCESS HERE. // Returning success even though the alert is not raised is // consistent with the LM2.0 code which doesn't check the // return code for the NetAlertRaise API anyway. Returning // anything else would require a re-design of how errors are // handled by the caller of this routine. // return(NERR_Success); } //******************************************************************* // // PUT THE MESSAGE IN THE DISPLAY QUEUE // MsgDisplayQueueAdd( AlertBuffer, (DWORD)AlertLength, SessionId, BigTime); // // //******************************************************************* RtlFreeUnicodeString(&unicodeString); return(NERR_Success); }