Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1613 lines
41 KiB

/*++
Copyright (c) 1991-92 Microsoft Corporation
Module Name:
msginit.c
Abstract:
Messenger Service Initialization Routines.
The following is a list of functions in this file:
MsgInitializeMsgr
BufferInit
InitSharedData
SetComputerName
GetNumNets
MsgGetBufSize
SetUpMessageFile
Author:
Dan Lafferty (danl) 18-Jul-1991
Environment:
User Mode - Win32
Notes:
optional-notes
Revision History:
19-Aug-1997 wlees
PNP support. Retry if lana's not present yet.
27-Jun-1995 AnirudhS
LocalFree(dataPtr) must be called AFTER MsgFreeSupportSeg, because
the latter tries to _close a handle stored in dataPtr.
08-Feb-1994 Danl
Removed the restriction that the memory allocated had to be
restricted to less than a 64K segment. We don't worry about
segments anymore.
12-Jan-1993 Danl
In error paths where we call MsgCloseWakeupSems, I need to do the
LocalFree(dataPtr) after the call to MsgCloseWakeupSems. Otherwise,
it access violates because MsgCloseWakeupSems uses the shared date
in the block pointed to by the dataPtr.
21-Apr-1992 JohnRo
Fixed bug printing a status when message name add fails.
Changed to use FORMAT_ equates throughout.
18-Feb-1992 ritaw
Convert to Win32 service control APIs.
18-Jul-1991 danl
Created as a composite of the original LM2,0 routines.
--*/
//
// Includes
//
#include <stdlib.h> // atol
#include "msrv.h" // Messenger prototypes and constants
#include <winsvc.h> // Service control APIs
#include <winsock2.h> // Windows sockets
#include <netdebug.h> // NetpAssert, FORMAT_ equates.
#include <rpc.h> // DataTypes and runtime APIs
#include <msgsvc.h> // generated by the MIDL complier
#include <netlibnt.h> // NetpNtStatusToApiStatus prototypes
#include <tstring.h> // Unicode string macros
#include <string.h> // memcpy
#include <lmwksta.h> // NetWrkstaTransportEnum
#include <lmapibuf.h> // NetApiBufferFree
#include <netlib.h> // UNUSED macro
#include <msgrutil.h> // NetpNetBiosReset
#include <apperr2.h> // APE2_ALERTER_PRINTING_SUCCESS
#include "msgdbg.h" // MSG_LOG
#include "heap.h" // heap management routines and macros.
#include "msgdata.h" // Global data
#include "msgsec.h" // Messenger security information
#include "msgnames.h" // MSGR_INTERFACE_NAME
#include "msgtext.h" // MTXT_MsgsvcTitle
#include "msgsvcsend.h" // Broadcast message send interface
#include "apiutil.h" // for MsgAddSessionInList
// The per net data and heap buffer are allocated once. Later on we may
// wish to keep them separate.
#define BOOKKEEPING_SIZE(n) (n * sizeof(NET_DATA))
//
// Global Data
//
static DWORD bufferSize; // Message buffer size
static DWORD msrv_pid; // pid of message server
extern LPTSTR MessageFileName;
//
// Local Function Prototypes
//
VOID
MsgBufferInit(
IN DWORD dwBufLen
);
NET_API_STATUS
MsgInitSharedData(
DWORD NumNets
);
NET_API_STATUS
MsgSetComputerName(
DWORD NumNets
);
DWORD
MsgGetNumNets(VOID);
NET_API_STATUS
MsgGetBufSize (
OUT LPDWORD bufferSize
);
DWORD
MsgSetUpMessageFile(VOID);
STATIC VOID
MsgInitMessageBoxTitle(
VOID
);
NET_API_STATUS
MsgrInitializeMsgrInternal1(
void
);
NET_API_STATUS
MsgrInitializeMsgrInternal2(
void
);
VOID
MsgInitEndpoint(
PVOID Context // This passed in as context
);
NET_API_STATUS
MsgInitializeMsgr(
IN DWORD argc,
IN LPTSTR *argv
)
/*++
Routine Description:
Registers the control handler with the dispatcher thread. Then it
performs all initialization including the starting of the RPC server.
If any of the initialization fails, MsgStatusUpdate is called so that the
status is updated and the thread is terminated.
Arguments:
Return Value:
--*/
{
NET_API_STATUS status;
DWORD msgrState;
DWORD bufLen;
WSADATA wsaData;
NTSTATUS ntStatus;
//
// Initialize the Thread Manager. This initializes some locks used
// on the Thread and Status databases.
//
status = MsgThreadManagerInit();
if (status != NO_ERROR)
{
MSG_LOG1(ERROR,
"MsgInitializeMsgr: Thread manager init failed %d\n",
status);
return MsgBeginForcedShutdown(IMMEDIATE, status);
}
//
// Initialize the status structure
//
MsgStatusInit();
//
// Register this service with the ControlHandler.
// Now we can accept control requests and be requested to UNINSTALL.
//
MSG_LOG(TRACE, "Calling RegisterServiceCtrlHandlerEx\n",0);
if ((MsgrStatusHandle = RegisterServiceCtrlHandlerEx(
SERVICE_MESSENGER,
MsgrCtrlHandler,
NULL
)) == (SERVICE_STATUS_HANDLE) NULL) {
status = GetLastError();
MSG_LOG(ERROR,
"FAILURE: RegisterServiceCtrlHandlerEx status = " FORMAT_API_STATUS
"\n", status);
return( MsgBeginForcedShutdown (
IMMEDIATE,
status));
}
//
// Notify that installation is pending
//
msgrState = MsgStatusUpdate(STARTING);
if (msgrState != STARTING) {
//
// An UNINSTALL control request must have been received
//
return(msgrState);
}
//
// Init the _HYDRA_ WinStation message support
//
status = MultiUserInitMessage();
if (status != NERR_Success)
{
MSG_LOG(ERROR, "MultiUser Initialization Failed " FORMAT_RPC_STATUS "\n",
status);
return (MsgBeginForcedShutdown(
IMMEDIATE,
status));
}
//
// Check that the workstation is started
//
MSG_LOG(TRACE, "Calling NetServiceControl\n",0);
if (! NetpIsServiceStarted(SERVICE_WORKSTATION)) {
MSG_LOG(ERROR, "WorkStation Service is not started\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
NERR_WkstaNotStarted));
}
// *** INSTALLATION HINT ***
msgrState = MsgStatusUpdate(STARTING);
if (msgrState != STARTING) {
return(msgrState);
}
//
// Get the default buffer size.
//
status = MsgGetBufSize(&bufferSize);
if (status != NERR_Success)
{
MSG_LOG(ERROR, "MsgGetBufSize Failed\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
status));
}
// *** INSTALLATION HINT ***
msgrState = MsgStatusUpdate(STARTING);
if (msgrState != STARTING) {
return(msgrState);
}
if (bufferSize > MAX_SIZMESSBUF || bufferSize < MIN_SIZMESSBUF) {
MSG_LOG(ERROR, "Message Buffer Size is illegal\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
ERROR_INVALID_PARAMETER));
}
//
// This is the size of the buffer (that SDBUFFER points to) in the
// shared data area. This is calculated as:
//
// The size of a message buffer (bufferSize)
// plus
// space for 4 Multi-block message headers and names,
// plus
// space for one Multi-block text header for each text block that
// fits into the message buffer. (bufferSize/TXTMAX).
//
// The number of headers is rounded up by one.
// (bufferSize+TXTMAX-1)/TXTMAX
//
bufferSize += (4 * (sizeof(MBB) + (2 * NCBNAMSZ))) +
((( (bufferSize+TXTMAX-1)/TXTMAX) + 1) * sizeof(MBT));
// ***** INSTALLATION HINT *****
msgrState = MsgStatusUpdate(STARTING);
if (msgrState != STARTING) {
return(msgrState);
}
//
// Ask the Worksta for the computer name. If the computer
// has no name, then abort.
//
// The computername and the username are in unicode format.
//
// NOTE: the username that is returned is a name we may want to add
// to the table.
//
MSG_LOG(TRACE, "Getting the ComputerName\n",0);
bufLen = sizeof(machineName);
*machineName = TEXT('\0');
if (!GetComputerName(machineName,&bufLen)) {
MSG_LOG(ERROR,"GetComputerName failed \n",0);
status = GetLastError();
}
if ( (status != NERR_Success) ||
(*machineName == TEXT('\0')) || (*machineName == TEXT(' ')))
{
//
// fatal error if no name
//
MSG_LOG(ERROR, "GetWkstaNames Failed\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
NERR_NoComputerName));
}
machineName[NCBNAMSZ] = TEXT('\0'); // make sure it's terminated
MachineNameLen = (SHORT) STRLEN(machineName);
// ***** INSTALLATION HINT *****
msgrState = MsgStatusUpdate(STARTING);
if (msgrState != STARTING)
{
return(msgrState);
}
//
// Initialize the configuration lock. This lock covers the allocation and deallocation
// of the data structures related to lan adapters.
//
if (MsgConfigurationLock(MSG_INITIALIZE,"MsgInitializeMsgr"))
{
//
// Do first phase of lan adapter related configuration
//
status = MsgrInitializeMsgrInternal1();
if (status != NERR_Success)
{
MSG_LOG1(ERROR, "MsgrInitializeMsgrInternal1 Failure %d\n", status);
}
}
else
{
MSG_LOG0(ERROR, "MsgConfigurationLock -- MSG_INITIALIZE failed\n");
status = ERROR_NOT_ENOUGH_MEMORY;
}
if (status != NERR_Success)
{
MsgFreeSharedData();
if (wakeupSem != NULL)
{
MsgFreeSupportSeg();
}
MsgCloseWakeupSems(); // Close the ones that have been created
return (MsgBeginForcedShutdown(
IMMEDIATE,
status));
}
// ***** INSTALLATION HINT *****
msgrState = MsgStatusUpdate(STARTING);
if (msgrState != STARTING)
{
return(msgrState);
}
//
// Change from IMMEDIATE Shutdowns to PENDING shutdowns.
// This is because at this point we have names on the adapters
// to clean up.
//
status = MsgrInitializeMsgrInternal2();
if (status != NERR_Success)
{
MSG_LOG1(ERROR, "MsgrInitializeMsgrInternal2 Failure\n", status);
return (MsgBeginForcedShutdown(
PENDING,
status));
}
//
// Build the name of the file that is to be used to get the
// message header and tail.
//
MSG_LOG(TRACE, "Calling MsgSetUpMessageFile\n",0);
status = MsgSetUpMessageFile();
if (status != NO_ERROR)
{
MSG_LOG1(ERROR, "MsgSetUpMessageFile Failure\n", status);
return (MsgBeginForcedShutdown(
PENDING,
status));
}
//
// Start the Group messenger thread to handle all domain messaging
//
MSG_LOG(TRACE, "Calling MsgInitGroupSupport\n",0);
if ( status = MsgInitGroupSupport( SD_NUMNETS() ) )
{
MSG_LOG(ERROR, "InitGroupSupport Failed\n",0);
return (MsgBeginForcedShutdown(
PENDING,
NERR_GrpMsgProcessor));
}
//
// Initialize the Display Code
//
status = MsgDisplayInit();
if (status != NO_ERROR)
{
MSG_LOG1(ERROR, "Could not initialize the display functions %d\n", status);
return (MsgBeginForcedShutdown(
PENDING,
status));
}
//
// Create the security descriptor that is to be used in access
// checks on the API interface.
//
MSG_LOG(TRACE, "Calling MsgCreateMessageNameObject\n",0);
status = MsgCreateMessageNameObject();
if (status != NERR_Success)
{
MSG_LOG(ERROR, "MsgCreateMessageNameObject (security descriptor) "
"Failed\n", 0);
return (MsgBeginForcedShutdown(
PENDING,
status));
}
//
// Initialize the text for the message box title.
//
MsgInitMessageBoxTitle();
//
// Start the Messengers RPC server.
//
// NOTE: Now all RPC servers in services.exe share the same pipe name.
// However, in order to support communication with version 1.0 of WinNt,
// it is necessary for the Client Pipe name to remain the same as
// it was in version 1.0. Mapping to the new name is performed in
// the Named Pipe File System code.
//
MSG_LOG(TRACE,
"MsgInitializeMsgr:Getting ready to start RPC server\n",0);
status = MsgsvcGlobalData->StartRpcServer(
MSGR_INTERFACE_NAME,
msgsvc_ServerIfHandle);
if (!NT_SUCCESS(status)) {
MSG_LOG(ERROR, "RPC Initialization Failed " FORMAT_RPC_STATUS "\n",
status);
return (MsgBeginForcedShutdown(
PENDING,
status));
}
//
// Start thread to register with endpoint mapper (may take a while)
//
ntStatus = RtlQueueWorkItem(MsgInitEndpoint, // Callback
NULL, // pContext
WT_EXECUTEONLYONCE | // Long one-shot callback
WT_EXECUTELONGFUNCTION);
if (!NT_SUCCESS(ntStatus)) {
MSG_LOG(ERROR, "MsgInit: failed to start endpoint registration thread: %#x\n",
ntStatus);
return (MsgBeginForcedShutdown(
PENDING,
status));
}
// Initialize winsock (needed for name resolution)
//
status = WSAStartup(MAKEWORD(2,1),&wsaData);
if (status != ERROR_SUCCESS) {
MSG_LOG(ERROR, "Initialization of Winsock DLL failed " FORMAT_RPC_STATUS "\n",
status);
return (MsgBeginForcedShutdown(
PENDING,
status));
}
//
// Update the status to indicate that installation is complete.
// Get the current state back in case the ControlHandling thread has
// told us to shutdown.
//
MSG_LOG(TRACE, "Exiting MsgInitializeMsgr - Init Done!\n",0);
return (MsgStatusUpdate(RUNNING));
}
NET_API_STATUS
MsgrInitializeMsgrInternal1(
void
)
/*++
Routine Description:
Initialize volatile state related to lanas.
These initializations can be undone immediately if there is an error.
Arguments:
None
Return Value:
None
--*/
{
DWORD NumNets;
NET_API_STATUS status;
MSG_LOG(TRACE, "Calling MsgGetNumNets\n",0);
NumNets = MsgGetNumNets();
if (NumNets == 0)
{
MSG_LOG(TRACE, "FYI: No lana's enabled at this time\n",0);
// Not having any networks is no longer an error, ie Numnets == 0 is ok
}
//
// Initialize shared memory areas.
//
MSG_LOG(TRACE, "Calling MsgInitSharedData\n",0);
status = MsgInitSharedData(NumNets);
if (status != NERR_Success)
{
return status;
}
//*****************************************
//
// STUFF FROM Init_msrv() in MSRV.C
//
//*****************************************
heap = SD_BUFFER(); // Initialize data heap pointer
heapln = SD_BUFLEN(); // Initialize data heap length
//
// Set up the segement to hold the net bios handles, lana-nums
// and wakeup Semaphores.
//
MSG_LOG(TRACE, "Calling MsgInitSupportSeg\n",0);
status = MsgInitSupportSeg();
if (status != NERR_Success)
{
MSG_LOG(ERROR, "InitSupportSeg Failed\n",0);
return status;
}
//
// Now initialize global net bios handles & lana nums. Initializes net_lana_num[]
//
MSG_LOG(TRACE, "Calling MsgInit_NetBios\n",0);
status = MsgInit_NetBios();
if (status != NERR_Success)
{
MSG_LOG1(ERROR, "MsgInit_NetBios failed %d\n", status);
return status;
}
//
// Get the wake up semaphore handles. Initializes wakeupSem[]
//
MSG_LOG(TRACE, "Calling MsgCreateWakeupSems\n",0);
//
// This always returns TRUE
//
MsgCreateWakeupSems(SD_NUMNETS());
//
// Open NETBIOS for use by messenger.
// If any failures occur beyond this we must remember to close.
//
MsgsvcGlobalData->NetBiosOpen();
//
// Set computer name on adapters - if any
//
MSG_LOG(TRACE, "Calling MsgSetComputerName\n",0);
status = MsgSetComputerName(SD_NUMNETS());
if(status != NERR_Success)
{
MSG_LOG1(ERROR, "SetComputerName failed %d\n", status);
MsgsvcGlobalData->NetBiosClose();
return status;
}
return NERR_Success;
}
NET_API_STATUS
MsgrInitializeMsgrInternal2(
void
)
/*++
Routine Description:
Initialize volatile lana state. These initializations cannot be undone easily. If this routine
fails we must go through a full shutdown in order to clean up.
Arguments:
None
Return Value:
None
--*/
{
//
// Installation is successful and complete. If there is a
// user logged on then an attempt is made to add the user name
// to this message server. No attempt is made at error reporting
// if this fails, there may not be a user logged on, and if there is,
// the user name may already exist as a message name on another
// station.
//
// This is when we add usernames to the message table if we can.
// Sometime this needs to handle multiple users??? (not in version 1)
//
if (g_IsTerminalServer)
{
MsgAddAlreadyLoggedOnUserNames();
}
else
{
MsgAddUserNames();
}
return NERR_Success;
}
VOID
MsgBufferInit(
IN DWORD dwBufLen
)
/*++
Routine Description:
This function is called during initialization to set up
the message buffer in the shared data area.
This function assumes that the shared data area is locked
in memory, that the access semaphore for the shared data
area is set, and that the global far pointer, dataPtr, is
valid. BufferInit() initializes the heap structure of the
buffer.
SIDE EFFECTS
The buffer in shared memory is initialized.
Arguments:
dwBuflen - buffer length
Return Value:
none
--*/
{
LPHEAPHDR hp; // Heap block pointer
hp = (LPHEAPHDR) SD_BUFFER(); // Get the address of buffer
HP_SIZE(*hp) = dwBufLen; // Set the size of the first block
HP_FLAG(*hp) = 0; // Unallocated
SD_BUFLEN() = dwBufLen; // Save the length of the buffer
}
DWORD
MsgInitSharedData(
DWORD NumNets
)
/*++
Routine Description:
This function creates and initializes the shared data area.
It sets up the computer name and initializes the message
buffer.
SIDE EFFECTS
Calls MsgBufferInit().
Arguments:
NumNets - Number of network adapters to support.
Return Value:
RETURN
NERR_Success if the operation was successful
ERROR_NOT_ENOUGH_MEMORY - If the memory alloc for the shared
memory segment fails.
--*/
{
DWORD i,j; // Index
ULONG size;
PNCB_DATA pNcbData;
DWORD MinimumNumNets = ((NumNets == 0)? 1 : NumNets); // 1 is the minimum
//
// Create and initialize shared data area.
//
size = bufferSize + BOOKKEEPING_SIZE(MinimumNumNets);
if ((GlobalData.NetData = (PNET_DATA)LocalAlloc(LMEM_ZEROINIT, size)) == NULL) {
goto NoMemory;
}
//
// In case NumNets = 0, keep 1 dummy NetData.
// This is not very pretty but should avoid any trouble, without having to modify
// too much code.
//
GlobalData.Buffer = (PCHAR) (&GlobalData.NetData[MinimumNumNets]);
for (i = 0; i < NumNets ; i++ )
{
// Allocate the list array at the maximum size, but only allocate
// a small initial number of NCBs.
if ((GlobalData.NetData[i].NcbList =
LocalAlloc(LMEM_ZEROINIT,
sizeof(PNCB_DATA) * NCB_MAX_ENTRIES)) == NULL)
{
goto NoMemory;
}
GlobalData.NetData[i].NumNcbs = NCB_INIT_ENTRIES;
for (j=0; j < NCB_INIT_ENTRIES; j++)
{
if ((GlobalData.NetData[i].NcbList[j] = pNcbData =
(PNCB_DATA) LocalAlloc(LMEM_ZEROINIT,
sizeof(NCB_DATA))) == NULL)
{
goto NoMemory;
}
pNcbData->Ncb.ncb_cmd_cplt = 0xff;
pNcbData->Ncb.ncb_retcode = 0;
}
}
//
// Initialize the shared data lock. The shared data is shared between
// the API threads and the worker threads.
//
if (!MsgDatabaseLock(MSG_INITIALIZE,"InitSharedData"))
{
MSG_LOG0(ERROR,
"MsgInitSharedData: MsgDatabaseLock failed\n");
goto NoMemory;
}
//
// Initialize the "used-to-be shared" data
//
SD_NUMNETS() = NumNets;
SD_MESLOG() = 0; // Message logging disabled
for ( j = 0; j < SD_NUMNETS(); j++ )
{
for(i = 0; i < NCBMAX(j); ++i)
{
//
// Mark entries as free
//
SD_NAMEFLAGS(j,i) = NFDEL;
//create empty session lists
InitializeListHead(&(SD_SIDLIST(j,i)));
}
}
//
// Initialize the message buffer
//
MsgBufferInit(bufferSize);
//
// NT NOTE:
// Skip Initializing the Support Set and Wakeup sems.
// Init_msrv will end up doing that.
//
return(NERR_Success);
NoMemory:
MSG_LOG(ERROR,"[MSG]InitSharedData:LocalAlloc Failure "
FORMAT_API_STATUS "\n", GetLastError());
return(ERROR_NOT_ENOUGH_MEMORY);
}
VOID
MsgFreeSharedData(VOID)
{
PNET_DATA pNetData;
PNCB_DATA pNcbData;
DWORD i,j;
if (pNetData = GlobalData.NetData) {
for (i = 0; i < SD_NUMNETS() ; i++, pNetData++ ) {
if (pNetData->NcbList) {
for (j = 0; j < NCBMAX(i) ; j++ ) {
if (pNcbData = GETNCBDATA(i,j)) {
LocalFree(pNcbData);
}
}
LocalFree(pNetData->NcbList);
}
}
LocalFree(GlobalData.NetData);
GlobalData.NetData = NULL;
}
}
NET_API_STATUS
MsgSetComputerName(
IN DWORD NumNets
)
/*++
Routine Description:
This function sets up the shared data area for the computer name
so that it can receive messages.
This function sets things up so that the computer name will be able
to receive messages. First, it adds the user name form of the computer
name to the local adapter. If successful, it then initializes one slot
in the name table in the shared data area: a computer name
receiving messages
SIDE EFFECTS
Locks the init data segment around net bios usage.
Calls the net bios. Makes entries in the shared data area.
Arguments:
NumNets - The number of network adapters that is supported
Return Value:
0 = success
non-zero = failure
--*/
{
NET_API_STATUS status = NERR_Success;
NCB ncb;
UCHAR res;
DWORD i;
unsigned short j;
struct {
ADAPTER_STATUS AdapterStatus;
NAME_BUFFER NameBuffer[16];
} Astat;
//
// Loop for each net.
//
for ( i = 0; i < NumNets; i++ )
{
// NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW
//
// Reset the adapter
//
MSG_LOG1(TRACE,"Calling NetBiosReset for lana #%d\n",GETNETLANANUM(i));
status = MsgsvcGlobalData->NetBiosReset(GETNETLANANUM(i));
if (status != NERR_Success)
{
MSG_LOG(ERROR,"MsgSetComputerName: NetBiosReset failed "
FORMAT_API_STATUS "\n", status);
MSG_LOG(ERROR,"MsgSetComputerName: AdapterNum " FORMAT_DWORD
"\n",i);
//
// If it fails, skip to the Next Net.
//
continue;
}
//
//
// NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW
//
// Set call name for local adapter
//
clearncb(&ncb);
status = MsgFmtNcbName(ncb.ncb_name, machineName, 3);
if (status != NERR_Success)
{
MSG_LOG1(ERROR, "SetComputerName: Format name failed!", status);
return status;
}
ncb.ncb_command = NCBADDNAME; // Add name (wait)
ncb.ncb_lana_num = GETNETLANANUM(i); // Use the LANMAN adapter
//
// Copy the name
// (At this point the name is ansi - not unicode)
//
memcpy(SD_NAMES(i,0), ncb.ncb_name, NCBNAMSZ);
if (g_IsTerminalServer)
{
MSG_LOG(TRACE,"SetComputerName: Adding session EVERYBODY_SESSION_ID in the list\n",0);
MsgAddSessionInList(&(SD_SIDLIST(i,0)),(ULONG)EVERYBODY_SESSION_ID);
}
MSG_LOG1(TRACE,"MsgSetComputerName: Adding ComputerName to lana #%d\n",
GETNETLANANUM(i));
res = Msgsendncb( &ncb, i);
//
// If the lana is being reinitialized we need to force a reset
//
if ((res & 0xff) == NRC_ENVNOTDEF)
{
MSG_LOG1(TRACE,"SetComputerName: NetBios ADDNAME failed 0x%x - doing reset\n",res);
status = NetpNetBiosReset(GETNETLANANUM(i));
if (status == NERR_Success)
{
//
// rebuild the add name request
//
clearncb(&ncb);
status = MsgFmtNcbName(ncb.ncb_name, machineName, 3);
if (status != NERR_Success)
{
MSG_LOG1(ERROR, "SetComputerName: Format name failed %d!", status);
return status;
}
ncb.ncb_command = NCBADDNAME; // Add name (wait)
ncb.ncb_lana_num = GETNETLANANUM(i); // Use the LANMAN adapter
MSG_LOG1(TRACE,"MsgSetComputerName: Adding ComputerName<03> to lana #%d\n",
GETNETLANANUM(i));
res = Msgsendncb(&ncb, i); // reissue the ncb
}
}
if(res != 0)
{
MSG_LOG1(TRACE,"SetComputerName: NetBios ADDNAME failed 0x%x\n",res);
if((res & 0xff) == NRC_DUPNAME)
{
//
// If the name already exists on the adapter card (the
// workstation may have added it), we want to get the
// name number and pretend that we just added it.
//
// Name already exists. Issue an ASTAT to find the name
// number.
//
clearncb(&ncb);
ncb.ncb_buffer = (char FAR *) &Astat; // Set buffer address
ncb.ncb_length = sizeof(Astat); // Set buffer length
ncb.ncb_callname[0] = '*'; // local adapter status
ncb.ncb_command = NCBASTAT; // Adapter status (wait)
res = Msgsendncb(&ncb,i);
if( res != NRC_GOODRET)
{
//
// Failed to add name
//
MSG_LOG1(ERROR, "SetComputerName:sendncb (ASTAT) failed 0x%x\n", res);
return MsgMapNetError(res);
}
//
// Loop to name number
//
for(j = 0; j< Astat.AdapterStatus.name_count; ++j)
{
if (((Astat.NameBuffer[j].name_flags & 7) == 4)
&&
(memcmp( Astat.NameBuffer[j].name,
SD_NAMES(i,0),
NCBNAMSZ) == 0))
{
break; // Found the name
}
}
if (j == Astat.AdapterStatus.name_count)
{
//
// Failed to find
//
MSG_LOG(ERROR,
"SetComputerName:DupName-failed to find NameNum\n",0);
return NERR_NoComputerName;
}
SD_NAMENUMS(i,0) = Astat.NameBuffer[j].name_num; // Save num
MSG_LOG1(TRACE,"SetComputerName: use existing name num (%d) instead\n",
Astat.NameBuffer[j].name_num);
}
else
{
//
// Fail if name not on the card after the call
//
MSG_LOG(ERROR, "SetComputerName:Name Not on Card. netbios rc = 0x%x\n",res);
return NERR_NoComputerName;
}
}
else
{
SD_NAMENUMS(i,0) = ncb.ncb_num; // Save the name number
}
SD_NAMEFLAGS(i,0) = NFNEW | NFMACHNAME; // Name is new
} // End for all nets
return NERR_Success;
}
DWORD
MsgGetNumNets(VOID)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NCB ncb;
LANA_ENUM lanaBuffer;
unsigned char nbStatus;
//
// Find the number of networks by sending an enum request via Netbios.
//
clearncb(&ncb);
ncb.ncb_command = NCBENUM; // Enumerate LANA nums (wait)
ncb.ncb_buffer = (char FAR *)&lanaBuffer;
ncb.ncb_length = sizeof(LANA_ENUM);
nbStatus = Netbios (&ncb);
if (nbStatus != NRC_GOODRET) {
MSG_LOG(ERROR, "GetNumNets:Netbios LanaEnum failed rc="
FORMAT_DWORD "\n", (DWORD) nbStatus);
return(FALSE);
}
return((DWORD)lanaBuffer.length);
#ifdef replaced
LPBYTE transportInfo;
int count=0;
USHORT loopback_found = 0;
NET_API_STATUS status;
DWORD entriesRead;
DWORD totalEntries;
//
// First try and find the networks mananged by the LAN manager
//
// NOTE: This call will fail if there are more than MSNGR_MAX_NETS
// in the machine. This is not a problem unless there are fewer
// than MSNGR_MAX_NETS that would qualify for messaging service.
// In this case, it might be argued that the messenger should start.
// For now, this is not the case. - ERICPE
//
status = NetWkstaTransportEnum (
NULL, // server name (local)
0, // level
&transportInfo, // bufptr
-1, // preferred maximum length
&entriesRead, // entries read
&totalEntries, // total entries
NULL); // resumeHandle
//
// Free up the buffer that RPC allocated for us.
//
NetApiBufferFree(transportInfo);
if (status != NERR_Success) {
MSG_LOG(ERROR,"GetNumNets:NetWkstaTransportEnum failed "
FORMAT_API_STATUS "\n", status);
return(0);
}
MSG_LOG(TRACE,"GetNumNets: numnets = " FORMAT_DWORD "\n", totalEntries);
return(totalEntries);
#endif
}
NET_API_STATUS
MsgGetBufSize (
OUT LPDWORD bufferSize
)
/*++
Routine Description:
This routine fills in the default buffer size
Arguments:
bufferSize - This is a pointer to where the buffer size is to be stored.
Return Value:
NERR_Success - No errors, the returned bufferSize is valid.
--*/
{
//
// Use the default.
//
*bufferSize = 8192;
return NERR_Success;
}
DWORD
MsgSetUpMessageFile (
VOID
)
/*++
Routine Description:
Builds the name of the message file that is to be used in any
subsequent DosGetMessage calls. The name is built in the Global
variable MessageFileName.
Arguments:
none
Return Value:
NERR_Success - The operation was successful
ERROR_NOT_ENOUGH_MEMORY - Couldn't allocate memory for MessageFileName.
--*/
{
//
// allocate some space for the message file name to be built.
//
MessageFileName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, (MSGFILENAMLEN+sizeof(TCHAR)));
if (MessageFileName == NULL) {
MSG_LOG(ERROR,"[MSG]SetUpMessageFile:LocalAlloc Failure "
FORMAT_API_STATUS "\n", GetLastError());
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// This message filename (netmsg.dll) is defined in lmcons.h
//
STRCPY(MessageFileName,MESSAGE_FILENAME);
return (NERR_Success);
}
STATIC VOID
MsgInitMessageBoxTitle(
VOID
)
/*++
Routine Description:
Obtains the title text for the message box used to display messages.
If the title is successfully obtained from the message file, then
that title is pointed to by GlobalAllocatedMsgTitle and
GlobalMessageBoxTitle. If unsuccessful, then GlobalMessageBoxTitle
left pointing to the DefaultMessageBoxTitle.
NOTE: If successful, a buffer is allocated by this function. The
pointer stored in GlobalAllocatedMsgTitle and it should be freed when
done with this buffer.
Arguments:
Return Value:
none
--*/
{
LPVOID hModule;
DWORD msgSize;
DWORD status=NO_ERROR;
GlobalAllocatedMsgTitle = NULL;
hModule = LoadLibrary( L"netmsg.dll");
if ( hModule == NULL) {
status = GetLastError();
MSG_LOG1(ERROR, "LoadLibrary() fails with winError = %d\n", GetLastError());
return;
}
msgSize = FormatMessageW(
FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
hModule,
MTXT_MsgsvcTitle, // MessageId
0, // dwLanguageId
(LPWSTR)&GlobalAllocatedMsgTitle, // lpBuffer
0, // nSize
NULL);
if (msgSize == 0) {
status = GetLastError();
MSG_LOG1(ERROR,"Could not find MessageBox title in a message file %d\n",
status);
}
else {
GlobalMessageBoxTitle = GlobalAllocatedMsgTitle;
}
//
// Get the messages as Ansi since we'll be comparing them to an
// Ansi message that comes in from a remote Alerter service.
//
msgSize = FormatMessageA(
FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
hModule,
APE2_ALERTER_PRINTING_SUCCESS, // MessageId
0, // dwLanguageId
(LPSTR) &g_lpAlertSuccessMessage, // lpBuffer
0, // nSize
NULL);
if (msgSize == 0)
{
// No loss -- we just won't be able to filter print success alerts
status = GetLastError();
MSG_LOG1(ERROR,
"Could not find Alerter print success message %d\n",
status);
}
else
{
//
// Trim the message to end after the "Printing Complete" line.
//
LPSTR lpTemp = g_lpAlertSuccessMessage;
g_dwAlertSuccessLen = 0;
while (*lpTemp && *lpTemp != '\r')
{
lpTemp++;
g_dwAlertSuccessLen++;
}
*lpTemp = '\0';
}
msgSize = FormatMessageA(
FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
hModule,
APE2_ALERTER_PRINTING_FAILURE, // MessageId
0, // dwLanguageId
(LPSTR) &g_lpAlertFailureMessage, // lpBuffer
0, // nSize
NULL);
if (msgSize == 0)
{
// No loss -- we just won't be able to filter print success alerts
status = GetLastError();
MSG_LOG1(ERROR,
"Could not find Alerter print failure message %d\n",
status);
}
else
{
//
// Trim the message to end after the "Printing Complete" line.
//
LPSTR lpTemp = g_lpAlertFailureMessage;
g_dwAlertFailureLen = 0;
while (*lpTemp && *lpTemp != '\r')
{
lpTemp++;
g_dwAlertFailureLen++;
}
*lpTemp = '\0';
}
FreeLibrary(hModule);
return;
}
VOID
MsgInitEndpoint(
PVOID Context // This passed in as context.
)
/*++
Routine Description:
This function is called to initialize our RPC server entry point. We
do this in a separate thread because we may have to wait because
RpcSS is not ready yet.
Arguments:
Context - Context parameter
Return Value:
None
--*/
{
RPC_BINDING_VECTOR *bindingVector = NULL;
DWORD status, tries;
MSG_LOG(TRACE, "MsgInitEndpoint starting in separate thread\n",0);
//
// Create endpoint for receiving RPC calls
// This is for netbiosless notifications
//
for( tries = 0; tries < 3; tries++ ) {
status = RpcServerUseProtseq(
TEXT("ncadg_ip_udp"),
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
NULL // Do we need an empty SD here?
);
if ( (status == RPC_S_OK) || (status == RPC_S_DUPLICATE_ENDPOINT) ) {
break;
}
MSG_LOG(ERROR, "RPC Init (UseProt Udp) Failed "
FORMAT_RPC_STATUS " - trying again\n", status);
Sleep( 30 * 1000 );
}
if ( (status != RPC_S_OK) && (status != RPC_S_DUPLICATE_ENDPOINT) ) {
if (status == RPC_S_SERVER_UNAVAILABLE) {
MSG_LOG( ERROR, "Failed to use UDP, check RPCSS service\n",0 );
} else {
MSG_LOG( ERROR, "Failed to use UDP, check TCP/IP\n",0 );
}
// give up
return;
}
status = RpcServerInqBindings(
&bindingVector
);
if (status != ERROR_SUCCESS) {
MSG_LOG( ERROR, "RpcServerInqBindings failed with %d\n",status );
return;
}
// Try to register in a loop in case RPCSS is not running yet
for( tries = 0; tries < 3; tries++ ) {
status = RpcEpRegister(
msgsvcsend_ServerIfHandle,
bindingVector,
NULL,
TEXT("Messenger Service")
);
if (status == RPC_S_OK) {
break;
}
MSG_LOG( ERROR, "Msgr: RpcEpRegister failed with %d - trying again\n", status );
RpcEpUnregister( msgsvcsend_ServerIfHandle,
bindingVector,
NULL );
// ignore error
Sleep( 10 * 1000 );
}
RpcBindingVectorFree( &bindingVector );
if (status != RPC_S_OK) {
// give up
return;
}
//
// Register RPC interface
//
status = RpcServerRegisterIf(
msgsvcsend_ServerIfHandle, // interface to register
NULL, // MgrTypeUuid
NULL); // MgrEpv; null means use default
if (status != RPC_S_OK) {
MSG_LOG(ERROR, "RPC Init (RegIf MsgSvcSend) Failed "
FORMAT_RPC_STATUS "\n", status);
return;
}
MSG_LOG(TRACE, "MsgInitEndpoint final status %d\n", status);
return;
}