summaryrefslogtreecommitdiffstats
path: root/private/net/svcdlls/msgsvc/server/msgapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/net/svcdlls/msgsvc/server/msgapi.c')
-rw-r--r--private/net/svcdlls/msgsvc/server/msgapi.c1103
1 files changed, 1103 insertions, 0 deletions
diff --git a/private/net/svcdlls/msgsvc/server/msgapi.c b/private/net/svcdlls/msgsvc/server/msgapi.c
new file mode 100644
index 000000000..c9733f793
--- /dev/null
+++ b/private/net/svcdlls/msgsvc/server/msgapi.c
@@ -0,0 +1,1103 @@
+/*++
+
+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);
+}
+
+
+