Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1103 lines
32 KiB

/*++
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:
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 <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 <winbasep.h> // BUGBUG (where is this really - currently win/inc)
#include <timelib.h> // NetpGetTimeFormat
// 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.
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
UNUSED (ServerName);
//
// If ResumeHandle is present and valid, initialize it.
//
if (ARGUMENT_PRESENT(ResumeHandle) && (*ResumeHandle < NCBMAX)) {
hResume = *ResumeHandle;
}
//
// 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);
return(ERROR_ACCESS_DENIED);
}
//
// Determine the size of one element in the returned array.
//
switch( InfoStruct->Level) {
case 0:
entry_length = sizeof(MSG_INFO_0);
break;
case 1:
entry_length = sizeof(MSG_INFO_1);
break;
default:
return(ERROR_INVALID_LEVEL);
}
//
// 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 * ((NCBNAMSZ+1) * sizeof(WCHAR))) + // max possible num strings
(NCBMAX * entry_length)); // max possible num structs
}
else {
retBufSize = PrefMaxLen;
}
infoBuf = (LPBYTE)MIDL_user_allocate(retBufSize);
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) && (status==NERR_Success); ++i) {
if(!(SD_NAMEFLAGS(neti,i) & (NFDEL | NFDEL_PENDING))) {
//
// 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; 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;
return(status);
}
//
// 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:
return (ERROR_INVALID_LEVEL);
}
if (ARGUMENT_PRESENT(ResumeHandle)) {
*ResumeHandle = hResume;
}
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];
UNUSED (ServerName);
//
// 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);
return(ERROR_ACCESS_DENIED);
}
//
// 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);
return (NERR_NotLocalName);
}
status = NERR_Success;
//
// Look for the name in the shared data name array. (1st net only).
//
if (MsgLookupName(0, formattedName) == -1) {
MSG_LOG(ERROR,"NetrMessageGetInfo: Name not in table\n",0);
status = NERR_NotLocalName;
return (status);
}
//
// 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());
return( ERROR_NOT_ENOUGH_MEMORY);
}
//
// 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());
return( ERROR_NOT_ENOUGH_MEMORY);
}
//
// 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:
return(ERROR_INVALID_LEVEL);
}
return(NERR_Success);
}
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.
Assorted Error codes from MsgAddName.
--*/
{
NET_API_STATUS status=0;
UNUSED(ServerName);
//
// 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);
return(ERROR_ACCESS_DENIED);
}
//
// Save away the Time Format for this user.
//
EnterCriticalSection(&TimeFormatCritSec);
if (!CloseProfileUserMapping()) {
MSG_LOG0(ERROR, "NetrMessageNameAdd: CloseProfileUserMapping failed\n");
}
status = RpcImpersonateClient(NULL);
if (status != NERR_Success) {
MSG_LOG1(ERROR, "NetrMessageNameAdd: RpcImpersonateClient failed %d\n",
GetLastError());
}
if (!OpenProfileUserMapping()) {
MSG_LOG0(ERROR, "NetrMessageNameAdd: OpenProfileUserMapping failed\n");
}
NetpGetTimeFormat(&GlobalTimeFormat);
if (!CloseProfileUserMapping()) {
MSG_LOG0(ERROR, "NetrMessageNameAdd: CloseProfileUserMapping failed\n");
}
status = RpcRevertToSelf();
if (status != NERR_Success) {
MSG_LOG(ERROR, "NetrMessageNameAdd: RpcRevertToSelf failed %d\n",
GetLastError());
}
if (!OpenProfileUserMapping()) {
MSG_LOG0(ERROR, "NetrMessageNameAdd: 2nd-OpenProfileUserMapping failed\n");
}
LeaveCriticalSection(&TimeFormatCritSec);
//
// Since a new user may have just logged on, we want to check to see if
// there are any messages to be displayd.
//
MsgDisplayThreadWakeup();
//
// Call the function that actually adds the name.
//
return(MsgAddName(Name));
}
NET_API_STATUS
MsgAddName(
LPWSTR Name
)
/*++
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++ ) {
for( i = 0, err_code = 0; i < 10; i++) {
name_i = MsgLookupName(neti, ncb.ncb_name);
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;
}
}
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");
for(i = 0; i < NCBMAX; ++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;
}
}
//
// Unlock the shared database
//
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
if( i >= NCBMAX) {
//
// If no room in name table
//
err_code = NERR_TooManyNames;
}
else {
//
// Send ADDNAME
//
ncb.ncb_command = NCBADDNAME; // Add name (wait)
ncb.ncb_lana_num = net_lana_num[neti];
MSG_LOG1(TRACE,"MsgNameAdd: Calling sendncb for lana #%d...\n",
net_lana_num[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;
//
// 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 = net_lana_num[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");
name_i = MsgLookupName(i,(char far *)(ncb.ncb_name));
if (name_i == -1) {
err_code = NERR_InternalError;
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
break;
}
MsgDatabaseLock(MSG_RELEASE, "MsgAddName");
//
// 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",net_lana_num[i])
ncb.ncb_command = NCBDELNAME;
ncb.ncb_lana_num = net_lana_num[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
} // end add names to net loop
} // end if ( !err_cd )
return(err_code); // Return status
}
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.
--*/
{
NCB ncb; // Network control block
DWORD flags; // Name flags
DWORD i; // Index into name table
DWORD neti; // Network Index
NET_API_STATUS status=0;
NET_API_STATUS end_result=0;
DWORD name_len;
UCHAR net_err;
UNUSED(ServerName);
//
// 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_DEL, // Desired Access
&MsgMessageNameMapping); // Generic Mapping
if (status != NERR_Success) {
MSG_LOG(TRACE,
"NetrMessageNameDel:NetpAccessCheckAndAudit FAILED %X\n",
status);
return(ERROR_ACCESS_DENIED);
}
//
// Initialize the NCB
//
clearncb(&ncb);
//
// Format the username (this makes it non-unicode);
//
status = MsgFmtNcbName(ncb.ncb_name, Name, NAME_LOCAL_END);
if (status != NERR_Success) {
MSG_LOG(TRACE,"NetrMessageNameDel: could not format name\n",0);
return (NERR_NotLocalName);
}
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 = MsgLookupName( neti, ncb.ncb_name))) == -1) {
//
// No such name to delete - exit
//
MsgDatabaseLock(MSG_RELEASE, "NetrMessageNameDel");
return(NERR_NotLocalName);
}
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
//
return(NERR_DelComputerName);
}
if(flags & NFLOCK) {
//
// If name is locked
//
return(NERR_NameInUse);
}
//
// Delete the Name
//
ncb.ncb_command = NCBDELNAME; // Delete name (wait)
ncb.ncb_lana_num = net_lana_num[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;
}
MsgDatabaseLock(MSG_RELEASE, "NetrMessageNameDel");
status = MsgMapNetError(net_err); // Map network error status
end_result = NERR_IncompleteDel; // Unable to delete name
}
} // End for all nets
return(end_result);
}