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.

488 lines
18 KiB

  1. /*++
  2. Copyright (c) 1987 - 1999 Microsoft Corporation
  3. Module Name:
  4. smbutils.c
  5. Abstract:
  6. This module implements the routines that aid in the assembly/disassembly of SMB's
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #define BASE_DOS_ERROR ((NTSTATUS )0xC0010000L)
  11. #include "lmerr.h"
  12. #include "nb30.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, SmbPutString)
  15. #pragma alloc_text(PAGE, SmbPutUnicodeString)
  16. #pragma alloc_text(PAGE, SmbPutUnicodeStringAndUpcase)
  17. #pragma alloc_text(PAGE, SmbPutUnicodeStringAsOemString)
  18. #pragma alloc_text(PAGE, SmbPutUnicodeStringAsOemStringAndUpcase)
  19. #endif
  20. NTSTATUS
  21. SmbPutString(
  22. PBYTE *pBufferPointer,
  23. PSTRING pString,
  24. PULONG pSize)
  25. {
  26. NTSTATUS Status;
  27. PBYTE pBuffer = *pBufferPointer;
  28. PAGED_CODE();
  29. if (*pSize > pString->Length) {
  30. RtlCopyMemory(
  31. pBuffer,
  32. pString->Buffer,
  33. pString->Length);
  34. *pSize -= pString->Length;
  35. *pBufferPointer = pBuffer + pString->Length;
  36. Status = STATUS_SUCCESS;
  37. } else {
  38. Status = STATUS_BUFFER_OVERFLOW;
  39. }
  40. return Status;
  41. }
  42. NTSTATUS
  43. SmbPutUnicodeString(
  44. PBYTE *pBufferPointer,
  45. PUNICODE_STRING pUnicodeString,
  46. PULONG pSize)
  47. {
  48. NTSTATUS Status;
  49. PBYTE pBuffer = *pBufferPointer;
  50. PAGED_CODE();
  51. if (*pSize >= (pUnicodeString->Length + sizeof(WCHAR))) {
  52. WCHAR NullChar = L'\0';
  53. RtlCopyMemory(
  54. pBuffer,
  55. pUnicodeString->Buffer,
  56. pUnicodeString->Length);
  57. RtlCopyMemory(
  58. (pBuffer + pUnicodeString->Length),
  59. &NullChar,
  60. sizeof(WCHAR));
  61. *pSize -= (pUnicodeString->Length + sizeof(WCHAR));
  62. *pBufferPointer = pBuffer + (pUnicodeString->Length + sizeof(WCHAR));
  63. Status = STATUS_SUCCESS;
  64. } else {
  65. Status = STATUS_BUFFER_OVERFLOW;
  66. }
  67. return Status;
  68. }
  69. NTSTATUS
  70. SmbPutUnicodeStringAndUpcase(
  71. PBYTE *pBufferPointer,
  72. PUNICODE_STRING pUnicodeString,
  73. PULONG pSize)
  74. {
  75. NTSTATUS Status;
  76. PBYTE pBuffer = *pBufferPointer;
  77. PAGED_CODE();
  78. if (*pSize >= (pUnicodeString->Length + sizeof(WCHAR))) {
  79. UNICODE_STRING BufferAsUnicode;
  80. WCHAR NullChar = L'\0';
  81. BufferAsUnicode.Buffer = (PWCHAR)pBuffer;
  82. BufferAsUnicode.Length = pUnicodeString->Length;
  83. BufferAsUnicode.MaximumLength = BufferAsUnicode.Length;
  84. RtlUpcaseUnicodeString(
  85. &BufferAsUnicode,
  86. pUnicodeString,
  87. FALSE);
  88. RtlCopyMemory(
  89. (pBuffer + pUnicodeString->Length),
  90. &NullChar,
  91. sizeof(WCHAR));
  92. *pSize -= (pUnicodeString->Length + sizeof(WCHAR));
  93. *pBufferPointer = pBuffer + (pUnicodeString->Length + sizeof(WCHAR));
  94. Status = STATUS_SUCCESS;
  95. } else {
  96. Status = STATUS_BUFFER_OVERFLOW;
  97. }
  98. return Status;
  99. }
  100. NTSTATUS
  101. SmbPutUnicodeStringAsOemString(
  102. PBYTE *pBufferPointer,
  103. PUNICODE_STRING pUnicodeString,
  104. PULONG pSize)
  105. {
  106. NTSTATUS Status;
  107. OEM_STRING OemString;
  108. PBYTE pBuffer = *pBufferPointer;
  109. PAGED_CODE();
  110. OemString.MaximumLength = (USHORT)*pSize;
  111. OemString.Buffer = pBuffer;
  112. // The Rtl routine pads the converted string with a NULL.
  113. Status = RtlUnicodeStringToOemString(
  114. &OemString, // destination string
  115. pUnicodeString, // source string
  116. FALSE); // No memory allocation for destination
  117. if (NT_SUCCESS(Status)) {
  118. if (OemString.Length < *pSize) {
  119. // put the null
  120. pBuffer += (OemString.Length + 1);
  121. *pBufferPointer = pBuffer;
  122. *pSize -= (OemString.Length + 1); // the NULL is not included in the length by the RTL routine.
  123. } else {
  124. Status = STATUS_BUFFER_OVERFLOW;
  125. }
  126. }
  127. return Status;
  128. }
  129. NTSTATUS
  130. SmbPutUnicodeStringAsOemStringAndUpcase(
  131. PBYTE *pBufferPointer,
  132. PUNICODE_STRING pUnicodeString,
  133. PULONG pSize)
  134. {
  135. NTSTATUS Status;
  136. OEM_STRING OemString;
  137. PBYTE pBuffer = *pBufferPointer;
  138. PAGED_CODE();
  139. OemString.MaximumLength = (USHORT)*pSize;
  140. OemString.Buffer = pBuffer;
  141. // The Rtl routine pads the converted string with a NULL.
  142. Status = RtlUpcaseUnicodeStringToOemString(
  143. &OemString, // destination string
  144. pUnicodeString, // source string
  145. FALSE); // No memory allocation for destination
  146. if (NT_SUCCESS(Status)) {
  147. if (OemString.Length < *pSize) {
  148. // put the null
  149. pBuffer += (OemString.Length + 1);
  150. *pBufferPointer = pBuffer;
  151. *pSize -= (OemString.Length + 1); // the NULL is not included in the length by the RTL routine.
  152. } else {
  153. Status = STATUS_BUFFER_OVERFLOW;
  154. }
  155. }
  156. return Status;
  157. }
  158. //
  159. // The maps for mapping various error codes into NTSTATUSs
  160. //
  161. typedef struct _STATUS_MAP {
  162. USHORT ErrorCode;
  163. NTSTATUS ResultingStatus;
  164. } STATUS_MAP, *PSTATUS_MAP;
  165. STATUS_MAP
  166. SmbErrorMap[] = {
  167. { SMB_ERR_BAD_PASSWORD, STATUS_WRONG_PASSWORD },
  168. { SMB_ERR_ACCESS, STATUS_NETWORK_ACCESS_DENIED },
  169. { SMB_ERR_BAD_TID, STATUS_NETWORK_NAME_DELETED },
  170. { SMB_ERR_BAD_NET_NAME, STATUS_BAD_NETWORK_NAME }, // Invalid network name
  171. { SMB_ERR_BAD_DEVICE, STATUS_BAD_DEVICE_TYPE }, // Invalid device request
  172. { SMB_ERR_QUEUE_FULL, STATUS_PRINT_QUEUE_FULL }, // Print queue full
  173. { SMB_ERR_QUEUE_TOO_BIG, STATUS_NO_SPOOL_SPACE }, // No space on print dev
  174. { SMB_ERR_BAD_PRINT_FID, STATUS_PRINT_CANCELLED }, // Invalid printfile FID
  175. { SMB_ERR_SERVER_PAUSED, STATUS_SHARING_PAUSED }, // Server is paused
  176. { SMB_ERR_MESSAGE_OFF, STATUS_REQUEST_NOT_ACCEPTED }, // Server not receiving msgs
  177. { SMB_ERR_BAD_TYPE, STATUS_BAD_DEVICE_TYPE }, // Reserved
  178. { SMB_ERR_BAD_SMB_COMMAND, STATUS_NOT_IMPLEMENTED }, // SMB command not recognized
  179. { SMB_ERR_BAD_PERMITS, STATUS_NETWORK_ACCESS_DENIED }, // Access permissions invalid
  180. { SMB_ERR_NO_ROOM, STATUS_DISK_FULL }, // No room for buffer message
  181. { SMB_ERR_NO_RESOURCE, STATUS_REQUEST_NOT_ACCEPTED }, // No resources available for request
  182. { SMB_ERR_TOO_MANY_UIDS, STATUS_TOO_MANY_SESSIONS }, // Too many UIDs active in session
  183. { SMB_ERR_BAD_UID, STATUS_USER_SESSION_DELETED }, // UID not known as a valid UID
  184. { SMB_ERR_USE_MPX, STATUS_SMB_USE_MPX }, // Can't support Raw; use MPX
  185. { SMB_ERR_USE_STANDARD, STATUS_SMB_USE_STANDARD }, // Can't support Raw, use standard r/w
  186. { SMB_ERR_INVALID_NAME, STATUS_OBJECT_NAME_INVALID },
  187. { SMB_ERR_INVALID_NAME_RANGE, STATUS_OBJECT_NAME_INVALID },
  188. { SMB_ERR_NO_SUPPORT,STATUS_NOT_SUPPORTED }, // Function not supported
  189. { NERR_PasswordExpired, STATUS_PASSWORD_EXPIRED },
  190. { NERR_AccountExpired, STATUS_ACCOUNT_DISABLED },
  191. { NERR_InvalidLogonHours, STATUS_INVALID_LOGON_HOURS },
  192. { NERR_InvalidWorkstation, STATUS_INVALID_WORKSTATION },
  193. { NERR_DuplicateShare, STATUS_LOGON_FAILURE }
  194. // { SMB_ERR_QUEUE_EOF, STATUS_UNEXPECTED_NETWORK_ERROR },// EOF on print queue dump
  195. // { SMB_ERR_SERVER_ERROR, STATUS_UNEXPECTED_NETWORK_ERROR}, // Internal server error
  196. // { SMB_ERR_FILE_SPECS, STATUS_UNEXPECTED_NETWORK_ERROR }, // FID and pathname were incompatible
  197. // { SMB_ERR_BAD_ATTRIBUTE_MODE, STATUS_UNEXPECTED_NETWORK_ERROR }, // Invalid attribute mode specified
  198. // { SMB_ERR_NO_SUPPORT_INTERNAL,STATUS_UNEXPECTED_NETWORK_ERROR }, // Internal code for NO_SUPPORT--
  199. // // allows codes to be stored in a byte
  200. // { SMB_ERR_ERROR, STATUS_UNEXPECTED_NETWORK_ERROR },
  201. // { SMB_ERR_CONTINUE_MPX, STATUS_UNEXPECTED_NETWORK_ERROR }, // Reserved
  202. // { SMB_ERR_TOO_MANY_NAMES, STATUS_UNEXPECTED_NETWORK_ERROR }, // Too many remote user names
  203. // { SMB_ERR_TIMEOUT, STATUS_UNEXPECTED_NETWORK_ERROR }, // Operation was timed out
  204. // { SMB_ERR_RESERVED2, STATUS_UNEXPECTED_NETWORK_ERROR },
  205. // { SMB_ERR_RESERVED3, STATUS_UNEXPECTED_NETWORK_ERROR },
  206. // { SMB_ERR_RESERVED4, STATUS_UNEXPECTED_NETWORK_ERROR },
  207. // { SMB_ERR_RESERVED5, STATUS_UNEXPECTED_NETWORK_ERROR },
  208. };
  209. ULONG
  210. SmbErrorMapLength = sizeof(SmbErrorMap) / sizeof(SmbErrorMap[0]);
  211. STATUS_MAP
  212. Os2ErrorMap[] = {
  213. { ERROR_INVALID_FUNCTION, STATUS_NOT_IMPLEMENTED },
  214. { ERROR_FILE_NOT_FOUND, STATUS_NO_SUCH_FILE },
  215. { ERROR_PATH_NOT_FOUND, STATUS_OBJECT_PATH_NOT_FOUND },
  216. { ERROR_TOO_MANY_OPEN_FILES,STATUS_TOO_MANY_OPENED_FILES },
  217. { ERROR_ACCESS_DENIED, STATUS_ACCESS_DENIED },
  218. { ERROR_INVALID_HANDLE, STATUS_INVALID_HANDLE },
  219. { ERROR_NOT_ENOUGH_MEMORY, STATUS_INSUFFICIENT_RESOURCES },
  220. { ERROR_INVALID_ACCESS, STATUS_ACCESS_DENIED },
  221. { ERROR_INVALID_DATA, STATUS_DATA_ERROR },
  222. { ERROR_CURRENT_DIRECTORY, STATUS_DIRECTORY_NOT_EMPTY },
  223. { ERROR_NOT_SAME_DEVICE, STATUS_NOT_SAME_DEVICE },
  224. { ERROR_NO_MORE_FILES, STATUS_NO_MORE_FILES },
  225. { ERROR_WRITE_PROTECT, STATUS_MEDIA_WRITE_PROTECTED},
  226. { ERROR_NOT_READY, STATUS_DEVICE_NOT_READY },
  227. { ERROR_CRC, STATUS_CRC_ERROR },
  228. { ERROR_BAD_LENGTH, STATUS_DATA_ERROR },
  229. { ERROR_NOT_DOS_DISK, STATUS_DISK_CORRUPT_ERROR }, //***
  230. { ERROR_SECTOR_NOT_FOUND, STATUS_NONEXISTENT_SECTOR },
  231. { ERROR_OUT_OF_PAPER, STATUS_DEVICE_PAPER_EMPTY},
  232. { ERROR_SHARING_VIOLATION, STATUS_SHARING_VIOLATION },
  233. { ERROR_LOCK_VIOLATION, STATUS_FILE_LOCK_CONFLICT },
  234. { ERROR_WRONG_DISK, STATUS_WRONG_VOLUME },
  235. { ERROR_NOT_SUPPORTED, STATUS_NOT_SUPPORTED },
  236. { ERROR_REM_NOT_LIST, STATUS_REMOTE_NOT_LISTENING },
  237. { ERROR_DUP_NAME, STATUS_DUPLICATE_NAME },
  238. { ERROR_BAD_NETPATH, STATUS_BAD_NETWORK_PATH },
  239. { ERROR_NETWORK_BUSY, STATUS_NETWORK_BUSY },
  240. { ERROR_DEV_NOT_EXIST, STATUS_DEVICE_DOES_NOT_EXIST },
  241. { ERROR_TOO_MANY_CMDS, STATUS_TOO_MANY_COMMANDS },
  242. { ERROR_ADAP_HDW_ERR, STATUS_ADAPTER_HARDWARE_ERROR },
  243. { ERROR_BAD_NET_RESP, STATUS_INVALID_NETWORK_RESPONSE },
  244. { ERROR_UNEXP_NET_ERR, STATUS_UNEXPECTED_NETWORK_ERROR },
  245. { ERROR_BAD_REM_ADAP, STATUS_BAD_REMOTE_ADAPTER },
  246. { ERROR_PRINTQ_FULL, STATUS_PRINT_QUEUE_FULL },
  247. { ERROR_NO_SPOOL_SPACE, STATUS_NO_SPOOL_SPACE },
  248. { ERROR_PRINT_CANCELLED, STATUS_PRINT_CANCELLED },
  249. { ERROR_NETNAME_DELETED, STATUS_NETWORK_NAME_DELETED },
  250. { ERROR_NETWORK_ACCESS_DENIED, STATUS_NETWORK_ACCESS_DENIED },
  251. { ERROR_BAD_DEV_TYPE, STATUS_BAD_DEVICE_TYPE },
  252. { ERROR_BAD_NET_NAME, STATUS_BAD_NETWORK_NAME },
  253. { ERROR_TOO_MANY_NAMES, STATUS_TOO_MANY_NAMES },
  254. { ERROR_TOO_MANY_SESS, STATUS_TOO_MANY_SESSIONS },
  255. { ERROR_SHARING_PAUSED, STATUS_SHARING_PAUSED },
  256. { ERROR_REQ_NOT_ACCEP, STATUS_REQUEST_NOT_ACCEPTED },
  257. { ERROR_REDIR_PAUSED, STATUS_REDIRECTOR_PAUSED },
  258. { ERROR_FILE_EXISTS, STATUS_OBJECT_NAME_COLLISION },
  259. { ERROR_INVALID_PASSWORD, STATUS_WRONG_PASSWORD },
  260. { ERROR_INVALID_PARAMETER, STATUS_INVALID_PARAMETER },
  261. { ERROR_NET_WRITE_FAULT, STATUS_NET_WRITE_FAULT },
  262. { ERROR_BROKEN_PIPE, STATUS_PIPE_BROKEN },
  263. { ERROR_OPEN_FAILED, STATUS_OPEN_FAILED },
  264. { ERROR_BUFFER_OVERFLOW, STATUS_BUFFER_OVERFLOW },
  265. { ERROR_DISK_FULL, STATUS_DISK_FULL },
  266. { ERROR_SEM_TIMEOUT, STATUS_IO_TIMEOUT },
  267. { ERROR_INSUFFICIENT_BUFFER,STATUS_BUFFER_TOO_SMALL },
  268. { ERROR_INVALID_NAME, STATUS_OBJECT_NAME_INVALID },
  269. { ERROR_INVALID_LEVEL, STATUS_INVALID_LEVEL },
  270. { ERROR_BAD_PATHNAME, STATUS_OBJECT_PATH_INVALID }, //*
  271. { ERROR_BAD_PIPE, STATUS_INVALID_PARAMETER },
  272. { ERROR_PIPE_BUSY, STATUS_PIPE_NOT_AVAILABLE },
  273. { ERROR_NO_DATA, STATUS_PIPE_EMPTY },
  274. { ERROR_PIPE_NOT_CONNECTED, STATUS_PIPE_DISCONNECTED },
  275. { ERROR_MORE_DATA, STATUS_BUFFER_OVERFLOW },
  276. { ERROR_VC_DISCONNECTED, STATUS_VIRTUAL_CIRCUIT_CLOSED },
  277. { ERROR_INVALID_EA_NAME, STATUS_INVALID_EA_NAME },
  278. { ERROR_EA_LIST_INCONSISTENT,STATUS_EA_LIST_INCONSISTENT },
  279. // { ERROR_EA_LIST_TOO_LONG, STATUS_EA_LIST_TO_LONG },
  280. { ERROR_EAS_DIDNT_FIT, STATUS_EA_TOO_LARGE },
  281. { ERROR_EA_FILE_CORRUPT, STATUS_EA_CORRUPT_ERROR },
  282. { ERROR_EA_TABLE_FULL, STATUS_EA_CORRUPT_ERROR },
  283. { ERROR_INVALID_EA_HANDLE, STATUS_EA_CORRUPT_ERROR }
  284. // { ERROR_BAD_UNIT, STATUS_UNSUCCESSFUL}, // ***
  285. // { ERROR_BAD_COMMAND, STATUS_UNSUCCESSFUL}, // ***
  286. // { ERROR_SEEK, STATUS_UNSUCCESSFUL },// ***
  287. // { ERROR_WRITE_FAULT, STATUS_UNSUCCESSFUL}, // ***
  288. // { ERROR_READ_FAULT, STATUS_UNSUCCESSFUL}, // ***
  289. // { ERROR_GEN_FAILURE, STATUS_UNSUCCESSFUL }, // ***
  290. };
  291. ULONG
  292. Os2ErrorMapLength = sizeof(Os2ErrorMap) / sizeof(Os2ErrorMap[0]);
  293. NTSTATUS
  294. GetSmbResponseNtStatus(
  295. PSMB_HEADER pSmbHeader,
  296. PSMB_EXCHANGE pExchange
  297. )
  298. {
  299. NTSTATUS Status;
  300. USHORT Error;
  301. USHORT i;
  302. ASSERT( pSmbHeader != NULL );
  303. // If this SMB contains an NT status for the operation, return
  304. // that, otherwise map the resulting error.
  305. if (SmbGetUshort(&pSmbHeader->Flags2) & SMB_FLAGS2_NT_STATUS) {
  306. Status = SmbGetUlong( & ((PNT_SMB_HEADER)pSmbHeader)->Status.NtStatus );
  307. if ((Status == STATUS_SUCCESS) || NT_ERROR(Status) || NT_WARNING(Status)) {
  308. return Status;
  309. }
  310. // else fall through and treat it as an SMB error ..
  311. // This needs to be done because in certain cases NT servers return SMB
  312. // specific error codes eventhough the NTSTATUS flag is set
  313. }
  314. if (pSmbHeader->ErrorClass == SMB_ERR_SUCCESS) {
  315. return STATUS_SUCCESS;
  316. }
  317. Error = SmbGetUshort(&pSmbHeader->Error);
  318. if (Error == SMB_ERR_SUCCESS) {
  319. // Umm, non success ErrorClass but success Error code.
  320. Status = STATUS_UNEXPECTED_NETWORK_ERROR;
  321. } else {
  322. // Map the error code depending on Error Class
  323. switch (pSmbHeader->ErrorClass) {
  324. case SMB_ERR_CLASS_DOS:
  325. case SMB_ERR_CLASS_HARDWARE:
  326. Status = BASE_DOS_ERROR + Error;
  327. for (i = 0; i < Os2ErrorMapLength; i++) {
  328. if (Os2ErrorMap[i].ErrorCode == Error) {
  329. Status = Os2ErrorMap[i].ResultingStatus;
  330. break;
  331. }
  332. }
  333. break;
  334. case SMB_ERR_CLASS_SERVER:
  335. Status = STATUS_UNEXPECTED_NETWORK_ERROR;
  336. for (i = 0; i < SmbErrorMapLength; i++) {
  337. if (SmbErrorMap[i].ErrorCode == Error) {
  338. //The error of STATUS_NETWORK_ACCESS_DENIED should be mapped as STATUS_NO_SUCH_FILE for
  339. //the non-NT servers in case it tries to access the PIPE.
  340. if (SmbErrorMap[i].ResultingStatus == STATUS_NETWORK_ACCESS_DENIED) {
  341. SMBCE_SERVER Server = pExchange->SmbCeContext.pServerEntry->Server;
  342. NET_ROOT_TYPE NetRootType = pExchange->SmbCeContext.pVNetRoot->pNetRoot->Type;
  343. if (NetRootType == NET_ROOT_PIPE) {
  344. if ( (Server.Dialect != NTLANMAN_DIALECT) ||
  345. !FlagOn(Server.DialectFlags,DF_NT_STATUS) ) {
  346. Status = STATUS_NO_SUCH_FILE;
  347. break;
  348. }
  349. }
  350. }
  351. Status = SmbErrorMap[i].ResultingStatus;
  352. break;
  353. }
  354. }
  355. break;
  356. default:
  357. Status = STATUS_UNEXPECTED_NETWORK_ERROR;
  358. break;
  359. }
  360. }
  361. return Status;
  362. }
  363. BOOLEAN
  364. IsValidShortFileName(
  365. PUNICODE_STRING Name
  366. )
  367. {
  368. BOOLEAN IsValidName = TRUE;
  369. int NumberOfChars;
  370. int CurrentNameStart = 0;
  371. int CurrentNameEnd = 0;
  372. int CurrentDot = 0;
  373. int i;
  374. if (Name == NULL) {
  375. return TRUE;
  376. }
  377. NumberOfChars = Name->Length/sizeof(UNICODE_NULL);
  378. while(IsValidName && CurrentNameStart < NumberOfChars) {
  379. CurrentNameEnd = NumberOfChars;
  380. for (i=CurrentNameStart+1;i<NumberOfChars;i++) {
  381. if (Name->Buffer[i] == L'\\') {
  382. CurrentNameEnd = i;
  383. break;
  384. }
  385. }
  386. if (CurrentNameEnd - CurrentNameStart > 13) {
  387. IsValidName = FALSE;
  388. }
  389. if (IsValidName) {
  390. CurrentDot = CurrentNameEnd;
  391. for (i=CurrentNameStart;i<CurrentNameEnd;i++) {
  392. if (Name->Buffer[i] == L'.') {
  393. if (CurrentDot == CurrentNameEnd) {
  394. CurrentDot = i;
  395. } else {
  396. IsValidName = FALSE;
  397. }
  398. }
  399. }
  400. if (IsValidName) {
  401. if (CurrentDot - CurrentNameStart > 9 ||
  402. CurrentNameEnd - CurrentDot > 4) {
  403. IsValidName = FALSE;
  404. }
  405. }
  406. }
  407. CurrentNameStart = CurrentNameEnd;
  408. }
  409. return IsValidName;
  410. }
  411.