/********************************************************************/ /** 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 // NetpDbgHexDump #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 ); #if DBG VOID MsgDbgHexDumpLine( IN LPBYTE StartAddr, IN DWORD BytesInThisLine ); VOID MsgDbgHexDump( IN LPBYTE StartAddr, IN DWORD Length ); #endif //DBG // // 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) { // // Report to error log // NetpAssert(0); // NT code should never get here. MsgErrorLogWrite( error, SERVICE_MESSENGER, (LPBYTE)&status, sizeof(DWORD), NULL, 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); MsgErrorLogWrite( // Report to error log error, SERVICE_MESSENGER, (LPBYTE)&status, sizeof(DWORD), NULL, 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 MsgErrorLogWrite( IN DWORD Code, IN LPTSTR Component, IN LPBYTE Buffer, IN DWORD BufferSize, IN LPSTR Strings, IN DWORD NumStrings ) /*++ Routine Description: Writes an entry to the event manager on the local computer. This function needs to get the error message text out of the message file and send it to the event logger. Arguments: Code - Specifies the code of the error that occured. Component - Points to a NUL terminated string that specifies which component encountered the error. UNICODE STRING. Buffer - Points to a string of raw data associated with the error condition. BufferSize - size (in bytes) of the buffer. Strings - NOT USED. Points to NUL terminated strings that contain the error message. ANSI STRINGS. NumStrings - NOT USED. Specifies how many concatenated NUL terminated strings are stored in Strings. Return Value: --*/ { DWORD status; WORD msglen=0; LPBYTE msgBuf; // // Get a message associated with the message code from the message // file. // msgBuf = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, ERROR_LOG_SIZE); if (msgBuf == NULL) { status = GetLastError(); MSG_LOG(ERROR,"MsgErrorLogWrite: LocalAlloc FAILURE %X\n", status); return(status); } // // TODO ITEM: // If we actually used strings, then they must be converted to unicode. // However, since they are never used, this isn't very important. // status = DosGetMessage ( &Strings, // String substitution table (USHORT)NumStrings, // Num Entries in table above msgBuf, // Buffer receiving message ERROR_LOG_SIZE, // size of buffer receiving msg (USHORT)Code, // message num to retrieve MessageFileName, // Name of message file &msglen); // Num bytes returned if (status != NERR_Success) { LocalFree(msgBuf); return(status); } #if DBG DbgPrint("MsgErrorLogWrite: COMPONENT = %ws\n",Component); DbgPrint("MsgErrorLogWrite: %s\n",msgBuf); if ( Buffer != NULL ) { MsgDbgHexDump( (LPBYTE)Buffer, BufferSize); } #endif //DBG UNREFERENCED_PARAMETER(Buffer); UNREFERENCED_PARAMETER(BufferSize); LocalFree(msgBuf); return(NERR_Success); } 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); } #if DBG VOID MsgDbgHexDumpLine( IN LPBYTE StartAddr, IN DWORD BytesInThisLine ) /*++ Routine Description: Arguments: Return Value: --*/ { LPBYTE BytePtr; DWORD BytesDone; DWORD HexPosition; DbgPrint(FORMAT_LPVOID " ", (LPVOID) StartAddr); BytePtr = StartAddr; BytesDone = 0; while (BytesDone < BytesInThisLine) { DbgPrint("%02X", *BytePtr); // space for "xx" (see pad below). SPACE_BETWEEN_BYTES; ++BytesDone; if ( (BytesDone % sizeof(DWORD)) == 0) { SPACE_BETWEEN_DWORDS; } ++BytePtr; } HexPosition = BytesDone; while (HexPosition < BYTES_PER_LINE) { DbgPrint(" "); // space for "xx" (see byte above). SPACE_BETWEEN_BYTES; ++HexPosition; if ( (HexPosition % sizeof(DWORD)) == 0) { SPACE_BETWEEN_DWORDS; } } BytePtr = StartAddr; BytesDone = 0; while (BytesDone < BytesInThisLine) { if (isprint(*BytePtr)) { DbgPrint( FORMAT_CHAR, (CHAR) *BytePtr ); } else { DbgPrint( "." ); } ++BytesDone; ++BytePtr; } DbgPrint("\n"); } // MsgDbgHexDumpLine VOID MsgDbgHexDump( IN LPBYTE StartAddr, IN DWORD Length ) /*++ Routine Description: MsgDbgHexDump: do a hex dump of some number of bytes to the debug terminal or whatever. This is a no-op in a nondebug build. Arguments: Return Value: --*/ { DWORD BytesLeft = Length; LPBYTE LinePtr = StartAddr; DWORD LineSize; while (BytesLeft > 0) { LineSize = MIN(BytesLeft, BYTES_PER_LINE); MsgDbgHexDumpLine( LinePtr, LineSize ); BytesLeft -= LineSize; LinePtr += LineSize; } } // NetpDbgHexDump #endif // DBG