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.

657 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. apiutil.c
  5. Abstract:
  6. Contains functions used by the Messenger API. This file contains the
  7. following functions:
  8. MsgIsValidMsgName
  9. MsgMapNetError
  10. MsgLookupName
  11. message_sec_check
  12. MsgGatherInfo
  13. MsgUnformatName
  14. MsgLookupNameForThisSession
  15. MsgIsSessionInList (HYDRA specific)
  16. MsgAddSessionInList (HYDRA specific)
  17. MsgRemoveSessionFromList (HYDRA specific)
  18. Author:
  19. Dan Lafferty (danl) 22-Jul-1991
  20. Environment:
  21. User Mode -Win32
  22. Notes:
  23. These functions were ported from LM2.0. This file contains functions
  24. from several LM2.0 files. Not all functions were used in this file
  25. since some were made obsolete by the NT Service Model.
  26. The following LM2.0 files were incorportated into this single file:
  27. msgutils.c
  28. msgutil2.c
  29. dupname.c
  30. netname.c
  31. Revision History:
  32. 22-Jul-1991 danl
  33. ported from LM2.0
  34. --*/
  35. //
  36. // Includes
  37. //
  38. #include "msrv.h"
  39. #include <tstring.h> // Unicode string macros
  40. #include <lmwksta.h>
  41. #include <lmmsg.h>
  42. #include <smbtypes.h> // needed for smb.h
  43. #include <smb.h> // Server Message Block definitions
  44. #include <icanon.h> // I_NetNameValidate
  45. #include <netlib.h> // NetpCopyStringToBuffer
  46. #include "msgdbg.h" // MSG_LOG
  47. #include "heap.h"
  48. #include "msgdata.h"
  49. #include "apiutil.h"
  50. //
  51. // Table of NetBios mappings to Net Errors.
  52. //
  53. DWORD const mpnetmes[] =
  54. {
  55. 0x23, // 00 Number of messages
  56. NERR_NetworkError, // 01 NRC_BUFLEN -> invalid length
  57. 0xffffffff, // 02 NRC_BFULL , not expected
  58. NERR_NetworkError, // 03 NRC_ILLCMD -> invalid command
  59. 0xffffffff, // 04 not defined
  60. NERR_NetworkError, // 05 NRC_CMDTMO -> network busy
  61. NERR_NetworkError, // 06 NRC_INCOMP -> messgae incomplete
  62. 0xffffffff, // 07 NRC_BADDR , not expected
  63. NERR_NetworkError, // 08 NRC_SNUMOUT -> bad session
  64. NERR_NoNetworkResource, // 09 NRC_NORES -> network busy
  65. NERR_NetworkError, // 0a NRC_SCLOSED -> session closed
  66. NERR_NetworkError, // 0b NRC_CMDCAN -> command cancelled
  67. 0xffffffff, // 0c NRC_DMAFAIL, unexpected
  68. NERR_AlreadyExists, // 0d NRC_DUPNAME -> already exists
  69. NERR_TooManyNames, // 0e NRC_NAMTFUL -> too many names
  70. NERR_DeleteLater, // 0f NRC_ACTSES -> delete later
  71. 0xffffffff, // 10 NRC_INVALID , unexpected
  72. NERR_NetworkError, // 11 NRC_LOCTFUL -> too many sessions
  73. ERROR_REM_NOT_LIST, // 12 NRC_REMTFUL -> remote not listening*/
  74. NERR_NetworkError, // 13 NRC_ILLNN -> bad name
  75. NERR_NameNotFound, // 14 NRC_NOCALL -> name not found
  76. ERROR_INVALID_PARAMETER, // 15 NRC_NOWILD -> bad parameter
  77. NERR_DuplicateName, // 16 NRC_INUSE -> name in use, retry
  78. ERROR_INVALID_PARAMETER, // 17 NRC_NAMERR -> bad parameter
  79. NERR_NetworkError, // 18 NRC_SABORT -> session ended
  80. NERR_DuplicateName, // 19 NRC_NAMCONF -> duplicate name
  81. 0xffffffff, // 1a not defined
  82. 0xffffffff, // 1b not defined
  83. 0xffffffff, // 1c not defined
  84. 0xffffffff, // 1d not defined
  85. 0xffffffff, // 1e not defined
  86. 0xffffffff, // 1f not defined
  87. 0xffffffff, // 20 not defined
  88. NERR_NetworkError, // 21 NRC_IFBUSY -> network busy
  89. NERR_NetworkError, // 22 NRC_TOOMANY -> retry later
  90. NERR_NetworkError // 23 NRC_BRIDGE -> bridge error
  91. };
  92. DWORD
  93. MsgIsValidMsgName(
  94. IN LPTSTR name
  95. )
  96. /*++
  97. Routine Description:
  98. Check for a valid messaging name.
  99. This function checks for the validity of a messaging name.
  100. Arguments:
  101. name - pointer to name to validate.
  102. Return Value:
  103. Error code from I_NetNameValidate
  104. --*/
  105. {
  106. TCHAR namebuf[NCBNAMSZ];
  107. DWORD err_code;
  108. //
  109. // Message names cannot be larger than (NCBNAMSZ - 1) characters
  110. //
  111. if (STRLEN(name) > (NCBNAMSZ - 1))
  112. {
  113. return ERROR_INVALID_PARAMETER;
  114. }
  115. STRCPY(namebuf, name);
  116. err_code = I_NetNameValidate(NULL, namebuf, NAMETYPE_COMPUTER, 0L);
  117. if (err_code != 0)
  118. {
  119. return err_code;
  120. }
  121. //
  122. // Any name beginning with a * must be rejected as the message
  123. // server relies on being able to ASTAT the name, and an ASTAT
  124. // name commencing with a * means ASTAT the local card.
  125. //
  126. if(namebuf[0] == TEXT('*'))
  127. {
  128. return ERROR_INVALID_PARAMETER;
  129. }
  130. return NERR_Success;
  131. }
  132. DWORD
  133. MsgMapNetError(
  134. IN UCHAR Code // Error code
  135. )
  136. /*++
  137. Routine Description:
  138. Map NetBios Error code to a message number
  139. Arguments:
  140. code - Error code from NetBios (can be 0)
  141. Return Value:
  142. Message code as defined in msgs.h
  143. --*/
  144. {
  145. DWORD dwCode;
  146. dwCode = 0 | (UCHAR)Code;
  147. if( dwCode == 0) {
  148. return(NERR_Success); // Special case
  149. }
  150. if((dwCode > 0) && (dwCode < mpnetmes[0])) {
  151. return(mpnetmes[dwCode]);
  152. }
  153. return (NERR_NetworkError); // Can't map it!
  154. }
  155. DWORD
  156. MsgLookupName(
  157. IN DWORD net, // The network card to search
  158. IN LPSTR name // Formatted name (Non-unicode)
  159. )
  160. /*++
  161. Routine Description:
  162. This function looks up a formatted name in the name table in the
  163. Message Server's shared data area.
  164. This function looks the given name up in the name table in the shared
  165. data area. In order to match the given name, the first NCBNAMLEN - 1
  166. characters of the name in the name table must be identical to the same
  167. characters in the given name, and the name in the name table must not be
  168. marked as deleted. This function assumes that the shared data area is
  169. accessible and that the global variable, dataPtr, is valid.
  170. Arguments:
  171. name - pointer to formatted name
  172. Return Value:
  173. DWORD - index into table if found, -1 otherwise
  174. --*/
  175. {
  176. DWORD i; // Index
  177. for(i = 0; i < NCBMAX(net); ++i) { // Loop to search for name
  178. if( !memcmp( name, SD_NAMES(net,i), NCBNAMSZ - 1) &&
  179. !(SD_NAMEFLAGS(net,i) & NFDEL) ) {
  180. //
  181. // Return index if match found
  182. //
  183. return(i);
  184. }
  185. }
  186. return(0xffffffff); // No match
  187. }
  188. // For HYDRA, we want to make sure that the name exists for THIS client session.
  189. DWORD
  190. MsgLookupNameForThisSession(
  191. IN DWORD net, // The network card to search
  192. IN LPSTR name, // Formatted name to loook for (Non-unicode)
  193. IN ULONG SessionId // Session Id to look for
  194. )
  195. /*++
  196. Routine Description:
  197. Same as MsgLookupName except that we care about the session Id.
  198. This function looks up a formatted name in the name table in the
  199. Message Server's shared data area. The name found must have the
  200. requested SessionId in its session list to be considered as OK.
  201. Arguments:
  202. name - pointer to formatted name
  203. SessionId - the requested Session Id
  204. Return Value:
  205. DWORD - index into table if found, -1 otherwise
  206. --*/
  207. {
  208. DWORD i; // Index
  209. DWORD dwMsgrState; // messanger state
  210. if (!g_IsTerminalServer) // regular NT case
  211. {
  212. //
  213. // if we are not on HYDRA, forget the SessionId
  214. //
  215. return MsgLookupName(net, name);
  216. }
  217. else // HYDRA case
  218. {
  219. //
  220. // dont try to access table if messanger stop is pending,
  221. // we may not have GlobalData available
  222. //
  223. dwMsgrState = GetMsgrState();
  224. if (RUNNING == dwMsgrState)
  225. {
  226. for(i = 0; i < NCBMAX(net); ++i) { // Loop to search for name
  227. if( !memcmp( name, SD_NAMES(net,i), NCBNAMSZ - 1) &&
  228. !(SD_NAMEFLAGS(net,i) & NFDEL) &&
  229. (MsgIsSessionInList(&(SD_SIDLIST(net,i)), SessionId ))
  230. ) {
  231. return (i);
  232. }
  233. }
  234. }
  235. return(0xffffffff); // No match
  236. }
  237. }
  238. // message_sec_check
  239. //
  240. // A common routine to check caller priv/auth against that
  241. // required to call the message apis.
  242. //
  243. //
  244. NET_API_STATUS
  245. message_sec_check(VOID)
  246. {
  247. #ifdef later
  248. //
  249. // API security check. This call can be called by anyone locally,
  250. // but only by admins in the remote case.
  251. I_SecSyncSet(SECSYNC_READER);
  252. if ( ( clevel == ACCESS_REMOTE ) &&
  253. ( callinf != NULL ) &&
  254. ( CALLER_PRIV(callinf) != USER_PRIV_ADMIN ) )
  255. {
  256. I_SecSyncClear(SECSYNC_READER);
  257. return(ERROR_ACCESS_DENIED);
  258. }
  259. I_SecSyncClear(SECSYNC_READER);
  260. #endif
  261. return (NERR_Success);
  262. }
  263. NET_API_STATUS
  264. MsgGatherInfo (
  265. IN DWORD Level,
  266. IN LPSTR FormattedName,
  267. IN OUT LPBYTE *InfoBufPtr,
  268. IN OUT LPBYTE *StringBufPtr
  269. )
  270. /*++
  271. Routine Description:
  272. Arguments:
  273. Level - Indicates the level of information that is being returned.
  274. FormattedName - This is a name that messages are received by. This
  275. name is formated for NCB transactions. Therefore, it is made
  276. up of ANSI characters that are space padded to fill out a packet
  277. of NCBNAMSZ characters. The last character is always a 03
  278. (indicating a non-forwarded name).
  279. InfoBufPtr - On input, this is a pointer to a pointer to where the
  280. messenger information is to be placed. On successful return, this
  281. location contains a pointer to the location where the next
  282. information will be placed (on the next call to this function).
  283. StringBufPtr - On input, thisis a pointer to a pointer to where the
  284. NUL terminated name string for that info record is to be placed.
  285. On successful return, this location contains a pointer to the
  286. location where the next set of strings will be placed (on the
  287. next call to this function).
  288. Return Value:
  289. NERR_Success - The information was successfully gathered and placed
  290. in the info buffer.
  291. NERR_Internal_Error - The Formatted Name could not be correctly
  292. translated into a meaningful Unicode Name.
  293. ERROR_INVALID_LEVEL - An illegal info level was passed in.
  294. ERROR_NOT_ENOUGH_MEMORY - Not enough room to store gathered information.
  295. --*/
  296. {
  297. NET_API_STATUS status;
  298. BOOL bStatus;
  299. PCHAR fixedDataEnd; // pointer to free space from top of buffer.
  300. LPMSG_INFO_0 infoBuf0;
  301. LPMSG_INFO_1 infoBuf1;
  302. TCHAR unicodeName[NCBNAMSZ];
  303. //
  304. // Convert the name to Unicode
  305. //
  306. status = MsgUnformatName(unicodeName, FormattedName);
  307. if (status != NERR_Success) {
  308. return(status);
  309. }
  310. switch (Level) {
  311. case LEVEL_0:
  312. infoBuf0 = (LPMSG_INFO_0)*InfoBufPtr;
  313. fixedDataEnd = (PCHAR)infoBuf0 + sizeof(MSG_INFO_0);
  314. if( fixedDataEnd >= *StringBufPtr) {
  315. return(ERROR_NOT_ENOUGH_MEMORY);
  316. }
  317. bStatus = NetpCopyStringToBuffer (
  318. unicodeName, // The String
  319. STRLEN(unicodeName), // StringLength
  320. fixedDataEnd, // FixedDataEnd
  321. (PVOID)StringBufPtr, // EndOfVariableData
  322. &infoBuf0->msgi0_name); // VariableDataPointer
  323. if (bStatus == FALSE) {
  324. MSG_LOG(TRACE,"MsgGatherInfo(level0): Not enough room\n",0);
  325. return(ERROR_NOT_ENOUGH_MEMORY);
  326. }
  327. *InfoBufPtr = (LPBYTE)fixedDataEnd;
  328. break;
  329. case LEVEL_1:
  330. infoBuf1 = (LPMSG_INFO_1)*InfoBufPtr;
  331. fixedDataEnd = (PCHAR)infoBuf1 + sizeof(MSG_INFO_1);
  332. if( fixedDataEnd >= *StringBufPtr) {
  333. return(ERROR_NOT_ENOUGH_MEMORY);
  334. }
  335. bStatus = NetpCopyStringToBuffer (
  336. unicodeName, // The String
  337. STRLEN(unicodeName), // StringLength
  338. fixedDataEnd, // FixedDataEnd
  339. (PVOID)StringBufPtr, // EndOfVariableData
  340. &infoBuf1->msgi1_name); // VariableDataPointer
  341. if (bStatus == FALSE) {
  342. MSG_LOG(TRACE,"MsgGatherInfo(level1): Not enough room\n",0);
  343. return(ERROR_NOT_ENOUGH_MEMORY);
  344. }
  345. //
  346. // Set all the forward information to NULL since forwarding
  347. // is not supported.
  348. //
  349. infoBuf1->msgi1_forward_flag = 0;
  350. infoBuf1->msgi1_forward = NULL;
  351. *InfoBufPtr = (LPBYTE)fixedDataEnd;
  352. break;
  353. default:
  354. MSG_LOG(TRACE,"MsgGatherInfo Invalid level\n",0);
  355. return(ERROR_INVALID_LEVEL);
  356. break;
  357. }
  358. return(NERR_Success);
  359. }
  360. NET_API_STATUS
  361. MsgUnformatName(
  362. OUT LPTSTR UnicodeName,
  363. IN LPSTR FormattedName
  364. )
  365. /*++
  366. Routine Description:
  367. This routine creates a Unicode NUL-Terminated version of a NetBios
  368. Formatted name.
  369. Arguments:
  370. UnicodeName - This is a pointer to a location where the un-formatted
  371. NUL terminated Unicode Name is to be copied.
  372. FormattedName - This is a pointer to an NCB formatted name. This
  373. name always contains NCBNAMSZ characters of which the last character
  374. is a code used for a forward/non-forward flag. These strings
  375. are space padded.
  376. Return Value:
  377. NERR_Success - The operation was successful.
  378. NERR_Internal - The operation was unsuccessful.
  379. --*/
  380. {
  381. UNICODE_STRING unicodeString;
  382. OEM_STRING ansiString;
  383. NTSTATUS ntStatus;
  384. int i;
  385. //
  386. // Translate the ansi string in the name table to a unicode name
  387. //
  388. #ifdef UNICODE
  389. unicodeString.Length = (NCBNAMSZ -1) * sizeof(WCHAR);
  390. unicodeString.MaximumLength = NCBNAMSZ * sizeof(WCHAR);
  391. unicodeString.Buffer = (LPWSTR)UnicodeName;
  392. ansiString.Length = NCBNAMSZ-1;
  393. ansiString.MaximumLength = NCBNAMSZ;
  394. ansiString.Buffer = FormattedName;
  395. ntStatus = RtlOemStringToUnicodeString(
  396. &unicodeString, // Destination
  397. &ansiString, // Source
  398. FALSE); // Don't allocate the destination.
  399. if (!NT_SUCCESS(ntStatus)) {
  400. MSG_LOG(ERROR,
  401. "UnformatName:RtlOemStringToUnicodeString Failed rc=%X\n",
  402. ntStatus);
  403. //
  404. // Indicate a failure
  405. //
  406. return(NERR_InternalError);
  407. }
  408. #else
  409. UNUSED (ntStatus);
  410. UNUSED (ansiString);
  411. UNUSED (unicodeString);
  412. strncpy(UnicodeName, FormattedName, NCBNAMSZ-1);
  413. #endif
  414. //
  415. // Remove excess Space characters starting at the back (skipping
  416. // the 03 flag character.
  417. //
  418. i = NCBNAMSZ-2;
  419. while ( UnicodeName[i] == TEXT(' ')) {
  420. UnicodeName[i--] = TEXT('\0');
  421. if (i < 0) {
  422. MSG_LOG(ERROR,
  423. "UnformatName:Nothing but space characters\n",0);
  424. return(NERR_InternalError);
  425. }
  426. }
  427. return(NERR_Success);
  428. }
  429. BOOL
  430. MsgIsSessionInList(
  431. IN PLIST_ENTRY SessionIdList,
  432. IN ULONG SessionId
  433. )
  434. {
  435. BOOL bRet = FALSE;
  436. PLIST_ENTRY pList = SessionIdList;
  437. PMSG_SESSION_ID_ITEM pItem;
  438. while (pList->Flink != SessionIdList) // loop until we find it (or the end of the list)
  439. {
  440. pList = pList->Flink;
  441. pItem = CONTAINING_RECORD(pList, MSG_SESSION_ID_ITEM, List);
  442. if ( (pItem->SessionId == SessionId) || (pItem->SessionId == EVERYBODY_SESSION_ID) )
  443. {
  444. bRet = TRUE; // we found it !
  445. break;
  446. }
  447. }
  448. return bRet;
  449. }
  450. VOID
  451. MsgRemoveSessionFromList(
  452. IN PLIST_ENTRY SessionIdList,
  453. ULONG SessionId
  454. )
  455. {
  456. PLIST_ENTRY pList = SessionIdList;
  457. PMSG_SESSION_ID_ITEM pItem;
  458. while (pList->Flink != SessionIdList) // loop until we find it (or the end of the list)
  459. {
  460. pList = pList->Flink;
  461. pItem = CONTAINING_RECORD(pList, MSG_SESSION_ID_ITEM, List);
  462. if (pItem->SessionId == SessionId)
  463. {
  464. // we found it. Let's remove it
  465. RemoveEntryList(pList);
  466. //Free the memory
  467. LocalFree(pItem);
  468. break;
  469. }
  470. }
  471. }
  472. BOOL
  473. MsgAddSessionInList(
  474. IN PLIST_ENTRY SessionIdList,
  475. ULONG SessionId
  476. )
  477. {
  478. BOOL bRet;
  479. PMSG_SESSION_ID_ITEM pItem;
  480. // allocate a new item
  481. pItem = (PMSG_SESSION_ID_ITEM) LocalAlloc(LMEM_ZEROINIT,sizeof(MSG_SESSION_ID_ITEM));
  482. if (pItem == NULL) // If this happens, we really have big problems...
  483. {
  484. MSG_LOG(ERROR,"MsgAddSessionInList: Unable to allocate memory\n",0);
  485. bRet = FALSE;
  486. }
  487. else // OK
  488. {
  489. bRet = TRUE;
  490. // initialize the item
  491. pItem->SessionId = SessionId;
  492. // insert the item in the list
  493. InsertTailList(SessionIdList, &pItem->List);
  494. }
  495. return bRet;
  496. }