Source code of Windows XP (NT5)
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
39 KiB

  1. /*++
  2. Copyright (c) 1991-92 Microsoft Corporation
  3. Module Name:
  4. msginit.c
  5. Abstract:
  6. Messenger Service Initialization Routines.
  7. The following is a list of functions in this file:
  8. MsgInitializeMsgr
  9. BufferInit
  10. InitSharedData
  11. SetComputerName
  12. GetNumNets
  13. MsgGetBufSize
  14. SetUpMessageFile
  15. Author:
  16. Dan Lafferty (danl) 18-Jul-1991
  17. Environment:
  18. User Mode - Win32
  19. Notes:
  20. optional-notes
  21. Revision History:
  22. 19-Aug-1997 wlees
  23. PNP support. Retry if lana's not present yet.
  24. 27-Jun-1995 AnirudhS
  25. LocalFree(dataPtr) must be called AFTER MsgFreeSupportSeg, because
  26. the latter tries to _close a handle stored in dataPtr.
  27. 08-Feb-1994 Danl
  28. Removed the restriction that the memory allocated had to be
  29. restricted to less than a 64K segment. We don't worry about
  30. segments anymore.
  31. 12-Jan-1993 Danl
  32. In error paths where we call MsgCloseWakeupSems, I need to do the
  33. LocalFree(dataPtr) after the call to MsgCloseWakeupSems. Otherwise,
  34. it access violates because MsgCloseWakeupSems uses the shared date
  35. in the block pointed to by the dataPtr.
  36. 21-Apr-1992 JohnRo
  37. Fixed bug printing a status when message name add fails.
  38. Changed to use FORMAT_ equates throughout.
  39. 18-Feb-1992 ritaw
  40. Convert to Win32 service control APIs.
  41. 18-Jul-1991 danl
  42. Created as a composite of the original LM2,0 routines.
  43. --*/
  44. //
  45. // Includes
  46. //
  47. #include <stdlib.h> // atol
  48. #include "msrv.h" // Messenger prototypes and constants
  49. #include <winsvc.h> // Service control APIs
  50. #include <winsock2.h> // Windows sockets
  51. #include <netdebug.h> // NetpAssert, FORMAT_ equates.
  52. #include <rpc.h> // DataTypes and runtime APIs
  53. #include <msgsvc.h> // generated by the MIDL complier
  54. #include <netlibnt.h> // NetpNtStatusToApiStatus prototypes
  55. #include <tstring.h> // Unicode string macros
  56. #include <string.h> // memcpy
  57. #include <lmwksta.h> // NetWrkstaTransportEnum
  58. #include <lmapibuf.h> // NetApiBufferFree
  59. #include <netlib.h> // UNUSED macro
  60. #include <msgrutil.h> // NetpNetBiosReset
  61. #include <apperr2.h> // APE2_ALERTER_PRINTING_SUCCESS
  62. #include "msgdbg.h" // MSG_LOG
  63. #include "heap.h" // heap management routines and macros.
  64. #include "msgdata.h" // Global data
  65. #include "msgsec.h" // Messenger security information
  66. #include "msgnames.h" // MSGR_INTERFACE_NAME
  67. #include "msgtext.h" // MTXT_MsgsvcTitle
  68. #include "msgsvcsend.h" // Broadcast message send interface
  69. #include "apiutil.h" // for MsgAddSessionInList
  70. // The per net data and heap buffer are allocated once. Later on we may
  71. // wish to keep them separate.
  72. #define BOOKKEEPING_SIZE(n) (n * sizeof(NET_DATA))
  73. #define MAXSEG (0xffff)
  74. #define LMI_PARM_M_SIZMESSBUF TEXT("/sizmessbuf")
  75. //
  76. // Global Data
  77. //
  78. static DWORD bufferSize; // Message buffer size
  79. static DWORD msrv_pid; // pid of message server
  80. extern LPTSTR MessageFileName;
  81. //
  82. // Local Function Prototypes
  83. //
  84. VOID
  85. MsgBufferInit(
  86. IN DWORD dwBufLen
  87. );
  88. NET_API_STATUS
  89. MsgInitSharedData(
  90. DWORD NumNets
  91. );
  92. NET_API_STATUS
  93. MsgSetComputerName(
  94. DWORD NumNets
  95. );
  96. DWORD
  97. MsgGetNumNets(VOID);
  98. NET_API_STATUS
  99. MsgGetBufSize (
  100. OUT LPDWORD bufferSize
  101. );
  102. DWORD
  103. MsgSetUpMessageFile(VOID);
  104. STATIC VOID
  105. MsgInitMessageBoxTitle(
  106. VOID
  107. );
  108. NET_API_STATUS
  109. MsgrInitializeMsgrInternal1(
  110. void
  111. );
  112. NET_API_STATUS
  113. MsgrInitializeMsgrInternal2(
  114. void
  115. );
  116. VOID
  117. MsgInitEndpoint(
  118. PVOID Context // This passed in as context
  119. );
  120. NET_API_STATUS
  121. MsgInitializeMsgr(
  122. IN DWORD argc,
  123. IN LPTSTR *argv
  124. )
  125. /*++
  126. Routine Description:
  127. Registers the control handler with the dispatcher thread. Then it
  128. performs all initialization including the starting of the RPC server.
  129. If any of the initialization fails, MsgStatusUpdate is called so that the
  130. status is updated and the thread is terminated.
  131. Arguments:
  132. Return Value:
  133. --*/
  134. {
  135. NET_API_STATUS status;
  136. DWORD msgrState;
  137. DWORD bufLen;
  138. WSADATA wsaData;
  139. NTSTATUS ntStatus;
  140. //
  141. // Initialize the Thread Manager. This initializes some locks used
  142. // on the Thread and Status databases.
  143. //
  144. status = MsgThreadManagerInit();
  145. if (status != NO_ERROR)
  146. {
  147. MSG_LOG1(ERROR,
  148. "MsgInitializeMsgr: Thread manager init failed %d\n",
  149. status);
  150. return MsgBeginForcedShutdown(IMMEDIATE, status);
  151. }
  152. //
  153. // Initialize the status structure
  154. //
  155. MsgStatusInit();
  156. //
  157. // Register this service with the ControlHandler.
  158. // Now we can accept control requests and be requested to UNINSTALL.
  159. //
  160. MSG_LOG(TRACE, "Calling RegisterServiceCtrlHandlerEx\n",0);
  161. if ((MsgrStatusHandle = RegisterServiceCtrlHandlerEx(
  162. SERVICE_MESSENGER,
  163. MsgrCtrlHandler,
  164. NULL
  165. )) == (SERVICE_STATUS_HANDLE) NULL) {
  166. status = GetLastError();
  167. MSG_LOG(ERROR,
  168. "FAILURE: RegisterServiceCtrlHandlerEx status = " FORMAT_API_STATUS
  169. "\n", status);
  170. return( MsgBeginForcedShutdown (
  171. IMMEDIATE,
  172. status));
  173. }
  174. //
  175. // Notify that installation is pending
  176. //
  177. msgrState = MsgStatusUpdate(STARTING);
  178. if (msgrState != STARTING) {
  179. //
  180. // An UNINSTALL control request must have been received
  181. //
  182. return(msgrState);
  183. }
  184. //
  185. // Init the _HYDRA_ WinStation message support
  186. //
  187. status = MultiUserInitMessage();
  188. if (status != NERR_Success)
  189. {
  190. MSG_LOG(ERROR, "MultiUser Initialization Failed " FORMAT_RPC_STATUS "\n",
  191. status);
  192. return (MsgBeginForcedShutdown(
  193. IMMEDIATE,
  194. status));
  195. }
  196. //
  197. // Check that the workstation is started
  198. //
  199. MSG_LOG(TRACE, "Calling NetServiceControl\n",0);
  200. if (! NetpIsServiceStarted(SERVICE_WORKSTATION)) {
  201. MSG_LOG(ERROR, "WorkStation Service is not started\n",0);
  202. return (MsgBeginForcedShutdown(
  203. IMMEDIATE,
  204. NERR_WkstaNotStarted));
  205. }
  206. // *** INSTALLATION HINT ***
  207. msgrState = MsgStatusUpdate(STARTING);
  208. if (msgrState != STARTING) {
  209. return(msgrState);
  210. }
  211. //
  212. // Get the default buffer size.
  213. //
  214. status = MsgGetBufSize(&bufferSize);
  215. if (status != NERR_Success)
  216. {
  217. MSG_LOG(ERROR, "MsgGetBufSize Failed\n",0);
  218. return (MsgBeginForcedShutdown(
  219. IMMEDIATE,
  220. status));
  221. }
  222. // *** INSTALLATION HINT ***
  223. msgrState = MsgStatusUpdate(STARTING);
  224. if (msgrState != STARTING) {
  225. return(msgrState);
  226. }
  227. if (bufferSize > MAX_SIZMESSBUF || bufferSize < MIN_SIZMESSBUF) {
  228. MSG_LOG(ERROR, "Message Buffer Size is illegal\n",0);
  229. return (MsgBeginForcedShutdown(
  230. IMMEDIATE,
  231. ERROR_INVALID_PARAMETER));
  232. }
  233. //
  234. // This is the size of the buffer (that SDBUFFER points to) in the
  235. // shared data area. This is calculated as:
  236. //
  237. // The size of a message buffer (bufferSize)
  238. // plus
  239. // space for 4 Multi-block message headers and names,
  240. // plus
  241. // space for one Multi-block text header for each text block that
  242. // fits into the message buffer. (bufferSize/TXTMAX).
  243. //
  244. // The number of headers is rounded up by one.
  245. // (bufferSize+TXTMAX-1)/TXTMAX
  246. //
  247. bufferSize += (4 * (sizeof(MBB) + (2 * NCBNAMSZ))) +
  248. ((( (bufferSize+TXTMAX-1)/TXTMAX) + 1) * sizeof(MBT));
  249. // ***** INSTALLATION HINT *****
  250. msgrState = MsgStatusUpdate(STARTING);
  251. if (msgrState != STARTING) {
  252. return(msgrState);
  253. }
  254. //
  255. // Ask the Worksta for the computer name. If the computer
  256. // has no name, then abort.
  257. //
  258. // The computername and the username are in unicode format.
  259. //
  260. // NOTE: the username that is returned is a name we may want to add
  261. // to the table.
  262. //
  263. MSG_LOG(TRACE, "Getting the ComputerName\n",0);
  264. bufLen = sizeof(machineName);
  265. *machineName = TEXT('\0');
  266. if (!GetComputerName(machineName,&bufLen)) {
  267. MSG_LOG(ERROR,"GetComputerName failed \n",0);
  268. status = GetLastError();
  269. }
  270. if ( (status != NERR_Success) ||
  271. (*machineName == TEXT('\0')) || (*machineName == TEXT(' ')))
  272. {
  273. //
  274. // fatal error if no name
  275. //
  276. MSG_LOG(ERROR, "GetWkstaNames Failed\n",0);
  277. return (MsgBeginForcedShutdown(
  278. IMMEDIATE,
  279. NERR_NoComputerName));
  280. }
  281. machineName[NCBNAMSZ] = TEXT('\0'); // make sure it's terminated
  282. MachineNameLen = (SHORT) STRLEN(machineName);
  283. // ***** INSTALLATION HINT *****
  284. msgrState = MsgStatusUpdate(STARTING);
  285. if (msgrState != STARTING)
  286. {
  287. return(msgrState);
  288. }
  289. //
  290. // Initialize the configuration lock. This lock covers the allocation and deallocation
  291. // of the data structures related to lan adapters.
  292. //
  293. if (MsgConfigurationLock(MSG_INITIALIZE,"MsgInitializeMsgr"))
  294. {
  295. //
  296. // Do first phase of lan adapter related configuration
  297. //
  298. status = MsgrInitializeMsgrInternal1();
  299. if (status != NERR_Success)
  300. {
  301. MSG_LOG1(ERROR, "MsgrInitializeMsgrInternal1 Failure %d\n", status);
  302. }
  303. }
  304. else
  305. {
  306. MSG_LOG0(ERROR, "MsgConfigurationLock -- MSG_INITIALIZE failed\n");
  307. status = ERROR_NOT_ENOUGH_MEMORY;
  308. }
  309. if (status != NERR_Success)
  310. {
  311. MsgFreeSharedData();
  312. if (wakeupSem != NULL)
  313. {
  314. MsgFreeSupportSeg();
  315. }
  316. MsgCloseWakeupSems(); // Close the ones that have been created
  317. return (MsgBeginForcedShutdown(
  318. IMMEDIATE,
  319. status));
  320. }
  321. // ***** INSTALLATION HINT *****
  322. msgrState = MsgStatusUpdate(STARTING);
  323. if (msgrState != STARTING)
  324. {
  325. return(msgrState);
  326. }
  327. //
  328. // Change from IMMEDIATE Shutdowns to PENDING shutdowns.
  329. // This is because at this point we have names on the adapters
  330. // to clean up.
  331. //
  332. status = MsgrInitializeMsgrInternal2();
  333. if (status != NERR_Success)
  334. {
  335. MSG_LOG1(ERROR, "MsgrInitializeMsgrInternal2 Failure\n", status);
  336. return (MsgBeginForcedShutdown(
  337. PENDING,
  338. status));
  339. }
  340. //
  341. // Build the name of the file that is to be used to get the
  342. // message header and tail. Don't care about errors, since
  343. // any error will result in the file not being used and is
  344. // resorting to the old standby strings.
  345. //
  346. MSG_LOG(TRACE, "Calling MsgSetUpMessageFile\n",0);
  347. MsgSetUpMessageFile();
  348. //
  349. // Start the Group messenger thread to handle all domain messaging
  350. //
  351. MSG_LOG(TRACE, "Calling MsgInitGroupSupport\n",0);
  352. if ( status = MsgInitGroupSupport( SD_NUMNETS() ) )
  353. {
  354. MSG_LOG(ERROR, "InitGroupSupport Failed\n",0);
  355. return (MsgBeginForcedShutdown(
  356. PENDING,
  357. NERR_GrpMsgProcessor));
  358. }
  359. //
  360. // Initialize the Display Code
  361. //
  362. status = MsgDisplayInit();
  363. if (status != NO_ERROR)
  364. {
  365. MSG_LOG1(ERROR, "Could not initialize the display functions %d\n", status);
  366. return (MsgBeginForcedShutdown(
  367. PENDING,
  368. status));
  369. }
  370. //
  371. // Create the security descriptor that is to be used in access
  372. // checks on the API interface.
  373. //
  374. MSG_LOG(TRACE, "Calling MsgCreateMessageNameObject\n",0);
  375. status = MsgCreateMessageNameObject();
  376. if (status != NERR_Success)
  377. {
  378. MSG_LOG(ERROR, "MsgCreateMessageNameObject (security descriptor) "
  379. "Failed\n", 0);
  380. return (MsgBeginForcedShutdown(
  381. PENDING,
  382. status));
  383. }
  384. //
  385. // Initialize the text for the message box title.
  386. //
  387. MsgInitMessageBoxTitle();
  388. //
  389. // Start the Messengers RPC server.
  390. //
  391. // NOTE: Now all RPC servers in services.exe share the same pipe name.
  392. // However, in order to support communication with version 1.0 of WinNt,
  393. // it is necessary for the Client Pipe name to remain the same as
  394. // it was in version 1.0. Mapping to the new name is performed in
  395. // the Named Pipe File System code.
  396. //
  397. MSG_LOG(TRACE,
  398. "MsgInitializeMsgr:Getting ready to start RPC server\n",0);
  399. status = MsgsvcGlobalData->StartRpcServer(
  400. MSGR_INTERFACE_NAME,
  401. msgsvc_ServerIfHandle);
  402. if (!NT_SUCCESS(status)) {
  403. MSG_LOG(ERROR, "RPC Initialization Failed " FORMAT_RPC_STATUS "\n",
  404. status);
  405. return (MsgBeginForcedShutdown(
  406. PENDING,
  407. status));
  408. }
  409. //
  410. // Start thread to register with endpoint mapper (may take a while)
  411. //
  412. ntStatus = RtlQueueWorkItem(MsgInitEndpoint, // Callback
  413. NULL, // pContext
  414. WT_EXECUTEONLYONCE | // Long one-shot callback
  415. WT_EXECUTELONGFUNCTION);
  416. if (!NT_SUCCESS(ntStatus)) {
  417. MSG_LOG(ERROR, "MsgInit: failed to start endpoint registration thread: %#x\n",
  418. ntStatus);
  419. return (MsgBeginForcedShutdown(
  420. PENDING,
  421. status));
  422. }
  423. // Initialize winsock (needed for name resolution)
  424. //
  425. status = WSAStartup(MAKEWORD(2,1),&wsaData);
  426. if (status != ERROR_SUCCESS) {
  427. MSG_LOG(ERROR, "Initialization of Winsock DLL failed " FORMAT_RPC_STATUS "\n",
  428. status);
  429. return (MsgBeginForcedShutdown(
  430. PENDING,
  431. status));
  432. }
  433. //
  434. // Update the status to indicate that installation is complete.
  435. // Get the current state back in case the ControlHandling thread has
  436. // told us to shutdown.
  437. //
  438. MSG_LOG(TRACE, "Exiting MsgInitializeMsgr - Init Done!\n",0);
  439. return (MsgStatusUpdate(RUNNING));
  440. }
  441. NET_API_STATUS
  442. MsgrInitializeMsgrInternal1(
  443. void
  444. )
  445. /*++
  446. Routine Description:
  447. Initialize volatile state related to lanas.
  448. These initializations can be undone immediately if there is an error.
  449. Arguments:
  450. None
  451. Return Value:
  452. None
  453. --*/
  454. {
  455. DWORD NumNets;
  456. NET_API_STATUS status;
  457. MSG_LOG(TRACE, "Calling MsgGetNumNets\n",0);
  458. NumNets = MsgGetNumNets();
  459. if (NumNets == 0)
  460. {
  461. MSG_LOG(TRACE, "FYI: No lana's enabled at this time\n",0);
  462. // Not having any networks is no longer an error, ie Numnets == 0 is ok
  463. }
  464. //
  465. // Initialize shared memory areas.
  466. //
  467. MSG_LOG(TRACE, "Calling MsgInitSharedData\n",0);
  468. status = MsgInitSharedData(NumNets);
  469. if (status != NERR_Success)
  470. {
  471. return status;
  472. }
  473. //*****************************************
  474. //
  475. // STUFF FROM Init_msrv() in MSRV.C
  476. //
  477. //*****************************************
  478. heap = SD_BUFFER(); // Initialize data heap pointer
  479. heapln = SD_BUFLEN(); // Initialize data heap length
  480. //
  481. // Set up the segement to hold the net bios handles, lana-nums
  482. // and wakeup Semaphores.
  483. //
  484. MSG_LOG(TRACE, "Calling MsgInitSupportSeg\n",0);
  485. status = MsgInitSupportSeg();
  486. if (status != NERR_Success)
  487. {
  488. MSG_LOG(ERROR, "InitSupportSeg Failed\n",0);
  489. return status;
  490. }
  491. //
  492. // Now initialize global net bios handles & lana nums. Initializes net_lana_num[]
  493. //
  494. MSG_LOG(TRACE, "Calling MsgInit_NetBios\n",0);
  495. status = MsgInit_NetBios();
  496. if (status != NERR_Success)
  497. {
  498. MSG_LOG1(ERROR, "MsgInit_NetBios failed %d\n", status);
  499. return status;
  500. }
  501. //
  502. // Get the wake up semaphore handles. Initializes wakeupSem[]
  503. //
  504. MSG_LOG(TRACE, "Calling MsgCreateWakeupSems\n",0);
  505. //
  506. // This always returns TRUE
  507. //
  508. MsgCreateWakeupSems(SD_NUMNETS());
  509. //
  510. // Open NETBIOS for use by messenger.
  511. // If any failures occur beyond this we must remember to close.
  512. //
  513. MsgsvcGlobalData->NetBiosOpen();
  514. //
  515. // Set computer name on adapters - if any
  516. //
  517. MSG_LOG(TRACE, "Calling MsgSetComputerName\n",0);
  518. status = MsgSetComputerName(SD_NUMNETS());
  519. if(status != NERR_Success)
  520. {
  521. MSG_LOG1(ERROR, "SetComputerName failed %d\n", status);
  522. MsgsvcGlobalData->NetBiosClose();
  523. return status;
  524. }
  525. return NERR_Success;
  526. }
  527. NET_API_STATUS
  528. MsgrInitializeMsgrInternal2(
  529. void
  530. )
  531. /*++
  532. Routine Description:
  533. Initialize volatile lana state. These initializations cannot be undone easily. If this routine
  534. fails we must go through a full shutdown in order to clean up.
  535. Arguments:
  536. None
  537. Return Value:
  538. None
  539. --*/
  540. {
  541. //
  542. // Installation is successful and complete. If there is a
  543. // user logged on then an attempt is made to add the user name
  544. // to this message server. No attempt is made at error reporting
  545. // if this fails, there may not be a user logged on, and if there is,
  546. // the user name may already exist as a message name on another
  547. // station.
  548. //
  549. // This is when we add usernames to the message table if we can.
  550. // Sometime this needs to handle multiple users??? (not in version 1)
  551. //
  552. if (g_IsTerminalServer)
  553. {
  554. MsgAddAlreadyLoggedOnUserNames();
  555. }
  556. else
  557. {
  558. MsgAddUserNames();
  559. }
  560. return NERR_Success;
  561. }
  562. VOID
  563. MsgBufferInit(
  564. IN DWORD dwBufLen
  565. )
  566. /*++
  567. Routine Description:
  568. This function is called during initialization to set up
  569. the message buffer in the shared data area.
  570. This function assumes that the shared data area is locked
  571. in memory, that the access semaphore for the shared data
  572. area is set, and that the global far pointer, dataPtr, is
  573. valid. BufferInit() initializes the heap structure of the
  574. buffer.
  575. SIDE EFFECTS
  576. The buffer in shared memory is initialized.
  577. Arguments:
  578. dwBuflen - buffer length
  579. Return Value:
  580. none
  581. --*/
  582. {
  583. LPHEAPHDR hp; // Heap block pointer
  584. hp = (LPHEAPHDR) SD_BUFFER(); // Get the address of buffer
  585. HP_SIZE(*hp) = dwBufLen; // Set the size of the first block
  586. HP_FLAG(*hp) = 0; // Unallocated
  587. SD_BUFLEN() = dwBufLen; // Save the length of the buffer
  588. }
  589. DWORD
  590. MsgInitSharedData(
  591. DWORD NumNets
  592. )
  593. /*++
  594. Routine Description:
  595. This function creates and initializes the shared data area.
  596. It sets up the computer name and initializes the message
  597. buffer.
  598. SIDE EFFECTS
  599. Calls MsgBufferInit().
  600. Arguments:
  601. NumNets - Number of network adapters to support.
  602. Return Value:
  603. RETURN
  604. NERR_Success if the operation was successful
  605. ERROR_NOT_ENOUGH_MEMORY - If the memory alloc for the shared
  606. memory segment fails.
  607. --*/
  608. {
  609. DWORD i,j; // Index
  610. ULONG size;
  611. PNCB_DATA pNcbData;
  612. DWORD MinimumNumNets = ((NumNets == 0)? 1 : NumNets); // 1 is the minimum
  613. //
  614. // Create and initialize shared data area.
  615. //
  616. size = bufferSize + BOOKKEEPING_SIZE(MinimumNumNets);
  617. if ((GlobalData.NetData = (PNET_DATA)LocalAlloc(LMEM_ZEROINIT, size)) == NULL) {
  618. goto NoMemory;
  619. }
  620. //
  621. // In case NumNets = 0, keep 1 dummy NetData.
  622. // This is not very pretty but should avoid any trouble, without having to modify
  623. // too much code.
  624. //
  625. GlobalData.Buffer = (PCHAR) (&GlobalData.NetData[MinimumNumNets]);
  626. for (i = 0; i < NumNets ; i++ )
  627. {
  628. // Allocate the list array at the maximum size, but only allocate
  629. // a small initial number of NCBs.
  630. if ((GlobalData.NetData[i].NcbList =
  631. LocalAlloc(LMEM_ZEROINIT,
  632. sizeof(PNCB_DATA) * NCB_MAX_ENTRIES)) == NULL)
  633. {
  634. goto NoMemory;
  635. }
  636. GlobalData.NetData[i].NumNcbs = NCB_INIT_ENTRIES;
  637. for (j=0; j < NCB_INIT_ENTRIES; j++)
  638. {
  639. if ((GlobalData.NetData[i].NcbList[j] = pNcbData =
  640. (PNCB_DATA) LocalAlloc(LMEM_ZEROINIT,
  641. sizeof(NCB_DATA))) == NULL)
  642. {
  643. goto NoMemory;
  644. }
  645. pNcbData->Ncb.ncb_cmd_cplt = 0xff;
  646. pNcbData->Ncb.ncb_retcode = 0;
  647. }
  648. }
  649. //
  650. // Initialize the shared data lock. The shared data is shared between
  651. // the API threads and the worker threads.
  652. //
  653. if (!MsgDatabaseLock(MSG_INITIALIZE,"InitSharedData"))
  654. {
  655. MSG_LOG0(ERROR,
  656. "MsgInitSharedData: MsgDatabaseLock failed\n");
  657. goto NoMemory;
  658. }
  659. //
  660. // Initialize the "used-to-be shared" data
  661. //
  662. SD_NUMNETS() = NumNets;
  663. SD_MSRV() = 0; // No message server active
  664. SD_LOGNAM()[0] = '\0'; // No log file yet
  665. SD_MESLOG() = 0; // Message logging disabled
  666. SD_MESQF() = INULL; // Message queue is empty
  667. SD_MESQB() = INULL;
  668. for ( j = 0; j < SD_NUMNETS(); j++ )
  669. {
  670. for(i = 0; i < NCBMAX(j); ++i)
  671. {
  672. //
  673. // Mark entries as free
  674. //
  675. SD_NAMEFLAGS(j,i) = NFDEL;
  676. //create empty session lists
  677. InitializeListHead(&(SD_SIDLIST(j,i)));
  678. }
  679. }
  680. //
  681. // Initialize the message buffer
  682. //
  683. MsgBufferInit(bufferSize);
  684. //
  685. // NT NOTE:
  686. // Skip Initializing the Support Set and Wakeup sems.
  687. // Init_msrv will end up doing that.
  688. //
  689. return(NERR_Success);
  690. NoMemory:
  691. MSG_LOG(ERROR,"[MSG]InitSharedData:LocalAlloc Failure "
  692. FORMAT_API_STATUS "\n", GetLastError());
  693. return(ERROR_NOT_ENOUGH_MEMORY);
  694. }
  695. VOID
  696. MsgFreeSharedData(VOID)
  697. {
  698. PNET_DATA pNetData;
  699. PNCB_DATA pNcbData;
  700. DWORD i,j;
  701. if (pNetData = GlobalData.NetData) {
  702. for (i = 0; i < SD_NUMNETS() ; i++, pNetData++ ) {
  703. if (pNetData->NcbList) {
  704. for (j = 0; j < NCBMAX(i) ; j++ ) {
  705. if (pNcbData = GETNCBDATA(i,j)) {
  706. LocalFree(pNcbData);
  707. }
  708. }
  709. LocalFree(pNetData->NcbList);
  710. }
  711. }
  712. LocalFree(GlobalData.NetData);
  713. GlobalData.NetData = NULL;
  714. }
  715. }
  716. NET_API_STATUS
  717. MsgSetComputerName(
  718. IN DWORD NumNets
  719. )
  720. /*++
  721. Routine Description:
  722. This function sets up the shared data area for the computer name
  723. so that it can receive messages.
  724. This function sets things up so that the computer name will be able
  725. to receive messages. First, it adds the user name form of the computer
  726. name to the local adapter. If successful, it then initializes one slot
  727. in the name table in the shared data area: a computer name
  728. receiving messages
  729. SIDE EFFECTS
  730. Locks the init data segment around net bios usage.
  731. Calls the net bios. Makes entries in the shared data area.
  732. Arguments:
  733. NumNets - The number of network adapters that is supported
  734. Return Value:
  735. 0 = success
  736. non-zero = failure
  737. --*/
  738. {
  739. NET_API_STATUS status = NERR_Success;
  740. NCB ncb;
  741. UCHAR res;
  742. DWORD i;
  743. unsigned short j;
  744. struct {
  745. ADAPTER_STATUS AdapterStatus;
  746. NAME_BUFFER NameBuffer[16];
  747. } Astat;
  748. //
  749. // Loop for each net.
  750. //
  751. for ( i = 0; i < NumNets; i++ )
  752. {
  753. // NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW
  754. //
  755. // Reset the adapter
  756. //
  757. MSG_LOG1(TRACE,"Calling NetBiosReset for lana #%d\n",GETNETLANANUM(i));
  758. status = MsgsvcGlobalData->NetBiosReset(GETNETLANANUM(i));
  759. if (status != NERR_Success)
  760. {
  761. MSG_LOG(ERROR,"MsgSetComputerName: NetBiosReset failed "
  762. FORMAT_API_STATUS "\n", status);
  763. MSG_LOG(ERROR,"MsgSetComputerName: AdapterNum " FORMAT_DWORD
  764. "\n",i);
  765. //
  766. // If it fails, skip to the Next Net.
  767. //
  768. continue;
  769. }
  770. //
  771. //
  772. // NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW
  773. //
  774. // Set call name for local adapter
  775. //
  776. clearncb(&ncb);
  777. status = MsgFmtNcbName(ncb.ncb_name, machineName, 3);
  778. if (status != NERR_Success)
  779. {
  780. MSG_LOG1(ERROR, "SetComputerName: Format name failed!", status);
  781. return status;
  782. }
  783. ncb.ncb_command = NCBADDNAME; // Add name (wait)
  784. ncb.ncb_lana_num = GETNETLANANUM(i); // Use the LANMAN adapter
  785. //
  786. // Copy the name
  787. // (At this point the name is ansi - not unicode)
  788. //
  789. memcpy(SD_NAMES(i,0), ncb.ncb_name, NCBNAMSZ);
  790. if (g_IsTerminalServer)
  791. {
  792. MSG_LOG(TRACE,"SetComputerName: Adding session EVERYBODY_SESSION_ID in the list\n",0);
  793. MsgAddSessionInList(&(SD_SIDLIST(i,0)),(ULONG)EVERYBODY_SESSION_ID);
  794. }
  795. MSG_LOG1(TRACE,"MsgSetComputerName: Adding ComputerName to lana #%d\n",
  796. GETNETLANANUM(i));
  797. res = Msgsendncb( &ncb, i);
  798. //
  799. // If the lana is being reinitialized we need to force a reset
  800. //
  801. if ((res & 0xff) == NRC_ENVNOTDEF)
  802. {
  803. MSG_LOG1(TRACE,"SetComputerName: NetBios ADDNAME failed 0x%x - doing reset\n",res);
  804. status = NetpNetBiosReset(GETNETLANANUM(i));
  805. if (status == NERR_Success)
  806. {
  807. //
  808. // rebuild the add name request
  809. //
  810. clearncb(&ncb);
  811. status = MsgFmtNcbName(ncb.ncb_name, machineName, 3);
  812. if (status != NERR_Success)
  813. {
  814. MSG_LOG1(ERROR, "SetComputerName: Format name failed %d!", status);
  815. return status;
  816. }
  817. ncb.ncb_command = NCBADDNAME; // Add name (wait)
  818. ncb.ncb_lana_num = GETNETLANANUM(i); // Use the LANMAN adapter
  819. MSG_LOG1(TRACE,"MsgSetComputerName: Adding ComputerName<03> to lana #%d\n",
  820. GETNETLANANUM(i));
  821. res = Msgsendncb(&ncb, i); // reissue the ncb
  822. }
  823. }
  824. if(res != 0)
  825. {
  826. MSG_LOG1(TRACE,"SetComputerName: NetBios ADDNAME failed 0x%x\n",res);
  827. if((res & 0xff) == NRC_DUPNAME)
  828. {
  829. //
  830. // If the name already exists on the adapter card (the
  831. // workstation may have added it), we want to get the
  832. // name number and pretend that we just added it.
  833. //
  834. // Name already exists. Issue an ASTAT to find the name
  835. // number.
  836. //
  837. clearncb(&ncb);
  838. ncb.ncb_buffer = (char FAR *) &Astat; // Set buffer address
  839. ncb.ncb_length = sizeof(Astat); // Set buffer length
  840. ncb.ncb_callname[0] = '*'; // local adapter status
  841. ncb.ncb_command = NCBASTAT; // Adapter status (wait)
  842. res = Msgsendncb(&ncb,i);
  843. if( res != NRC_GOODRET)
  844. {
  845. //
  846. // Failed to add name
  847. //
  848. MSG_LOG1(ERROR, "SetComputerName:sendncb (ASTAT) failed 0x%x\n", res);
  849. return MsgMapNetError(res);
  850. }
  851. //
  852. // Loop to name number
  853. //
  854. for(j = 0; j< Astat.AdapterStatus.name_count; ++j)
  855. {
  856. if (((Astat.NameBuffer[j].name_flags & 7) == 4)
  857. &&
  858. (memcmp( Astat.NameBuffer[j].name,
  859. SD_NAMES(i,0),
  860. NCBNAMSZ) == 0))
  861. {
  862. break; // Found the name
  863. }
  864. }
  865. if (j == Astat.AdapterStatus.name_count)
  866. {
  867. //
  868. // Failed to find
  869. //
  870. MSG_LOG(ERROR,
  871. "SetComputerName:DupName-failed to find NameNum\n",0);
  872. return NERR_NoComputerName;
  873. }
  874. SD_NAMENUMS(i,0) = Astat.NameBuffer[j].name_num; // Save num
  875. MSG_LOG1(TRACE,"SetComputerName: use existing name num (%d) instead\n",
  876. Astat.NameBuffer[j].name_num);
  877. }
  878. else
  879. {
  880. //
  881. // Fail if name not on the card after the call
  882. //
  883. MSG_LOG(ERROR, "SetComputerName:Name Not on Card. netbios rc = 0x%x\n",res);
  884. return NERR_NoComputerName;
  885. }
  886. }
  887. else
  888. {
  889. SD_NAMENUMS(i,0) = ncb.ncb_num; // Save the name number
  890. }
  891. SD_NAMEFLAGS(i,0) = NFNEW | NFMACHNAME; // Name is new
  892. } // End for all nets
  893. return NERR_Success;
  894. }
  895. DWORD
  896. MsgGetNumNets(VOID)
  897. /*++
  898. Routine Description:
  899. Arguments:
  900. Return Value:
  901. --*/
  902. {
  903. NCB ncb;
  904. LANA_ENUM lanaBuffer;
  905. unsigned char nbStatus;
  906. //
  907. // Find the number of networks by sending an enum request via Netbios.
  908. //
  909. clearncb(&ncb);
  910. ncb.ncb_command = NCBENUM; // Enumerate LANA nums (wait)
  911. ncb.ncb_buffer = (char FAR *)&lanaBuffer;
  912. ncb.ncb_length = sizeof(LANA_ENUM);
  913. nbStatus = Netbios (&ncb);
  914. if (nbStatus != NRC_GOODRET) {
  915. MSG_LOG(ERROR, "GetNumNets:Netbios LanaEnum failed rc="
  916. FORMAT_DWORD "\n", (DWORD) nbStatus);
  917. return(FALSE);
  918. }
  919. return((DWORD)lanaBuffer.length);
  920. #ifdef replaced
  921. LPBYTE transportInfo;
  922. int count=0;
  923. USHORT loopback_found = 0;
  924. NET_API_STATUS status;
  925. DWORD entriesRead;
  926. DWORD totalEntries;
  927. //
  928. // First try and find the networks mananged by the LAN manager
  929. //
  930. // NOTE: This call will fail if there are more than MSNGR_MAX_NETS
  931. // in the machine. This is not a problem unless there are fewer
  932. // than MSNGR_MAX_NETS that would qualify for messaging service.
  933. // In this case, it might be argued that the messenger should start.
  934. // For now, this is not the case. - ERICPE
  935. //
  936. status = NetWkstaTransportEnum (
  937. NULL, // server name (local)
  938. 0, // level
  939. &transportInfo, // bufptr
  940. -1, // preferred maximum length
  941. &entriesRead, // entries read
  942. &totalEntries, // total entries
  943. NULL); // resumeHandle
  944. //
  945. // Free up the buffer that RPC allocated for us.
  946. //
  947. NetApiBufferFree(transportInfo);
  948. if (status != NERR_Success) {
  949. MSG_LOG(ERROR,"GetNumNets:NetWkstaTransportEnum failed "
  950. FORMAT_API_STATUS "\n", status);
  951. return(0);
  952. }
  953. MSG_LOG(TRACE,"GetNumNets: numnets = " FORMAT_DWORD "\n", totalEntries);
  954. return(totalEntries);
  955. #endif
  956. }
  957. NET_API_STATUS
  958. MsgGetBufSize (
  959. OUT LPDWORD bufferSize
  960. )
  961. /*++
  962. Routine Description:
  963. This routine fills in the default buffer size
  964. Arguments:
  965. bufferSize - This is a pointer to where the buffer size is to be stored.
  966. Return Value:
  967. NERR_Success - No errors, the returned bufferSize is valid.
  968. --*/
  969. {
  970. //
  971. // Use the default.
  972. //
  973. *bufferSize = 8192;
  974. return NERR_Success;
  975. }
  976. DWORD
  977. MsgSetUpMessageFile (
  978. VOID
  979. )
  980. /*++
  981. Routine Description:
  982. Builds the name of the message file that is to be used in any
  983. subsequent DosGetMessage calls. The name is built in the Global
  984. variable MessageFileName.
  985. Arguments:
  986. none
  987. Return Value:
  988. NERR_Success - The operation was successful
  989. ERROR_NOT_ENOUGH_MEMORY - Couldn't allocate memory for MessageFileName.
  990. --*/
  991. {
  992. //
  993. // allocate some space for the message file name to be built.
  994. //
  995. MessageFileName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, (MSGFILENAMLEN+sizeof(TCHAR)));
  996. if (MessageFileName == NULL) {
  997. MSG_LOG(ERROR,"[MSG]SetUpMessageFile:LocalAlloc Failure "
  998. FORMAT_API_STATUS "\n", GetLastError());
  999. return(ERROR_NOT_ENOUGH_MEMORY);
  1000. }
  1001. //
  1002. // This message filename (netmsg.dll) is defined in lmcons.h
  1003. //
  1004. STRCPY(MessageFileName,MESSAGE_FILENAME);
  1005. return (NERR_Success);
  1006. }
  1007. STATIC VOID
  1008. MsgInitMessageBoxTitle(
  1009. VOID
  1010. )
  1011. /*++
  1012. Routine Description:
  1013. Obtains the title text for the message box used to display messages.
  1014. If the title is successfully obtained from the message file, then
  1015. that title is pointed to by GlobalAllocatedMsgTitle and
  1016. GlobalMessageBoxTitle. If unsuccessful, then GlobalMessageBoxTitle
  1017. left pointing to the DefaultMessageBoxTitle.
  1018. NOTE: If successful, a buffer is allocated by this function. The
  1019. pointer stored in GlobalAllocatedMsgTitle and it should be freed when
  1020. done with this buffer.
  1021. Arguments:
  1022. Return Value:
  1023. none
  1024. --*/
  1025. {
  1026. LPVOID hModule;
  1027. DWORD msgSize;
  1028. DWORD status=NO_ERROR;
  1029. GlobalAllocatedMsgTitle = NULL;
  1030. hModule = LoadLibrary( L"netmsg.dll");
  1031. if ( hModule == NULL) {
  1032. status = GetLastError();
  1033. MSG_LOG1(ERROR, "LoadLibrary() fails with winError = %d\n", GetLastError());
  1034. return;
  1035. }
  1036. msgSize = FormatMessageW(
  1037. FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
  1038. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  1039. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1040. hModule,
  1041. MTXT_MsgsvcTitle, // MessageId
  1042. 0, // dwLanguageId
  1043. (LPWSTR)&GlobalAllocatedMsgTitle, // lpBuffer
  1044. 0, // nSize
  1045. NULL);
  1046. if (msgSize == 0) {
  1047. status = GetLastError();
  1048. MSG_LOG1(ERROR,"Could not find MessageBox title in a message file %d\n",
  1049. status);
  1050. }
  1051. else {
  1052. GlobalMessageBoxTitle = GlobalAllocatedMsgTitle;
  1053. }
  1054. //
  1055. // Get the messages as Ansi since we'll be comparing them to an
  1056. // Ansi message that comes in from a remote Alerter service.
  1057. //
  1058. msgSize = FormatMessageA(
  1059. FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
  1060. FORMAT_MESSAGE_IGNORE_INSERTS |
  1061. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1062. hModule,
  1063. APE2_ALERTER_PRINTING_SUCCESS, // MessageId
  1064. 0, // dwLanguageId
  1065. (LPSTR) &g_lpAlertSuccessMessage, // lpBuffer
  1066. 0, // nSize
  1067. NULL);
  1068. if (msgSize == 0)
  1069. {
  1070. // No loss -- we just won't be able to filter print success alerts
  1071. status = GetLastError();
  1072. MSG_LOG1(ERROR,
  1073. "Could not find Alerter print success message %d\n",
  1074. status);
  1075. }
  1076. else
  1077. {
  1078. //
  1079. // Trim the message to end after the "Printing Complete" line.
  1080. //
  1081. LPSTR lpTemp = g_lpAlertSuccessMessage;
  1082. g_dwAlertSuccessLen = 0;
  1083. while (*lpTemp && *lpTemp != '\r')
  1084. {
  1085. lpTemp++;
  1086. g_dwAlertSuccessLen++;
  1087. }
  1088. *lpTemp = '\0';
  1089. }
  1090. msgSize = FormatMessageA(
  1091. FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
  1092. FORMAT_MESSAGE_IGNORE_INSERTS |
  1093. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1094. hModule,
  1095. APE2_ALERTER_PRINTING_FAILURE, // MessageId
  1096. 0, // dwLanguageId
  1097. (LPSTR) &g_lpAlertFailureMessage, // lpBuffer
  1098. 0, // nSize
  1099. NULL);
  1100. if (msgSize == 0)
  1101. {
  1102. // No loss -- we just won't be able to filter print success alerts
  1103. status = GetLastError();
  1104. MSG_LOG1(ERROR,
  1105. "Could not find Alerter print failure message %d\n",
  1106. status);
  1107. }
  1108. else
  1109. {
  1110. //
  1111. // Trim the message to end after the "Printing Complete" line.
  1112. //
  1113. LPSTR lpTemp = g_lpAlertFailureMessage;
  1114. g_dwAlertFailureLen = 0;
  1115. while (*lpTemp && *lpTemp != '\r')
  1116. {
  1117. lpTemp++;
  1118. g_dwAlertFailureLen++;
  1119. }
  1120. *lpTemp = '\0';
  1121. }
  1122. FreeLibrary(hModule);
  1123. return;
  1124. }
  1125. VOID
  1126. MsgInitEndpoint(
  1127. PVOID Context // This passed in as context.
  1128. )
  1129. /*++
  1130. Routine Description:
  1131. This function is called to initialize our RPC server entry point. We
  1132. do this in a separate thread because we may have to wait because
  1133. RpcSS is not ready yet.
  1134. Arguments:
  1135. Context - Context parameter
  1136. Return Value:
  1137. None
  1138. --*/
  1139. {
  1140. RPC_BINDING_VECTOR *bindingVector = NULL;
  1141. DWORD status, tries;
  1142. MSG_LOG(TRACE, "MsgInitEndpoint starting in separate thread\n",0);
  1143. //
  1144. // Create endpoint for receiving RPC calls
  1145. // This is for netbiosless notifications
  1146. //
  1147. for( tries = 0; tries < 3; tries++ ) {
  1148. status = RpcServerUseProtseq(
  1149. TEXT("ncadg_ip_udp"),
  1150. RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
  1151. NULL // Do we need an empty SD here?
  1152. );
  1153. if ( (status == RPC_S_OK) || (status == RPC_S_DUPLICATE_ENDPOINT) ) {
  1154. break;
  1155. }
  1156. MSG_LOG(ERROR, "RPC Init (UseProt Udp) Failed "
  1157. FORMAT_RPC_STATUS " - trying again\n", status);
  1158. Sleep( 30 * 1000 );
  1159. }
  1160. if ( (status != RPC_S_OK) && (status != RPC_S_DUPLICATE_ENDPOINT) ) {
  1161. if (status == RPC_S_SERVER_UNAVAILABLE) {
  1162. MSG_LOG( ERROR, "Failed to use UDP, check RPCSS service\n",0 );
  1163. } else {
  1164. MSG_LOG( ERROR, "Failed to use UDP, check TCP/IP\n",0 );
  1165. }
  1166. // give up
  1167. return;
  1168. }
  1169. status = RpcServerInqBindings(
  1170. &bindingVector
  1171. );
  1172. if (status != ERROR_SUCCESS) {
  1173. MSG_LOG( ERROR, "RpcServerInqBindings failed with %d\n",status );
  1174. return;
  1175. }
  1176. // Try to register in a loop in case RPCSS is not running yet
  1177. for( tries = 0; tries < 3; tries++ ) {
  1178. status = RpcEpRegister(
  1179. msgsvcsend_ServerIfHandle,
  1180. bindingVector,
  1181. NULL,
  1182. TEXT("Messenger Service")
  1183. );
  1184. if (status == RPC_S_OK) {
  1185. break;
  1186. }
  1187. MSG_LOG( ERROR, "Msgr: RpcEpRegister failed with %d - trying again\n", status );
  1188. RpcEpUnregister( msgsvcsend_ServerIfHandle,
  1189. bindingVector,
  1190. NULL );
  1191. // ignore error
  1192. Sleep( 10 * 1000 );
  1193. }
  1194. RpcBindingVectorFree( &bindingVector );
  1195. if (status != RPC_S_OK) {
  1196. // give up
  1197. return;
  1198. }
  1199. //
  1200. // Register RPC interface
  1201. //
  1202. status = RpcServerRegisterIf(
  1203. msgsvcsend_ServerIfHandle, // interface to register
  1204. NULL, // MgrTypeUuid
  1205. NULL); // MgrEpv; null means use default
  1206. if (status != RPC_S_OK) {
  1207. MSG_LOG(ERROR, "RPC Init (RegIf MsgSvcSend) Failed "
  1208. FORMAT_RPC_STATUS "\n", status);
  1209. return;
  1210. }
  1211. MSG_LOG(TRACE, "MsgInitEndpoint final status %d\n", status);
  1212. return;
  1213. }