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.

1932 lines
46 KiB

  1. // NOTE:
  2. //
  3. // Unless the data read from the STATIC file is converted to UNICODE, we should
  4. // not have UNICODE defined for this module
  5. //
  6. /*++
  7. Copyright (c) 1990 Microsoft Corporation
  8. Module Name:
  9. winsprs.c
  10. Abstract:
  11. This source contains the functions that parse the lmhosts file.
  12. Functions:
  13. GetTokens,
  14. IsKeyWord,
  15. Fgets,
  16. PrimeDb
  17. ExpandName,
  18. RegOrdinaryName,
  19. RegGrpName
  20. WinsPrsDoStaticInit
  21. Portability:
  22. This module is portable
  23. Author:
  24. Pradeep Bahl (PradeepB) Apr-1993
  25. Stole the parsing code from lm_parse.c, lm_io.c, and lm_parse.c in
  26. streams\tcpip\nbt; Modified it appropriately
  27. Revision History:
  28. Modification date Person Description of modification
  29. ----------------- ------- ----------------------------
  30. --*/
  31. /*
  32. * Includes
  33. */
  34. #include <ctype.h>
  35. #include <string.h>
  36. #include "wins.h"
  37. #include "nms.h" //required for DBGPRINT statements
  38. #include <winuser.h>
  39. #include "winsevt.h"
  40. #include "winsprs.h"
  41. #include "winsmsc.h"
  42. #include "nmsmsgf.h"
  43. #include "nmsnmh.h"
  44. #include "comm.h"
  45. #include "winsintf.h"
  46. /*
  47. * Local Macro Declarations
  48. */
  49. #define DOMAIN_TOKEN "#DOM:"
  50. #define PRELOAD_TOKEN "#PRE"
  51. #define INCLUDE_TOKEN "#INCLUDE"
  52. #define BEG_ALT_TOKEN "#BEGIN_ALTERNATE"
  53. #define END_ALT_TOKEN "#END_ALTERNATE"
  54. #define DOMAIN_TOKEN_SIZE (sizeof(DOMAIN_TOKEN) - 1)
  55. //
  56. // To mark special groups in the lmhosts file
  57. //
  58. #define SPEC_GRP_TOKEN "#SG:"
  59. #define SPEC_GRP_TOKEN_SIZE (sizeof(SPEC_GRP_TOKEN) - 1)
  60. //
  61. // To indicate an mh node
  62. //
  63. #define MH_TOKEN "#MH"
  64. #define MH_TOKEN_SIZE (sizeof(MH_TOKEN) - 1)
  65. #define QUOTE_CHAR '"'
  66. #define TAB_CHAR '\t'
  67. #define SPACE_CHAR ' '
  68. #define CARRIAGE_RETURN_CHAR '\r'
  69. #define NEWLINE_CHAR '\n'
  70. #define COMMENT_CHAR '#'
  71. #define BACKSLASH_CHAR '\\'
  72. #define ZERO_CHAR '0'
  73. #define x_CHAR 'x'
  74. #define X_CHAR 'X'
  75. //
  76. // Size of array to hold a non-coded netbios name read from a file (lmhosts)
  77. //
  78. #define NON_CODED_NAME_SIZE 17
  79. /*
  80. * Local Typedef Declarations
  81. */
  82. //
  83. // Private Definitions
  84. //
  85. typedef struct _FILE_PARAM_T {
  86. PWINSCNF_DATAFILE_INFO_T pDataFile;
  87. DWORD NoOfFiles;
  88. } FILE_PARAM_T, *PFILE_PARAM_T;
  89. //
  90. // GetTokens() parses a line and returns the tokens in the following
  91. // order:
  92. //
  93. typedef enum _TOKEN_ORDER_E {
  94. E_IPADDRESS = 0, // first token
  95. E_NBNAME, // 2nd token
  96. E_GROUPNAME, // 3rd or 4th token
  97. E_NOTUSED, // #PRE, if any
  98. E_MAX_TOKENS // this must be last
  99. } TOKEN_ORDER_E, *PTOKEN_ORDER_E;
  100. //
  101. // If the line category is E_SPEC_GRP, then we have just one token
  102. //
  103. #define SPEC_GRP_TOKEN_POS 0
  104. //
  105. // As each line in an lmhosts file is parsed, it is classified into one of
  106. // the categories enumerated below.
  107. //
  108. // However, Preload is a special member of the enum (ignored by us).
  109. //
  110. //
  111. typedef enum _TYPE_OF_LINE_E {
  112. E_COMMENT = 0x0000, // comment line
  113. E_ORDINARY = 0x0001, // ip_addr NetBIOS name
  114. E_DOMAIN = 0x0002, // ... #DOM:name
  115. E_INCLUDE = 0x0003, // #INCLUDE file
  116. E_BEGIN_ALTERNATE = 0x0004, // #BEGIN_ALTERNATE
  117. E_END_ALTERNATE = 0x0005, // #END_ALTERNATE
  118. E_SPEC_GRP = 0x0006, // #Spec Grp
  119. E_SGWADD = 0x0007, // #Spec Grp with add
  120. E_PRELOAD = 0x8000, // ... #PRE
  121. E_MH = 0x8001 // ip_addr NetBIOS name
  122. // for a mh machine
  123. } TYPE_OF_LINE_E, *PTYPE_OF_LINE_E;
  124. //
  125. // In an lmhosts file, the following are recognized as keywords:
  126. //
  127. // #BEGIN_ALTERNATE #END_ALTERNATE #PRE
  128. // #DOM: #INCLUDE
  129. //
  130. // Information about each keyword is kept in a KEYWORD structure.
  131. //
  132. //
  133. typedef struct _KEYWORD_T { // reserved keyword
  134. LPBYTE pKString; // NULL terminated
  135. size_t KStrlen; // length of token
  136. TYPE_OF_LINE_E KType_e; // type of line
  137. DWORD KNoOfOperands; // max operands on line
  138. } KEYWORD_T, *PKEYWORD_T;
  139. //
  140. // Information about the type of line read is kept in the LINE_CHARACTERISTICS
  141. // structure
  142. //
  143. typedef struct _LINE_CHARACTERISTICS_T
  144. {
  145. int LineCategory:4; // enum _TYPE_OF_LINE
  146. int LinePreload:1; // marked with #PRE ?
  147. int Mh:1; // marked with #MH ?
  148. } LINE_CHARACTERISTICS_T, *PLINE_CHARACTERISTICS_T;
  149. /*
  150. * Global Variable Definitions
  151. */
  152. /*
  153. * Local Variable Definitions
  154. */
  155. //
  156. // In an lmhosts file, the token '#' in any column usually denotes that
  157. // the rest of the line is to be ignored. However, a '#' may also be the
  158. // first character of a keyword.
  159. //
  160. // Keywords are divided into two groups:
  161. //
  162. // 1. decorations that must either be the 3rd or 4th token of a line,
  163. // 2. directives that must begin in column 0,
  164. //
  165. //
  166. KEYWORD_T Decoration[] = {
  167. DOMAIN_TOKEN, sizeof(DOMAIN_TOKEN) - 1, E_DOMAIN, 4,
  168. PRELOAD_TOKEN, sizeof(PRELOAD_TOKEN) - 1, E_PRELOAD, 4,
  169. SPEC_GRP_TOKEN, sizeof(SPEC_GRP_TOKEN) - 1, E_SGWADD, 4,
  170. MH_TOKEN, sizeof(MH_TOKEN) - 1, E_MH, 4,
  171. NULL, 0 // must be last
  172. };
  173. KEYWORD_T Directive[] = {
  174. INCLUDE_TOKEN, sizeof(INCLUDE_TOKEN) - 1, E_INCLUDE, 2,
  175. BEG_ALT_TOKEN, sizeof(BEG_ALT_TOKEN) - 1, E_BEGIN_ALTERNATE, 1,
  176. END_ALT_TOKEN, sizeof(END_ALT_TOKEN) - 1, E_END_ALTERNATE, 1,
  177. SPEC_GRP_TOKEN, sizeof(SPEC_GRP_TOKEN) - 1, E_SPEC_GRP, 1,
  178. NULL, 0 // must be last
  179. };
  180. /*
  181. * Local Function Prototype Declarations
  182. */
  183. /* prototypes for functions local to this module go here */
  184. //
  185. // Local (Private) Functions
  186. //
  187. STATIC
  188. BOOL
  189. ChkAdd(
  190. LPBYTE pstrAdd,
  191. LPDWORD pAdd
  192. );
  193. STATIC
  194. LINE_CHARACTERISTICS_T
  195. GetTokens (
  196. IN OUT LPBYTE pLine,
  197. OUT LPBYTE *ppToken,
  198. IN OUT LPDWORD pNumTokens
  199. );
  200. STATIC
  201. PKEYWORD_T
  202. IsKeyWord (
  203. IN LPBYTE pString,
  204. IN PKEYWORD_T pTable
  205. );
  206. STATIC
  207. LPBYTE
  208. Fgets (
  209. PWINSPRS_FILE_INFO_T pFileInfo,
  210. LPDWORD pCount
  211. );
  212. STATIC
  213. VOID
  214. PrimeDb (
  215. PWINSPRS_FILE_INFO_T pFileInfo
  216. );
  217. STATIC
  218. BOOL
  219. ExpandName (
  220. OUT LPBYTE pDest,
  221. IN LPBYTE pSrc,
  222. IN BYTE LastCh,
  223. OUT LPBOOL pfQuoted
  224. );
  225. STATIC
  226. VOID
  227. CheckForInt(
  228. IN OUT LPBYTE pDest,
  229. IN BOOL fQuoted
  230. );
  231. STATIC
  232. VOID
  233. RegOrdinaryName(
  234. LPBYTE pName,
  235. DWORD IpAdd
  236. );
  237. VOID
  238. RegGrpName(
  239. LPBYTE pName,
  240. DWORD IpAdd,
  241. DWORD TypeOfRec
  242. );
  243. STATIC
  244. DWORD
  245. DoStaticInitThdFn(
  246. IN LPVOID pThdParam
  247. );
  248. STATIC
  249. LINE_CHARACTERISTICS_T
  250. GetTokens (
  251. IN OUT LPBYTE pLine,
  252. OUT LPBYTE *ppToken,
  253. IN OUT LPDWORD pNumTokens
  254. )
  255. /*++
  256. Routine Description:
  257. This function parses a line for tokens. A maximum of *pnumtokens
  258. are collected.
  259. Arguments:
  260. pLine - pointer to the NULL terminated line to parse
  261. pToken - an array of pointers to tokens collected
  262. pNumTokens - on input, number of elements in the array, token[];
  263. on output, number of tokens collected in token[]
  264. Return Value:
  265. The characteristics of this lmhosts line.
  266. Notes:
  267. 1. Each token must be separated by white space. Hence, the keyword
  268. "#PRE" in the following line won't be recognized:
  269. 11.1.12.132 lothair#PRE
  270. 2. Any ordinary line can be decorated with a "#PRE", a "#DOM:name" or
  271. both. Hence, the following lines must all be recognized:
  272. 111.21.112.3 kernel #DOM:ntwins #PRE
  273. 111.21.112.4 orville #PRE #DOM:ntdev
  274. 111.21.112.7 cliffv4 #DOM:ntlan
  275. 111.21.112.132 lothair #PRE
  276. --*/
  277. {
  278. enum _PARSE_E
  279. { // current fsm state
  280. E_START_OF_LINE,
  281. E_WHITESPACE,
  282. E_TOKEN
  283. } State_e;
  284. LPBYTE pCh; // current fsm input
  285. //LPBYTE pByte; // current fsm input
  286. PKEYWORD_T pKeyword;
  287. DWORD Index;
  288. DWORD MaxTokens;
  289. LINE_CHARACTERISTICS_T Retval;
  290. BOOL fQuoteSeen = FALSE;
  291. BOOL fBreakOut = FALSE;
  292. //
  293. // Zero out the token array
  294. //
  295. RtlZeroMemory(ppToken, *pNumTokens * sizeof(LPBYTE *));
  296. State_e = E_START_OF_LINE;
  297. Retval.LineCategory = E_ORDINARY;
  298. Retval.LinePreload = 0;
  299. Retval.Mh = 0;
  300. MaxTokens = *pNumTokens;
  301. Index = 0;
  302. for (pCh = pLine; *pCh != (BYTE)NULL && !fBreakOut; pCh++)
  303. {
  304. switch ((int)*pCh)
  305. {
  306. //
  307. // does the '#' signify the start of a reserved keyword, or the
  308. // start of a comment ?
  309. //
  310. case COMMENT_CHAR:
  311. //
  312. // if a quote character has been seen earlier, skip this
  313. // char
  314. //
  315. if(fQuoteSeen)
  316. {
  317. continue;
  318. }
  319. //
  320. // See if we have a keyword. Use the appropriate table for the
  321. // lookup
  322. //
  323. pKeyword = IsKeyWord(
  324. pCh,
  325. (State_e == E_START_OF_LINE) ?
  326. Directive : Decoration
  327. );
  328. //
  329. // If it is a keyword
  330. //
  331. if (pKeyword)
  332. {
  333. State_e = E_TOKEN;
  334. MaxTokens = pKeyword->KNoOfOperands;
  335. switch (pKeyword->KType_e)
  336. {
  337. case E_PRELOAD:
  338. Retval.LinePreload = 1;
  339. continue;
  340. case E_MH:
  341. Retval.Mh = 1;
  342. continue;
  343. //
  344. // It is one of the other keywords
  345. //
  346. default:
  347. ASSERT(Index < MaxTokens);
  348. ppToken[Index++] = pCh;
  349. Retval.LineCategory = pKeyword->KType_e;
  350. continue;
  351. }
  352. ASSERT(0);
  353. }
  354. //
  355. // Since it is not a keyword, it is a comment
  356. //
  357. if (State_e == E_START_OF_LINE)
  358. {
  359. Retval.LineCategory = E_COMMENT;
  360. }
  361. /* fall through */
  362. case CARRIAGE_RETURN_CHAR:
  363. case NEWLINE_CHAR:
  364. *pCh = (BYTE) NULL;
  365. fBreakOut = TRUE;
  366. break; //break out of the loop. We are done
  367. case SPACE_CHAR:
  368. case TAB_CHAR:
  369. //
  370. // if State is Token, and there is no ending quote to worry about
  371. // we change the state to WhiteSpace
  372. //
  373. if (State_e == E_TOKEN)
  374. {
  375. if (!fQuoteSeen)
  376. {
  377. State_e = E_WHITESPACE;
  378. *pCh = (BYTE)NULL;
  379. //
  380. // If we have accumulated the desired number of tokens
  381. // break out of the loop
  382. //
  383. if (Index == MaxTokens)
  384. {
  385. fBreakOut = TRUE;
  386. break;
  387. }
  388. }
  389. }
  390. continue;
  391. case QUOTE_CHAR:
  392. //
  393. // Check whether we have seen the beginning quote char earlier
  394. //
  395. if(fQuoteSeen)
  396. {
  397. //
  398. // Ending quote consumed. Set flag to FALSE
  399. //
  400. fQuoteSeen = FALSE;
  401. }
  402. else // companion quote not seen earlier
  403. {
  404. //
  405. // This could be the starting quote of the #DOM:
  406. // keyword's string or could be the starting
  407. // quote of the nbtname string
  408. //
  409. if (State_e == E_TOKEN)
  410. {
  411. //
  412. // It is the starting quote of the #DOM: keyword
  413. // string
  414. //
  415. // --ft: the statement above doesn't stand for legal LMHOSTS lines like:
  416. // #SG:"SGNoMember"
  417. // so I commented out the assert below:
  418. //ASSERT(Index > E_NBNAME);
  419. }
  420. else
  421. {
  422. //
  423. // Must be the starting quote of the Nbt name
  424. //
  425. ASSERT(Index == E_NBNAME);
  426. State_e = E_TOKEN;
  427. //
  428. // Store the pointer to the token
  429. //
  430. ppToken[Index++] = pCh;
  431. }
  432. fQuoteSeen = TRUE;
  433. }
  434. continue;
  435. default:
  436. //
  437. // If this is the token state, continue
  438. //
  439. if (State_e == E_TOKEN)
  440. {
  441. continue;
  442. }
  443. ASSERT(Index < MaxTokens);
  444. State_e = E_TOKEN;
  445. //
  446. // Store the pointer to the token
  447. //
  448. ppToken[Index++] = pCh;
  449. continue;
  450. } // end of switch
  451. } // end of for loop
  452. *pNumTokens = Index;
  453. return(Retval);
  454. } // GetTokens
  455. STATIC
  456. PKEYWORD_T
  457. IsKeyWord (
  458. IN LPBYTE pString,
  459. IN PKEYWORD_T pKTable
  460. )
  461. /*++
  462. Routine Description:
  463. This function determines whether the string is a reserved keyword.
  464. Arguments:
  465. pString - the string to search
  466. pKTable - an array of keywords to look for
  467. Return Value:
  468. A pointer to the relevant keyword object, or NULL if unsuccessful
  469. --*/
  470. {
  471. size_t StringSize;
  472. PKEYWORD_T pSpecial;
  473. StringSize = strlen(pString);
  474. for (pSpecial = pKTable; pSpecial->pKString; pSpecial++) {
  475. //
  476. // If the length of the string is less than that of the keyword,
  477. // go on to the next keyword in the table
  478. //
  479. if (StringSize < pSpecial->KStrlen)
  480. {
  481. continue;
  482. }
  483. //
  484. // if length of string is greater than or equal to the keyword
  485. // length and the string matches the keyword in the # of characters
  486. // that comprise the keywordm, return the address of the keyword
  487. // structure
  488. //
  489. FUTURES("use lstrncmp when it becomes available")
  490. if (
  491. (StringSize >= pSpecial->KStrlen)
  492. &&
  493. !strncmp(pString, pSpecial->pKString, pSpecial->KStrlen)
  494. )
  495. {
  496. return(pSpecial);
  497. }
  498. }
  499. return((PKEYWORD_T) NULL);
  500. } // IsKeyWord
  501. VOID
  502. PrimeDb (
  503. PWINSPRS_FILE_INFO_T pFileInfo
  504. )
  505. /*++
  506. Routine Description:
  507. This function primes the WINS db
  508. Arguments:
  509. Externals Used:
  510. None
  511. Return Value:
  512. None
  513. Error Handling:
  514. Called by:
  515. Side Effects:
  516. Comments:
  517. None
  518. --*/
  519. {
  520. LPBYTE CurrLine;
  521. DWORD Count;
  522. DWORD NWords;
  523. LPBYTE ppToken[E_MAX_TOKENS];
  524. LINE_CHARACTERISTICS_T CurrLineChar;
  525. DWORD Add;
  526. BOOL fBadAdd;
  527. DWORD TkSize;
  528. DWORD TypeOfRec;
  529. try {
  530. //
  531. // Loop over all records
  532. //
  533. pFileInfo->pCurrPos = pFileInfo->pFileBuff;
  534. while (CurrLine = Fgets(pFileInfo, &Count) )
  535. {
  536. NWords = E_MAX_TOKENS;
  537. fBadAdd = FALSE;
  538. CurrLineChar = GetTokens(CurrLine, ppToken, &NWords);
  539. switch (CurrLineChar.LineCategory)
  540. {
  541. case E_SGWADD:
  542. TypeOfRec = NMSDB_USER_SPEC_GRP_ENTRY;
  543. TkSize = SPEC_GRP_TOKEN_SIZE;
  544. //fall through
  545. case E_DOMAIN:
  546. if (CurrLineChar.LineCategory == E_DOMAIN)
  547. {
  548. TypeOfRec = NMSDB_SPEC_GRP_ENTRY;
  549. TkSize = DOMAIN_TOKEN_SIZE;
  550. }
  551. //
  552. // If there are too few words in the line, go
  553. // get the next line
  554. //
  555. if ((NWords - 1) < E_GROUPNAME)
  556. {
  557. continue;
  558. }
  559. if (ChkAdd(ppToken[E_IPADDRESS], &Add))
  560. {
  561. //
  562. // Register the domain name (group name with 1C at
  563. // the end)
  564. //
  565. RegGrpName(
  566. ppToken[E_GROUPNAME] + TkSize,
  567. Add,
  568. TypeOfRec
  569. );
  570. }
  571. else
  572. {
  573. fBadAdd = TRUE;
  574. }
  575. //
  576. // Fall through
  577. //
  578. case E_ORDINARY:
  579. //
  580. // If there are too few words in the line, go
  581. // get the next line
  582. //
  583. // Don't use (NWords - 1) < E_NBNAME since
  584. // NWords can be 0 in which case the test will
  585. // fail
  586. //
  587. if (NWords < (E_NBNAME + 1))
  588. {
  589. continue;
  590. }
  591. else
  592. {
  593. if (!fBadAdd && ChkAdd(ppToken[E_IPADDRESS], &Add))
  594. {
  595. if (CurrLineChar.Mh)
  596. {
  597. RegGrpName(
  598. ppToken[E_NBNAME],
  599. Add,
  600. NMSDB_MULTIHOMED_ENTRY
  601. );
  602. }
  603. else
  604. {
  605. //
  606. // register the name
  607. //
  608. RegOrdinaryName( ppToken[E_NBNAME], Add);
  609. }
  610. }
  611. else
  612. {
  613. WinsMscLogEvtStrs(
  614. ppToken[E_NBNAME],
  615. WINS_EVT_BAD_ADDRESS,
  616. FALSE
  617. );
  618. DBGPRINT2(ERR, "PrimeDb: Name (%s) has bad address = (%s). It is being ignored\n", ppToken[E_NBNAME], ppToken[E_IPADDRESS]);
  619. }
  620. }
  621. continue;
  622. case E_SPEC_GRP:
  623. //
  624. // Register the domain name (group name with 1C at
  625. // the end)
  626. //
  627. RegGrpName(
  628. ppToken[SPEC_GRP_TOKEN_POS] + SPEC_GRP_TOKEN_SIZE,
  629. 0,
  630. NMSDB_USER_SPEC_GRP_ENTRY);
  631. continue;
  632. case E_INCLUDE: // fall through
  633. case E_BEGIN_ALTERNATE: // fall through
  634. case E_END_ALTERNATE: // fall through
  635. continue;
  636. default:
  637. continue;
  638. }
  639. }
  640. } // end of try block
  641. finally {
  642. //
  643. // deallocate the memory to which the file was mapped
  644. //
  645. WinsMscDealloc(pFileInfo->pFileBuff);
  646. }
  647. return;
  648. } // PrimeDb
  649. LPBYTE
  650. Fgets (
  651. IN PWINSPRS_FILE_INFO_T pFileInfo,
  652. OUT LPDWORD pNoOfCh
  653. )
  654. /*++
  655. Routine Description:
  656. This function is vaguely similar to fgets(3).
  657. Starting at the current seek position, it reads through a newline
  658. character, or the end of the file. If a newline is encountered, it
  659. is replaced with a NULL character.
  660. Arguments:
  661. pfile - file to read from
  662. nbytes - the number of characters read, excluding the NULL character
  663. Return Value:
  664. A pointer to the beginning of the line, or NULL if we are at or past
  665. the end of the file.
  666. --*/
  667. {
  668. LPBYTE pEndOfLine;
  669. LPBYTE pStartOfLine;
  670. SIZE_T MaxCh;
  671. //
  672. // Store the current position in the memory buffer
  673. //
  674. pStartOfLine = (LPBYTE)pFileInfo->pCurrPos;
  675. //
  676. // If it is greater or equal than the limit, return NULL
  677. //
  678. if (pStartOfLine >= (LPBYTE)pFileInfo->pLimit) {
  679. return(NULL);
  680. }
  681. //
  682. // Store the max. number of bytes between the current position and
  683. // the end of the buffer.
  684. //
  685. MaxCh = (pFileInfo->pLimit - pFileInfo->pCurrPos);
  686. //
  687. // get to the end of the line
  688. //
  689. pEndOfLine = (LPBYTE)memchr(pStartOfLine, NEWLINE_CHAR, (size_t)MaxCh);
  690. if (!pEndOfLine)
  691. {
  692. DBGPRINT0(FLOW, "Data file does not end in newline\n");
  693. return(NULL);
  694. }
  695. *pEndOfLine = (BYTE)NULL;
  696. pFileInfo->pCurrPos = pEndOfLine + 1; //adjust the pointer
  697. ASSERT(pFileInfo->pCurrPos <= pFileInfo->pLimit);
  698. *pNoOfCh = (DWORD) (pEndOfLine - pStartOfLine);
  699. return(pStartOfLine);
  700. } // Fgets
  701. VOID
  702. RegOrdinaryName(
  703. IN LPBYTE pName,
  704. IN DWORD IPAdd
  705. )
  706. /*++
  707. Routine Description:
  708. This function registers a unique name
  709. Arguments:
  710. pName - Name to register
  711. IPAdd - Address to register
  712. Externals Used:
  713. None
  714. Return Value:
  715. None
  716. Error Handling:
  717. Called by:
  718. Side Effects:
  719. Comments:
  720. None
  721. --*/
  722. {
  723. BYTE Dest[WINS_MAX_LINE_SZ];
  724. BOOL fQuoted;
  725. COMM_ADD_T NodeAdd;
  726. LPBYTE pDest = Dest;
  727. NodeAdd.AddLen = sizeof(COMM_IP_ADD_T);
  728. NodeAdd.AddTyp_e = COMM_ADD_E_TCPUDPIP;
  729. NodeAdd.Add.IPAdd = IPAdd;
  730. //
  731. // Form the name. If the name is < 16 characters, 0x20 will
  732. // be put in the Sixteenth bytes
  733. //
  734. if (!ExpandName(Dest, pName, 0x20, &fQuoted))
  735. {
  736. DBGPRINT1(ERR, "Name (%s) has more than 16 characters\n", pName);
  737. return;
  738. }
  739. NMSMSGF_MODIFY_NAME_IF_REQD_M(Dest);
  740. NmsNmhNamRegInd(
  741. NULL,
  742. Dest,
  743. strlen(Dest) + 1, //we always store the terminating
  744. //NULL
  745. &NodeAdd,
  746. NMSMSGF_E_BNODE,
  747. NULL,
  748. 0,
  749. 0,
  750. FALSE, //it is a name registration (not a refresh)
  751. NMSDB_ENTRY_IS_STATIC,
  752. 0 //not an administrative action
  753. );
  754. //
  755. // If the name was not quoted, register the other two records
  756. // (same name -- different suffixes)
  757. //
  758. if(!fQuoted)
  759. {
  760. #if 0
  761. if (*pDest == 0x1B)
  762. {
  763. WINS_SWAP_BYTES_M(pDest, pDest + 15);
  764. }
  765. #endif
  766. Dest[NON_CODED_NAME_SIZE - 2] = 0x3;
  767. NmsNmhNamRegInd(
  768. NULL,
  769. Dest,
  770. strlen(Dest) + 1, //we always store the terminating
  771. //NULL
  772. &NodeAdd,
  773. NMSMSGF_E_BNODE,
  774. NULL,
  775. 0,
  776. 0,
  777. FALSE, //it is a name registration (not a refresh)
  778. NMSDB_ENTRY_IS_STATIC,
  779. 0 //not an administrative action
  780. );
  781. Dest[NON_CODED_NAME_SIZE - 2] = 0x0;
  782. NmsNmhNamRegInd(
  783. NULL,
  784. Dest,
  785. strlen(Dest) + 2, //add 1 since terminating 0x0 is
  786. //to be stored (will be taken
  787. //as NULL by strlen
  788. &NodeAdd,
  789. NMSMSGF_E_BNODE,
  790. NULL,
  791. 0,
  792. 0,
  793. FALSE, //it is a name registration (not a refresh)
  794. NMSDB_ENTRY_IS_STATIC,
  795. 0 //not an administrative action
  796. );
  797. }
  798. return;
  799. }
  800. VOID
  801. RegGrpName(
  802. IN LPBYTE pName,
  803. IN DWORD IPAdd,
  804. IN DWORD TypeOfRec
  805. )
  806. /*++
  807. Routine Description:
  808. This function registers a domain name
  809. Arguments:
  810. pName - Name to register
  811. IpAdd - Address to register
  812. Externals Used:
  813. None
  814. Return Value:
  815. None
  816. Error Handling:
  817. Called by:
  818. Side Effects:
  819. Comments:
  820. None
  821. --*/
  822. {
  823. BYTE Dest[WINS_MAX_LINE_SZ];
  824. BOOL fQuoted;
  825. NMSMSGF_CNT_ADD_T CntAdd;
  826. DWORD RecType;
  827. BYTE SixteenthByte;
  828. if (*pName == EOS)
  829. {
  830. WinsMscLogEvtStrs(pName, WINS_EVT_NAME_FMT_ERR, FALSE);
  831. return;
  832. }
  833. //
  834. // don't want 0 ip address to be put in
  835. //
  836. if (IPAdd)
  837. {
  838. CntAdd.NoOfAdds = 1;
  839. CntAdd.Add[0].AddLen = sizeof(COMM_IP_ADD_T);
  840. CntAdd.Add[0].AddTyp_e = COMM_ADD_E_TCPUDPIP;
  841. CntAdd.Add[0].Add.IPAdd = IPAdd;
  842. }
  843. else
  844. {
  845. CntAdd.NoOfAdds = 0;
  846. }
  847. if (TypeOfRec != NMSDB_SPEC_GRP_ENTRY)
  848. {
  849. SixteenthByte = 0x20;
  850. }
  851. else
  852. {
  853. SixteenthByte = 0x1C;
  854. }
  855. //
  856. // We can get called for domains, user. spec. grps and mh names.
  857. //
  858. RecType = (TypeOfRec == NMSDB_USER_SPEC_GRP_ENTRY) ?
  859. NMSDB_SPEC_GRP_ENTRY : TypeOfRec;
  860. //
  861. // If the name length is < 16 characters, 0x20 or 0x1C will be put in
  862. // the Sixteenth byte
  863. //
  864. if (!ExpandName(Dest, pName, SixteenthByte, &fQuoted))
  865. {
  866. return;
  867. }
  868. if (RecType == NMSDB_MULTIHOMED_ENTRY)
  869. {
  870. //
  871. // switch the 1st and Sixteenth bytes if the Sixteenth byte is a 0x1B. This
  872. // is done only for non-group names
  873. //
  874. NMSMSGF_MODIFY_NAME_IF_REQD_M(Dest);
  875. }
  876. //
  877. // register the group
  878. //
  879. NmsNmhNamRegGrp(
  880. NULL,
  881. Dest,
  882. strlen(Dest) + 1, // to store the null
  883. &CntAdd,
  884. 0, //Node type (not used)
  885. NULL,
  886. 0,
  887. 0,
  888. RecType,
  889. FALSE, //it is a name registration (not a refresh)
  890. NMSDB_ENTRY_IS_STATIC,
  891. 0 //not an administrative action
  892. );
  893. if (RecType == NMSDB_MULTIHOMED_ENTRY)
  894. {
  895. //
  896. // If the name was not quoted, register the other two records
  897. // (same name -- different suffixes)
  898. //
  899. if(!fQuoted)
  900. {
  901. Dest[NON_CODED_NAME_SIZE - 2] = 0x3;
  902. NmsNmhNamRegGrp(
  903. NULL,
  904. Dest,
  905. strlen(Dest) + 1, // to store the null
  906. &CntAdd,
  907. 0, //Node type (not used)
  908. NULL,
  909. 0,
  910. 0,
  911. RecType,
  912. FALSE, //it is a name registration (not a refresh)
  913. NMSDB_ENTRY_IS_STATIC,
  914. 0 //not an administrative action
  915. );
  916. Dest[NON_CODED_NAME_SIZE - 2] = 0x0;
  917. NmsNmhNamRegGrp(
  918. NULL,
  919. Dest,
  920. strlen(Dest) + 2, // to store the null
  921. &CntAdd,
  922. 0, //Node type (not used)
  923. NULL,
  924. 0,
  925. 0,
  926. RecType,
  927. FALSE, //it is a name registration (not a refresh)
  928. NMSDB_ENTRY_IS_STATIC,
  929. 0 //not an administrative action
  930. );
  931. }
  932. }
  933. return;
  934. }
  935. BOOL
  936. ExpandName (
  937. OUT LPBYTE pDest,
  938. IN LPBYTE pSrc,
  939. IN BYTE LastCh,
  940. OUT LPBOOL pfQuoted
  941. )
  942. /*++
  943. Routine Description:
  944. This function expands an lmhosts entry into a full 16 byte NetBIOS
  945. name. It is padded with blanks up to 15 bytes; the Sixteenth byte is the
  946. input parameter, last.
  947. Both dest and source are NULL terminated strings.
  948. Arguments:
  949. pDest - sizeof(dest) must be WINSPRS_NONCODED_NMSZ
  950. pSrc - the lmhosts entry
  951. LastCh - the Sixteenth byte of the NetBIOS name
  952. pfQuoted - flag to indicate whether the string was quoted or not
  953. Return Value:
  954. None
  955. --*/
  956. {
  957. BYTE Ch;
  958. DWORD i = 0;
  959. LPBYTE pFrom = pSrc;
  960. LPBYTE pTo = pDest;
  961. // Detect if it is quoted name..
  962. *pfQuoted = (*pFrom == QUOTE_CHAR);
  963. // ..and skip the initial quote char
  964. pFrom += *pfQuoted;
  965. // count for as many chars as are in a legal NetBios name (15) plus
  966. // the terminating char. (NON_CODED_NAME_SIZE is #defined to be 17)
  967. for (i = 0; i < NON_CODED_NAME_SIZE - 1; i++)
  968. {
  969. // get the next char from the name
  970. Ch = *(pFrom++);
  971. // check if it is a terminating char
  972. if (!Ch || (*pfQuoted ? Ch == QUOTE_CHAR : Ch == NEWLINE_CHAR))
  973. break;
  974. // check if the name doesn't exceed the legal 15 chars
  975. if (i == NON_CODED_NAME_SIZE - 2)
  976. {
  977. // We have picked up 15 characters already and there are more in the name
  978. // This is illegal so log error and bail out
  979. DBGPRINT1(ERR, "Name (%s) has more than 16 characters\n", pSrc);
  980. WinsMscLogEvtStrs(pSrc, WINS_EVT_BAD_NAME, FALSE);
  981. return FALSE;
  982. }
  983. // If the char is a leading DBCS byte then accept the extended char as it
  984. // is (take the trailing byte and go on.
  985. if (IsDBCSLeadByteEx(CP_ACP, Ch))
  986. {
  987. *pTo++ = Ch;
  988. *pTo++ = *pFrom++;
  989. continue;
  990. }
  991. // If the name is not quoted, map lower case alpha chars to upper case.
  992. // Note: don't use _toupper since _toupper does not check whether its
  993. // argument is indeed a lowercase char.
  994. if (!*pfQuoted && IsCharAlpha(Ch))
  995. {
  996. if(IsCharLower(Ch))
  997. {
  998. LPBYTE pCh;
  999. BYTE sCh[2];
  1000. sCh[0] = Ch;
  1001. sCh[1] = (BYTE)NULL;
  1002. pCh = (LPBYTE)CharUpperA(sCh);
  1003. Ch = *pCh;
  1004. }
  1005. }
  1006. // Check if we have hex value in the name
  1007. if (Ch == BACKSLASH_CHAR)
  1008. {
  1009. DWORD NoOfChar;
  1010. INT NumValue = 0;
  1011. CHAR Ch2;
  1012. BOOL fFailed = FALSE;
  1013. // the hex value can be either \A3 or \xFC (obviously with any kind of hex digits)
  1014. Ch = *pFrom;
  1015. Ch2 = *(pFrom+1);
  1016. if (Ch == BACKSLASH_CHAR)
  1017. {
  1018. // '\\' should be seen as one '\', hence keep Ch as it is and break from switch
  1019. pFrom++;
  1020. }
  1021. else
  1022. {
  1023. if ((Ch == X_CHAR || Ch == x_CHAR) ||
  1024. (Ch == ZERO_CHAR && (Ch2 == X_CHAR || Ch2 == x_CHAR))
  1025. )
  1026. {
  1027. DBGPRINT1(TMP, "Parsing hex num %s\n", pFrom);
  1028. // skip over x or 0x.
  1029. pFrom += (Ch == X_CHAR || Ch == x_CHAR) ? 1 : 2;
  1030. // we do have a hex number here. Pick up at most the first two digits.
  1031. fFailed = (sscanf(pFrom, "%2x%n", &NumValue, &NoOfChar) == 0 || NoOfChar == 0);
  1032. DBGPRINT2(TMP, "fFailed=%d; HexNumValue=0x%x\n", fFailed, NumValue);
  1033. }
  1034. else
  1035. {
  1036. DBGPRINT1(TMP, "Parsing dec num %s\n", pFrom);
  1037. // it might be a decimal number. Pick up at most the first 3 digits.
  1038. fFailed = (sscanf(pFrom, "%3u%n", &NumValue, &NoOfChar) == 0 || NoOfChar == 0 || NumValue > 255);
  1039. DBGPRINT2(TMP, "fFailed=%d; DecNumValue=%u\n", fFailed, NumValue);
  1040. }
  1041. if (fFailed)
  1042. {
  1043. // log an event and bail out with error.
  1044. DBGPRINT1(ERR, "Name (%s) contains incorrectly formed character code.\n", pSrc);
  1045. WinsMscLogEvtStrs(pSrc, WINS_EVT_BAD_CHARCODING, FALSE);
  1046. return FALSE;
  1047. }
  1048. // everything went fine, copy the hex value back to Ch
  1049. Ch = (BYTE)NumValue;
  1050. // and make sure to advance on the pFrom string
  1051. pFrom += NoOfChar;
  1052. }
  1053. }
  1054. // finally copy the char to the destination string
  1055. *pTo = Ch;
  1056. // advance with the pointer on the destination string
  1057. pTo++;
  1058. } //end of for loop
  1059. // if there were less than expected char, form the valid netbios name
  1060. // by padding it with spaces
  1061. for (;i < NON_CODED_NAME_SIZE - 2; i++, pTo++)
  1062. *pTo = SPACE_CHAR;
  1063. *pTo = (BYTE)NULL;
  1064. *(pTo+1) = (BYTE)NULL;
  1065. CheckForInt(pDest, *pfQuoted);
  1066. // at the end, append the LastCh (16th byte) to the name.
  1067. *pTo = LastCh;
  1068. return(TRUE);
  1069. } // ExpandName
  1070. VOID
  1071. CheckForInt(
  1072. LPBYTE pDest,
  1073. BOOL fQuoted
  1074. )
  1075. /*++
  1076. Routine Description:
  1077. This function munges the name so that if there are any characters
  1078. from a different code set, they are converted properly
  1079. Arguments:
  1080. Externals Used:
  1081. None
  1082. Return Value:
  1083. Success status codes --
  1084. Error status codes --
  1085. Error Handling:
  1086. Called by:
  1087. Side Effects:
  1088. Comments:
  1089. None
  1090. --*/
  1091. {
  1092. WCHAR UnicodeBuf[255];
  1093. UNICODE_STRING UnicodeStr;
  1094. STRING TmpStr;
  1095. NTSTATUS NTStatus;
  1096. DBGENTER("CheckForInt\n");
  1097. //
  1098. // Now, convert to UNICODE then to OEM to force the ANSI -> OEM munge.
  1099. // Then convert back to UNICODE and uppercase the name. Finally convert
  1100. // back to OEM.
  1101. //
  1102. UnicodeStr.Length = 0;
  1103. UnicodeStr.MaximumLength = sizeof(UnicodeBuf);
  1104. UnicodeStr.Buffer = UnicodeBuf;
  1105. RtlInitString(&TmpStr, pDest);
  1106. NTStatus = RtlAnsiStringToUnicodeString(&UnicodeStr, &TmpStr, FALSE);
  1107. if (!NT_SUCCESS(NTStatus))
  1108. {
  1109. DBGPRINT1(ERR, "CheckForInt: Ansi -> Unicode failed, NTStatus %X\n",
  1110. NTStatus);
  1111. goto ERROR_PROC;
  1112. }
  1113. NTStatus = RtlUnicodeStringToOemString(&TmpStr, &UnicodeStr, FALSE);
  1114. if (!NT_SUCCESS(NTStatus))
  1115. {
  1116. DBGPRINT1(ERR, "CheckForInt: Unicode -> Oem failed, NTStatus %X\n",
  1117. NTStatus);
  1118. goto ERROR_PROC;
  1119. }
  1120. NTStatus = RtlOemStringToUnicodeString(&UnicodeStr, &TmpStr, FALSE);
  1121. if (!NT_SUCCESS(NTStatus))
  1122. {
  1123. DBGPRINT1(ERR, "CheckForInt: Oem -> Unicode failed, NTStatus %X\n",
  1124. NTStatus);
  1125. goto ERROR_PROC;
  1126. }
  1127. if (!fQuoted)
  1128. NTStatus = RtlUpcaseUnicodeStringToOemString(&TmpStr, &UnicodeStr, FALSE);
  1129. else
  1130. NTStatus = RtlUnicodeStringToOemString(&TmpStr, &UnicodeStr, FALSE);
  1131. if (!NT_SUCCESS(NTStatus))
  1132. {
  1133. DBGPRINT1(ERR, "CheckForInt: Unicode -> Oem failed, NTStatus %X\n",
  1134. NTStatus);
  1135. goto ERROR_PROC;
  1136. }
  1137. ERROR_PROC:
  1138. DBGLEAVE("CheckForInt\n");
  1139. return;
  1140. }
  1141. STATUS
  1142. WinsPrsDoStaticInit(
  1143. IN PWINSCNF_DATAFILE_INFO_T pDataFile,
  1144. IN DWORD NoOfFiles,
  1145. IN BOOL fAsync
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. This function is called to do the STATIC initialization of the WINS
  1150. db
  1151. Arguments:
  1152. pDataFiles - Pointer to buffer containing one or more data file
  1153. structures (PWINSCNF_DATAFILE_INFO_T)
  1154. Externals Used:
  1155. None
  1156. Return Value:
  1157. None
  1158. Error Handling:
  1159. Called by:
  1160. Init()
  1161. Side Effects:
  1162. Comments:
  1163. None
  1164. --*/
  1165. {
  1166. DWORD ThdId;
  1167. PFILE_PARAM_T pFileParam;
  1168. STATUS RetStat = WINS_SUCCESS;
  1169. HANDLE sThdHdl = NULL;
  1170. try {
  1171. WinsMscAlloc(sizeof(FILE_PARAM_T), &pFileParam);
  1172. pFileParam->pDataFile = pDataFile;
  1173. pFileParam->NoOfFiles = NoOfFiles;
  1174. if (fAsync)
  1175. {
  1176. sThdHdl =
  1177. WinsMscCreateThd(DoStaticInitThdFn, pFileParam, &ThdId);
  1178. //
  1179. // We don't need the handle, so let us close it
  1180. //
  1181. CloseHandle(sThdHdl);
  1182. }
  1183. else
  1184. {
  1185. RetStat = DoStaticInitThdFn(pFileParam);
  1186. }
  1187. }
  1188. except(EXCEPTION_EXECUTE_HANDLER) {
  1189. DBGPRINTEXC("WinsPrsDoStaticInit");
  1190. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_STATIC_INIT_ERR);
  1191. }
  1192. return(RetStat);
  1193. }
  1194. DWORD
  1195. DoStaticInitThdFn(
  1196. IN LPVOID pThdParam
  1197. )
  1198. /*++
  1199. Routine Description:
  1200. This thread reads one or more files to do STATIC initialization
  1201. Arguments:
  1202. Externals Used:
  1203. None
  1204. Return Value:
  1205. Success status codes --
  1206. Error status codes --
  1207. Error Handling:
  1208. Called by:
  1209. Side Effects:
  1210. Comments:
  1211. None
  1212. --*/
  1213. {
  1214. WINSPRS_FILE_INFO_T FileInfo;
  1215. DWORD i;
  1216. PWINSCNF_DATAFILE_INFO_T pDataFile =
  1217. (((PFILE_PARAM_T)pThdParam)->pDataFile);
  1218. DWORD NoOfFiles =
  1219. (((PFILE_PARAM_T)pThdParam)->NoOfFiles);
  1220. LPVOID pSvDataFilePtr = pDataFile;
  1221. DWORD RetStat = WINS_SUCCESS;
  1222. //
  1223. // initialize this thread with the db engine
  1224. //
  1225. // This is not an RPC thread. It could have been created either by
  1226. // the main thread (doing an init/reinit) or by an rpc thread. For
  1227. // either case, we do not want the counter NmsTermThdCnt to be
  1228. // incremented in NmsDbThdInit(). Instead of passing a client
  1229. // var to indicate which thread invoked it, we call it an RPC
  1230. // thread to have NmsDbThdInit do the right thing. NmsDbOpenTables
  1231. // will also do the right thing.
  1232. //
  1233. NmsDbThdInit(WINS_E_WINSRPC);
  1234. NmsDbOpenTables(WINS_E_WINSRPC);
  1235. EnterCriticalSection(&WinsIntfCrtSec);
  1236. WinsIntfNoCncrntStaticInits++;
  1237. LeaveCriticalSection(&WinsIntfCrtSec);
  1238. try {
  1239. for (
  1240. i = 0;
  1241. i < NoOfFiles;
  1242. i++, pDataFile = (PWINSCNF_DATAFILE_INFO_T)((LPBYTE)pDataFile +
  1243. WINSCNF_FILE_INFO_SZ)
  1244. )
  1245. {
  1246. //
  1247. // Open the file
  1248. //
  1249. if (
  1250. !WinsMscOpenFile(
  1251. pDataFile->FileNm,
  1252. pDataFile->StrType,
  1253. &FileInfo.FileHdl
  1254. )
  1255. )
  1256. {
  1257. WINSEVT_STRS_T EvtStrs;
  1258. #ifndef UNICODE
  1259. DBGPRINT1(ERR, "WinsPrsDoStaticInit: Could not open file= (%s)\n", pDataFile->FileNm);
  1260. #else
  1261. #ifdef WINSDBG
  1262. IF_DBG(ERR)
  1263. {
  1264. wprintf(L"WinsPrsDoStatisInit: Could not open file = (%s)\n", pDataFile->FileNm);
  1265. }
  1266. #endif
  1267. #endif
  1268. EvtStrs.NoOfStrs = 1;
  1269. EvtStrs.pStr[0] = pDataFile->FileNm;
  1270. WINSEVT_LOG_STR_M(WINS_EVT_CANT_OPEN_DATAFILE, &EvtStrs);
  1271. RetStat = WINS_FAILURE;
  1272. continue;
  1273. }
  1274. #ifndef UNICODE
  1275. DBGPRINT1(DET, "WinsPrsDoStaticInit: Opened file (%s) for doing STATIC initialization\n", pDataFile->FileNm);
  1276. #else
  1277. #ifdef WINSDBG
  1278. IF_DBG(ERR)
  1279. {
  1280. wprintf(L"WinsPrsDoStatisInit: Opened file (%s) for doing STATIC initialization\n", pDataFile->FileNm);
  1281. }
  1282. #endif
  1283. #endif
  1284. //
  1285. // Map the file into allocated memory
  1286. //
  1287. if(!WinsMscMapFile(&FileInfo))
  1288. {
  1289. continue;
  1290. }
  1291. //
  1292. // prime the db
  1293. //
  1294. PrimeDb(&FileInfo);
  1295. } // end of for loop
  1296. } // end of try ..
  1297. except(EXCEPTION_EXECUTE_HANDLER) {
  1298. DBGPRINTEXC("DoStaticInitThdFn");
  1299. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_STATIC_INIT_ERR);
  1300. }
  1301. EnterCriticalSection(&WinsIntfCrtSec);
  1302. WinsIntfNoCncrntStaticInits--;
  1303. LeaveCriticalSection(&WinsIntfCrtSec);
  1304. //
  1305. // Let us end the session
  1306. //
  1307. try {
  1308. NmsDbCloseTables();
  1309. NmsDbEndSession();
  1310. }
  1311. except (EXCEPTION_EXECUTE_HANDLER) {
  1312. DBGPRINTEXC("DoStaticInit: During wrap up");
  1313. }
  1314. //
  1315. // Deallocate the memory
  1316. //
  1317. ASSERT(pSvDataFilePtr != NULL);
  1318. WinsMscDealloc(pSvDataFilePtr);
  1319. //
  1320. // Be sure to deallocate the thread param
  1321. //
  1322. WinsMscDealloc(pThdParam);
  1323. // ExitThread(WINS_SUCCESS);
  1324. return(RetStat); //to shutup compiler warning
  1325. }
  1326. BOOL
  1327. ChkAdd(
  1328. LPBYTE pstrAdd,
  1329. LPDWORD pAdd
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. This function converts a dotted decimel ip address to
  1334. a DWORD. We don't use inet_addr() to do this, since it
  1335. returns 0xFFFFFFFF for an address that has one of its
  1336. parts > 255 and returns some value for an invalid address
  1337. (for example, one with 3 dots)
  1338. Arguments:
  1339. Externals Used:
  1340. None
  1341. Return Value:
  1342. Success status codes --
  1343. Error status codes --
  1344. Error Handling:
  1345. Called by:
  1346. Side Effects:
  1347. Comments:
  1348. None
  1349. --*/
  1350. {
  1351. BYTE Tmp[WINS_MAX_LINE_SZ];
  1352. DWORD Word[4];
  1353. LPBYTE pPos;
  1354. DWORD Count = 0;
  1355. BOOL fInvalid = FALSE;
  1356. //
  1357. // We must see three dots
  1358. //
  1359. while(Count < 4)
  1360. {
  1361. if ((pPos = strchr(pstrAdd, (int)'.')) != NULL)
  1362. {
  1363. do
  1364. {
  1365. //
  1366. // Copy all chars before the dot
  1367. //
  1368. (void)RtlCopyMemory(Tmp, pstrAdd, pPos - pstrAdd);
  1369. //
  1370. // Put a NULL at the end
  1371. //
  1372. Tmp[pPos - pstrAdd] = EOS;
  1373. Word[Count] = (DWORD)atol(Tmp);
  1374. //
  1375. //atol returns 0 if it can not convert
  1376. //but 0 can be a valid return too (if we have '0' to
  1377. // connvert
  1378. //
  1379. if (Word[Count] == 0)
  1380. {
  1381. if (Tmp[0] != '0')
  1382. {
  1383. fInvalid = TRUE;
  1384. break;
  1385. }
  1386. }
  1387. else
  1388. {
  1389. if (Word[Count] > 255)
  1390. {
  1391. fInvalid = TRUE;
  1392. break;
  1393. }
  1394. }
  1395. Count++;
  1396. pstrAdd = ++pPos;
  1397. } while ((Count == 3) && (pPos = pstrAdd + strlen(pstrAdd)));
  1398. if (fInvalid)
  1399. {
  1400. break;
  1401. }
  1402. }
  1403. else
  1404. {
  1405. //
  1406. // less than 3 dots seen, break out of the loop
  1407. //
  1408. break;
  1409. }
  1410. } // end of while (Count < 4)
  1411. if ((Count < 4) || fInvalid)
  1412. {
  1413. return(FALSE);
  1414. }
  1415. else
  1416. {
  1417. *pAdd = (LONG)((Word[0] << 24) + (Word[1] << 16) +
  1418. (Word[2] << 8) + Word[3]);
  1419. }
  1420. return(TRUE);
  1421. }
  1422. #if 0
  1423. VOID
  1424. GetFullPath(
  1425. IN LPBYTE pTarget,
  1426. OUT LPBYTE pPath
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. This function returns the full path of the STATIC file. This is done
  1431. by forming a unicode string from the concatenation of the C strings
  1432. DatabasePath and the string, file.
  1433. You must RtlFreeUnicodeString(path) after calling this function
  1434. successfully !
  1435. Arguments:
  1436. target - the name of the file. This can either be a full path name
  1437. or a mere file name.
  1438. path - a pointer to a UNICODE_STRING structure
  1439. Return Value:
  1440. STATUS_SUCCESS if successful.
  1441. Notes:
  1442. RtlMoveMemory() handles overlapped copies; RtlCopyMemory() doesn't.
  1443. --*/
  1444. {
  1445. NTSTATUS status;
  1446. ULONG unicodesize;
  1447. STRING directory, file, prefix, remote;
  1448. RtlInitString(&prefix, "\\DosDevices");
  1449. RtlInitString(&remote, "\\DosDevices\\UNC");
  1450. //
  1451. // if the target begins with a '\', or contains a DOS drive letter,
  1452. // then assume that it specifies a full path. Otherwise, prepend the
  1453. // default directory, DatabasePath, to create a full path.
  1454. //
  1455. //
  1456. if ((*target == '\\') || (target[1] == ':')) {
  1457. RtlInitString(&directory, target);
  1458. RtlInitString(&file, NULL);
  1459. }
  1460. else {
  1461. RtlInitString(&directory, DatabasePath);
  1462. RtlInitString(&file, target);
  1463. }
  1464. ASSERT(RtlAnsiStringToUnicodeSize(&prefix) <=
  1465. RtlAnsiStringToUnicodeSize(&remote));
  1466. unicodesize = RtlAnsiStringToUnicodeSize(&remote) +
  1467. RtlAnsiStringToUnicodeSize(&directory) +
  1468. RtlAnsiStringToUnicodeSize(&file) +
  1469. 2 * sizeof(OBJ_NAME_PATH_SEPARATOR) +
  1470. sizeof(UNICODE_NULL);
  1471. path->Length = 0;
  1472. path->MaximumLength = (USHORT) unicodesize;
  1473. path->Buffer = ExAllocatePool(NonPagedPool, unicodesize);
  1474. if (!path->Buffer) {
  1475. return(STATUS_NO_MEMORY);
  1476. }
  1477. //
  1478. // does the directory specify a DOS drive ?
  1479. //
  1480. // If the second character of directory is a colon, then it must specify
  1481. // a DOS drive. If so, it must be prefixed with "\\DosDevices".
  1482. //
  1483. //
  1484. if (directory.Buffer[1] == ':') {
  1485. status = LmpConcatenate(path, &prefix);
  1486. if (status != STATUS_SUCCESS) {
  1487. path->MaximumLength = 0;
  1488. ExFreePool(path->Buffer);
  1489. return(status);
  1490. }
  1491. }
  1492. //
  1493. // does the directory specify a remote file ?
  1494. //
  1495. // If so, it must be prefixed with "\\DosDevices\\UNC", and the double
  1496. // slashes of the UNC name eliminated.
  1497. //
  1498. //
  1499. if ((directory.Buffer[0] == '\\') && (directory.Buffer[1] == '\\')) {
  1500. status = LmpConcatenate(path, &remote);
  1501. if (status != STATUS_SUCCESS) {
  1502. path->MaximumLength = 0;
  1503. ExFreePool(path->Buffer);
  1504. return(status);
  1505. }
  1506. directory.Length--;
  1507. ASSERT(((ULONG) directory.Length - 1) > 0);
  1508. RtlMoveMemory( // overlapped copy
  1509. &(directory.Buffer[1]), // Destination
  1510. &(directory.Buffer[2]), // Source
  1511. (ULONG) directory.Length - 1); // Length
  1512. }
  1513. //
  1514. // is the first part of the directory "%SystemRoot%" ?
  1515. //
  1516. // If so, it must be changed to "\\SystemRoot\\".
  1517. //
  1518. // 0123456789 123456789 1
  1519. // %SystemRoot%\somewhere
  1520. //
  1521. //
  1522. if (strncmp(directory.Buffer, "%SystemRoot%", 12) == 0) {
  1523. directory.Buffer[0] = '\\';
  1524. directory.Buffer[11] = '\\';
  1525. if (directory.Buffer[12] == '\\') {
  1526. ASSERT(directory.Length >= 13);
  1527. if (directory.Length > 13) {
  1528. RtlMoveMemory( // overlapped copy
  1529. &(directory.Buffer[12]), // Destination
  1530. &(directory.Buffer[13]), // Source
  1531. (ULONG) directory.Length - 13); // Length
  1532. directory.Buffer[directory.Length - 1] = (CHAR) NULL;
  1533. }
  1534. directory.Length--;
  1535. }
  1536. }
  1537. status = LmpConcatenate(path, &directory);
  1538. if (status != STATUS_SUCCESS) {
  1539. path->MaximumLength = 0;
  1540. ExFreePool(path->Buffer);
  1541. return(status);
  1542. }
  1543. if (!(file.Length)) {
  1544. return(status);
  1545. }
  1546. status = LmpConcatenate(path, &file);
  1547. if (status != STATUS_SUCCESS) {
  1548. path->MaximumLength = 0;
  1549. ExFreePool(path->Buffer);
  1550. return(status);
  1551. }
  1552. return(STATUS_SUCCESS);
  1553. } // LmGetFullPath
  1554. #endif
  1555.