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.

813 lines
20 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. wssend.c
  5. Abstract:
  6. This module contains the worker routines for sending
  7. domain wide and directed messages, which are used to implement
  8. NetMessageBufferSend API.
  9. Author:
  10. Rita Wong (ritaw) 29-July-1991
  11. Revision History:
  12. --*/
  13. #include "wsutil.h"
  14. #include "wsmsg.h"
  15. //-------------------------------------------------------------------//
  16. // //
  17. // Local function prototypes //
  18. // //
  19. //-------------------------------------------------------------------//
  20. STATIC
  21. BOOL
  22. WsVerifySmb(
  23. IN PUCHAR SmbBuffer,
  24. IN WORD SmbBufferSize,
  25. IN UCHAR SmbFunctionCode,
  26. OUT PUCHAR SmbReturnClass,
  27. OUT PUSHORT SmbReturnCode
  28. );
  29. STATIC
  30. NET_API_STATUS
  31. WsMapSmbStatus(
  32. UCHAR SmbReturnClass,
  33. USHORT SmbReturnCode
  34. );
  35. NET_API_STATUS
  36. WsSendToGroup(
  37. IN LPTSTR DomainName,
  38. IN LPTSTR Sender,
  39. IN LPBYTE Message,
  40. IN WORD MessageSize
  41. )
  42. /*++
  43. Routine Description:
  44. This function writes a datagram to the \\DomainName\MAILSLOT\MESSNGR
  45. mailslot which is read by every Messenger service of workstations
  46. that have the domain name as the primary domain. Reception is not
  47. guaranteed.
  48. The DomainName may be a computername. This is acceptable because the
  49. Datagram Receiver listens on the computername (besides the primary domain)
  50. for datagrams. When a computername is specified, the message is sent
  51. to that one computer alone.
  52. Arguments:
  53. DomainName - Supplies the name of the target domain. This actually
  54. can be a computername, in which case, the datagram only reaches
  55. one recipient.
  56. Sender - Supplies the name of the sender.
  57. Return Value:
  58. NET_API_STATUS - NERR_Success or reason for failure.
  59. --*/
  60. {
  61. NET_API_STATUS status = NERR_Success;
  62. HANDLE MessengerMailslot;
  63. DWORD NumberOfBytesWritten;
  64. BYTE MailslotBuffer[MAX_GROUP_MESSAGE_SIZE + MAX_PATH + MAX_PATH + 4];
  65. LPSTR AnsiSender;
  66. LPSTR AnsiReceiver;
  67. LPBYTE CurrentPos;
  68. //
  69. // Canonicalize the domain name
  70. //
  71. status = I_NetNameCanonicalize(
  72. NULL,
  73. DomainName,
  74. DomainName,
  75. (NCBNAMSZ + 2) * sizeof(TCHAR),
  76. NAMETYPE_DOMAIN,
  77. 0
  78. );
  79. if (status != NERR_Success) {
  80. NetpKdPrint(("[Wksta] Error canonicalizing domain name %ws %lu\n",
  81. DomainName, status));
  82. return status;
  83. }
  84. //
  85. // Open \\DomainName\MAILSLOT\MESSNGR mailslot to
  86. // send message to.
  87. //
  88. if ((status = WsOpenDestinationMailslot(
  89. DomainName,
  90. MESSENGER_MAILSLOT_W,
  91. &MessengerMailslot
  92. )) != NERR_Success) {
  93. return status;
  94. }
  95. //
  96. // Package the message to be sent. It consists of:
  97. // Sender (must be ANSI)
  98. // DomainName (must be ANSI)
  99. // Message
  100. //
  101. //
  102. // Convert the names to ANSI
  103. //
  104. AnsiSender = NetpAllocStrFromWStr(Sender);
  105. if (AnsiSender == NULL) {
  106. (void) CloseHandle(MessengerMailslot);
  107. return ERROR_NOT_ENOUGH_MEMORY;
  108. }
  109. AnsiReceiver = NetpAllocStrFromWStr(DomainName);
  110. if (AnsiReceiver == NULL) {
  111. NetApiBufferFree(AnsiSender);
  112. (void) CloseHandle(MessengerMailslot);
  113. return ERROR_NOT_ENOUGH_MEMORY;
  114. }
  115. RtlZeroMemory(MailslotBuffer, sizeof( MailslotBuffer ) );
  116. //
  117. // Copy Sender into mailslot buffer
  118. //
  119. strcpy(MailslotBuffer, AnsiSender);
  120. CurrentPos = MailslotBuffer + strlen(AnsiSender) + 1;
  121. //
  122. // Copy DomainName into mailslot buffer
  123. //
  124. strcpy(CurrentPos, AnsiReceiver);
  125. CurrentPos += (strlen(AnsiReceiver) + 1);
  126. //
  127. // Copy Message into mailslot buffer
  128. //
  129. strncpy(CurrentPos, Message, MessageSize);
  130. CurrentPos += MessageSize;
  131. *CurrentPos = '\0';
  132. //
  133. // Send the datagram to the domain
  134. //
  135. if (WriteFile(
  136. MessengerMailslot,
  137. MailslotBuffer,
  138. (DWORD) (CurrentPos - MailslotBuffer + 1),
  139. &NumberOfBytesWritten,
  140. NULL
  141. ) == FALSE) {
  142. status = GetLastError();
  143. NetpKdPrint(("[Wksta] Error sending datagram to %ws %lu\n",
  144. AnsiReceiver, status));
  145. if (status == ERROR_PATH_NOT_FOUND ||
  146. status == ERROR_BAD_NET_NAME) {
  147. status = NERR_NameNotFound;
  148. }
  149. }
  150. else {
  151. NetpAssert(NumberOfBytesWritten ==
  152. (DWORD) (CurrentPos - MailslotBuffer + 1));
  153. }
  154. NetApiBufferFree(AnsiSender);
  155. NetApiBufferFree(AnsiReceiver);
  156. (void) CloseHandle(MessengerMailslot);
  157. return status;
  158. }
  159. NET_API_STATUS
  160. WsSendMultiBlockBegin(
  161. IN UCHAR LanAdapterNumber,
  162. IN UCHAR SessionNumber,
  163. IN LPTSTR ToName,
  164. IN LPTSTR FromName,
  165. OUT short *MessageId
  166. )
  167. /*++
  168. Routine Description:
  169. This function sends the header of a multi-block directed message on a
  170. session we had established earlier. It waits for an acknowlegement from
  171. the recipient. If the recipient got the message successfully, it
  172. sends back a message group id which is returned by this function for
  173. subsequent use in sending the body and trailer of a multi-block message.
  174. Arguments:
  175. LanAdapterNumber - Supplies the number of the LAN adapter.
  176. SessionNumber - Supplies the session number of a session established with
  177. NetBIOS CALL and LISTEN commands.
  178. ToName - Supplies the name of the recipient.
  179. FromName - Supplies the name of the sender.
  180. MessageId - Returns the message group id.
  181. Return Value:
  182. NET_API_STATUS - NERR_Success or reason for failure.
  183. --*/
  184. {
  185. NET_API_STATUS status;
  186. UCHAR SmbBuffer[WS_SMB_BUFFER_SIZE];
  187. WORD SmbSize;
  188. char SendName[NCBNAMSZ + 1];
  189. UCHAR SmbReturnClass;
  190. USHORT SmbReturnCode;
  191. LPSTR AnsiToName;
  192. LPSTR AnsiFromName;
  193. AnsiToName = NetpAllocStrFromWStr(ToName);
  194. if (AnsiToName == NULL) {
  195. return ERROR_NOT_ENOUGH_MEMORY;
  196. }
  197. AnsiFromName = NetpAllocStrFromWStr(FromName);
  198. if (AnsiFromName == NULL) {
  199. NetApiBufferFree(AnsiToName);
  200. return ERROR_NOT_ENOUGH_MEMORY;
  201. }
  202. strncpy(SendName, AnsiToName, sizeof(SendName) );
  203. SendName[NCBNAMSZ - 1] = '\0'; // Null terminate at max size
  204. //
  205. // Make and send the SMB
  206. //
  207. SmbSize = WsMakeSmb(
  208. SmbBuffer,
  209. SMB_COM_SEND_START_MB_MESSAGE,
  210. 0,
  211. "ss",
  212. AnsiFromName,
  213. SendName
  214. );
  215. NetApiBufferFree(AnsiToName);
  216. NetApiBufferFree(AnsiFromName);
  217. IF_DEBUG(MESSAGE) {
  218. NetpKdPrint(("[Wksta] Send start multi-block message. Size=%u\n",
  219. SmbSize));
  220. #if DBG
  221. NetpHexDump(SmbBuffer, SmbSize);
  222. #endif
  223. }
  224. if ((status = NetpNetBiosSend(
  225. LanAdapterNumber,
  226. SessionNumber,
  227. SmbBuffer,
  228. SmbSize
  229. )) != NERR_Success) {
  230. NetpKdPrint(("[Wksta] Failed to send start of multi-block message %lu\n",
  231. status));
  232. return status;
  233. }
  234. //
  235. // Get response
  236. //
  237. if ((status = NetpNetBiosReceive(
  238. LanAdapterNumber,
  239. SessionNumber,
  240. SmbBuffer,
  241. WS_SMB_BUFFER_SIZE,
  242. (HANDLE) NULL,
  243. &SmbSize
  244. )) != NERR_Success) {
  245. NetpKdPrint(("[Wksta] Failed to receive verification to multi-"
  246. "block message start %lu\n", status));
  247. return status;
  248. }
  249. if (! WsVerifySmb(
  250. SmbBuffer,
  251. SmbSize,
  252. SMB_COM_SEND_START_MB_MESSAGE,
  253. &SmbReturnClass,
  254. &SmbReturnCode
  255. )) {
  256. //
  257. // Unexpected behaviour
  258. //
  259. return NERR_NetworkError;
  260. }
  261. //
  262. // Set the message group id
  263. //
  264. *MessageId = *((UNALIGNED short *) &SmbBuffer[sizeof(SMB_HEADER) + 1]);
  265. IF_DEBUG(MESSAGE) {
  266. NetpKdPrint(("[Wksta] Message Id=x%x\n", *MessageId));
  267. }
  268. return WsMapSmbStatus(SmbReturnClass, SmbReturnCode);
  269. }
  270. NET_API_STATUS
  271. WsSendMultiBlockEnd(
  272. IN UCHAR LanAdapterNumber,
  273. IN UCHAR SessionNumber,
  274. IN short MessageId
  275. )
  276. /*++
  277. Routine Description:
  278. This function sends the end marker of a multi-block directed message on
  279. a session we had establised earlier. It waits for an acknowlegement from
  280. the recipient.
  281. Arguments:
  282. LanAdapterNumber - Supplies the number of the LAN adapter.
  283. SessionNumber - Supplies the session number of a session established with
  284. NetBIOS CALL and LISTEN commands.
  285. MessageId - Supplies the message group id gotten from
  286. WsSendMultiBlockBegin.
  287. Return Value:
  288. NET_API_STATUS - NERR_Success or reason for failure.
  289. --*/
  290. {
  291. NET_API_STATUS status;
  292. UCHAR SmbBuffer[WS_SMB_BUFFER_SIZE];
  293. WORD SmbSize; // Size of SMB data
  294. UCHAR SmbReturnClass;
  295. USHORT SmbReturnCode;
  296. SmbSize = WsMakeSmb(
  297. SmbBuffer,
  298. SMB_COM_SEND_END_MB_MESSAGE,
  299. 1,
  300. "",
  301. MessageId
  302. );
  303. IF_DEBUG(MESSAGE) {
  304. NetpKdPrint(("[Wksta] Send end multi-block message. Size=%u\n",
  305. SmbSize));
  306. #if DBG
  307. NetpHexDump(SmbBuffer, SmbSize);
  308. #endif
  309. }
  310. if ((status = NetpNetBiosSend(
  311. LanAdapterNumber,
  312. SessionNumber,
  313. SmbBuffer,
  314. SmbSize
  315. )) != NERR_Success) {
  316. NetpKdPrint(("[Wksta] Failed to send end of multi-block message %lu\n",
  317. status));
  318. return status;
  319. }
  320. //
  321. // Get response
  322. //
  323. if ((status = NetpNetBiosReceive(
  324. LanAdapterNumber,
  325. SessionNumber,
  326. SmbBuffer,
  327. WS_SMB_BUFFER_SIZE,
  328. (HANDLE) NULL,
  329. &SmbSize
  330. )) != NERR_Success) {
  331. NetpKdPrint(("[Wksta] Failed to receive verification to multi-"
  332. "block message end %lu\n", status));
  333. return status;
  334. }
  335. if (! WsVerifySmb(
  336. SmbBuffer,
  337. SmbSize,
  338. SMB_COM_SEND_END_MB_MESSAGE,
  339. &SmbReturnClass,
  340. &SmbReturnCode
  341. )) {
  342. return NERR_NetworkError; // Unexpected behaviour
  343. }
  344. return WsMapSmbStatus(SmbReturnClass,SmbReturnCode);
  345. }
  346. NET_API_STATUS
  347. WsSendMultiBlockText(
  348. IN UCHAR LanAdapterNumber,
  349. IN UCHAR SessionNumber,
  350. IN PCHAR TextBuffer,
  351. IN WORD TextBufferSize,
  352. IN short MessageId
  353. )
  354. /*++
  355. Routine Description:
  356. This function sends the body of a multi-block directed message on a
  357. session we had established earlier. It waits for an acknowlegement from
  358. the recipient.
  359. Arguments:
  360. LanAdapterNumber - Supplies the number of the LAN adapter.
  361. SessionNumber - Supplies the session number of a session established with
  362. NetBIOS CALL and LISTEN commands.
  363. TextBuffer - Supplies the buffer of the message to be sent.
  364. TextBufferSize - Supplies the size of the message buffer.
  365. MessageId - Supplies the message group id gotten from
  366. WsSendMultiBlockBegin.
  367. Return Value:
  368. NET_API_STATUS - NERR_Success or reason for failure.
  369. --*/
  370. {
  371. NET_API_STATUS status;
  372. UCHAR SmbBuffer[WS_SMB_BUFFER_SIZE];
  373. WORD SmbSize; // Buffer length
  374. UCHAR SmbReturnClass;
  375. USHORT SmbReturnCode;
  376. IF_DEBUG(MESSAGE) {
  377. NetpKdPrint(("[Wksta] Send body multi-block message. Size=%u\n",
  378. TextBufferSize));
  379. }
  380. SmbSize = WsMakeSmb(
  381. SmbBuffer,
  382. SMB_COM_SEND_TEXT_MB_MESSAGE,
  383. 1,
  384. "t",
  385. MessageId,
  386. TextBufferSize,
  387. TextBuffer
  388. );
  389. IF_DEBUG(MESSAGE) {
  390. NetpKdPrint(("[Wksta] SMB for body of multi-block message. Size=%u\n",
  391. SmbSize));
  392. }
  393. if ((status = NetpNetBiosSend(
  394. LanAdapterNumber,
  395. SessionNumber,
  396. SmbBuffer,
  397. SmbSize
  398. )) != NERR_Success) {
  399. NetpKdPrint(("[Wksta] Failed to send body of multi-block message %lu\n",
  400. status));
  401. return status;
  402. }
  403. //
  404. // Get response
  405. //
  406. if ((status = NetpNetBiosReceive(
  407. LanAdapterNumber,
  408. SessionNumber,
  409. SmbBuffer,
  410. WS_SMB_BUFFER_SIZE,
  411. (HANDLE) NULL,
  412. &SmbSize
  413. )) != NERR_Success) {
  414. NetpKdPrint(("[Wksta] Failed to receive verification to multi-"
  415. "block message body %lu\n", status));
  416. return status;
  417. }
  418. if (! WsVerifySmb(
  419. SmbBuffer,
  420. SmbSize,
  421. SMB_COM_SEND_TEXT_MB_MESSAGE,
  422. &SmbReturnClass,
  423. &SmbReturnCode
  424. )) {
  425. return NERR_NetworkError; // Unexpected behaviour
  426. }
  427. return WsMapSmbStatus(SmbReturnClass, SmbReturnCode);
  428. }
  429. NET_API_STATUS
  430. WsSendSingleBlockMessage(
  431. IN UCHAR LanAdapterNumber,
  432. IN UCHAR SessionNumber,
  433. IN LPTSTR ToName,
  434. IN LPTSTR FromName,
  435. IN PCHAR Message,
  436. IN WORD MessageSize
  437. )
  438. /*++
  439. Routine Description:
  440. This function sends a directed message in one SMB on a session we had
  441. established earlier. It waits for an acknowlegement from the recipient.
  442. Arguments:
  443. LanAdapterNumber - Supplies the number of the LAN adapter.
  444. SessionNumber - Supplies the session number of a session established with
  445. NetBIOS CALL and LISTEN commands.
  446. ToName - Supplies the name of the recipient.
  447. FromName - Supplies the name of the sender.
  448. Message - Supplies the buffer of the message to be sent.
  449. MessageSize - Supplies the size of the message.
  450. Return Value:
  451. NET_API_STATUS - NERR_Success or reason for failure.
  452. --*/
  453. {
  454. NET_API_STATUS status;
  455. UCHAR SmbBuffer[WS_SMB_BUFFER_SIZE];
  456. WORD SmbSize; // Buffer length
  457. UCHAR SmbReturnClass;
  458. USHORT SmbReturnCode;
  459. LPSTR AnsiToName;
  460. LPSTR AnsiFromName;
  461. AnsiToName = NetpAllocStrFromWStr(ToName);
  462. if (AnsiToName == NULL) {
  463. return ERROR_NOT_ENOUGH_MEMORY;
  464. }
  465. AnsiFromName = NetpAllocStrFromWStr(FromName);
  466. if (AnsiFromName == NULL) {
  467. NetApiBufferFree(AnsiToName);
  468. return ERROR_NOT_ENOUGH_MEMORY;
  469. }
  470. SmbSize = WsMakeSmb(
  471. SmbBuffer,
  472. SMB_COM_SEND_MESSAGE,
  473. 0,
  474. "sst",
  475. AnsiFromName,
  476. AnsiToName,
  477. MessageSize,
  478. Message
  479. );
  480. NetApiBufferFree(AnsiToName);
  481. NetApiBufferFree(AnsiFromName);
  482. IF_DEBUG(MESSAGE) {
  483. NetpKdPrint(("[Wksta] Send single block message. Size=%u\n", SmbSize));
  484. #if DBG
  485. NetpHexDump(SmbBuffer, SmbSize);
  486. #endif
  487. }
  488. //
  489. // Send SMB
  490. //
  491. if ((status = NetpNetBiosSend(
  492. LanAdapterNumber,
  493. SessionNumber,
  494. SmbBuffer,
  495. SmbSize
  496. )) != NERR_Success) {
  497. NetpKdPrint(("[Wksta] Failed to send single block message %lu\n",
  498. status));
  499. return status;
  500. }
  501. //
  502. // Get response
  503. //
  504. if ((status = NetpNetBiosReceive(
  505. LanAdapterNumber,
  506. SessionNumber,
  507. SmbBuffer,
  508. WS_SMB_BUFFER_SIZE,
  509. (HANDLE) NULL,
  510. &SmbSize
  511. )) != NERR_Success) {
  512. NetpKdPrint(("[Wksta] Failed to receive verification to single"
  513. " block message %lu\n", status));
  514. return status;
  515. }
  516. if (! WsVerifySmb(
  517. SmbBuffer,
  518. SmbSize,
  519. SMB_COM_SEND_MESSAGE,
  520. &SmbReturnClass,
  521. &SmbReturnCode
  522. )) {
  523. return NERR_NetworkError; // Unexpected behaviour
  524. }
  525. return WsMapSmbStatus(SmbReturnClass, SmbReturnCode);
  526. }
  527. STATIC
  528. BOOL
  529. WsVerifySmb(
  530. IN PUCHAR SmbBuffer,
  531. IN WORD SmbBufferSize,
  532. IN UCHAR SmbFunctionCode,
  533. OUT PUCHAR SmbReturnClass,
  534. OUT PUSHORT SmbReturnCode
  535. )
  536. /*++
  537. Routine Description:
  538. This function checks the format of a received SMB; it returns TRUE if
  539. if the SMB format is valid, and FALSE otherwise.
  540. Arguments:
  541. SmbBuffer - Supplies the SMB buffer
  542. SmbBufferSize - Supplies the size of SmbBuffer in bytes
  543. SmbFunctionCode - Supplies the function code for which the SMB is received
  544. to determine the proper SMB format.
  545. SmbReturnClass - Returns the class of the SMB only if the SMB format is
  546. valid.
  547. SmbReturnCode - Returns the error code of the SMB.
  548. Return Value:
  549. TRUE if SMB is valid; FALSE otherwise.
  550. --*/
  551. {
  552. PSMB_HEADER Smb = (PSMB_HEADER) SmbBuffer; // Pointer to SMB header
  553. int SmbCheckCode;
  554. int ParameterCount;
  555. //
  556. // Assume error
  557. //
  558. *SmbReturnClass = (UCHAR) 0xff;
  559. *SmbReturnCode = Smb->Error;
  560. switch (SmbFunctionCode) {
  561. case SMB_COM_SEND_MESSAGE: // Single-block message
  562. case SMB_COM_SEND_TEXT_MB_MESSAGE: // Text of multi-block message
  563. case SMB_COM_SEND_END_MB_MESSAGE: // End of multi-block message
  564. ParameterCount = 0;
  565. break;
  566. case SMB_COM_SEND_START_MB_MESSAGE: // Beginning of multi-block message
  567. ParameterCount = 1;
  568. break;
  569. default: // Unknown SMB
  570. NetpKdPrint(("[Wksta] WsVerifySmb unknown SMB\n"));
  571. return FALSE;
  572. }
  573. if (! (SmbCheckCode = NetpSmbCheck(
  574. SmbBuffer,
  575. SmbBufferSize,
  576. SmbFunctionCode,
  577. ParameterCount,
  578. ""
  579. ))) {
  580. //
  581. // Set the return class if valid SMB
  582. //
  583. *SmbReturnClass = Smb->ErrorClass;
  584. return TRUE;
  585. }
  586. else {
  587. //
  588. // Invalid SMB
  589. //
  590. NetpKdPrint(("[Wksta] WsVerifySmb invalid SMB %d\n", SmbCheckCode));
  591. return FALSE;
  592. }
  593. }
  594. STATIC
  595. NET_API_STATUS
  596. WsMapSmbStatus(
  597. UCHAR SmbReturnClass,
  598. USHORT SmbReturnCode
  599. )
  600. /*++
  601. Routine Description:
  602. This function converts an SMB status to API status.
  603. Arguments:
  604. SmbReturnClass - Supplies the SMB class
  605. SmbReturnCode - Supplies the SMB return code.
  606. Return Value:
  607. NET_API_STATUS - NERR_Success or reason for failure.
  608. --*/
  609. {
  610. switch (SmbReturnClass) {
  611. case SMB_ERR_SUCCESS:
  612. return NERR_Success;
  613. case SMB_ERR_CLASS_SERVER:
  614. //
  615. // SMB error
  616. //
  617. NetpKdPrint(("[Wksta] SMB error SmbReturnCode=%u\n", SmbReturnCode));
  618. if (SmbReturnCode == SMB_ERR_SERVER_PAUSED) {
  619. return NERR_PausedRemote; // Server paused
  620. }
  621. else {
  622. return NERR_BadReceive; // Send not received
  623. }
  624. break;
  625. default:
  626. return NERR_BadReceive;
  627. }
  628. }