/*++ 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 // atol #include "msrv.h" // Messenger prototypes and constants #include // Service control APIs #include // Windows sockets #include // NetpAssert, FORMAT_ equates. #include // DataTypes and runtime APIs #include // generated by the MIDL complier #include // NetpNtStatusToApiStatus prototypes #include // Unicode string macros #include // memcpy #include // NetWrkstaTransportEnum #include // NetApiBufferFree #include // UNUSED macro #include // NetpNetBiosReset #include // 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)) #define MAXSEG (0xffff) #define LMI_PARM_M_SIZMESSBUF TEXT("/sizmessbuf") // // 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. Don't care about errors, since // any error will result in the file not being used and is // resorting to the old standby strings. // MSG_LOG(TRACE, "Calling MsgSetUpMessageFile\n",0); MsgSetUpMessageFile(); // // 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_MSRV() = 0; // No message server active SD_LOGNAM()[0] = '\0'; // No log file yet SD_MESLOG() = 0; // Message logging disabled SD_MESQF() = INULL; // Message queue is empty SD_MESQB() = INULL; 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; }