1599 lines
45 KiB
C
1599 lines
45 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
msgapi.c
|
||
|
||
Abstract:
|
||
|
||
Provides API functions for the messaging system.
|
||
|
||
Author:
|
||
|
||
Dan Lafferty (danl) 23-Jul-1991
|
||
|
||
Environment:
|
||
|
||
User Mode -Win32
|
||
|
||
Notes:
|
||
|
||
optional-notes
|
||
|
||
Revision History:
|
||
|
||
02-Sep-1993 wlees
|
||
Provide synchronization between rpc routines and Pnp reconfiguration
|
||
|
||
13-Jan-1993 danl
|
||
NetrMessageNameGetInfo: Allocation size calculation was incorrectly
|
||
trying to take the sizeof((NCBNAMSZ+1)*sizeof(WCHAR)). NCBNAMSZ is
|
||
a #define constant value.
|
||
|
||
22-Jul-1991 danl
|
||
Ported from LM2.0
|
||
|
||
--*/
|
||
|
||
//
|
||
// Includes
|
||
//
|
||
|
||
#include "msrv.h"
|
||
|
||
#include <tstring.h> // Unicode string macros
|
||
#include <lmmsg.h>
|
||
|
||
#include <netlib.h> // UNUSED macro
|
||
#include <netlibnt.h> // NetpNtStatusToApiStatus
|
||
|
||
#include <msgrutil.h> // NetpNetBiosReset
|
||
#include <rpc.h>
|
||
#include <msgsvc.h> // MIDL generated header file
|
||
#include "msgdbg.h" // MSG_LOG
|
||
#include "heap.h"
|
||
#include "msgdata.h"
|
||
#include "apiutil.h"
|
||
#include "msgsec.h" // Messenger Security Information
|
||
|
||
#include "msgsvcsend.h" // Broadcast message send interface
|
||
// Static data descriptor strings for remoting the Message APIs
|
||
|
||
static char nulstr[] = "";
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
NetrMessageNameEnum(
|
||
IN LPWSTR ServerName,
|
||
IN OUT LPMSG_ENUM_STRUCT InfoStruct,
|
||
IN DWORD PrefMaxLen,
|
||
OUT LPDWORD TotalEntries,
|
||
IN OUT LPDWORD ResumeHandle OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function provides information about the message service name table
|
||
at two levels of detail.
|
||
|
||
Arguments:
|
||
|
||
ServerName - Pointer to a string containing the name of the computer
|
||
that is to execute the API function.
|
||
|
||
InfoStruct - Pointer to a structure that contains the information that
|
||
RPC needs about the returned data. This structure contains the
|
||
following information:
|
||
Level - The desired information level - indicates how to
|
||
interpret the structure of the returned buffer.
|
||
EntriesRead - Indicates how many elements are returned in the
|
||
array of structures that are returned.
|
||
BufferPointer - Location for the pointer to the array of
|
||
structures that are being returned.
|
||
|
||
PrefMaxLen - Indicates a maximum size limit that the caller will allow
|
||
for the return buffer.
|
||
|
||
TotalEntries - Pointer to a value that upon return indicates the total
|
||
number of entries in the "active" database.
|
||
|
||
ResumeHandle - Inidcates where in the linked list to start the
|
||
enumeration. This is an optional parameter and can be NULL.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - The operation was successful. EntriesRead is valid.
|
||
|
||
ERROR_INVALID_LEVEL - An invalid info level was passed in.
|
||
|
||
ERROR_MORE_DATA - Not all the information in the database could be
|
||
returned due to the limititation placed on buffer size by
|
||
PrefMaxLen. One or more information records will be found in
|
||
the buffer. EntriesRead is valid.
|
||
|
||
ERROR_SERVICE_NOT_ACTIVE - The service is stopping.
|
||
|
||
NERR_BufTooSmall - The limitation (PrefMaxLen) on buffer size didn't
|
||
allow any information to be returned. Not even a single record
|
||
could be fit in a buffer that small.
|
||
|
||
NERR_InternalError - A name in the name table could not be translated
|
||
from ansi characters to unicode characters. (Note: this
|
||
currently causes 0 entries to be returned.)
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD hResume = 0; // resume handle value
|
||
DWORD entriesRead = 0;
|
||
DWORD retBufSize;
|
||
LPBYTE infoBuf;
|
||
LPBYTE infoBufTemp;
|
||
LPBYTE stringBuf;
|
||
|
||
DWORD entry_length; // Length of one name entry in buf
|
||
DWORD i,j,k; // index for name loop and flags
|
||
NET_API_STATUS status=0;
|
||
DWORD neti; // net index
|
||
ULONG SessionId = 0; // client session Id
|
||
|
||
DWORD dwMsgrState = GetMsgrState();
|
||
|
||
UNUSED (ServerName);
|
||
|
||
if (dwMsgrState == STOPPING || dwMsgrState == STOPPED) {
|
||
return ERROR_SERVICE_NOT_ACTIVE;
|
||
}
|
||
|
||
//
|
||
// Synchronize with Pnp configuration routine
|
||
//
|
||
MsgConfigurationLock(MSG_GET_SHARED,"NetrMessageNameEnum");
|
||
|
||
//
|
||
// If ResumeHandle is present and valid, initialize it.
|
||
//
|
||
if (ARGUMENT_PRESENT(ResumeHandle) && (*ResumeHandle < NCBMAX(0))) {
|
||
hResume = *ResumeHandle;
|
||
}
|
||
|
||
//
|
||
// In Hydra case, the display thread never goes asleep.
|
||
//
|
||
if (!g_IsTerminalServer)
|
||
{
|
||
//
|
||
// Wakeup the display thread so that any queue'd messages can be
|
||
// displayed.
|
||
//
|
||
MsgDisplayThreadWakeup();
|
||
}
|
||
|
||
//
|
||
// Initialize some of the return counts.
|
||
//
|
||
|
||
*TotalEntries = 0;
|
||
|
||
//
|
||
// API security check. This call can be called by anyone locally,
|
||
// but only by admins in the remote case.
|
||
//
|
||
|
||
status = NetpAccessCheckAndAudit(
|
||
SERVICE_MESSENGER, // Subsystem Name
|
||
(LPWSTR)MESSAGE_NAME_OBJECT, // Object Type Name
|
||
MessageNameSd, // Security Descriptor
|
||
MSGR_MESSAGE_NAME_ENUM, // Desired Access
|
||
&MsgMessageNameMapping); // Generic Mapping
|
||
|
||
if (status != NERR_Success) {
|
||
MSG_LOG(TRACE,
|
||
"NetrMessageNameEnum:NetpAccessCheckAndAudit FAILED %X\n",
|
||
status);
|
||
status = ERROR_ACCESS_DENIED;
|
||
goto exit;
|
||
}
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
// get the client session id
|
||
status = MsgGetClientSessionId(&SessionId);
|
||
if (status != NERR_Success) {
|
||
MSG_LOG(TRACE,
|
||
"NetrMessageNameEnum:Could not get client session Id \n",0);
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Determine the size of one element in the returned array.
|
||
//
|
||
switch( InfoStruct->Level) {
|
||
case 0:
|
||
if (InfoStruct->MsgInfo.Level0 == NULL)
|
||
{
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto exit;
|
||
}
|
||
entry_length = sizeof(MSG_INFO_0);
|
||
break;
|
||
|
||
case 1:
|
||
if (InfoStruct->MsgInfo.Level0 == NULL)
|
||
{
|
||
status = ERROR_INVALID_PARAMETER;
|
||
goto exit;
|
||
}
|
||
entry_length = sizeof(MSG_INFO_1);
|
||
break;
|
||
|
||
default:
|
||
status = ERROR_INVALID_LEVEL;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Allocate enough space for return buffer
|
||
//
|
||
if (PrefMaxLen == -1) {
|
||
//
|
||
// If the caller has not specified a size, calculate a size
|
||
// that will hold the entire enumeration.
|
||
//
|
||
retBufSize =
|
||
((NCBMAX(0) * ((NCBNAMSZ+1) * sizeof(WCHAR))) + // max possible num strings
|
||
(NCBMAX(0) * entry_length)); // max possible num structs
|
||
}
|
||
else {
|
||
retBufSize = PrefMaxLen;
|
||
}
|
||
|
||
infoBuf = (LPBYTE)MIDL_user_allocate(retBufSize);
|
||
|
||
if (infoBuf == NULL) {
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
}
|
||
|
||
stringBuf = infoBuf + (retBufSize & ~1); // & ~1 to align Unicode strings
|
||
|
||
//
|
||
// Block until data free
|
||
//
|
||
MsgDatabaseLock(MSG_GET_EXCLUSIVE,"NetrMessageNameEnum");
|
||
|
||
//
|
||
// Now copy as many names from the shared data name table as will fit
|
||
// into the callers buffer. The shared data is locked so that the name
|
||
// table can not change while it is being copied (eg by someone
|
||
// deleting a forwarded name on this station after the check for a valid
|
||
// name has been made but before the name has been read). The level 1
|
||
// information is not copied in this loop as it requires network
|
||
// activity which must be avoided while the shared data is locked.
|
||
//
|
||
|
||
//
|
||
// HISTORY:
|
||
//
|
||
// The original LM2.0 code looked at the names on all nets, and
|
||
// threw away duplicate ones. This implies that a name may appear
|
||
// on one net and not on another. Although, this can never happen if
|
||
// the names are always added via NetMessageNameAdd since that API
|
||
// will not add the name unless it can be added to all nets. However,
|
||
// forwarded names are added via a network receive, and may be added
|
||
// from one net only.
|
||
//
|
||
// Since NT is not supporting forwarding, it is no longer necessary to
|
||
// check each net. Since the only way to add names if via NetServiceAdd,
|
||
// this will assure that the name listed for one network are the same
|
||
// as the names listed for the others.
|
||
//
|
||
|
||
infoBufTemp = infoBuf;
|
||
neti=j=0;
|
||
status = NERR_Success;
|
||
|
||
for(i=hResume; (i<NCBMAX(neti)) && (status==NERR_Success); ++i) {
|
||
|
||
if (!(SD_NAMEFLAGS(neti,i) & (NFDEL | NFDEL_PENDING))) {
|
||
//
|
||
// in HYDRA case, we also consider the SessionId
|
||
//
|
||
if ((g_IsTerminalServer) && (!(MsgIsSessionInList(&(SD_SIDLIST(neti,i)), SessionId )))) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// If a name is found we put it in the buffer if the
|
||
// following conditions are met. If we are processing
|
||
// the first net's names, put it in, it cannot be a
|
||
// duplicate. Otherwise, only put it in if it is not
|
||
// a duplicate of a name that is already in the user
|
||
// buffer.
|
||
// (NT_NOTE: duplicate names cannot occur).
|
||
//
|
||
|
||
//
|
||
// translate the name to unicode and put it into the buffer
|
||
//
|
||
status = MsgGatherInfo (
|
||
InfoStruct->Level,
|
||
SD_NAMES(neti,i),
|
||
&infoBufTemp,
|
||
&stringBuf);
|
||
|
||
if (status == NERR_Success) {
|
||
entriesRead++;
|
||
hResume++;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Calculate the total number of entries by seeing how many names are
|
||
// left in the table and adding that to the entries read.
|
||
//
|
||
if (status == ERROR_NOT_ENOUGH_MEMORY) {
|
||
|
||
status = ERROR_MORE_DATA;
|
||
|
||
for (k=0; i < NCBMAX(neti); i++) {
|
||
if(!(SD_NAMEFLAGS(neti,i) & (NFDEL | NFDEL_PENDING))) {
|
||
k++;
|
||
}
|
||
}
|
||
*TotalEntries = k;
|
||
}
|
||
*TotalEntries += entriesRead;
|
||
|
||
//
|
||
// Free up the shared data table
|
||
//
|
||
MsgDatabaseLock(MSG_RELEASE,"NetrMessageNameEnum");
|
||
|
||
//
|
||
// If some unexpected error occured, ( couldn't unformat the name
|
||
// - or a bogus info level was passed in), then return the error.
|
||
//
|
||
|
||
if ( ! ((status == NERR_Success) || (status == ERROR_MORE_DATA)) ) {
|
||
MIDL_user_free(infoBuf);
|
||
infoBuf = NULL;
|
||
entriesRead = 0;
|
||
hResume = 0;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// if there were no entries read then either there were no more
|
||
// entries in the table, or the resume number was bogus.
|
||
// In this case, we want to free the allocated buffer storage.
|
||
//
|
||
if (entriesRead == 0) {
|
||
MIDL_user_free(infoBuf);
|
||
infoBuf = NULL;
|
||
entriesRead = 0;
|
||
hResume = 0;
|
||
status = NERR_Success;
|
||
if (*TotalEntries > 0) {
|
||
status = NERR_BufTooSmall;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we have finished enumerating everything, reset the resume
|
||
// handle to start at the beginning next time.
|
||
//
|
||
if (entriesRead == *TotalEntries) {
|
||
hResume = 0;
|
||
}
|
||
|
||
//
|
||
// Load up the information to return
|
||
//
|
||
switch(InfoStruct->Level) {
|
||
case 0:
|
||
InfoStruct->MsgInfo.Level0->EntriesRead = entriesRead;
|
||
InfoStruct->MsgInfo.Level0->Buffer = (PMSG_INFO_0)infoBuf;
|
||
break;
|
||
|
||
case 1:
|
||
InfoStruct->MsgInfo.Level0->EntriesRead = entriesRead;
|
||
InfoStruct->MsgInfo.Level0->Buffer = (PMSG_INFO_0)infoBuf;
|
||
break;
|
||
|
||
default:
|
||
//
|
||
// This was checked above
|
||
//
|
||
ASSERT(FALSE);
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(ResumeHandle)) {
|
||
*ResumeHandle = hResume;
|
||
}
|
||
|
||
exit:
|
||
|
||
MsgConfigurationLock(MSG_RELEASE,"NetrMessageNameEnum");
|
||
|
||
return (status);
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
NetrMessageNameGetInfo(
|
||
IN LPWSTR ServerName, // unicode server name, NULL if local
|
||
IN LPWSTR Name, // Ptr to asciz name to query
|
||
IN DWORD Level, // Level of detail requested
|
||
OUT LPMSG_INFO InfoStruct // Ptr to buffer for info
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This funtion provides forwarding information about a known message server
|
||
name table entry. However, since we do not support forwarding in NT,
|
||
this API is totally useless. We'll support it anyway though for
|
||
compatibility purposes.
|
||
|
||
Arguments:
|
||
|
||
ServerName - Pointer to a string containing the name of the computer
|
||
that is to execute the API function.
|
||
|
||
Name - The Messaging name that we are to get info on.
|
||
|
||
Level - The level of information desired
|
||
|
||
InfoStruct - Pointer to a location where the pointer to the returned
|
||
information structure is to be placed.
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS status=NERR_Success;
|
||
LPMSG_INFO_0 infoBuf0;
|
||
LPMSG_INFO_1 infoBuf1;
|
||
CHAR formattedName[NCBNAMSZ];
|
||
ULONG SessionId = 0; // Client Session Id
|
||
|
||
DWORD dwMsgrState = GetMsgrState();
|
||
|
||
UNUSED (ServerName);
|
||
|
||
if (dwMsgrState == STOPPING || dwMsgrState == STOPPED)
|
||
{
|
||
return ERROR_SERVICE_NOT_ACTIVE;
|
||
}
|
||
|
||
if (MsgIsValidMsgName(Name) != 0)
|
||
{
|
||
return ERROR_INVALID_NAME;
|
||
}
|
||
|
||
//
|
||
// Synchronize with Pnp configuration routine
|
||
//
|
||
MsgConfigurationLock(MSG_GET_SHARED,"NetrMessageNameGetInfo");
|
||
|
||
//
|
||
// In Hydra case, the display thread never goes asleep.
|
||
//
|
||
if (!g_IsTerminalServer)
|
||
{
|
||
//
|
||
// Wakeup the display thread so that any queue'd messages can be
|
||
// displayed.
|
||
//
|
||
MsgDisplayThreadWakeup();
|
||
}
|
||
|
||
//
|
||
// API security check. This call can be called by anyone locally,
|
||
// but only by admins in the remote case.
|
||
//
|
||
|
||
status = NetpAccessCheckAndAudit(
|
||
SERVICE_MESSENGER, // Subsystem Name
|
||
(LPWSTR)MESSAGE_NAME_OBJECT, // Object Type Name
|
||
MessageNameSd, // Security Descriptor
|
||
MSGR_MESSAGE_NAME_INFO_GET, // Desired Access
|
||
&MsgMessageNameMapping); // Generic Mapping
|
||
|
||
if (status != NERR_Success) {
|
||
MSG_LOG(TRACE,
|
||
"NetrMessageNameGetInfo:NetpAccessCheckAndAudit FAILED %X\n",
|
||
status);
|
||
status = ERROR_ACCESS_DENIED;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Format the name so it matches what is stored in the name table.
|
||
//
|
||
status = MsgFmtNcbName(formattedName, Name, NAME_LOCAL_END);
|
||
if (status != NERR_Success) {
|
||
MSG_LOG(ERROR,"NetrMessageGetInfo: could not format name\n",0);
|
||
status = NERR_NotLocalName;
|
||
goto exit;
|
||
}
|
||
|
||
|
||
status = NERR_Success;
|
||
|
||
//
|
||
// Look for the name in the shared data name array. (1st net only).
|
||
//
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
// get the client session id
|
||
status = MsgGetClientSessionId(&SessionId);
|
||
if (status != NERR_Success) {
|
||
MSG_LOG(ERROR,"NetrMessageGetInfo: could not get session id\n",0);
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
// look for the name in the database
|
||
if (MsgLookupNameForThisSession(0, formattedName, SessionId) == -1) {
|
||
MSG_LOG(ERROR,"NetrMessageGetInfo: Name not in table\n",0);
|
||
status = NERR_NotLocalName;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Allocate storage for the returned buffer, and fill it in.
|
||
//
|
||
|
||
switch(Level) {
|
||
case 0:
|
||
infoBuf0 = (LPMSG_INFO_0)MIDL_user_allocate(
|
||
sizeof(MSG_INFO_0) + ((NCBNAMSZ+1)*sizeof(WCHAR)));
|
||
if (infoBuf0 == NULL) {
|
||
MSG_LOG(ERROR,
|
||
"NetrMessageNameGetInfo MIDL allocate FAILED %X\n",
|
||
GetLastError());
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// copy the name and set the pointer in the structure to point
|
||
// to it.
|
||
//
|
||
STRCPY((LPWSTR)(infoBuf0 + 1), Name);
|
||
infoBuf0->msgi0_name = (LPWSTR)(infoBuf0 + 1);
|
||
(*InfoStruct).MsgInfo0 = infoBuf0;
|
||
|
||
break;
|
||
|
||
case 1:
|
||
infoBuf1 = (LPMSG_INFO_1)MIDL_user_allocate(
|
||
sizeof(MSG_INFO_1) + ((NCBNAMSZ+1)*sizeof(WCHAR)) );
|
||
|
||
if (infoBuf1 == NULL) {
|
||
MSG_LOG(ERROR,
|
||
"NetrMessageNameGetInfo MIDL allocate FAILED %X\n",
|
||
GetLastError());
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Copy the name, update pointers, and set forward info fields.
|
||
//
|
||
STRCPY((LPWSTR)(infoBuf1 + 1), Name);
|
||
|
||
infoBuf1->msgi1_name = (LPWSTR)(infoBuf1 + 1);
|
||
infoBuf1->msgi1_forward_flag = 0;
|
||
infoBuf1->msgi1_forward = NULL;
|
||
|
||
(*InfoStruct).MsgInfo1 = infoBuf1;
|
||
break;
|
||
|
||
default:
|
||
status = ERROR_INVALID_LEVEL;
|
||
goto exit;
|
||
}
|
||
|
||
status = NERR_Success;
|
||
|
||
exit:
|
||
MsgConfigurationLock(MSG_RELEASE,"NetrMessageNameGetInfo");
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NET_API_STATUS
|
||
NetrMessageNameAdd(
|
||
LPWSTR ServerName, // NULL = local
|
||
LPWSTR Name // Pointer to name to add.
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function performs a security check for all calls to this
|
||
RPC interface. Then it adds a new name to the Message
|
||
Server's name table by calling the MsgAddName function.
|
||
|
||
Arguments:
|
||
|
||
ServerName - Pointer to a string containing the name of the computer
|
||
that is to execute the API function.
|
||
|
||
Name - A pointer to the name to be added.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - The operation was successful.
|
||
|
||
ERROR_ACCESS_DENIED - If the Security Check Failed.
|
||
|
||
ERROR_SERVICE_NOT_ACTIVE - The service is stopping
|
||
|
||
Assorted Error codes from MsgAddName.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS status=0;
|
||
ULONG SessionId = 0;
|
||
|
||
DWORD dwMsgrState = GetMsgrState();
|
||
|
||
UNUSED (ServerName);
|
||
|
||
if (dwMsgrState == STOPPING || dwMsgrState == STOPPED) {
|
||
return ERROR_SERVICE_NOT_ACTIVE;
|
||
}
|
||
|
||
//
|
||
// Synchronize with Pnp configuration routine
|
||
//
|
||
MsgConfigurationLock(MSG_GET_SHARED,"NetrMessageNameAdd");
|
||
|
||
//
|
||
// API security check. This call can be called by anyone locally,
|
||
// but only by admins in the remote case.
|
||
//
|
||
|
||
status = NetpAccessCheckAndAudit(
|
||
SERVICE_MESSENGER, // Subsystem Name
|
||
(LPWSTR)MESSAGE_NAME_OBJECT, // Object Type Name
|
||
MessageNameSd, // Security Descriptor
|
||
MSGR_MESSAGE_NAME_ADD, // Desired Access
|
||
&MsgMessageNameMapping); // Generic Mapping
|
||
|
||
if (status != NERR_Success) {
|
||
MSG_LOG(TRACE,
|
||
"NetrMessageNameAdd:NetpAccessCheckAndAudit FAILED %X\n",
|
||
status);
|
||
status = ERROR_ACCESS_DENIED;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// In Hydra case, the display thread never goes asleep.
|
||
//
|
||
if (!g_IsTerminalServer)
|
||
{
|
||
//
|
||
// Since a new user may have just logged on, we want to check to see if
|
||
// there are any messages to be displayd.
|
||
//
|
||
MsgDisplayThreadWakeup();
|
||
|
||
}
|
||
else
|
||
{
|
||
// get the client session id
|
||
status = MsgGetClientSessionId(&SessionId);
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR, "NetrMessageNameAdd: could not get client session id\n",0);
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Call the function that actually adds the name.
|
||
//
|
||
MSG_LOG(TRACE, "NetrMessageNameAdd: call MsgAddName for Session %x\n",SessionId);
|
||
|
||
status = MsgAddName(Name, SessionId);
|
||
|
||
exit:
|
||
MsgConfigurationLock(MSG_RELEASE,"NetrMessageNameAdd");
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
MsgAddName(
|
||
LPWSTR Name,
|
||
ULONG SessionId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function adds a new name to the Message Server's name table.
|
||
It is available to be called internally (from within the Messenger
|
||
service).
|
||
|
||
The task of adding a new name to the Message Server's name table consists
|
||
of verifying that a session can be established for a new name (Note: this
|
||
check is subject to failure in a multiprocessing environment, since the
|
||
state of the adapter may change between the time of the check and the time
|
||
of the attempt to establish a session), verifying that the name does not
|
||
already exist in the local name table, adding the name to the local adapter
|
||
via an ADD NAME net bios call, adding the name to the Message Server's name
|
||
table and marking it as new, waking up the Message Server using the wakeup
|
||
semaphore, and checking to see if messages for the new name have been
|
||
forwarded (if they have been forwarded, the value of the fwd_action
|
||
flag is used to determine the action to be taken).
|
||
|
||
|
||
SIDE EFFECTS
|
||
|
||
Calls the net bios. May modify the Message Server's shared data area.
|
||
May call DosSemClear() on the wakeup semaphore.
|
||
|
||
Arguments:
|
||
|
||
Name - A pointer to the name to be added.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - The operation was successful.
|
||
|
||
assorted errors.
|
||
|
||
--*/
|
||
{
|
||
NCB ncb; // Network control block
|
||
TCHAR namebuf[NCBNAMSZ+2]; // General purpose name buffer
|
||
UCHAR net_err=0; // Storage for net error codes
|
||
NET_API_STATUS err_code=0; // Storage for return error codes
|
||
DWORD neti,i,name_i; // Index
|
||
NET_API_STATUS status=0;
|
||
|
||
if (MsgIsValidMsgName(Name) != 0)
|
||
{
|
||
return ERROR_INVALID_NAME;
|
||
}
|
||
|
||
MSG_LOG(TRACE,"Attempting to add the following name: %ws\n",Name);
|
||
|
||
STRNCPY( namebuf, Name, NCBNAMSZ+1);
|
||
namebuf[NCBNAMSZ+1] = '\0';
|
||
|
||
//
|
||
// Initialize the NCB
|
||
//
|
||
clearncb(&ncb);
|
||
|
||
//
|
||
// Format the name for NetBios.
|
||
// This converts the Unicode string to ansi.
|
||
//
|
||
status = MsgFmtNcbName(ncb.ncb_name, namebuf, NAME_LOCAL_END);
|
||
|
||
if (status != NERR_Success) {
|
||
MSG_LOG(ERROR,"MsgAddName: could not format name\n",0);
|
||
return (ERROR_INVALID_NAME);
|
||
}
|
||
|
||
//
|
||
// Check if the local name already exists on any netcard
|
||
// in this machine. This check does not mean the name dosn't
|
||
// exist on some other machine on the network(s).
|
||
//
|
||
|
||
for ( neti = 0; neti < SD_NUMNETS(); neti++ ) {
|
||
|
||
//
|
||
// Gain access to the shared database.
|
||
//
|
||
MsgDatabaseLock(MSG_GET_EXCLUSIVE,"MsgAddName");
|
||
|
||
for( i = 0, err_code = 0; i < 10; i++) {
|
||
|
||
// check if this alias is not already existing for this session
|
||
name_i = MsgLookupNameForThisSession(neti, ncb.ncb_name, SessionId);
|
||
|
||
if ((name_i) == -1) {
|
||
break;
|
||
}
|
||
|
||
if( (SD_NAMEFLAGS(neti,name_i) & NFDEL_PENDING) && (i < 9)) {
|
||
|
||
//
|
||
// Delete is pending so wait for it
|
||
//
|
||
Sleep(500L);
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Setup error code
|
||
//
|
||
err_code = NERR_AlreadyExists;
|
||
break;
|
||
}
|
||
}
|
||
|
||
MsgDatabaseLock(MSG_RELEASE,"MsgAddName");
|
||
|
||
if ( err_code == NERR_AlreadyExists ) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( err_code == 0)
|
||
{
|
||
//
|
||
// Either the name was not forwarded or the fwd_action flag
|
||
// was set so go ahead and try to add the name to each net.
|
||
//
|
||
|
||
ncb.ncb_name[NCBNAMSZ - 1] = NAME_LOCAL_END;
|
||
|
||
//
|
||
// on each network
|
||
//
|
||
for ( neti = 0; neti < SD_NUMNETS(); neti++ ) {
|
||
|
||
//
|
||
// Gain access to the shared database.
|
||
//
|
||
MsgDatabaseLock(MSG_GET_EXCLUSIVE,"MsgAddName");
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
// before looking for an empty slot,
|
||
// check if this alias does not already exist for another session
|
||
for( i = 0; i < 10; i++)
|
||
{
|
||
name_i = MsgLookupName(neti, ncb.ncb_name);
|
||
|
||
if ((name_i != -1) && (SD_NAMEFLAGS(neti, name_i) & NFDEL_PENDING))
|
||
{
|
||
//
|
||
// Delete is pending so wait for it
|
||
//
|
||
Sleep(500L);
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (name_i != -1)
|
||
{
|
||
if (SD_NAMEFLAGS(neti, name_i) & NFDEL_PENDING) // still there ?
|
||
{
|
||
err_code = NERR_InternalError; // what else can we do ?
|
||
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
|
||
break;
|
||
}
|
||
|
||
// this alias already exists for another session, so just add the session id in the list
|
||
MSG_LOG(TRACE,"MsgAddName: Alias already existing. Just adding Session %x \n", SessionId);
|
||
|
||
MsgAddSessionInList(&(SD_SIDLIST(neti, name_i)), SessionId); //There is not much we can do if this call fails
|
||
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
|
||
continue;
|
||
}
|
||
}
|
||
|
||
for(i = 0; i < NCBMAX(neti); ++i)
|
||
{
|
||
//
|
||
// Loop to find empty slot
|
||
//
|
||
if (SD_NAMEFLAGS(neti,i) & NFDEL)
|
||
{
|
||
//
|
||
// If empty slot found, Lock slot in table and
|
||
// end the search
|
||
//
|
||
SD_NAMEFLAGS(neti,i) = NFLOCK;
|
||
MSG_LOG2(TRACE,"MsgAddName: Lock slot %d in table "
|
||
"for net %d\n",i,neti);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ((i == NCBMAX(neti)) && (i < NCB_MAX_ENTRIES))
|
||
{
|
||
// We can add another NCB - must hold the lock.
|
||
PNCB_DATA pNcbDataNew;
|
||
PNET_DATA pNetData = GETNETDATA(neti);
|
||
|
||
if (pNcbDataNew = (PNCB_DATA) LocalAlloc(LMEM_ZEROINIT,
|
||
sizeof(NCB_DATA)))
|
||
{
|
||
// Initialize and lock the NCB
|
||
pNcbDataNew->Ncb.ncb_cmd_cplt = 0xff;
|
||
pNcbDataNew->NameFlags = NFLOCK;
|
||
// Add the new NCB to the list
|
||
pNetData->NcbList[i] = pNcbDataNew;
|
||
//
|
||
//create an empty session list
|
||
//
|
||
InitializeListHead(&(SD_SIDLIST(neti,i)));
|
||
pNetData->NumNcbs++; // This must be done last
|
||
}
|
||
else
|
||
{
|
||
err_code = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Unlock the shared database
|
||
//
|
||
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
|
||
|
||
if( i >= NCBMAX(neti))
|
||
{
|
||
//
|
||
// If no room in name table
|
||
//
|
||
err_code = NERR_TooManyNames;
|
||
}
|
||
else if (err_code == NERR_Success)
|
||
{
|
||
//
|
||
// Send ADDNAME
|
||
//
|
||
ncb.ncb_command = NCBADDNAME; // Add name (wait)
|
||
ncb.ncb_lana_num = GETNETLANANUM(neti);
|
||
|
||
MSG_LOG1(TRACE,"MsgNameAdd: Calling sendncb for lana #%d...\n",
|
||
GETNETLANANUM(neti));
|
||
|
||
if ((net_err = Msgsendncb(&ncb,neti)) == 0)
|
||
{
|
||
MSG_LOG(TRACE,"MsgAddName: sendncb returned SUCCESS\n",0);
|
||
//
|
||
// successful add - Get the Lock.
|
||
//
|
||
MsgDatabaseLock(MSG_GET_EXCLUSIVE,"MsgAddName");
|
||
//
|
||
// Copy the name to shared memory
|
||
//
|
||
MSG_LOG3(TRACE,"MsgAddName: copy name (%s)\n\tto "
|
||
"shared data table (net,loc)(%d,%d)\n",
|
||
ncb.ncb_name, neti, i);
|
||
memcpy(SD_NAMES(neti,i),ncb.ncb_name, NCBNAMSZ);
|
||
//
|
||
// Set the name no.
|
||
//
|
||
SD_NAMENUMS(neti,i) = ncb.ncb_num ;
|
||
//
|
||
// Set new name flag
|
||
//
|
||
SD_NAMEFLAGS(neti,i) = NFNEW;
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
// Add the session id in the list
|
||
MSG_LOG(TRACE,"MsgAddName: Alias created for Session %x \n", SessionId);
|
||
MsgAddSessionInList(&(SD_SIDLIST(neti, i)), SessionId);
|
||
// If this fails due to low memory, we would find the name in the list and messages will
|
||
// not get deliviered. Doesn't cause any crashes. This is the best we can do
|
||
}
|
||
//
|
||
// Unlock share table
|
||
//
|
||
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
|
||
|
||
//
|
||
// START A SESSION for this name.
|
||
//
|
||
|
||
err_code = MsgNewName(neti,i);
|
||
|
||
if (err_code != NERR_Success) {
|
||
MSG_LOG(TRACE, "MsgAddName: A Session couldn't be "
|
||
"created for this name %d\n",err_code);
|
||
|
||
|
||
MSG_LOG(TRACE,"MsgAddName: Delete the name "
|
||
"that failed (%s)\n",ncb.ncb_name)
|
||
ncb.ncb_command = NCBDELNAME;
|
||
|
||
ncb.ncb_lana_num = GETNETLANANUM(i);
|
||
net_err = Msgsendncb( &ncb, i);
|
||
if (net_err != 0) {
|
||
MSG_LOG(ERROR,"MsgAddName: Delete name "
|
||
"failed %d - pretend it's deleted anyway\n",net_err);
|
||
}
|
||
|
||
//
|
||
// Re-mark slot empty
|
||
//
|
||
SD_NAMEFLAGS(neti,i) = NFDEL;
|
||
|
||
MSG_LOG2(TRACE,"MsgAddName: UnLock slot %d in table "
|
||
"for net %d\n",i,neti);
|
||
MSG_LOG(TRACE,"MsgAddName: Name Deleted\n",0)
|
||
}
|
||
else {
|
||
//
|
||
//
|
||
// Wakeup the worker thread for that network.
|
||
//
|
||
|
||
SetEvent(wakeupSem[neti]);
|
||
|
||
}
|
||
|
||
}
|
||
else {
|
||
//
|
||
// else set error code
|
||
//
|
||
MSG_LOG(TRACE,
|
||
"MsgAddName: sendncb returned FAILURE 0x%x\n",
|
||
net_err);
|
||
err_code = MsgMapNetError(net_err);
|
||
//
|
||
// Re-mark slot empty
|
||
//
|
||
SD_NAMEFLAGS(neti,i) = NFDEL;
|
||
MSG_LOG2(TRACE,"MsgAddName: UnLock slot %d in table "
|
||
"for net %d\n",i,neti);
|
||
}
|
||
}
|
||
|
||
if ( err_code != NERR_Success )
|
||
{
|
||
//
|
||
//Try to delete the add names that were successful
|
||
//
|
||
|
||
for ( i = 0; i < neti; i++ )
|
||
{
|
||
MsgDatabaseLock(MSG_GET_EXCLUSIVE,"MsgAddName");
|
||
|
||
// try to delete only the alias for this session
|
||
name_i = MsgLookupNameForThisSession(i,
|
||
(char far *)(ncb.ncb_name),
|
||
SessionId);
|
||
|
||
if (name_i == -1)
|
||
{
|
||
err_code = NERR_InternalError;
|
||
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
|
||
break;
|
||
}
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
// in any case remove the reference to the session
|
||
MSG_LOG(TRACE,"MsgAddName: Removing Session %x from list\n", SessionId);
|
||
MsgRemoveSessionFromList(&(SD_SIDLIST(i, name_i)), SessionId);
|
||
}
|
||
|
||
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
|
||
|
||
// if it was the last session using this alias then delete the alias
|
||
if ((!g_IsTerminalServer) || (IsListEmpty(&(SD_SIDLIST(i, name_i)))))
|
||
{
|
||
MSG_LOG(TRACE,"MsgAddName: Session list empty. Deleting the alias \n", 0);
|
||
//
|
||
// Delete name from card.
|
||
// If this call fails, we can't do much about it.
|
||
//
|
||
MSG_LOG1(TRACE,"MsgAddName: Delete the name that failed "
|
||
"for lana #%d\n",GETNETLANANUM(i))
|
||
ncb.ncb_command = NCBDELNAME;
|
||
|
||
ncb.ncb_lana_num = GETNETLANANUM(i);
|
||
Msgsendncb( &ncb, i);
|
||
|
||
//
|
||
// Re-mark slot empty
|
||
//
|
||
SD_NAMEFLAGS(i,name_i) = NFDEL;
|
||
MSG_LOG2(TRACE,"MsgAddName: UnLock slot %d in table "
|
||
"for net %d\n",i,neti);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If an add was unsuccessful, stop the loop
|
||
//
|
||
break;
|
||
|
||
} // end else (err_code != NERR_Success)
|
||
} // end add names to net loop
|
||
} // end if ( !err_cd )
|
||
|
||
MSG_LOG(TRACE,"MsgAddName: exit with err_code = %x\n",err_code);
|
||
|
||
return(err_code);
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
NetrMessageNameDel(
|
||
IN LPWSTR ServerName, // Blank = local, else remote.
|
||
IN LPWSTR Name // Pointer to name to be deleted
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function deletes a name from the Message Server's name table.
|
||
|
||
This function is called to delete a name that has been added by the
|
||
user or by a remote computer via a Start Forwarding request to the
|
||
Message Server. The user has no way of specifying whether the given
|
||
name is an additional name or a forwarded name, but since forwarding
|
||
of messages to one's own computer is prohibited, both forms of the
|
||
name cannot exist on one machine (unless the message system has been
|
||
circumvented--a simple enough thing to do). The given name is looked
|
||
up in the shared data area, and, if it is found, a DELETE NAME net bios
|
||
call is issued. If this call is successful, then the Message Server
|
||
will remove the name from its name table in shared memory, so this
|
||
function does not have to do so.
|
||
|
||
SIDE EFFECTS
|
||
|
||
Calls the net bios. Accesses the shared data area.
|
||
|
||
|
||
Arguments:
|
||
|
||
ServerName - Pointer to a string containing the name of the computer
|
||
that is to execute the API function.
|
||
|
||
Name - A pointer to the name to be deleted.
|
||
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - The operation was successful.
|
||
|
||
ERROR_SERVICE_NOT_ACTIVE - The service is stopping.
|
||
|
||
--*/
|
||
|
||
{
|
||
NCB ncb; // Network control block
|
||
DWORD flags; // Name flags
|
||
DWORD i; // Index into name table
|
||
DWORD neti; // Network Index
|
||
|
||
NET_API_STATUS end_result;
|
||
DWORD name_len;
|
||
UCHAR net_err;
|
||
ULONG SessionId = 0; // Client Session Id
|
||
|
||
DWORD dwMsgrState = GetMsgrState();
|
||
|
||
UNUSED (ServerName);
|
||
|
||
if (dwMsgrState == STOPPING || dwMsgrState == STOPPED)
|
||
{
|
||
return ERROR_SERVICE_NOT_ACTIVE;
|
||
}
|
||
|
||
if (MsgIsValidMsgName(Name) != 0)
|
||
{
|
||
return ERROR_INVALID_NAME;
|
||
}
|
||
|
||
//
|
||
// Synchronize with Pnp configuration routine
|
||
//
|
||
MsgConfigurationLock(MSG_GET_SHARED,"NetrMessageNameDel");
|
||
|
||
//
|
||
// In Hydra case, the display thread never goes asleep.
|
||
//
|
||
if (!g_IsTerminalServer)
|
||
{
|
||
//
|
||
// Wakeup the display thread so that any queue'd messages can be
|
||
// displayed.
|
||
//
|
||
MsgDisplayThreadWakeup();
|
||
|
||
}
|
||
|
||
//
|
||
// API security check. This call can be called by anyone locally,
|
||
// but only by admins in the remote case.
|
||
//
|
||
|
||
end_result = NetpAccessCheckAndAudit(
|
||
SERVICE_MESSENGER, // Subsystem Name
|
||
(LPWSTR) MESSAGE_NAME_OBJECT, // Object Type Name
|
||
MessageNameSd, // Security Descriptor
|
||
MSGR_MESSAGE_NAME_DEL, // Desired Access
|
||
&MsgMessageNameMapping); // Generic Mapping
|
||
|
||
if (end_result != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR,
|
||
"NetrMessageNameDel:NetpAccessCheckAndAudit FAILED %d\n",
|
||
end_result);
|
||
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Initialize the NCB
|
||
//
|
||
clearncb(&ncb);
|
||
|
||
//
|
||
// Format the username (this makes it non-unicode);
|
||
//
|
||
end_result = MsgFmtNcbName(ncb.ncb_name, Name, NAME_LOCAL_END);
|
||
|
||
if (end_result != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR,
|
||
"NetrMessageNameDel: could not format name %d\n",
|
||
end_result);
|
||
|
||
goto exit;
|
||
}
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
end_result = MsgGetClientSessionId(&SessionId);
|
||
|
||
if (end_result != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR,
|
||
"NetrMessageNameDel: could not get session id %d\n",
|
||
end_result);
|
||
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
end_result = NERR_Success;
|
||
|
||
//
|
||
// for all nets
|
||
//
|
||
for ( neti = 0; neti < SD_NUMNETS(); neti++ ) {
|
||
|
||
//
|
||
// Block until data free
|
||
//
|
||
MsgDatabaseLock(MSG_GET_EXCLUSIVE,"NetrMessageNameDel");
|
||
|
||
name_len = STRLEN(Name);
|
||
|
||
if((name_len > NCBNAMSZ)
|
||
||
|
||
((i = MsgLookupNameForThisSession( neti, ncb.ncb_name, SessionId))) == -1)
|
||
{
|
||
MSG_LOG(TRACE,"NetrMessageNameDel: Alias not found for Session %x \n", SessionId);
|
||
|
||
//
|
||
// No such name to delete - exit
|
||
//
|
||
MsgDatabaseLock(MSG_RELEASE, "NetrMessageNameDel");
|
||
end_result = NERR_NotLocalName;
|
||
goto exit;
|
||
}
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
// remove the session id from the list
|
||
MSG_LOG(TRACE,"NetrMessageNameDel: Removing Session %x from list\n", SessionId);
|
||
MsgRemoveSessionFromList(&(SD_SIDLIST(neti,i)), SessionId);
|
||
}
|
||
|
||
//
|
||
// in Hydra case, if it is not the last session using this alias, do not delete the alias
|
||
//
|
||
if ((g_IsTerminalServer) && (!IsListEmpty(&(SD_SIDLIST(neti,i)))))
|
||
{
|
||
MSG_LOG(TRACE,"NetrMessageNameDel: Session list is not empty. Do not delete the alias\n", 0);
|
||
MsgDatabaseLock(MSG_RELEASE, "NetrMessageNameDel");
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
MSG_LOG(TRACE,"NetrMessageNameDel: Session list is empty. Deleting the alias\n", 0);
|
||
}
|
||
|
||
flags = SD_NAMEFLAGS(neti,i);
|
||
|
||
if(!(flags & (NFMACHNAME | NFLOCK))
|
||
&&
|
||
!(flags & NFFOR))
|
||
{
|
||
//
|
||
// Show delete pending
|
||
//
|
||
SD_NAMEFLAGS(neti,i) |= NFDEL_PENDING;
|
||
}
|
||
|
||
MsgDatabaseLock(MSG_RELEASE, "NetrMessageNameDel");
|
||
|
||
if (flags & NFMACHNAME)
|
||
{
|
||
//
|
||
// If name is computer name
|
||
//
|
||
end_result = NERR_DelComputerName;
|
||
goto exit;
|
||
}
|
||
|
||
if(flags & NFLOCK)
|
||
{
|
||
//
|
||
// If name is locked
|
||
//
|
||
end_result = NERR_NameInUse;
|
||
MSG_LOG(TRACE,"NetrMessageNameDel: Deleting a locked name is forbidden\n", 0);
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Delete the Name
|
||
//
|
||
|
||
ncb.ncb_command = NCBDELNAME; // Delete name (wait)
|
||
ncb.ncb_lana_num = GETNETLANANUM(neti);
|
||
|
||
if( (net_err = Msgsendncb( &ncb, neti)) != 0 )
|
||
{
|
||
MSG_LOG(ERROR,"NetrMessageNameDel:send NCBDELNAME failed 0x%x\n",
|
||
net_err);
|
||
//
|
||
// The name that has been marked as delete pending was not
|
||
// successfully deleted so now go through all the work of
|
||
// finding the name again (cannot even use the same index
|
||
// in case deleted by another process) and remove the
|
||
// Del pending flag
|
||
//
|
||
|
||
//
|
||
// Attempt to block until data free but don't stop
|
||
// the recovery if can not block the data
|
||
//
|
||
|
||
MsgDatabaseLock(MSG_GET_EXCLUSIVE,"NetrMessageNameDel");
|
||
|
||
i = MsgLookupName(neti,ncb.ncb_name);
|
||
|
||
if(i != -1)
|
||
{
|
||
SD_NAMEFLAGS(neti,i) &= ~NFDEL_PENDING;
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
MSG_LOG(TRACE,"NetrMessageNameDel: Unable to delete alias. Re-adding Session %x \n", SessionId);
|
||
|
||
// re-insert the session id in the list
|
||
MsgAddSessionInList(&(SD_SIDLIST(neti,i)), SessionId);
|
||
}
|
||
|
||
end_result = NERR_IncompleteDel; // Unable to delete name
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Another thread deleted this name while we were executing
|
||
// above, so this name no longer exists.
|
||
//
|
||
end_result = NERR_NotLocalName;
|
||
}
|
||
|
||
MsgDatabaseLock(MSG_RELEASE, "NetrMessageNameDel");
|
||
}
|
||
|
||
} // End for all nets
|
||
|
||
exit:
|
||
|
||
MsgConfigurationLock(MSG_RELEASE,"NetrMessageNameDel");
|
||
|
||
return(end_result);
|
||
}
|
||
|
||
|
||
DWORD
|
||
NetrSendMessage(
|
||
RPC_BINDING_HANDLE hRpcBinding,
|
||
LPSTR From,
|
||
LPSTR To,
|
||
LPSTR Text
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the RPC handler for the SendMessage RPC. It takes the arguments, transforms them, and
|
||
passes them to Msglogsbm for display.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD length;
|
||
PCHAR newText;
|
||
DWORD dwMsgrState = GetMsgrState();
|
||
|
||
UNUSED(hRpcBinding);
|
||
|
||
if (dwMsgrState == STOPPING || dwMsgrState == STOPPED) {
|
||
return ERROR_SERVICE_NOT_ACTIVE;
|
||
}
|
||
|
||
MSG_LOG3(TRACE,
|
||
"NetrSendMessage, From '%s' To '%s' Text '%s'\n",
|
||
From, To, Text);
|
||
|
||
// Msglogsbm takes a wierd counted string argument with a short of length in the front.
|
||
// Whip one up
|
||
|
||
length = strlen( Text );
|
||
|
||
newText = LocalAlloc( LMEM_FIXED, length + 3 ); // newText should be aligned
|
||
|
||
if (newText == NULL)
|
||
{
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
*((PUSHORT) newText) = (USHORT) length;
|
||
|
||
strcpy( newText + 2, Text );
|
||
|
||
// Display the message
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
Msglogsbm( From, To, newText, (ULONG)EVERYBODY_SESSION_ID );
|
||
}
|
||
else
|
||
{
|
||
Msglogsbm (From, To, newText, 0);
|
||
}
|
||
|
||
LocalFree( newText );
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
MsgGetClientSessionId(
|
||
OUT PULONG pSessionId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function gets the session id of the client thread.
|
||
|
||
Note: it should be called only on HYDRA context, never in regular NT
|
||
|
||
Arguments:
|
||
|
||
pSessionId -
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NERR_Success or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS status;
|
||
NTSTATUS ntstatus;
|
||
HANDLE CurrentThreadToken;
|
||
ULONG SessionId;
|
||
ULONG ReturnLength;
|
||
|
||
ntstatus = RpcImpersonateClient(NULL);
|
||
|
||
if (ntstatus != RPC_S_OK)
|
||
{
|
||
MSG_LOG1(ERROR,
|
||
"MsgGetClientSessionId: RpcImpersonateClient FAILED %#x\n",
|
||
ntstatus);
|
||
|
||
return NetpNtStatusToApiStatus(ntstatus);
|
||
}
|
||
|
||
ntstatus = NtOpenThreadToken(
|
||
NtCurrentThread(),
|
||
TOKEN_QUERY,
|
||
TRUE, // Use messenger service's security context to open thread token
|
||
&CurrentThreadToken
|
||
);
|
||
|
||
if (! NT_SUCCESS(ntstatus)) // error
|
||
{
|
||
MSG_LOG(ERROR,"MsgGetClientSessionId : Cannot open the current thread token %08lx\n", ntstatus);
|
||
}
|
||
else // OK
|
||
{
|
||
//
|
||
// Get the session id of the client thread
|
||
//
|
||
|
||
ntstatus = NtQueryInformationToken(
|
||
CurrentThreadToken,
|
||
TokenSessionId,
|
||
&SessionId,
|
||
sizeof(ULONG),
|
||
&ReturnLength);
|
||
|
||
if (! NT_SUCCESS(ntstatus)) // Error
|
||
{
|
||
MSG_LOG(ERROR,
|
||
"MsgGetClientSessionId: Cannot query current thread's token %08lx\n",
|
||
ntstatus);
|
||
|
||
NtClose(CurrentThreadToken);
|
||
}
|
||
else // OK
|
||
{
|
||
NtClose(CurrentThreadToken);
|
||
*pSessionId = SessionId;
|
||
}
|
||
}
|
||
|
||
RpcRevertToSelf();
|
||
|
||
status = NetpNtStatusToApiStatus(ntstatus);
|
||
|
||
//
|
||
// temporary security to avoid any problem:
|
||
// if we cannot get the session id,
|
||
// assume it is for the console.
|
||
//
|
||
if (status != NERR_Success)
|
||
{
|
||
*pSessionId = 0;
|
||
status = NERR_Success;
|
||
}
|
||
|
||
return status;
|
||
}
|