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.

653 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. message.c
  5. Abstract:
  6. This module contains the worker routines for the NetMessageBufferSend
  7. API implemented in the Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 29-July-1991
  10. Revision History:
  11. Terence Kwan (terryk) 20-Oct-1993
  12. Initialize the system inside NetrMessageBufferSend for the first send
  13. --*/
  14. #include "wsutil.h"
  15. #include "wsconfig.h" // WsInfo.WsComputerName
  16. #include "wsmsg.h" // Send worker routines
  17. #include "wssec.h" // Security object
  18. #include <lmwksta.h> // NetWkstaUserGetInfo
  19. #include "msgsvcsend.h" // NetrSendMessage interface for internet direct send
  20. STATIC
  21. NET_API_STATUS
  22. WsGetSenderName(
  23. OUT LPTSTR Sender
  24. );
  25. STATIC
  26. DWORD
  27. WsSendInternetMessage(
  28. IN LPTSTR MessageName,
  29. IN LPTSTR To,
  30. IN LPTSTR Sender,
  31. IN LPBYTE Message,
  32. IN DWORD MessageSize
  33. );
  34. STATIC
  35. NET_API_STATUS
  36. WsSendDirectedMessage(
  37. IN LPTSTR To,
  38. IN LPTSTR Sender,
  39. IN LPBYTE Message,
  40. IN DWORD MessageSize
  41. );
  42. NET_API_STATUS
  43. NetrMessageBufferSend (
  44. IN LPTSTR ServerName,
  45. IN LPTSTR MessageName,
  46. IN LPTSTR FromName OPTIONAL,
  47. IN LPBYTE Message,
  48. IN DWORD MessageSize
  49. )
  50. /*++
  51. Routine Description:
  52. This function is the NetMessageBufferSend entry point in the
  53. Workstation service.
  54. Arguments:
  55. ServerName - Supplies the name of server to execute this function
  56. MessageName - Supplies the message alias to send the message to.
  57. FromName - Supplies the message alias of sender. If NULL, the sender
  58. alias will default to the currently logged on user.
  59. Message - Supplies a pointer to the message to send.
  60. MessageSize - Supplies the size of the message in number of bytes.
  61. Return Value:
  62. NET_API_STATUS - NERR_Success or reason for failure.
  63. --*/
  64. {
  65. NET_API_STATUS status;
  66. int i;
  67. TCHAR Sender[UNLEN + 1];
  68. TCHAR To[UNLEN + 1];
  69. LPTSTR Asterix = NULL;
  70. NTSTATUS ntstatus;
  71. UNICODE_STRING UnicodeMessage;
  72. OEM_STRING OemMessage;
  73. static BOOL fInitialize = FALSE;
  74. // Initialize the system if this this the first time.
  75. if ( !fInitialize )
  76. {
  77. if (( ntstatus = WsInitializeMessageSend( TRUE /* first time */)) != NERR_Success )
  78. {
  79. return(ntstatus);
  80. }
  81. fInitialize = TRUE;
  82. }
  83. UNREFERENCED_PARAMETER(ServerName);
  84. IF_DEBUG(MESSAGE) {
  85. NetpKdPrint(("[Wksta] NetMessageBufferSend MessageSize=%lu\n",
  86. MessageSize));
  87. }
  88. //
  89. // Any local user, and domain admins and operators are allowed to
  90. // send messages. Remote users besides domain admins, and operators
  91. // are denied access.
  92. //
  93. if (NetpAccessCheckAndAudit(
  94. WORKSTATION_DISPLAY_NAME, // Subsystem name
  95. (LPTSTR) MESSAGE_SEND_OBJECT, // Object type name
  96. MessageSendSd, // Security descriptor
  97. WKSTA_MESSAGE_SEND, // Desired access
  98. &WsMessageSendMapping // Generic mapping
  99. ) != NERR_Success) {
  100. return ERROR_ACCESS_DENIED;
  101. }
  102. if (! ARGUMENT_PRESENT(FromName)) {
  103. //
  104. // Get the caller's username
  105. //
  106. if ((status = WsGetSenderName(Sender)) != NERR_Success) {
  107. return status;
  108. }
  109. }
  110. else {
  111. //
  112. // Insure we don't overwrite our buffer.
  113. //
  114. if (STRLEN(FromName) > UNLEN) {
  115. STRNCPY(Sender, FromName, UNLEN);
  116. FromName[UNLEN] = TCHAR_EOS;
  117. }
  118. else {
  119. STRCPY(Sender, FromName);
  120. }
  121. }
  122. //
  123. // Convert the Unicode message to OEM character set (very similar
  124. // to ANSI)
  125. //
  126. UnicodeMessage.Buffer = (PWCHAR) Message;
  127. UnicodeMessage.Length = (USHORT) MessageSize;
  128. UnicodeMessage.MaximumLength = (USHORT) MessageSize;
  129. ntstatus = RtlUnicodeStringToOemString(
  130. &OemMessage,
  131. &UnicodeMessage,
  132. TRUE
  133. );
  134. if (! NT_SUCCESS(ntstatus)) {
  135. NetpKdPrint(("[Wksta] NetrMessageBufferSend: RtlUnicodeStringToOemString failed "
  136. FORMAT_NTSTATUS "\n", ntstatus));
  137. return NetpNtStatusToApiStatus(ntstatus);
  138. }
  139. //
  140. // If message name is longer than the maximum name length,
  141. // truncate the name. Since DNLEN is way less than UNLEN,
  142. // this will hold <DomainName*> if need be.
  143. //
  144. if (STRLEN(MessageName) > UNLEN)
  145. {
  146. STRNCPY(To, MessageName, UNLEN);
  147. To[UNLEN] = TCHAR_EOS;
  148. }
  149. else
  150. {
  151. STRCPY(To, MessageName);
  152. }
  153. //
  154. // Remove any trailing blanks from the "To" Name.
  155. //
  156. for (i = STRLEN(To) - 1; i >= 0; i--)
  157. {
  158. if (To[i] != TEXT(' '))
  159. {
  160. To[i + 1] = TEXT('\0');
  161. break;
  162. }
  163. }
  164. //
  165. // Don't allow broadcasts anymore.
  166. //
  167. if (STRNCMP(To, TEXT("*"), 2) == 0)
  168. {
  169. status = ERROR_INVALID_PARAMETER;
  170. goto CleanExit;
  171. }
  172. //
  173. // Send message to a domain. Recipient name should be in the form of
  174. // "DomainName*".
  175. //
  176. Asterix = STRRCHR(To, TCHAR_STAR);
  177. if ((Asterix) && (*(Asterix + 1) == TCHAR_EOS)) {
  178. *Asterix = TCHAR_EOS; // Overwrite trailing '*'
  179. //
  180. // If message size is too long to fit into a mailslot message,
  181. // truncate it.
  182. //
  183. if (OemMessage.Length > MAX_GROUP_MESSAGE_SIZE) {
  184. if ((status = WsSendToGroup(
  185. To,
  186. Sender,
  187. OemMessage.Buffer,
  188. MAX_GROUP_MESSAGE_SIZE
  189. )) == NERR_Success) {
  190. status = NERR_TruncatedBroadcast;
  191. goto CleanExit;
  192. }
  193. } else {
  194. status = WsSendToGroup(
  195. To,
  196. Sender,
  197. OemMessage.Buffer,
  198. (WORD) OemMessage.Length
  199. );
  200. goto CleanExit;
  201. }
  202. }
  203. //
  204. // Send a directed message
  205. //
  206. if (Asterix) {
  207. RtlFreeOemString(&OemMessage);
  208. return NERR_NameNotFound;
  209. }
  210. status = WsSendDirectedMessage(
  211. To,
  212. Sender,
  213. OemMessage.Buffer,
  214. OemMessage.Length
  215. );
  216. //
  217. // If error suggests adapters have changed, reinitialize and try again
  218. //
  219. if (status == NERR_NameNotFound) {
  220. NET_API_STATUS status1;
  221. (void) WsInitializeMessageSend( FALSE /* second time */ );
  222. status1 = WsSendDirectedMessage(
  223. To,
  224. Sender,
  225. OemMessage.Buffer,
  226. OemMessage.Length
  227. );
  228. // If this time we are successful, update final status
  229. if (status1 == NERR_Success) {
  230. status = NERR_Success;
  231. }
  232. }
  233. //
  234. // If error suggests that Netbios could not resolve the name, or is
  235. // not running, try sending an Internet message.
  236. //
  237. if (status == NERR_NameNotFound) {
  238. ntstatus = WsSendInternetMessage(
  239. MessageName,
  240. To,
  241. Sender,
  242. OemMessage.Buffer,
  243. OemMessage.Length );
  244. if (ntstatus == ERROR_SUCCESS) {
  245. status = NERR_Success;
  246. }
  247. }
  248. CleanExit:
  249. RtlFreeOemString(&OemMessage);
  250. return status;
  251. }
  252. STATIC
  253. NET_API_STATUS
  254. WsGetSenderName(
  255. OUT LPTSTR Sender
  256. )
  257. /*++
  258. Routine Description:
  259. This function retrives the username of person who called
  260. NetMessageBufferSend API. If the caller is not logged on, he/she has
  261. no name; in this case, we return the computer name as the sender name.
  262. Arguments:
  263. Sender - Returns the username of the caller of the NetMessageBufferSend
  264. API.
  265. Return Value:
  266. NET_API_STATUS - NERR_Success or reason for failure.
  267. --*/
  268. {
  269. //
  270. // No username, sender is computer name
  271. //
  272. STRCPY(Sender, WsInfo.WsComputerName);
  273. (VOID) I_NetNameCanonicalize(
  274. NULL,
  275. Sender,
  276. Sender,
  277. (UNLEN + 1) * sizeof(TCHAR),
  278. NAMETYPE_MESSAGEDEST,
  279. 0
  280. );
  281. return NERR_Success;
  282. }
  283. STATIC
  284. DWORD
  285. WsSendInternetMessage(
  286. IN LPTSTR MessageName,
  287. IN LPTSTR To,
  288. IN LPTSTR Sender,
  289. IN LPBYTE Message,
  290. IN DWORD MessageSize
  291. )
  292. /*++
  293. Routine Description:
  294. This routine sends the message to the computer specified by the MessageName. Note that the
  295. MessageName must be resolvable using "gethostbyname", that is usernames or other general
  296. net names are not supported for this type of send.
  297. Arguments:
  298. MessageName - The target name
  299. To - Target name truncated to 16 characters
  300. Sender - Sending computer name
  301. Message -
  302. MessageSize -
  303. Return Value:
  304. DWORD -
  305. --*/
  306. {
  307. DWORD status;
  308. LPSTR ansiTo = NULL;
  309. LPSTR ansiSender = NULL;
  310. LPSTR newMessage = NULL;
  311. LPTSTR pszStringBinding = NULL;
  312. RPC_BINDING_HANDLE hRpcBinding = NULL;
  313. IF_DEBUG( MESSAGE )
  314. NetpKdPrint(("[Wksta] WsSendInternet: enter, To %ws Sender %ws\n", To, Sender));
  315. // Convert arguments to ansi
  316. ansiTo = NetpAllocStrFromWStr( To );
  317. if (ansiTo == NULL) {
  318. IF_DEBUG( MESSAGE )
  319. NetpKdPrint(("[Wksta] WsSendInternet: alloc to failed\n"));
  320. status = ERROR_NOT_ENOUGH_MEMORY;
  321. goto release;
  322. }
  323. ansiSender = NetpAllocStrFromWStr( Sender );
  324. if (ansiSender == NULL) {
  325. IF_DEBUG( MESSAGE )
  326. NetpKdPrint(("[Wksta] WsSendInternet: alloc sender failed\n"));
  327. status = ERROR_NOT_ENOUGH_MEMORY;
  328. goto release;
  329. }
  330. newMessage = LocalAlloc( LMEM_FIXED, MessageSize + 1 );
  331. if (newMessage == NULL) {
  332. IF_DEBUG( MESSAGE )
  333. NetpKdPrint(("[Wksta] WsSendInternet: alloc message failed\n"));
  334. status = ERROR_NOT_ENOUGH_MEMORY;
  335. goto release;
  336. }
  337. memcpy( newMessage, Message, MessageSize );
  338. newMessage[MessageSize] = '\0';
  339. // Treat the To argument as a computer name and try to bind
  340. // Specify NULL endpoing, meaning bind to dynamic endpoint at call-time.
  341. status = RpcStringBindingCompose( NULL, // UUID
  342. TEXT("ncadg_ip_udp"), // pszProtocolSequence,
  343. MessageName, // pszNetworkAddress,
  344. NULL, // pszEndpoint,
  345. NULL, // Options
  346. &pszStringBinding);
  347. if (status != ERROR_SUCCESS) {
  348. IF_DEBUG( MESSAGE )
  349. NetpKdPrint(("[Wksta] WsSendInternet: RpcStringBindingCompose failure: "
  350. FORMAT_NTSTATUS "\n", status));
  351. goto release;
  352. }
  353. status = RpcBindingFromStringBinding(pszStringBinding, &hRpcBinding);
  354. if (status != ERROR_SUCCESS) {
  355. IF_DEBUG( MESSAGE )
  356. NetpKdPrint(("[Wksta] WsSendInternet: RpcBindingFromStringBinding failure: "
  357. FORMAT_NTSTATUS "\n", status));
  358. goto release;
  359. }
  360. status = NetrSendMessage( hRpcBinding, ansiSender, ansiTo, newMessage );
  361. if (status != ERROR_SUCCESS) {
  362. IF_DEBUG( MESSAGE ) {
  363. NetpKdPrint(("[Wksta] WsSendInternet: NetrSendMessage failure: "
  364. FORMAT_NTSTATUS "\n", status));
  365. }
  366. }
  367. release:
  368. if (ansiTo != NULL)
  369. NetApiBufferFree( ansiTo );
  370. if (ansiSender != NULL)
  371. NetApiBufferFree( ansiSender );
  372. if (newMessage != NULL)
  373. LocalFree( newMessage );
  374. if (pszStringBinding != NULL) {
  375. RpcStringFree( &pszStringBinding ); // remote calls done; unbind
  376. }
  377. if (hRpcBinding != NULL) {
  378. RpcBindingFree( &hRpcBinding ); // remote calls done; unbind
  379. }
  380. IF_DEBUG( MESSAGE ) {
  381. NetpKdPrint(("[Wksta] WsSendInternet: exit, ntstatus= %d\n", status));
  382. }
  383. return status;
  384. } /* WsSendInternetMessage */
  385. STATIC
  386. NET_API_STATUS
  387. WsSendDirectedMessage(
  388. IN LPTSTR To,
  389. IN LPTSTR Sender,
  390. IN LPBYTE Message,
  391. IN DWORD MessageSize
  392. )
  393. /*++
  394. Routine Description:
  395. This function sends the specified message as a directed message
  396. to the specified recipient. A call to the recipient is sent
  397. out on each LAN adapter. If there is no response we try the
  398. next LAN adapter until we hear from the targeted recipient.
  399. Arguments:
  400. To - Supplies the message alias of the recipient.
  401. Sender - Supplies the message alias of sender.
  402. Message - Supplies a pointer to the message to send.
  403. MessageSize - Supplies the size of the message in number of bytes.
  404. Return Value:
  405. NET_API_STATUS - NERR_Success or reason for failure.
  406. --*/
  407. {
  408. NET_API_STATUS status = NERR_NameNotFound;
  409. UCHAR i;
  410. BOOL NameFound = FALSE;
  411. UCHAR SessionNumber;
  412. short MessageId;
  413. //
  414. // Try each network until someone answers the call. Only the first name
  415. // found will receive the message. The same name on any other network
  416. // will never see the message. This is to remain consistent with all
  417. // other session based algorithms in LAN Man.
  418. //
  419. for (i = 0; i < WsNetworkInfo.LanAdapterNumbers.length; i++) {
  420. //
  421. // Attempt to establish a session
  422. //
  423. if ((status = NetpNetBiosCall(
  424. WsNetworkInfo.LanAdapterNumbers.lana[i],
  425. To,
  426. Sender,
  427. &SessionNumber
  428. )) == NERR_Success) {
  429. NameFound = TRUE;
  430. IF_DEBUG(MESSAGE) {
  431. NetpKdPrint(("[Wksta] Successfully called %ws\n", To));
  432. }
  433. if (MessageSize <= MAX_SINGLE_MESSAGE_SIZE) {
  434. //
  435. // Send single block message if possible
  436. //
  437. status = WsSendSingleBlockMessage(
  438. WsNetworkInfo.LanAdapterNumbers.lana[i],
  439. SessionNumber,
  440. To,
  441. Sender,
  442. Message,
  443. (WORD) MessageSize
  444. );
  445. }
  446. else {
  447. //
  448. // Message too long, got to send multi-block message
  449. //
  450. //
  451. // Send the begin message
  452. //
  453. if ((status = WsSendMultiBlockBegin(
  454. WsNetworkInfo.LanAdapterNumbers.lana[i],
  455. SessionNumber,
  456. To,
  457. Sender,
  458. &MessageId
  459. )) == NERR_Success) {
  460. //
  461. // Send the body of the message in as many blocks as necessary
  462. //
  463. for (; MessageSize > MAX_SINGLE_MESSAGE_SIZE;
  464. Message += MAX_SINGLE_MESSAGE_SIZE,
  465. MessageSize -= MAX_SINGLE_MESSAGE_SIZE) {
  466. if ((status = WsSendMultiBlockText(
  467. WsNetworkInfo.LanAdapterNumbers.lana[i],
  468. SessionNumber,
  469. Message,
  470. MAX_SINGLE_MESSAGE_SIZE,
  471. MessageId
  472. )) != NERR_Success) {
  473. break;
  474. }
  475. }
  476. if (status == NERR_Success && MessageSize > 0) {
  477. //
  478. // Send the remaining message body
  479. //
  480. status = WsSendMultiBlockText(
  481. WsNetworkInfo.LanAdapterNumbers.lana[i],
  482. SessionNumber,
  483. Message,
  484. (WORD) MessageSize,
  485. MessageId
  486. );
  487. }
  488. //
  489. // Send the end message
  490. //
  491. if (status == NERR_Success) {
  492. status = WsSendMultiBlockEnd(
  493. WsNetworkInfo.LanAdapterNumbers.lana[i],
  494. SessionNumber,
  495. MessageId
  496. );
  497. }
  498. }
  499. }
  500. (VOID) NetpNetBiosHangup(
  501. WsNetworkInfo.LanAdapterNumbers.lana[i],
  502. SessionNumber
  503. );
  504. } // Call successful
  505. if (NameFound) {
  506. break;
  507. }
  508. }
  509. return status;
  510. }