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.

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