|
|
/*++
Copyright (c) 1991-1992 Microsoft Corporation
Module Name:
apiutil.c
Abstract:
Contains functions used by the Messenger API. This file contains the following functions:
MsgIsValidMsgName MsgMapNetError MsgLookupName message_sec_check MsgGatherInfo MsgUnformatName
MsgLookupNameForThisSession MsgIsSessionInList (HYDRA specific) MsgAddSessionInList (HYDRA specific) MsgRemoveSessionFromList (HYDRA specific)
Author:
Dan Lafferty (danl) 22-Jul-1991
Environment:
User Mode -Win32
Notes:
These functions were ported from LM2.0. This file contains functions from several LM2.0 files. Not all functions were used in this file since some were made obsolete by the NT Service Model. The following LM2.0 files were incorportated into this single file: msgutils.c msgutil2.c dupname.c netname.c Revision History:
22-Jul-1991 danl ported from LM2.0
--*/
//
// Includes
//
#include "msrv.h"
#include <tstring.h> // Unicode string macros
#include <lmwksta.h>
#include <lmmsg.h>
#include <smbtypes.h> // needed for smb.h
#include <smb.h> // Server Message Block definitions
#include <icanon.h> // I_NetNameValidate
#include <netlib.h> // NetpCopyStringToBuffer
#include "msgdbg.h" // MSG_LOG
#include "heap.h"
#include "msgdata.h"
#include "apiutil.h"
//
// Table of NetBios mappings to Net Errors.
//
DWORD const mpnetmes[] = { 0x23, // 00 Number of messages
NERR_NetworkError, // 01 NRC_BUFLEN -> invalid length
0xffffffff, // 02 NRC_BFULL , not expected
NERR_NetworkError, // 03 NRC_ILLCMD -> invalid command
0xffffffff, // 04 not defined
NERR_NetworkError, // 05 NRC_CMDTMO -> network busy
NERR_NetworkError, // 06 NRC_INCOMP -> messgae incomplete
0xffffffff, // 07 NRC_BADDR , not expected
NERR_NetworkError, // 08 NRC_SNUMOUT -> bad session
NERR_NoNetworkResource, // 09 NRC_NORES -> network busy
NERR_NetworkError, // 0a NRC_SCLOSED -> session closed
NERR_NetworkError, // 0b NRC_CMDCAN -> command cancelled
0xffffffff, // 0c NRC_DMAFAIL, unexpected
NERR_AlreadyExists, // 0d NRC_DUPNAME -> already exists
NERR_TooManyNames, // 0e NRC_NAMTFUL -> too many names
NERR_DeleteLater, // 0f NRC_ACTSES -> delete later
0xffffffff, // 10 NRC_INVALID , unexpected
NERR_NetworkError, // 11 NRC_LOCTFUL -> too many sessions
ERROR_REM_NOT_LIST, // 12 NRC_REMTFUL -> remote not listening*/
NERR_NetworkError, // 13 NRC_ILLNN -> bad name
NERR_NameNotFound, // 14 NRC_NOCALL -> name not found
ERROR_INVALID_PARAMETER, // 15 NRC_NOWILD -> bad parameter
NERR_DuplicateName, // 16 NRC_INUSE -> name in use, retry
ERROR_INVALID_PARAMETER, // 17 NRC_NAMERR -> bad parameter
NERR_NetworkError, // 18 NRC_SABORT -> session ended
NERR_DuplicateName, // 19 NRC_NAMCONF -> duplicate name
0xffffffff, // 1a not defined
0xffffffff, // 1b not defined
0xffffffff, // 1c not defined
0xffffffff, // 1d not defined
0xffffffff, // 1e not defined
0xffffffff, // 1f not defined
0xffffffff, // 20 not defined
NERR_NetworkError, // 21 NRC_IFBUSY -> network busy
NERR_NetworkError, // 22 NRC_TOOMANY -> retry later
NERR_NetworkError // 23 NRC_BRIDGE -> bridge error
};
DWORD MsgIsValidMsgName( IN LPTSTR name )
/*++
Routine Description:
Check for a valid messaging name. This function checks for the validity of a messaging name.
Arguments:
name - pointer to name to validate.
Return Value:
Error code from I_NetNameValidate
--*/
{ TCHAR namebuf[NCBNAMSZ]; DWORD err_code;
//
// Message names cannot be larger than (NCBNAMSZ - 1) characters
//
if (STRLEN(name) > (NCBNAMSZ - 1)) { return ERROR_INVALID_PARAMETER; } STRCPY(namebuf, name);
err_code = I_NetNameValidate(NULL, namebuf, NAMETYPE_COMPUTER, 0L);
if (err_code != 0) { return err_code; } //
// Any name beginning with a * must be rejected as the message
// server relies on being able to ASTAT the name, and an ASTAT
// name commencing with a * means ASTAT the local card.
//
if(namebuf[0] == TEXT('*')) { return ERROR_INVALID_PARAMETER; }
return NERR_Success; }
DWORD MsgMapNetError( IN UCHAR Code // Error code
)
/*++
Routine Description:
Map NetBios Error code to a message number
Arguments:
code - Error code from NetBios (can be 0)
Return Value:
Message code as defined in msgs.h
--*/ { DWORD dwCode;
dwCode = 0 | (UCHAR)Code; if( dwCode == 0) { return(NERR_Success); // Special case
}
if((dwCode > 0) && (dwCode < mpnetmes[0])) { return(mpnetmes[dwCode]); }
return (NERR_NetworkError); // Can't map it!
}
DWORD MsgLookupName( IN DWORD net, // The network card to search
IN LPSTR name // Formatted name (Non-unicode)
)
/*++
Routine Description:
This function looks up a formatted name in the name table in the Message Server's shared data area. This function looks the given name up in the name table in the shared data area. In order to match the given name, the first NCBNAMLEN - 1 characters of the name in the name table must be identical to the same characters in the given name, and the name in the name table must not be marked as deleted. This function assumes that the shared data area is accessible and that the global variable, dataPtr, is valid.
Arguments:
name - pointer to formatted name
Return Value:
DWORD - index into table if found, -1 otherwise
--*/
{ DWORD i; // Index
for(i = 0; i < NCBMAX(net); ++i) { // Loop to search for name
if( !memcmp( name, SD_NAMES(net,i), NCBNAMSZ - 1) && !(SD_NAMEFLAGS(net,i) & NFDEL) ) {
//
// Return index if match found
//
return(i); } } return(0xffffffff); // No match
}
// For HYDRA, we want to make sure that the name exists for THIS client session.
DWORD MsgLookupNameForThisSession( IN DWORD net, // The network card to search
IN LPSTR name, // Formatted name to loook for (Non-unicode)
IN ULONG SessionId // Session Id to look for
) /*++
Routine Description:
Same as MsgLookupName except that we care about the session Id. This function looks up a formatted name in the name table in the Message Server's shared data area. The name found must have the requested SessionId in its session list to be considered as OK.
Arguments:
name - pointer to formatted name SessionId - the requested Session Id
Return Value:
DWORD - index into table if found, -1 otherwise
--*/
{ DWORD i; // Index
DWORD dwMsgrState; // messanger state
if (!g_IsTerminalServer) // regular NT case
{ //
// if we are not on HYDRA, forget the SessionId
//
return MsgLookupName(net, name); } else // HYDRA case
{ //
// dont try to access table if messanger stop is pending,
// we may not have GlobalData available
//
dwMsgrState = GetMsgrState(); if (RUNNING == dwMsgrState) { for(i = 0; i < NCBMAX(net); ++i) { // Loop to search for name
if( !memcmp( name, SD_NAMES(net,i), NCBNAMSZ - 1) && !(SD_NAMEFLAGS(net,i) & NFDEL) && (MsgIsSessionInList(&(SD_SIDLIST(net,i)), SessionId )) ) { return (i); } } } return(0xffffffff); // No match
} }
// message_sec_check
//
// A common routine to check caller priv/auth against that
// required to call the message apis.
//
//
NET_API_STATUS message_sec_check(VOID) { #ifdef later
//
// API security check. This call can be called by anyone locally,
// but only by admins in the remote case.
I_SecSyncSet(SECSYNC_READER);
if ( ( clevel == ACCESS_REMOTE ) && ( callinf != NULL ) && ( CALLER_PRIV(callinf) != USER_PRIV_ADMIN ) ) { I_SecSyncClear(SECSYNC_READER); return(ERROR_ACCESS_DENIED); } I_SecSyncClear(SECSYNC_READER); #endif
return (NERR_Success); }
NET_API_STATUS MsgGatherInfo ( IN DWORD Level, IN LPSTR FormattedName, IN OUT LPBYTE *InfoBufPtr, IN OUT LPBYTE *StringBufPtr )
/*++
Routine Description:
Arguments:
Level - Indicates the level of information that is being returned.
FormattedName - This is a name that messages are received by. This name is formated for NCB transactions. Therefore, it is made up of ANSI characters that are space padded to fill out a packet of NCBNAMSZ characters. The last character is always a 03 (indicating a non-forwarded name). InfoBufPtr - On input, this is a pointer to a pointer to where the messenger information is to be placed. On successful return, this location contains a pointer to the location where the next information will be placed (on the next call to this function).
StringBufPtr - On input, thisis a pointer to a pointer to where the NUL terminated name string for that info record is to be placed. On successful return, this location contains a pointer to the location where the next set of strings will be placed (on the next call to this function).
Return Value:
NERR_Success - The information was successfully gathered and placed in the info buffer.
NERR_Internal_Error - The Formatted Name could not be correctly translated into a meaningful Unicode Name.
ERROR_INVALID_LEVEL - An illegal info level was passed in.
ERROR_NOT_ENOUGH_MEMORY - Not enough room to store gathered information.
--*/ { NET_API_STATUS status; BOOL bStatus; PCHAR fixedDataEnd; // pointer to free space from top of buffer.
LPMSG_INFO_0 infoBuf0; LPMSG_INFO_1 infoBuf1; TCHAR unicodeName[NCBNAMSZ];
//
// Convert the name to Unicode
//
status = MsgUnformatName(unicodeName, FormattedName); if (status != NERR_Success) { return(status); } switch (Level) { case LEVEL_0: infoBuf0 = (LPMSG_INFO_0)*InfoBufPtr; fixedDataEnd = (PCHAR)infoBuf0 + sizeof(MSG_INFO_0);
if( fixedDataEnd >= *StringBufPtr) { return(ERROR_NOT_ENOUGH_MEMORY); }
bStatus = NetpCopyStringToBuffer ( unicodeName, // The String
STRLEN(unicodeName), // StringLength
fixedDataEnd, // FixedDataEnd
(PVOID)StringBufPtr, // EndOfVariableData
&infoBuf0->msgi0_name); // VariableDataPointer
if (bStatus == FALSE) { MSG_LOG(TRACE,"MsgGatherInfo(level0): Not enough room\n",0); return(ERROR_NOT_ENOUGH_MEMORY); } *InfoBufPtr = (LPBYTE)fixedDataEnd; break;
case LEVEL_1: infoBuf1 = (LPMSG_INFO_1)*InfoBufPtr;
fixedDataEnd = (PCHAR)infoBuf1 + sizeof(MSG_INFO_1); if( fixedDataEnd >= *StringBufPtr) { return(ERROR_NOT_ENOUGH_MEMORY); }
bStatus = NetpCopyStringToBuffer ( unicodeName, // The String
STRLEN(unicodeName), // StringLength
fixedDataEnd, // FixedDataEnd
(PVOID)StringBufPtr, // EndOfVariableData
&infoBuf1->msgi1_name); // VariableDataPointer
if (bStatus == FALSE) { MSG_LOG(TRACE,"MsgGatherInfo(level1): Not enough room\n",0); return(ERROR_NOT_ENOUGH_MEMORY); }
//
// Set all the forward information to NULL since forwarding
// is not supported.
//
infoBuf1->msgi1_forward_flag = 0; infoBuf1->msgi1_forward = NULL; *InfoBufPtr = (LPBYTE)fixedDataEnd; break;
default: MSG_LOG(TRACE,"MsgGatherInfo Invalid level\n",0); return(ERROR_INVALID_LEVEL); break; }
return(NERR_Success);
}
NET_API_STATUS MsgUnformatName( OUT LPTSTR UnicodeName, IN LPSTR FormattedName )
/*++
Routine Description:
This routine creates a Unicode NUL-Terminated version of a NetBios Formatted name.
Arguments:
UnicodeName - This is a pointer to a location where the un-formatted NUL terminated Unicode Name is to be copied.
FormattedName - This is a pointer to an NCB formatted name. This name always contains NCBNAMSZ characters of which the last character is a code used for a forward/non-forward flag. These strings are space padded.
Return Value:
NERR_Success - The operation was successful.
NERR_Internal - The operation was unsuccessful.
--*/ { UNICODE_STRING unicodeString; OEM_STRING ansiString; NTSTATUS ntStatus; int i;
//
// Translate the ansi string in the name table to a unicode name
//
#ifdef UNICODE
unicodeString.Length = (NCBNAMSZ -1) * sizeof(WCHAR); unicodeString.MaximumLength = NCBNAMSZ * sizeof(WCHAR); unicodeString.Buffer = (LPWSTR)UnicodeName;
ansiString.Length = NCBNAMSZ-1; ansiString.MaximumLength = NCBNAMSZ; ansiString.Buffer = FormattedName;
ntStatus = RtlOemStringToUnicodeString( &unicodeString, // Destination
&ansiString, // Source
FALSE); // Don't allocate the destination.
if (!NT_SUCCESS(ntStatus)) { MSG_LOG(ERROR, "UnformatName:RtlOemStringToUnicodeString Failed rc=%X\n", ntStatus); //
// Indicate a failure
//
return(NERR_InternalError); } #else
UNUSED (ntStatus); UNUSED (ansiString); UNUSED (unicodeString); strncpy(UnicodeName, FormattedName, NCBNAMSZ-1); #endif
//
// Remove excess Space characters starting at the back (skipping
// the 03 flag character.
//
i = NCBNAMSZ-2;
while ( UnicodeName[i] == TEXT(' ')) {
UnicodeName[i--] = TEXT('\0');
if (i < 0) { MSG_LOG(ERROR, "UnformatName:Nothing but space characters\n",0); return(NERR_InternalError); } } return(NERR_Success); }
BOOL MsgIsSessionInList( IN PLIST_ENTRY SessionIdList, IN ULONG SessionId ) { BOOL bRet = FALSE;
PLIST_ENTRY pList = SessionIdList; PMSG_SESSION_ID_ITEM pItem;
while (pList->Flink != SessionIdList) // loop until we find it (or the end of the list)
{ pList = pList->Flink; pItem = CONTAINING_RECORD(pList, MSG_SESSION_ID_ITEM, List); if ( (pItem->SessionId == SessionId) || (pItem->SessionId == EVERYBODY_SESSION_ID) ) { bRet = TRUE; // we found it !
break; } }
return bRet; }
VOID MsgRemoveSessionFromList( IN PLIST_ENTRY SessionIdList, ULONG SessionId ) { PLIST_ENTRY pList = SessionIdList; PMSG_SESSION_ID_ITEM pItem;
while (pList->Flink != SessionIdList) // loop until we find it (or the end of the list)
{ pList = pList->Flink; pItem = CONTAINING_RECORD(pList, MSG_SESSION_ID_ITEM, List); if (pItem->SessionId == SessionId) { // we found it. Let's remove it
RemoveEntryList(pList);
//Free the memory
LocalFree(pItem);
break; } } }
BOOL MsgAddSessionInList( IN PLIST_ENTRY SessionIdList, ULONG SessionId ) { BOOL bRet; PMSG_SESSION_ID_ITEM pItem;
// allocate a new item
pItem = (PMSG_SESSION_ID_ITEM) LocalAlloc(LMEM_ZEROINIT,sizeof(MSG_SESSION_ID_ITEM));
if (pItem == NULL) // If this happens, we really have big problems...
{ MSG_LOG(ERROR,"MsgAddSessionInList: Unable to allocate memory\n",0); bRet = FALSE; } else // OK
{ bRet = TRUE;
// initialize the item
pItem->SessionId = SessionId;
// insert the item in the list
InsertTailList(SessionIdList, &pItem->List); } return bRet; }
|