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.

913 lines
22 KiB

  1. /*++
  2. Copyright (c) 1991-92 Microsoft Corporation
  3. Module Name:
  4. msgrutil.c
  5. Abstract:
  6. This file contains functions that are used by the messenger service
  7. and its API as well as the NetMessageSend API.
  8. This module contains the following helper routines:
  9. NetpNetBiosReset
  10. NetpNetBiosAddName
  11. NetpNetBiosDelName
  12. NetpNetBiosGetAdapterNumbers
  13. NetpNetBiosCall
  14. NetpNetBiosHangup
  15. NetpNetBiosReceive
  16. NetpNetBiosSend
  17. NetpStringToNetBiosName
  18. NetpNetBiosStatusToApiStatus
  19. NetpSmbCheck
  20. These function prototypes can be found in net\inc\msgrutil.h.
  21. Authors:
  22. Rita Wong (ritaw) 26-July-1991
  23. Dan Lafferty (danl) 26-July-1991
  24. Revision History:
  25. 05-May-1992 JohnRo
  26. Quiet normal debug messages.
  27. Changed to use FORMAT_ equates for most things.
  28. Made changes suggested by PC-LINT.
  29. --*/
  30. #include <nt.h> // NT definitions
  31. #include <ntrtl.h> // NT runtime library definitions
  32. #include <nturtl.h>
  33. #include <windows.h> // Win32 constant definitions & error codes
  34. #include <lmcons.h> // LAN Manager common definitions
  35. #include <lmerr.h> // LAN Manager network error definitions
  36. #include <debuglib.h> // IF_DEBUG
  37. #include <netdebug.h> // NetpKdPrint(()), FORMAT_ equates.
  38. #include <smbtypes.h> // needed for smb.h
  39. #include <smb.h> // Server Message Block definitions
  40. #include <nb30.h> // NetBIOS 3.0 definitions
  41. #include <string.h> // strlen
  42. #include <msgrutil.h> // Function prototypes from this module
  43. #include <icanon.h> // I_NetNameCanonicalize()
  44. #include <tstring.h> // NetpAllocStrFromWStr(), STRLEN(), etc.
  45. #include <lmapibuf.h> // NetApiBufferFree().
  46. static
  47. NET_API_STATUS
  48. NetpIssueCallWithRetries(
  49. IN PNCB CallNcb,
  50. IN UCHAR LanAdapterNumber
  51. );
  52. NET_API_STATUS
  53. NetpNetBiosReset(
  54. IN UCHAR LanAdapterNumber
  55. )
  56. /*++
  57. Routine Description:
  58. This function resets LAN adapter.
  59. Arguments:
  60. LanAdapterNumber - Supplies the number of the LAN adapter.
  61. Return Value:
  62. NET_API_STATUS - NERR_Success or reason for failure.
  63. --*/
  64. {
  65. NCB Ncb;
  66. UCHAR NcbStatus;
  67. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  68. Ncb.ncb_command = NCBRESET;
  69. Ncb.ncb_lsn = 0;
  70. Ncb.ncb_callname[0] = 24; // Max Num Sessions
  71. Ncb.ncb_callname[1] = 0;
  72. Ncb.ncb_callname[2] = 16; // Max Num Names
  73. Ncb.ncb_callname[3] = 0;
  74. Ncb.ncb_lana_num = LanAdapterNumber;
  75. NcbStatus = Netbios(&Ncb);
  76. return NetpNetBiosStatusToApiStatus(NcbStatus);
  77. }
  78. NET_API_STATUS
  79. NetpNetBiosAddName(
  80. IN PCHAR NetBiosName,
  81. IN UCHAR LanAdapterNumber,
  82. OUT PUCHAR NetBiosNameNumber OPTIONAL
  83. )
  84. /*++
  85. Routine Description:
  86. This function adds a NetBIOS name to the specified LAN adapter.
  87. Arguments:
  88. NetBiosName - Supplies a NetBIOS name to be added.
  89. LanAdapterNumber - Supplies the number of the LAN adapter.
  90. Return Value:
  91. NET_API_STATUS - NERR_Success or reason for failure.
  92. --*/
  93. {
  94. NCB Ncb;
  95. UCHAR NcbStatus;
  96. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  97. Ncb.ncb_command = NCBADDNAME;
  98. memcpy(Ncb.ncb_name, NetBiosName, NCBNAMSZ);
  99. Ncb.ncb_lana_num = LanAdapterNumber;
  100. NcbStatus = Netbios(&Ncb);
  101. if (NcbStatus == NRC_GOODRET) {
  102. IF_DEBUG(NETBIOS) {
  103. Ncb.ncb_name[NCBNAMSZ - 1] = '\0';
  104. NetpKdPrint(("[Netlib] Successfully added name " FORMAT_LPSTR ". "
  105. "Name number is " FORMAT_DWORD "\n",
  106. Ncb.ncb_name, (DWORD) Ncb.ncb_num));
  107. }
  108. if (ARGUMENT_PRESENT(NetBiosNameNumber)) {
  109. *NetBiosNameNumber = Ncb.ncb_num;
  110. }
  111. return NERR_Success;
  112. }
  113. return NetpNetBiosStatusToApiStatus(NcbStatus);
  114. }
  115. NET_API_STATUS
  116. NetpNetBiosDelName(
  117. IN PCHAR NetBiosName,
  118. IN UCHAR LanAdapterNumber
  119. )
  120. /*++
  121. Routine Description:
  122. This function adds a NetBIOS name to the specified LAN adapter.
  123. Arguments:
  124. NetBiosName - Supplies a NetBIOS name to be added.
  125. LanAdapterNumber - Supplies the number of the LAN adapter.
  126. Return Value:
  127. NET_API_STATUS - NERR_Success or reason for failure.
  128. --*/
  129. {
  130. NCB Ncb;
  131. UCHAR NcbStatus;
  132. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  133. Ncb.ncb_command = NCBDELNAME;
  134. memcpy(Ncb.ncb_name, NetBiosName, NCBNAMSZ);
  135. Ncb.ncb_lana_num = LanAdapterNumber;
  136. NcbStatus = Netbios(&Ncb);
  137. if (NcbStatus == NRC_GOODRET) {
  138. IF_DEBUG(NETBIOS) {
  139. Ncb.ncb_name[NCBNAMSZ - 1] = '\0';
  140. NetpKdPrint(("[Netlib] Successfully deleted name " FORMAT_LPSTR ". "
  141. "Name number is " FORMAT_DWORD "\n",
  142. Ncb.ncb_name, (DWORD) Ncb.ncb_num));
  143. }
  144. return NERR_Success;
  145. }
  146. return NetpNetBiosStatusToApiStatus(NcbStatus);
  147. }
  148. NET_API_STATUS
  149. NetpNetBiosGetAdapterNumbers(
  150. OUT PLANA_ENUM LanAdapterBuffer,
  151. IN WORD LanAdapterBufferSize
  152. )
  153. /*++
  154. Routine Description:
  155. Arguments:
  156. LanAdapterBuffer - Returns LAN adapter numbers in this buffer.
  157. LanAdapterBufferSize - Supplies the size of the output buffer which LAN
  158. LAN adapter numbers will be written to.
  159. Return Value:
  160. NET_API_STATUS - NERR_Success or reason for failure.
  161. --*/
  162. {
  163. NCB Ncb;
  164. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  165. Ncb.ncb_command = NCBENUM;
  166. Ncb.ncb_buffer = (char FAR *) LanAdapterBuffer;
  167. Ncb.ncb_length = LanAdapterBufferSize;
  168. return NetpNetBiosStatusToApiStatus(Netbios(&Ncb));
  169. }
  170. NET_API_STATUS
  171. NetpStringToNetBiosName(
  172. OUT PCHAR NetBiosName,
  173. IN LPTSTR String,
  174. IN DWORD CanonicalizeType,
  175. IN WORD Type
  176. )
  177. /*++
  178. Routine Description:
  179. This function converts a zero terminated string plus a specified NetBIOS
  180. name type into a 16-byte NetBIOS name:
  181. [ ANSI String ][ Space Padding ][Type]
  182. If the input string for the NetBIOS name is fewer than 15 characters,
  183. spaces will be used to pad the string to 15 characters. The 16th byte
  184. designates the type of the NetBIOS name.
  185. Input strings that are longer than 15 characters will be truncated to
  186. 15 characters.
  187. Arguments:
  188. NetBiosName - Returns the formatted NetBIOS name.
  189. String - Supplies a pointer to a zero terminated string.
  190. CanonicalizeType - Supplies a value to determine how the string should be
  191. canonicalized.
  192. Type - Supplies the type of the NetBIOS name.
  193. Return Value:
  194. NET_API_STATUS - NERR_Success or reason for failure.
  195. --*/
  196. {
  197. NET_API_STATUS Status = NERR_Success;
  198. DWORD i;
  199. DWORD SourceStringLen;
  200. LPSTR SourceString;
  201. SourceStringLen = STRLEN(String);
  202. Status = I_NetNameCanonicalize(
  203. NULL,
  204. String,
  205. String,
  206. (SourceStringLen + 1) * sizeof(TCHAR),
  207. CanonicalizeType,
  208. 0
  209. );
  210. if (Status != NERR_Success) {
  211. IF_DEBUG(NETBIOS) {
  212. NetpKdPrint(("[Netlib] Error canonicalizing message alias "
  213. FORMAT_LPSTR " " FORMAT_API_STATUS "\n", String, Status));
  214. }
  215. return Status;
  216. }
  217. SourceString = NetpAllocStrFromWStr(String);
  218. if (SourceString == NULL) {
  219. return ERROR_NOT_ENOUGH_MEMORY;
  220. }
  221. //
  222. // Insure the string doesn't exceed the netbios name buffer.
  223. //
  224. if (SourceStringLen > NCBNAMSZ - 1) {
  225. SourceString[NCBNAMSZ - 1] = '\0';
  226. }
  227. (VOID) strncpy(NetBiosName, SourceString, NCBNAMSZ - 1);
  228. for (i = SourceStringLen; i < (NCBNAMSZ - 1); i++) {
  229. NetBiosName[i] = ' ';
  230. }
  231. NetBiosName[NCBNAMSZ - 1] = (CHAR) Type;
  232. (VOID) NetApiBufferFree(SourceString);
  233. return Status;
  234. }
  235. NET_API_STATUS
  236. NetpNetBiosCall(
  237. IN UCHAR LanAdapterNumber,
  238. IN LPTSTR NameToCall,
  239. IN LPTSTR Sender,
  240. OUT UCHAR *SessionNumber
  241. )
  242. /*++
  243. Routine Description:
  244. This function opens a session with the specified name to call.
  245. Arguments:
  246. LanAdapterNumber - Supplies the number of the LAN adapter.
  247. NameToCall - Supplies the name to call.
  248. Sender - Supplies the name who makes the call.
  249. SessionNumber - Returns the session number of the session established.
  250. Return Value:
  251. NET_API_STATUS - NERR_Success or reason for failure.
  252. --*/
  253. {
  254. NET_API_STATUS status;
  255. NCB Ncb;
  256. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  257. if ((status = NetpStringToNetBiosName(
  258. Ncb.ncb_callname,
  259. NameToCall,
  260. NAMETYPE_MESSAGEDEST,
  261. MESSAGE_ALIAS_TYPE
  262. )) != NERR_Success) {
  263. return status;
  264. }
  265. if ((status = NetpStringToNetBiosName(
  266. Ncb.ncb_name,
  267. Sender,
  268. NAMETYPE_MESSAGEDEST,
  269. MESSAGE_ALIAS_TYPE
  270. )) != NERR_Success) {
  271. return status;
  272. }
  273. Ncb.ncb_rto = 30; // Receives time out after 15 seconds
  274. Ncb.ncb_sto = 30; // Sends time out after 15 seconds
  275. Ncb.ncb_command = NCBCALL; // Call (wait)
  276. Ncb.ncb_lana_num = LanAdapterNumber;
  277. //
  278. // Issue the NetBIOS call with retries
  279. //
  280. if (NetpIssueCallWithRetries(&Ncb, LanAdapterNumber) != NERR_Success) {
  281. return NERR_NameNotFound;
  282. }
  283. *SessionNumber = Ncb.ncb_lsn;
  284. return NERR_Success;
  285. }
  286. NET_API_STATUS
  287. NetpNetBiosHangup(
  288. IN UCHAR LanAdapterNumber,
  289. IN UCHAR SessionNumber
  290. )
  291. /*++
  292. Routine Description:
  293. This function closes and opened session.
  294. Arguments:
  295. LanAdapterNumber - Supplies the number of the LAN adapter.
  296. SessionNumber - Supplies the session number of the session to close.
  297. Return Value:
  298. NET_API_STATUS - NERR_Success or reason for failure.
  299. --*/
  300. {
  301. NCB Ncb;
  302. UCHAR NcbStatus;
  303. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  304. Ncb.ncb_command = NCBHANGUP;
  305. Ncb.ncb_lana_num = LanAdapterNumber;
  306. Ncb.ncb_lsn = SessionNumber;
  307. NcbStatus = Netbios(&Ncb);
  308. if (NcbStatus == NRC_GOODRET) {
  309. IF_DEBUG(NETBIOS) {
  310. NetpKdPrint(("[Netlib] NetBIOS successfully hung up\n"));
  311. }
  312. return NERR_Success;
  313. }
  314. return NetpNetBiosStatusToApiStatus(NcbStatus);
  315. }
  316. NET_API_STATUS
  317. NetpNetBiosSend(
  318. IN UCHAR LanAdapterNumber,
  319. IN UCHAR SessionNumber,
  320. IN PCHAR SendBuffer,
  321. IN WORD SendBufferSize
  322. )
  323. /*++
  324. Routine Description:
  325. This function sends data in SendBuffer to the session partner specified
  326. by SessionNumber.
  327. Arguments:
  328. LanAdapterNumber - Supplies the number of the LAN adapter.
  329. SessionNumber - Supplies the session number of a session established with
  330. NetBIOS CALL and LISTEN commands.
  331. SendBuffer - Supplies a pointer to data to be sent.
  332. SendBufferSize - Supplies the size of the data in bytes.
  333. Return Value:
  334. NET_API_STATUS - NERR_Success or reason for failure.
  335. --*/
  336. {
  337. NCB Ncb;
  338. UCHAR NcbStatus;
  339. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  340. Ncb.ncb_command = NCBSEND;
  341. Ncb.ncb_lana_num = LanAdapterNumber;
  342. Ncb.ncb_lsn = SessionNumber;
  343. Ncb.ncb_buffer = SendBuffer;
  344. Ncb.ncb_length = SendBufferSize;
  345. NcbStatus = Netbios(&Ncb);
  346. if (NcbStatus == NRC_GOODRET) {
  347. IF_DEBUG(NETBIOS) {
  348. NetpKdPrint(("[Netlib] NetBIOS successfully sent data\n"));
  349. }
  350. return NERR_Success;
  351. }
  352. return NetpNetBiosStatusToApiStatus(NcbStatus);
  353. }
  354. NET_API_STATUS
  355. NetpNetBiosReceive(
  356. IN UCHAR LanAdapterNumber,
  357. IN UCHAR SessionNumber,
  358. OUT PUCHAR ReceiveBuffer,
  359. IN WORD ReceiveBufferSize,
  360. IN HANDLE EventHandle,
  361. OUT WORD *NumberOfBytesReceived
  362. )
  363. /*++
  364. Routine Description:
  365. This function posts a NetBIOS receive data request to the session
  366. partner specified by SessionNumber.
  367. Arguments:
  368. LanAdapterNumber - Supplies the number of the LAN adapter.
  369. SessionNumber - Supplies the session number of a session established with
  370. NetBIOS CALL and LISTEN commands.
  371. ReceiveBuffer - Returns the received data in this buffer.
  372. ReceiveBufferSize - Supplies the size of the receive buffer.
  373. EventHandle - Supplies a handle to a Win32 event which will be signalled
  374. when an ASYNCH receive command completes. If this value is zero,
  375. the receive command is synchronous.
  376. NumberOfBytesReceived - Returns the number of bytes of data received.
  377. Return Value:
  378. NET_API_STATUS - NERR_Success or reason for failure.
  379. --*/
  380. {
  381. NCB Ncb;
  382. UCHAR NcbStatus;
  383. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  384. Ncb.ncb_command = NCBRECV;
  385. Ncb.ncb_lana_num = LanAdapterNumber;
  386. Ncb.ncb_lsn = SessionNumber;
  387. Ncb.ncb_buffer = ReceiveBuffer;
  388. Ncb.ncb_length = ReceiveBufferSize;
  389. IF_DEBUG(NETBIOS) {
  390. NetpKdPrint(("[Netlib] ncb_length before receive is " FORMAT_WORD_ONLY
  391. "\n", (WORD) Ncb.ncb_length));
  392. }
  393. Ncb.ncb_event = EventHandle;
  394. NcbStatus = Netbios(&Ncb);
  395. if (NcbStatus == NRC_GOODRET) {
  396. IF_DEBUG(NETBIOS) {
  397. NetpKdPrint(("[Netlib] NetBIOS successfully received data\n"));
  398. NetpKdPrint(("[Netlib] ncb_length after receive is "
  399. FORMAT_WORD_ONLY "\n", (WORD) Ncb.ncb_length));
  400. }
  401. *NumberOfBytesReceived = Ncb.ncb_length;
  402. return NERR_Success;
  403. }
  404. return NetpNetBiosStatusToApiStatus(NcbStatus);
  405. }
  406. NET_API_STATUS
  407. NetpNetBiosStatusToApiStatus(
  408. UCHAR NetBiosStatus
  409. )
  410. {
  411. IF_DEBUG(NETBIOS) {
  412. NetpKdPrint(("[Netlib] Netbios status is x%02x\n", NetBiosStatus));
  413. }
  414. //
  415. // Slight optimization
  416. //
  417. if (NetBiosStatus == NRC_GOODRET) {
  418. return NERR_Success;
  419. }
  420. switch (NetBiosStatus) {
  421. case NRC_NORES: return NERR_NoNetworkResource;
  422. case NRC_DUPNAME: return NERR_AlreadyExists;
  423. case NRC_NAMTFUL: return NERR_TooManyNames;
  424. case NRC_ACTSES: return NERR_DeleteLater;
  425. case NRC_REMTFUL: return ERROR_REM_NOT_LIST;
  426. case NRC_NOCALL: return NERR_NameNotFound;
  427. case NRC_NOWILD:
  428. case NRC_NAMERR:
  429. return ERROR_INVALID_PARAMETER;
  430. case NRC_INUSE:
  431. case NRC_NAMCONF:
  432. return NERR_DuplicateName;
  433. default: return NERR_NetworkError;
  434. }
  435. }
  436. static
  437. NET_API_STATUS
  438. NetpIssueCallWithRetries(
  439. IN PNCB CallNcb,
  440. IN UCHAR LanAdapterNumber
  441. )
  442. /*++
  443. Routine Description:
  444. This function issues the NetBIOS call command with retries, just in case
  445. the receiving name is busy fielding a message at the moment.
  446. Arguments:
  447. CallNcb - Supplies a pointer to the NCB which has been initialized with
  448. the proper values to submit an NetBIOS call command.
  449. LanAdapterNumber - Supplies the number of the LAN adapter.
  450. Return Value:
  451. NET_API_STATUS - NERR_Success or reason for failure.
  452. --*/
  453. {
  454. #define NETP_MAX_CALL_RETRY 5
  455. NCB Ncb;
  456. WORD RetryCount = 0;
  457. UCHAR NetBiosStatus;
  458. NB30_ADAPTER_STATUS StatusBuffer; // Adapter status buffer
  459. //
  460. // It is possible that the remote receiving name is present but is
  461. // currently receiving another message and so is not listening.
  462. // If the return code from the call is NRC_NOCALL then check to see if
  463. // the name is actually present by issuing an ASTAT call to the name.
  464. // If the ASTAT succeeds then sleep and retry the call.
  465. //
  466. NetBiosStatus = Netbios(CallNcb);
  467. while (NetBiosStatus == NRC_NOCALL && RetryCount < NETP_MAX_CALL_RETRY) {
  468. //
  469. // Initialize ASTAT NCB
  470. //
  471. RtlZeroMemory((PVOID) &Ncb, sizeof(NCB));
  472. memcpy(Ncb.ncb_callname, CallNcb->ncb_callname, NCBNAMSZ);
  473. Ncb.ncb_buffer = (char FAR *) &StatusBuffer;
  474. Ncb.ncb_length = sizeof(StatusBuffer);
  475. Ncb.ncb_command = NCBASTAT; // Adapter status (wait)
  476. Ncb.ncb_lana_num = LanAdapterNumber;
  477. //
  478. // If failed, name is not present
  479. //
  480. if (Netbios(&Ncb) != NRC_GOODRET) {
  481. return NERR_NameNotFound;
  482. }
  483. Sleep(1000L);
  484. RetryCount++;
  485. NetBiosStatus = Netbios(CallNcb);
  486. }
  487. return NetpNetBiosStatusToApiStatus(NetBiosStatus);
  488. }
  489. int
  490. NetpSmbCheck(
  491. IN LPBYTE buffer, // Buffer containing SMB
  492. IN USHORT size, // size of SMB buffer (in bytes)
  493. IN UCHAR func, // Function code
  494. IN int parms, // Parameter count
  495. IN LPSTR fields // Buffer fields dope vector
  496. )
  497. /*++
  498. Routine Description:
  499. Checks Server Message Block for syntactical correctness
  500. This function is called to verify that a Server Message Block
  501. is of the specified form. The function returns zero if the
  502. SMB is correct; if an error is detected, a non-zero value
  503. indicating the nature of the error is returned.
  504. An SMB is a variable length structure whose exact size
  505. depends on the setting of certain fixed-offset fields
  506. and whose exact format cannot be determined except by
  507. examination of the whole structure. Smbcheck checks to
  508. see that an SMB conforms to a set of specified conditions.
  509. The "fields" parameter is a dope vector that describes the
  510. individual fields to be found in the buffer section at the
  511. end of the SMB. The vector is a null-terminated character
  512. string. Currently, the elements of the string must be as
  513. follows:
  514. 'b' - the next element in the buffer area should be
  515. a variable length buffer prefixed with a byte
  516. containing either 1 or 5 followed by two bytes
  517. containing the size of the buffer.
  518. 'd' - the next element in the buffer area is a null-terminated
  519. string prefixed with a byte containing 2.
  520. 'p' - the next element in the buffer area is a null-terminated
  521. string prefixed with a byte containing 3.
  522. 's' - the next element in the buffer area is a null-terminated
  523. string prefixed with a byte containing 4.
  524. Arguments:
  525. buffer - a pointer to the buffer containing the SMB
  526. size - the number of bytes in the buffer
  527. func - the expected SMB function code
  528. parms - the expected number of parameters
  529. fields - a dope vector describing the expected buffer fields
  530. within the SMB's buffer area (see below).
  531. Return Value:
  532. an integer status code; zero indicates no errors.
  533. --*/
  534. {
  535. PSMB_HEADER smb; // SMB header pointer
  536. LPBYTE limit; // Upper limit
  537. smb = (PSMB_HEADER) buffer; // Overlay header with buffer
  538. //
  539. // Must be long enough for header
  540. //
  541. if(size < sizeof(SMB_HEADER)) {
  542. return(2);
  543. }
  544. //
  545. // Message type must be 0xFF
  546. //
  547. if(smb->Protocol[0] != 0xff) {
  548. return(3);
  549. }
  550. //
  551. // Server must be "SMB"
  552. //
  553. if( smb->Protocol[1] != 'S' ||
  554. smb->Protocol[2] != 'M' ||
  555. smb->Protocol[3] != 'B') {
  556. return(4);
  557. }
  558. //
  559. // Must have proper function code
  560. //
  561. if(smb->Command != func) {
  562. return(5);
  563. }
  564. limit = &buffer[size]; // Set upper limit of SMB
  565. buffer += sizeof(SMB_HEADER); // Skip over header
  566. //
  567. // Parameter counts must match
  568. //
  569. if(*buffer++ != (BYTE)parms) {
  570. return(6);
  571. }
  572. //
  573. // Skip parameters and buffer size
  574. //
  575. buffer += (((SHORT)parms & 0xFF) + 1)*sizeof(SHORT);
  576. //
  577. // Check for overflow
  578. //
  579. if(buffer > limit) {
  580. return(7);
  581. }
  582. //
  583. // Loop to check buffer fields
  584. //
  585. while(*fields) {
  586. //
  587. // Switch on dope vector character
  588. //
  589. switch(*fields++) {
  590. case 'b': // Variable length data block
  591. if(*buffer != '\001' && *buffer != '\005') {
  592. return(8);
  593. }
  594. //
  595. // Check for block code
  596. //
  597. ++buffer; // Skip over block code
  598. size = (USHORT)*buffer++ & (USHORT)0xFF; // Get low-byte size
  599. size += ((USHORT)*buffer++ & (USHORT)0xFF)<< 8; // Get high-byte of buffer size
  600. buffer += size; // Increment pointer
  601. break;
  602. case 'd': // Null-terminated dialect string
  603. if(*buffer++ != '\002') { // Check for string code
  604. return(9);
  605. }
  606. buffer += strlen((LPVOID) buffer) + 1; // Skip over the string
  607. break;
  608. case 'p': // Null-terminated path string
  609. if(*buffer++ != '\003') { // Check for string code
  610. return(10);
  611. }
  612. buffer += strlen((LPVOID) buffer) + 1; // Skip over the string
  613. break;
  614. case 's': // Null-terminated string
  615. if(*buffer++ != '\004') { // Check for string code
  616. return(11);
  617. }
  618. buffer += strlen((LPVOID) buffer) + 1; // Skip over the string
  619. break;
  620. }
  621. //
  622. // Check against end of block
  623. //
  624. if(buffer > limit) {
  625. return(12);
  626. }
  627. }
  628. return(buffer != limit); // Should be false
  629. }