Source code of Windows XP (NT5)
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.

3847 lines
106 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. parse.c
  5. Abstract:
  6. This source contains the functions that parse the lmhosts file.
  7. Author:
  8. Jim Stewart May 2, 1993
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "hosts.h"
  13. #include <ctype.h>
  14. #include <string.h>
  15. #include "parse.tmh"
  16. #ifdef VXD
  17. extern BOOL fInInit;
  18. extern BOOLEAN CachePrimed;
  19. #endif
  20. //
  21. // Returns 0 if equal, 1 if not equal. Used to avoid using c-runtime
  22. //
  23. #define strncmp( pch1, pch2, length ) \
  24. (!CTEMemEqu( pch1, pch2, length ) )
  25. //
  26. // Private Definitions
  27. //
  28. // As an lmhosts file is parsed, a #INCLUDE directive is interpreted
  29. // according to the INCLUDE_STATE at that instance. This state is
  30. // determined by the #BEGIN_ALTERNATE and #END_ALTERNATE directives.
  31. //
  32. //
  33. typedef enum _INCLUDE_STATE
  34. {
  35. MustInclude = 0, // shouldn't fail
  36. TryToInclude, // in alternate block
  37. SkipInclude // satisfied alternate
  38. // block
  39. } INCLUDE_STATE;
  40. //
  41. // LmpGetTokens() parses a line and returns the tokens in the following
  42. // order:
  43. //
  44. typedef enum _TOKEN_ORDER_
  45. {
  46. IpAddress = 0, // first token
  47. NbName, // 2nd token
  48. GroupName, // 3rd or 4th token
  49. NotUsed, // #PRE, if any
  50. NotUsed2, // #NOFNR, if any
  51. MaxTokens // this must be last
  52. } TOKEN_ORDER;
  53. //
  54. // As each line in an lmhosts file is parsed, it is classified into one of
  55. // the categories enumerated below.
  56. //
  57. // However, Preload is a special member of the enum.
  58. //
  59. //
  60. typedef enum _TYPE_OF_LINE
  61. {
  62. Comment = 0x0000, // comment line
  63. Ordinary = 0x0001, // ip_addr NetBIOS name
  64. Domain = 0x0002, // ... #DOM:name
  65. Include = 0x0003, // #INCLUDE file
  66. BeginAlternate = 0x0004, // #BEGIN_ALTERNATE
  67. EndAlternate = 0x0005, // #END_ALTERNATE
  68. ErrorLine = 0x0006, // Error in line
  69. NoFNR = 0x4000, // ... #NOFNR
  70. Preload = 0x8000 // ... #PRE
  71. } TYPE_OF_LINE;
  72. //
  73. // In an lmhosts file, the following are recognized as keywords:
  74. //
  75. // #BEGIN_ALTERNATE #END_ALTERNATE #PRE
  76. // #DOM: #INCLUDE
  77. //
  78. // Information about each keyword is kept in a KEYWORD structure.
  79. //
  80. //
  81. typedef struct _KEYWORD
  82. { // reserved keyword
  83. char *k_string; // NULL terminated
  84. size_t k_strlen; // length of token
  85. TYPE_OF_LINE k_type; // type of line
  86. int k_noperands; // max operands on line
  87. } KEYWORD, *PKEYWORD;
  88. typedef struct _LINE_CHARACTERISTICS_
  89. {
  90. int l_category:4; // enum _TYPE_OF_LINE
  91. int l_preload:1; // marked with #PRE ?
  92. unsigned int l_nofnr:1; // marked with #NOFNR
  93. } LINE_CHARACTERISTICS, *PLINE_CHARACTERISTICS;
  94. //
  95. // Do not allow DNS name queries for the following Name Types:
  96. //
  97. // Name Number(h) Type Usage
  98. // --------------------------------------------------------------------------
  99. // <computername> 01 Unique Messenger Service
  100. // <\\--__MSBROWSE__> 01 Group Master Browser
  101. // <domain> 1B Unique Domain Master Browser
  102. // <domain> 1C Group Domain Controllers
  103. // <INet~Services> 1C Group IIS
  104. // <domain> 1D Unique Master Browser
  105. // <domain> 1E Group Browser Service Elections
  106. #define IsValidDnsNameTag(_c) \
  107. ((_c != 0x01) && \
  108. ((_c < 0x1B) || (_c > 0x1E)))
  109. //
  110. // Local Variables
  111. //
  112. //
  113. // In an lmhosts file, the token '#' in any column usually denotes that
  114. // the rest of the line is to be ignored. However, a '#' may also be the
  115. // first character of a keyword.
  116. //
  117. // Keywords are divided into two groups:
  118. //
  119. // 1. decorations that must either be the 3rd or 4th token of a line,
  120. // 2. directives that must begin in column 0,
  121. //
  122. //
  123. KEYWORD Decoration[] =
  124. {
  125. DOMAIN_TOKEN, sizeof(DOMAIN_TOKEN) - 1, Domain, 5,
  126. PRELOAD_TOKEN, sizeof(PRELOAD_TOKEN) - 1, Preload, 5,
  127. NOFNR_TOKEN, sizeof(NOFNR_TOKEN) -1, NoFNR, 5,
  128. NULL, 0 // must be last
  129. };
  130. KEYWORD Directive[] =
  131. {
  132. INCLUDE_TOKEN, sizeof(INCLUDE_TOKEN) - 1, Include, 2,
  133. BEG_ALT_TOKEN, sizeof(BEG_ALT_TOKEN) - 1, BeginAlternate, 1,
  134. END_ALT_TOKEN, sizeof(END_ALT_TOKEN) - 1, EndAlternate, 1,
  135. NULL, 0 // must be last
  136. };
  137. //
  138. // Local Variables
  139. //
  140. //
  141. // Each preloaded lmhosts entry corresponds to NSUFFIXES NetBIOS names,
  142. // each with a 16th byte from Suffix[].
  143. //
  144. // For example, an lmhosts entry specifying "popcorn" causes the
  145. // following NetBIOS names to be added to nbt.sys' name cache:
  146. //
  147. // "POPCORN "
  148. // "POPCORN 0x0"
  149. // "POPCORN 0x3"
  150. //
  151. //
  152. #define NSUFFIXES 3
  153. UCHAR Suffix[] = { // LAN Manager Component
  154. 0x20, // server
  155. 0x0, // redirector
  156. 0x03 // messenger
  157. };
  158. #ifndef VXD
  159. //
  160. // this structure tracks names queries that are passed up to user mode
  161. // to resolve via DnsQueries
  162. //
  163. tLMHSVC_REQUESTS DnsQueries;
  164. tLMHSVC_REQUESTS CheckAddr;
  165. #endif
  166. tLMHSVC_REQUESTS LmHostQueries; // Track names queries passed for LMhost processing
  167. tDOMAIN_LIST DomainNames;
  168. //
  169. // Local (Private) Functions
  170. //
  171. LINE_CHARACTERISTICS
  172. LmpGetTokens (
  173. IN OUT PUCHAR line,
  174. OUT PUCHAR *token,
  175. IN OUT int *pnumtokens
  176. );
  177. PKEYWORD
  178. LmpIsKeyWord (
  179. IN PUCHAR string,
  180. IN PKEYWORD table
  181. );
  182. BOOLEAN
  183. LmpBreakRecursion(
  184. IN PUCHAR path,
  185. IN PUCHAR target,
  186. IN ULONG TargetLength
  187. );
  188. LONG
  189. HandleSpecial(
  190. IN char **pch);
  191. ULONG
  192. AddToDomainList (
  193. IN PUCHAR pName,
  194. IN tIPADDRESS IpAddress,
  195. IN PLIST_ENTRY pDomainHead,
  196. IN BOOLEAN fPreload
  197. );
  198. NTSTATUS
  199. ChangeStateOfName (
  200. IN tIPADDRESS IpAddress,
  201. IN NBT_WORK_ITEM_CONTEXT *pContext,
  202. IN OUT NBT_WORK_ITEM_CONTEXT **ppContext,
  203. IN USHORT NameAddFlags
  204. );
  205. VOID
  206. LmHostTimeout(
  207. PVOID pContext,
  208. PVOID pContext2,
  209. tTIMERQENTRY *pTimerQEntry
  210. );
  211. NBT_WORK_ITEM_CONTEXT *
  212. GetNameToFind(
  213. OUT PUCHAR pName
  214. );
  215. VOID
  216. GetContext (
  217. IN OUT NBT_WORK_ITEM_CONTEXT **ppContext
  218. );
  219. VOID
  220. MakeNewListCurrent (
  221. PLIST_ENTRY pTmpDomainList
  222. );
  223. VOID
  224. RemoveNameAndCompleteReq (
  225. IN NBT_WORK_ITEM_CONTEXT *pContext,
  226. IN NTSTATUS status
  227. );
  228. PCHAR
  229. Nbtstrcat( PUCHAR pch, PUCHAR pCat, LONG Len );
  230. //******************* Pageable Routine Declarations ****************
  231. #ifdef ALLOC_PRAGMA
  232. #pragma CTEMakePageable(PAGE, LmGetIpAddr)
  233. #pragma CTEMakePageable(PAGE, HandleSpecial)
  234. #pragma CTEMakePageable(PAGE, LmpGetTokens)
  235. #pragma CTEMakePageable(PAGE, LmpIsKeyWord)
  236. #pragma CTEMakePageable(PAGE, LmpBreakRecursion)
  237. #pragma CTEMakePageable(PAGE, AddToDomainList)
  238. #pragma CTEMakePageable(PAGE, LmExpandName)
  239. #pragma CTEMakePageable(PAGE, LmInclude)
  240. #pragma CTEMakePageable(PAGE, LmGetFullPath)
  241. #pragma CTEMakePageable(PAGE, PrimeCache)
  242. #pragma CTEMakePageable(PAGE, DelayedScanLmHostFile)
  243. #pragma CTEMakePageable(PAGE, NbtCompleteLmhSvcRequest)
  244. #endif
  245. //******************* Pageable Routine Declarations ****************
  246. //----------------------------------------------------------------------------
  247. unsigned long
  248. LmGetIpAddr (
  249. IN PUCHAR path,
  250. IN PUCHAR target,
  251. IN CHAR RecurseDepth,
  252. OUT BOOLEAN *bFindName
  253. )
  254. /*++
  255. Routine Description:
  256. This function searches the file for an lmhosts entry that can be
  257. mapped to the second level encoding. It then returns the ip address
  258. specified in that entry.
  259. This function is called recursively, via LmInclude() !!
  260. Arguments:
  261. path - a fully specified path to a lmhosts file
  262. target - the unencoded 16 byte NetBIOS name to look for
  263. RecurseDepth- the depth to which we can resurse -- 0 => no more recursion
  264. Return Value:
  265. The ip address (network byte order), or 0 if no appropriate entry was
  266. found.
  267. Note that in most contexts (but not here), ip address 0 signifies
  268. "this host."
  269. --*/
  270. {
  271. PUCHAR buffer;
  272. PLM_FILE pfile;
  273. NTSTATUS status;
  274. int count, nwords;
  275. INCLUDE_STATE incstate;
  276. PUCHAR token[MaxTokens];
  277. LINE_CHARACTERISTICS current;
  278. unsigned long inaddr, retval;
  279. UCHAR temp[NETBIOS_NAME_SIZE+1];
  280. CTEPagedCode();
  281. //
  282. // Check for infinitely recursive name lookup in a #INCLUDE.
  283. //
  284. if (LmpBreakRecursion(path, target, NETBIOS_NAME_SIZE-1) == TRUE)
  285. {
  286. return (0);
  287. }
  288. #ifdef VXD
  289. //
  290. // if we came here via nbtstat -R and InDos is set, report error: user
  291. // can try nbtstat -R again. (since nbtstat can only be run from DOS box,
  292. // can InDos be ever set??? Might as well play safe)
  293. //
  294. if ( !fInInit && GetInDosFlag() )
  295. {
  296. return(0);
  297. }
  298. #endif
  299. pfile = LmOpenFile(path);
  300. if (!pfile)
  301. {
  302. return((unsigned long) 0);
  303. }
  304. *bFindName = FALSE;
  305. inaddr = 0;
  306. incstate = MustInclude;
  307. while (buffer = LmFgets(pfile, &count))
  308. {
  309. nwords = MaxTokens;
  310. current = LmpGetTokens(buffer, token, &nwords);
  311. switch ((ULONG)current.l_category)
  312. {
  313. case ErrorLine:
  314. continue;
  315. case Domain:
  316. case Ordinary:
  317. if (current.l_preload ||
  318. ((nwords - 1) < NbName))
  319. {
  320. continue;
  321. }
  322. break;
  323. case Include:
  324. if (!RecurseDepth || (incstate == SkipInclude) || (nwords < 2))
  325. {
  326. continue;
  327. }
  328. retval = LmInclude(token[1], LmGetIpAddr, target, (CHAR) (RecurseDepth-1), bFindName);
  329. if (retval != 0) {
  330. if (incstate == TryToInclude)
  331. {
  332. incstate = SkipInclude;
  333. }
  334. } else {
  335. if (incstate == MustInclude)
  336. {
  337. IF_DBG(NBT_DEBUG_LMHOST)
  338. KdPrint(("Nbt.LmGetIpAddr: Can't #INCLUDE \"%s\"", token[1]));
  339. }
  340. continue;
  341. }
  342. inaddr = retval;
  343. goto found;
  344. case BeginAlternate:
  345. ASSERT(nwords == 1);
  346. incstate = TryToInclude;
  347. continue;
  348. case EndAlternate:
  349. ASSERT(nwords == 1);
  350. incstate = MustInclude;
  351. continue;
  352. default:
  353. continue;
  354. }
  355. if (strlen(token[NbName]) == (NETBIOS_NAME_SIZE))
  356. {
  357. if (strncmp(token[NbName], target, (NETBIOS_NAME_SIZE)) != 0)
  358. {
  359. continue;
  360. }
  361. } else
  362. {
  363. //
  364. // attempt to match, in a case insensitive manner, the first 15
  365. // bytes of the lmhosts entry with the target name.
  366. //
  367. LmExpandName(temp, token[NbName], 0);
  368. if (strncmp(temp, target, NETBIOS_NAME_SIZE - 1) != 0)
  369. {
  370. continue;
  371. }
  372. }
  373. if (current.l_nofnr)
  374. {
  375. *bFindName = TRUE;
  376. }
  377. status = ConvertDottedDecimalToUlong(token[IpAddress],&inaddr);
  378. if (!NT_SUCCESS(status))
  379. {
  380. inaddr = 0;
  381. }
  382. break;
  383. }
  384. found:
  385. status = LmCloseFile(pfile);
  386. ASSERT(status == STATUS_SUCCESS);
  387. if (!NT_SUCCESS(status))
  388. {
  389. *bFindName = FALSE;
  390. }
  391. IF_DBG(NBT_DEBUG_LMHOST)
  392. KdPrint(("Nbt.LmGetIpAddr: (\"%15.15s<%X>\") = %X\n",target,target[15],inaddr));
  393. return(inaddr);
  394. } // LmGetIpAddr
  395. //----------------------------------------------------------------------------
  396. LONG
  397. HandleSpecial(
  398. IN CHAR **pch)
  399. /*++
  400. Routine Description:
  401. This function converts ASCII hex into a ULONG.
  402. Arguments:
  403. Return Value:
  404. The ip address (network byte order), or 0 if no appropriate entry was
  405. found.
  406. Note that in most contexts (but not here), ip address 0 signifies
  407. "this host."
  408. --*/
  409. {
  410. int sval;
  411. int rval;
  412. char *sp = *pch;
  413. int i;
  414. CTEPagedCode();
  415. sp++;
  416. switch (*sp)
  417. {
  418. case '\\':
  419. // the second character is also a \ so return a \ and set pch to
  420. // point to the next character (\)
  421. //
  422. *pch = sp;
  423. return((int)'\\');
  424. default:
  425. // convert some number of characters to hex and increment pch
  426. // the expected format is "\0x03"
  427. //
  428. // sscanf(sp, "%2x%n", &sval, &rval);
  429. sval = 0;
  430. rval = 0;
  431. sp++;
  432. // check for the 0x part of the hex number
  433. if (*sp != 'x')
  434. {
  435. *pch = sp;
  436. return(-1);
  437. }
  438. sp++;
  439. for (i=0;(( i<2 ) && *sp) ;i++ )
  440. {
  441. if (*sp != ' ')
  442. {
  443. // convert from ASCII to hex, allowing capitals too
  444. //
  445. if (*sp >= 'a')
  446. {
  447. sval = *sp - 'a' + 10 + sval*16;
  448. }
  449. else
  450. if (*sp >= 'A')
  451. {
  452. sval = *sp - 'A' + 10 + sval*16;
  453. }
  454. else
  455. {
  456. sval = *sp - '0' + sval*16;
  457. }
  458. sp++;
  459. rval++;
  460. }
  461. else
  462. break;
  463. }
  464. if (rval < 1)
  465. {
  466. *pch = sp;
  467. return(-1);
  468. }
  469. *pch += (rval+2); // remember to account for the characters 0 and x
  470. return(sval);
  471. }
  472. }
  473. #define LMHASSERT(s) if (!(s)) \
  474. { retval.l_category = ErrorLine; return(retval); }
  475. //----------------------------------------------------------------------------
  476. LINE_CHARACTERISTICS
  477. LmpGetTokens (
  478. IN OUT PUCHAR line,
  479. OUT PUCHAR *token,
  480. IN OUT int *pnumtokens
  481. )
  482. /*++
  483. Routine Description:
  484. This function parses a line for tokens. A maximum of *pnumtokens
  485. are collected.
  486. Arguments:
  487. line - pointer to the NULL terminated line to parse
  488. token - an array of pointers to tokens collected
  489. *pnumtokens - on input, number of elements in the array, token[];
  490. on output, number of tokens collected in token[]
  491. Return Value:
  492. The characteristics of this lmhosts line.
  493. Notes:
  494. 1. Each token must be separated by white space. Hence, the keyword
  495. "#PRE" in the following line won't be recognized:
  496. 11.1.12.132 lothair#PRE
  497. 2. Any ordinary line can be decorated with a "#PRE", a "#DOM:name" or
  498. both. Hence, the following lines must all be recognized:
  499. 111.21.112.3 kernel #DOM:ntwins #PRE
  500. 111.21.112.4 orville #PRE #DOM:ntdev
  501. 111.21.112.7 cliffv4 #DOM:ntlan
  502. 111.21.112.132 lothair #PRE
  503. --*/
  504. {
  505. enum _PARSE
  506. { // current fsm state
  507. StartofLine,
  508. WhiteSpace,
  509. AmidstToken
  510. } state;
  511. PUCHAR pch; // current fsm input
  512. PUCHAR och;
  513. PKEYWORD keyword;
  514. int index, maxtokens, quoted, rchar;
  515. LINE_CHARACTERISTICS retval;
  516. CTEPagedCode();
  517. CTEZeroMemory(token, *pnumtokens * sizeof(PUCHAR *));
  518. state = StartofLine;
  519. retval.l_category = Ordinary;
  520. retval.l_preload = 0;
  521. retval.l_nofnr = 0;
  522. maxtokens = *pnumtokens;
  523. index = 0;
  524. quoted = 0;
  525. for (pch = line; *pch; pch++)
  526. {
  527. switch (*pch)
  528. {
  529. //
  530. // does the '#' signify the start of a reserved keyword, or the
  531. // start of a comment ?
  532. //
  533. //
  534. case '#':
  535. if (quoted)
  536. {
  537. *och++ = *pch;
  538. continue;
  539. }
  540. keyword = LmpIsKeyWord(
  541. pch,
  542. (state == StartofLine) ? Directive : Decoration);
  543. if (keyword)
  544. {
  545. state = AmidstToken;
  546. maxtokens = keyword->k_noperands;
  547. switch (keyword->k_type)
  548. {
  549. case NoFNR:
  550. retval.l_nofnr = 1;
  551. continue;
  552. case Preload:
  553. retval.l_preload = 1;
  554. continue;
  555. default:
  556. LMHASSERT(maxtokens <= *pnumtokens);
  557. LMHASSERT(index < maxtokens);
  558. token[index++] = pch;
  559. retval.l_category = keyword->k_type;
  560. continue;
  561. }
  562. LMHASSERT(0);
  563. }
  564. if (state == StartofLine)
  565. {
  566. retval.l_category = Comment;
  567. }
  568. /* fall through */
  569. case '\r':
  570. case '\n':
  571. *pch = (UCHAR) NULL;
  572. if (quoted)
  573. {
  574. *och = (UCHAR) NULL;
  575. }
  576. goto done;
  577. case ' ':
  578. case '\t':
  579. if (quoted)
  580. {
  581. *och++ = *pch;
  582. continue;
  583. }
  584. if (state == AmidstToken)
  585. {
  586. state = WhiteSpace;
  587. *pch = (UCHAR) NULL;
  588. if (index == maxtokens)
  589. {
  590. goto done;
  591. }
  592. }
  593. continue;
  594. case '"':
  595. if ((state == AmidstToken) && quoted)
  596. {
  597. state = WhiteSpace;
  598. quoted = 0;
  599. *pch = (UCHAR) NULL;
  600. *och = (UCHAR) NULL;
  601. if (index == maxtokens)
  602. {
  603. goto done;
  604. }
  605. continue;
  606. }
  607. state = AmidstToken;
  608. quoted = 1;
  609. LMHASSERT(maxtokens <= *pnumtokens);
  610. LMHASSERT(index < maxtokens);
  611. token[index++] = pch + 1;
  612. och = pch + 1;
  613. continue;
  614. case '\\':
  615. if (quoted)
  616. {
  617. rchar = HandleSpecial(&pch);
  618. if (rchar == -1)
  619. {
  620. retval.l_category = ErrorLine;
  621. return(retval);
  622. }
  623. *och++ = (UCHAR)rchar;
  624. //
  625. // put null on end of string
  626. //
  627. continue;
  628. }
  629. default:
  630. if (quoted)
  631. {
  632. *och++ = *pch;
  633. continue;
  634. }
  635. if (state == AmidstToken)
  636. {
  637. continue;
  638. }
  639. state = AmidstToken;
  640. LMHASSERT(maxtokens <= *pnumtokens);
  641. LMHASSERT(index < maxtokens);
  642. token[index++] = pch;
  643. continue;
  644. }
  645. }
  646. done:
  647. //
  648. // if there is no name on the line, then return an error
  649. //
  650. if (index <= NbName && index != maxtokens)
  651. {
  652. retval.l_category = ErrorLine;
  653. }
  654. ASSERT(!*pch);
  655. ASSERT(maxtokens <= *pnumtokens);
  656. ASSERT(index <= *pnumtokens);
  657. *pnumtokens = index;
  658. return(retval);
  659. } // LmpGetTokens
  660. //----------------------------------------------------------------------------
  661. PKEYWORD
  662. LmpIsKeyWord (
  663. IN PUCHAR string,
  664. IN PKEYWORD table
  665. )
  666. /*++
  667. Routine Description:
  668. This function determines whether the string is a reserved keyword.
  669. Arguments:
  670. string - the string to search
  671. table - an array of keywords to look for
  672. Return Value:
  673. A pointer to the relevant keyword object, or NULL if unsuccessful
  674. --*/
  675. {
  676. size_t limit;
  677. PKEYWORD special;
  678. CTEPagedCode();
  679. limit = strlen(string);
  680. for (special = table; special->k_string; special++)
  681. {
  682. if (limit < special->k_strlen)
  683. {
  684. continue;
  685. }
  686. if ((limit >= special->k_strlen) &&
  687. !strncmp(string, special->k_string, special->k_strlen))
  688. {
  689. return(special);
  690. }
  691. }
  692. return((PKEYWORD) NULL);
  693. } // LmpIsKeyWord
  694. //----------------------------------------------------------------------------
  695. BOOLEAN
  696. LmpBreakRecursion(
  697. IN PUCHAR path,
  698. IN PUCHAR target,
  699. IN ULONG TargetLength
  700. )
  701. /*++
  702. Routine Description:
  703. This function checks that the file name we are about to open
  704. does not use the target name of this search, which would
  705. cause an infinite lookup loop.
  706. Arguments:
  707. path - a fully specified path to a lmhosts file
  708. target - the unencoded 16 byte NetBIOS name to look for
  709. Return Value:
  710. TRUE if the UNC server name in the file path is the same as the
  711. target of this search. FALSE otherwise.
  712. Notes:
  713. This function does not detect redirected drives.
  714. --*/
  715. {
  716. PCHAR keystring = "\\DosDevices\\UNC\\";
  717. PCHAR servername[NETBIOS_NAME_SIZE+1]; // for null on end
  718. PCHAR marker1;
  719. PCHAR marker2;
  720. PCHAR marker3;
  721. BOOLEAN retval = FALSE;
  722. tNAMEADDR *pNameAddr;
  723. ULONG uType;
  724. CTEPagedCode();
  725. //
  726. // Check for and extract the UNC server name
  727. //
  728. if ((path) && (strlen(path) > strlen(keystring)))
  729. {
  730. // check that the name is a unc name
  731. if (strncmp(path, keystring, strlen(keystring)) == 0)
  732. {
  733. marker1 = path + strlen(keystring); // the end of the \DosDevices\Unc\ string
  734. marker3 = &path[strlen(path)-1]; // the end of the whole path
  735. marker2 = strchr(marker1,'\\'); // the end of the server name
  736. if ((marker2) && // marker2 can be NULL if '\\' does not exist in the string
  737. (marker2 != marker3))
  738. {
  739. *marker2 = '\0';
  740. //
  741. // attempt to match, in a case insensitive manner, the
  742. // first 15 bytes of the lmhosts entry with the target
  743. // name.
  744. //
  745. LmExpandName((PUCHAR)servername, marker1, 0);
  746. if(strncmp((PUCHAR)servername, target, TargetLength) == 0)
  747. {
  748. //
  749. // break the recursion
  750. //
  751. retval = TRUE;
  752. IF_DBG(NBT_DEBUG_LMHOST)
  753. KdPrint(("Nbt.LmpBreakRecursion: Not including Lmhosts file <%s> because of recursive name\n",
  754. servername));
  755. }
  756. else
  757. {
  758. //
  759. // check if the name has been preloaded in the cache, and
  760. // if not, fail the request so we can't get into a loop
  761. // trying to include the remote file while trying to
  762. // resolve the remote name
  763. //
  764. pNameAddr = LockAndFindName(NBT_REMOTE,
  765. (PCHAR)servername,
  766. NbtConfig.pScope,
  767. &uType);
  768. if (!pNameAddr || !(pNameAddr->NameTypeState & PRELOADED) )
  769. {
  770. //
  771. // break the recursion
  772. //
  773. retval = TRUE;
  774. IF_DBG(NBT_DEBUG_LMHOST)
  775. KdPrint(("Nbt.LmpBreakRecursion: Not including Lmhosts #include because name not Preloaded %s\n",
  776. servername));
  777. }
  778. }
  779. *marker2 = '\\';
  780. }
  781. }
  782. }
  783. return(retval);
  784. }
  785. //----------------------------------------------------------------------------
  786. char *
  787. LmExpandName (
  788. OUT PUCHAR dest,
  789. IN PUCHAR source,
  790. IN UCHAR last
  791. )
  792. /*++
  793. Routine Description:
  794. This function expands an lmhosts entry into a full 16 byte NetBIOS
  795. name. It is padded with blanks up to 15 bytes; the 16th byte is the
  796. input parameter, last.
  797. This function does not encode 1st level names to 2nd level names nor
  798. vice-versa.
  799. Both dest and source are NULL terminated strings.
  800. Arguments:
  801. dest - sizeof(dest) must be NBT_NONCODED_NMSZ
  802. source - the lmhosts entry
  803. last - the 16th byte of the NetBIOS name
  804. Return Value:
  805. dest.
  806. --*/
  807. {
  808. char byte;
  809. char *retval = dest;
  810. char *src = source ;
  811. #ifndef VXD
  812. WCHAR unicodebuf[NETBIOS_NAME_SIZE+1];
  813. UNICODE_STRING unicode;
  814. STRING tmp;
  815. #endif
  816. NTSTATUS status;
  817. PUCHAR limit;
  818. CTEPagedCode();
  819. //
  820. // first, copy the source OEM string to the destination, pad it, and
  821. // add the last character.
  822. //
  823. limit = dest + NETBIOS_NAME_SIZE - 1;
  824. while ( (*source != '\0') && (dest < limit) )
  825. {
  826. *dest++ = *source++;
  827. }
  828. while(dest < limit)
  829. {
  830. *dest++ = ' ';
  831. }
  832. ASSERT(dest == (retval + NETBIOS_NAME_SIZE - 1));
  833. *dest = '\0';
  834. *(dest + 1) = '\0';
  835. dest = retval;
  836. #ifndef VXD
  837. //
  838. // Now, convert to unicode then to ANSI to force the OEM -> ANSI munge.
  839. // Then convert back to Unicode and uppercase the name. Finally convert
  840. // back to OEM.
  841. //
  842. unicode.Length = 0;
  843. unicode.MaximumLength = 2*(NETBIOS_NAME_SIZE+1);
  844. unicode.Buffer = unicodebuf;
  845. RtlInitString(&tmp, dest);
  846. status = RtlOemStringToUnicodeString(&unicode, &tmp, FALSE);
  847. if (!NT_SUCCESS(status))
  848. {
  849. IF_DBG(NBT_DEBUG_LMHOST)
  850. KdPrint (("Nbt.LmExpandName: Oem -> Unicode failed, status %X\n", status));
  851. goto oldupcase;
  852. }
  853. status = RtlUnicodeStringToAnsiString(&tmp, &unicode, FALSE);
  854. if (!NT_SUCCESS(status))
  855. {
  856. IF_DBG(NBT_DEBUG_LMHOST)
  857. KdPrint (("Nbt.LmExpandName: Unicode -> Ansi failed, status %X\n", status));
  858. goto oldupcase;
  859. }
  860. status = RtlAnsiStringToUnicodeString(&unicode, &tmp, FALSE);
  861. if (!NT_SUCCESS(status))
  862. {
  863. IF_DBG(NBT_DEBUG_LMHOST)
  864. KdPrint (("Nbt.LmExpandName: Ansi -> Unicode failed, status %X\n", status));
  865. goto oldupcase;
  866. }
  867. status = RtlUpcaseUnicodeStringToOemString(&tmp, &unicode, FALSE);
  868. if (!NT_SUCCESS(status))
  869. {
  870. IF_DBG(NBT_DEBUG_LMHOST)
  871. KdPrint (("Nbt.LmExpandName: Unicode upcase -> Oem failed, status %X\n", status));
  872. goto oldupcase;
  873. }
  874. // write the last byte to "0x20" or "0x03" or whatever
  875. // since we do not want it to go through the munge above.
  876. //
  877. dest[NETBIOS_NAME_SIZE-1] = last;
  878. return(retval);
  879. #endif
  880. oldupcase:
  881. for ( source = src ; dest < (retval + NETBIOS_NAME_SIZE - 1); dest++)
  882. {
  883. byte = *(source++);
  884. if (!byte)
  885. {
  886. break;
  887. }
  888. // Don't use the c-runtime (nt c defn. included first)
  889. // What about extended characters etc.? Since extended characters do
  890. // not normally part of netbios names, we will fix if requested
  891. *dest = (byte >= 'a' && byte <= 'z') ? byte-'a' + 'A' : byte ;
  892. // *dest = islower(byte) ? toupper(byte) : byte;
  893. }
  894. for (; dest < retval + NETBIOS_NAME_SIZE - 1; dest++)
  895. {
  896. *dest = ' ';
  897. }
  898. ASSERT(dest == (retval + NETBIOS_NAME_SIZE - 1));
  899. *dest = last;
  900. *(dest + 1) = (char) NULL;
  901. return(retval);
  902. } // LmExpandName
  903. //----------------------------------------------------------------------------
  904. unsigned long
  905. LmInclude(
  906. IN PUCHAR file,
  907. IN LM_PARSE_FUNCTION function,
  908. IN PUCHAR argument OPTIONAL,
  909. IN CHAR RecurseDepth,
  910. OUT BOOLEAN *NoFindName OPTIONAL
  911. )
  912. /*++
  913. Routine Description:
  914. LmInclude() is called to process a #INCLUDE directive in the lmhosts
  915. file.
  916. Arguments:
  917. file - the file to include
  918. function - function to parse the included file
  919. argument - optional second argument to the parse function
  920. RecurseDepth- the depth to which we can resurse -- 0 => no more recursion
  921. NoFindName - Are find names allowed for this address
  922. Return Value:
  923. The return value from the parse function. This should be -1 if the
  924. file could not be processed, or else some positive number.
  925. --*/
  926. {
  927. int retval;
  928. PUCHAR end;
  929. NTSTATUS status;
  930. PUCHAR path;
  931. CTEPagedCode();
  932. //
  933. // unlike C, treat both variations of the #INCLUDE directive identically:
  934. //
  935. // #INCLUDE file
  936. // #INCLUDE "file"
  937. //
  938. // If a leading '"' exists, skip over it.
  939. //
  940. if (*file == '"')
  941. {
  942. file++;
  943. end = strchr(file, '"');
  944. if (end)
  945. {
  946. *end = (UCHAR) NULL;
  947. }
  948. }
  949. //
  950. // check that the file to be included has been preloaded in the cache
  951. // since we do not want to have the name query come right back to here
  952. // to force another inclusion of the same remote file
  953. //
  954. #ifdef VXD
  955. return (*function)(file, argument, RecurseDepth, NoFindName ) ;
  956. #else
  957. status = LmGetFullPath(file, &path);
  958. if (status != STATUS_SUCCESS)
  959. {
  960. return(status);
  961. }
  962. // IF_DBG(NBT_DEBUG_LMHOST)
  963. KdPrint(("Nbt.LmInclude: #INCLUDE \"%s\"\n", path));
  964. retval = (*function) (path, argument, RecurseDepth, NoFindName);
  965. CTEMemFree(path);
  966. return(retval);
  967. #endif
  968. } // LmInclude
  969. #ifndef VXD // Not used by VXD
  970. //----------------------------------------------------------------------------
  971. NTSTATUS
  972. LmGetFullPath (
  973. IN PUCHAR target,
  974. OUT PUCHAR *ppath
  975. )
  976. /*++
  977. Routine Description:
  978. This function returns the full path of the lmhosts file. This is done
  979. by forming a string from the concatenation of the C strings
  980. DatabasePath and the string, file.
  981. Arguments:
  982. target - the name of the file. This can either be a full path name
  983. or a mere file name.
  984. path - a pointer to a UCHAR
  985. Return Value:
  986. STATUS_SUCCESS if successful.
  987. Notes:
  988. RtlMoveMemory() handles overlapped copies; RtlCopyMemory() doesn't.
  989. --*/
  990. {
  991. ULONG FileNameType;
  992. ULONG Len;
  993. PUCHAR path;
  994. CTEPagedCode();
  995. //
  996. // use a count to figure out what sort of string to build up
  997. //
  998. // 0 - local full path file name
  999. // 1 - local file name only, no path
  1000. // 2 - remote file name
  1001. // 3 - \SystemRoot\ starting file name, or \DosDevices\UNC\...
  1002. //
  1003. // if the target begins with a '\', or contains a DOS drive letter,
  1004. // then assume that it specifies a full path. Otherwise, prepend the
  1005. // directory used to specify the lmhost file itself.
  1006. //
  1007. //
  1008. if (target[1] == ':')
  1009. {
  1010. FileNameType = 0;
  1011. }
  1012. else
  1013. if (strncmp(&target[1],"SystemRoot",10) == 0)
  1014. {
  1015. FileNameType = 3;
  1016. }
  1017. else
  1018. if (strncmp(&target[0],"\\DosDevices\\",12) == 0)
  1019. {
  1020. FileNameType = 3;
  1021. }
  1022. else
  1023. if (strncmp(target,"\\DosDevices\\UNC\\",sizeof("\\DosDevices\\UNC\\")-1) == 0)
  1024. {
  1025. FileNameType = 3;
  1026. }
  1027. else
  1028. {
  1029. FileNameType = 1;
  1030. }
  1031. //
  1032. // does the directory specify a remote file ?
  1033. //
  1034. // If so, it must be prefixed with "\\DosDevices\\UNC", and the double
  1035. // slashes of the UNC name eliminated.
  1036. //
  1037. //
  1038. if ((target[1] == '\\') && (target[0] == '\\'))
  1039. {
  1040. FileNameType = 2;
  1041. }
  1042. path = NULL;
  1043. switch (FileNameType)
  1044. {
  1045. case 0:
  1046. //
  1047. // Full file name, put \DosDevices on front of name
  1048. //
  1049. Len = sizeof("\\DosDevices\\") + strlen(target);
  1050. path = NbtAllocMem (Len, NBT_TAG2('11'));
  1051. if (path)
  1052. {
  1053. ULONG Length=sizeof("\\DosDevices\\"); // Took out -1
  1054. strncpy(path,"\\DosDevices\\",Length);
  1055. Nbtstrcat(path,target,Len);
  1056. }
  1057. break;
  1058. case 1:
  1059. //
  1060. // only the file name is present, with no path, so use the path
  1061. // specified for the lmhost file in the registry NbtConfig.PathLength
  1062. // includes the last backslash of the path.
  1063. //
  1064. //Len = sizeof("\\DosDevices\\") + NbtConfig.PathLength + strlen(target);
  1065. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE); // # 247429
  1066. Len = NbtConfig.PathLength + strlen(target) +1;
  1067. path = NbtAllocMem (Len, NBT_TAG2('12'));
  1068. if (path)
  1069. {
  1070. //ULONG Length=sizeof("\\DosDevices") -1; // -1 not to count null
  1071. //strncpy(path,"\\DosDevices",Length);
  1072. strncpy(path,NbtConfig.pLmHosts,NbtConfig.PathLength);
  1073. path[NbtConfig.PathLength] = '\0';
  1074. Nbtstrcat(path,target,Len);
  1075. }
  1076. CTEExReleaseResource(&NbtConfig.Resource);
  1077. break;
  1078. case 2:
  1079. //
  1080. // Full file name, put \DosDevices\UNC on front of name and delete
  1081. // one of the two back slashes used for the remote name
  1082. //
  1083. Len = strlen(target);
  1084. path = NbtAllocMem (Len+sizeof("\\DosDevices\\UNC"), NBT_TAG2('13'));
  1085. if (path)
  1086. {
  1087. ULONG Length = sizeof("\\DosDevices\\UNC");
  1088. strncpy(path,"\\DosDevices\\UNC",Length);
  1089. // to delete the first \ from the two \\ on the front of the
  1090. // remote file name add one to target.
  1091. //
  1092. Nbtstrcat(path,target+1,Len+sizeof("\\DosDevices\\UNC"));
  1093. }
  1094. break;
  1095. case 3:
  1096. // the target is the full path
  1097. Len = strlen(target) + 1;
  1098. path = NbtAllocMem (Len, NBT_TAG2('14'));
  1099. if (path)
  1100. {
  1101. strncpy(path,target,Len);
  1102. }
  1103. break;
  1104. }
  1105. if (path)
  1106. {
  1107. *ppath = path;
  1108. return(STATUS_SUCCESS);
  1109. }
  1110. else
  1111. return(STATUS_UNSUCCESSFUL);
  1112. } // LmGetFullPath
  1113. //----------------------------------------------------------------------------
  1114. VOID
  1115. DelayedScanLmHostFile (
  1116. IN tDGRAM_SEND_TRACKING *pUnused1,
  1117. IN PVOID pUnused2,
  1118. IN PVOID pUnused3,
  1119. IN tDEVICECONTEXT *pDeviceContext
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. This function is called by the Executive Worker thread to scan the
  1124. LmHost file looking for a name. The name to query is on a list in
  1125. the DNSQueries structure.
  1126. Arguments:
  1127. Context -
  1128. Return Value:
  1129. none
  1130. --*/
  1131. {
  1132. NTSTATUS status;
  1133. LONG IpAddress;
  1134. ULONG IpAddrsList[2];
  1135. BOOLEAN bFound;
  1136. NBT_WORK_ITEM_CONTEXT *pContext;
  1137. BOOLEAN DoingDnsResolve = FALSE;
  1138. UCHAR pName[NETBIOS_NAME_SIZE];
  1139. PUCHAR LmHostsPath;
  1140. ULONG LoopCount;
  1141. tDGRAM_SEND_TRACKING *pTracker;
  1142. tDGRAM_SEND_TRACKING *pTracker0;
  1143. CTEPagedCode();
  1144. LoopCount = 0;
  1145. while (TRUE)
  1146. {
  1147. // get the next name on the linked list of LmHost name queries that
  1148. // are pending
  1149. //
  1150. pContext = NULL;
  1151. DoingDnsResolve = FALSE;
  1152. if (!(pContext = GetNameToFind(pName)))
  1153. {
  1154. return;
  1155. }
  1156. LoopCount ++;
  1157. IF_DBG(NBT_DEBUG_LMHOST)
  1158. KdPrint(("Nbt.DelayedScanLmHostFile: Lmhosts pName = %15.15s<%X>,LoopCount=%X\n",
  1159. pName,pName[15],LoopCount));
  1160. status = STATUS_TIMEOUT;
  1161. //
  1162. // check if the name is in the lmhosts file or pass to Dns if
  1163. // DNS is enabled
  1164. //
  1165. IpAddress = 0;
  1166. if (NbtConfig.EnableLmHosts)
  1167. {
  1168. #ifdef VXD
  1169. //
  1170. // if for some reason PrimeCache failed at startup time
  1171. // then this is when we retry.
  1172. //
  1173. if (!CachePrimed)
  1174. {
  1175. if (PrimeCache (NbtConfig.pLmHosts, NULL, MAX_RECURSE_DEPTH, NULL) != -1)
  1176. {
  1177. CachePrimed = TRUE ;
  1178. }
  1179. }
  1180. #endif
  1181. //
  1182. // The NbtConfig.pLmHosts path can change if the registry is
  1183. // read during this interval
  1184. // We cannot acquire the ResourceLock here since reading the
  1185. // LmHosts file might result in File operations + network reads
  1186. // that could cause a deadlock (Worker threads / ResourceLock)!
  1187. // Best solution at this time is to copy the path onto a local
  1188. // buffer under the Resource lock, and then try to read the file!
  1189. //
  1190. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  1191. if ((NbtConfig.pLmHosts) &&
  1192. (LmHostsPath = NbtAllocMem ((strlen(NbtConfig.pLmHosts)+1), NBT_TAG2('20'))))
  1193. {
  1194. CTEMemCopy (LmHostsPath, NbtConfig.pLmHosts, (strlen(NbtConfig.pLmHosts)+1));
  1195. CTEExReleaseResource(&NbtConfig.Resource);
  1196. IpAddress = LmGetIpAddr(LmHostsPath, pName, 1, &bFound);
  1197. CTEMemFree(LmHostsPath);
  1198. }
  1199. else
  1200. {
  1201. CTEExReleaseResource(&NbtConfig.Resource);
  1202. IpAddress = 0;
  1203. }
  1204. #ifdef VXD
  1205. //
  1206. // hmmm.. didn't find it in lmhosts: try hosts (if Dns is enabled)
  1207. //
  1208. if ((IpAddress == (ULONG)0) && (NbtConfig.ResolveWithDns))
  1209. {
  1210. IpAddress = LmGetIpAddr(NbtConfig.pHosts, pName, 1, &bFound);
  1211. }
  1212. #endif
  1213. }
  1214. if (IpAddress == (ULONG)0)
  1215. {
  1216. // check if the name query has been cancelled
  1217. //
  1218. LOCATION(0x61);
  1219. GetContext (&pContext);
  1220. //
  1221. // for some reason we didn't find our context: maybe cancelled.
  1222. // Go back to the big while loop...
  1223. //
  1224. if (!pContext)
  1225. {
  1226. continue;
  1227. }
  1228. //
  1229. // see if the name is in the 11.101.4.26 format: if so, we got the
  1230. // ipaddr! Use that ipaddr to get the server name
  1231. //
  1232. pTracker = ((NBT_WORK_ITEM_CONTEXT *)pContext)->pTracker;
  1233. pTracker0 = (tDGRAM_SEND_TRACKING *)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
  1234. if (pTracker0->Flags & (REMOTE_ADAPTER_STAT_FLAG|SESSION_SETUP_FLAG|DGRAM_SEND_FLAG))
  1235. {
  1236. IpAddress = Nbt_inet_addr(pTracker->pNameAddr->Name, pTracker0->Flags);
  1237. }
  1238. //
  1239. // yes, the name is the ipaddr: NbtCompleteLmhSvcRequest() starts
  1240. // the process of finding out server name for this ipaddr
  1241. //
  1242. if (IpAddress)
  1243. {
  1244. IpAddrsList[0] = IpAddress;
  1245. IpAddrsList[1] = 0;
  1246. //
  1247. // if this is in response to an adapter stat command (e.g.nbtstat -a) then
  1248. // don't try to find the server name (using remote adapter status!)
  1249. //
  1250. if (pTracker0->Flags & REMOTE_ADAPTER_STAT_FLAG)
  1251. {
  1252. //
  1253. // change the state to resolved if the name query is still pending
  1254. //
  1255. status = ChangeStateOfName(IpAddress, pContext, &pContext, NAME_RESOLVED_BY_IP);
  1256. }
  1257. else
  1258. {
  1259. NbtCompleteLmhSvcRequest(pContext, IpAddrsList, NBT_RESOLVE_WITH_DNS, 0, NULL, TRUE);
  1260. //
  1261. // done with this name query: go back to the big while loop
  1262. //
  1263. continue;
  1264. }
  1265. }
  1266. //
  1267. //
  1268. // inet_addr failed. If DNS resolution is enabled, try DNS
  1269. else if ((NbtConfig.ResolveWithDns) &&
  1270. (!(pTracker0->Flags & NO_DNS_RESOLUTION_FLAG)))
  1271. {
  1272. status = NbtProcessLmhSvcRequest (pContext, NBT_RESOLVE_WITH_DNS);
  1273. if (NT_SUCCESS(status))
  1274. {
  1275. DoingDnsResolve = TRUE;
  1276. }
  1277. }
  1278. }
  1279. else // if (IpAddress != (ULONG)0)
  1280. {
  1281. //
  1282. // change the state to resolved if the name query is still pending
  1283. //
  1284. status = ChangeStateOfName(IpAddress, NULL, &pContext, NAME_RESOLVED_BY_LMH);
  1285. }
  1286. //
  1287. // if DNS gets involved, then we wait for that to complete before calling
  1288. // completion routine.
  1289. //
  1290. if (!DoingDnsResolve)
  1291. {
  1292. LOCATION(0x60);
  1293. RemoveNameAndCompleteReq((NBT_WORK_ITEM_CONTEXT *)pContext, status);
  1294. }
  1295. }// of while(TRUE)
  1296. }
  1297. //----------------------------------------------------------------------------
  1298. ULONG
  1299. AddToDomainList (
  1300. IN PUCHAR pName,
  1301. IN tIPADDRESS IpAddress,
  1302. IN PLIST_ENTRY pDomainHead,
  1303. IN BOOLEAN fPreload
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. This function adds a name and ip address to the list of domains that
  1308. are stored in a list.
  1309. Arguments:
  1310. Return Value:
  1311. --*/
  1312. {
  1313. PLIST_ENTRY pHead;
  1314. PLIST_ENTRY pEntry;
  1315. tNAMEADDR *pNameAddr=NULL;
  1316. tIPADDRESS *pIpAddr;
  1317. CTEPagedCode();
  1318. pHead = pEntry = pDomainHead;
  1319. if (!IsListEmpty(pDomainHead))
  1320. {
  1321. pNameAddr = FindInDomainList(pName,pDomainHead);
  1322. if (pNameAddr)
  1323. {
  1324. //
  1325. // the name matches, so add to the end of the ip address list
  1326. //
  1327. if (pNameAddr->CurrentLength < pNameAddr->MaxDomainAddrLength)
  1328. {
  1329. pIpAddr = pNameAddr->pLmhSvcGroupList;
  1330. while (*pIpAddr != (ULONG)-1) {
  1331. pIpAddr++;
  1332. }
  1333. *pIpAddr++ = IpAddress;
  1334. *pIpAddr = (ULONG)-1;
  1335. pNameAddr->CurrentLength += sizeof(ULONG);
  1336. }
  1337. else
  1338. {
  1339. //
  1340. // need to allocate more memory for for ip addresses
  1341. //
  1342. if (pIpAddr = NbtAllocMem (pNameAddr->MaxDomainAddrLength+INITIAL_DOM_SIZE, NBT_TAG2('08')))
  1343. {
  1344. CTEMemCopy(pIpAddr, pNameAddr->pLmhSvcGroupList, pNameAddr->MaxDomainAddrLength);
  1345. //
  1346. // Free the old chunk of memory and tack the new one on
  1347. // to the pNameaddr
  1348. //
  1349. CTEMemFree(pNameAddr->pLmhSvcGroupList);
  1350. pNameAddr->pLmhSvcGroupList = pIpAddr;
  1351. pIpAddr = (PULONG)((PUCHAR)pIpAddr + pNameAddr->MaxDomainAddrLength);
  1352. //
  1353. // our last entry was -1: overwrite that one
  1354. //
  1355. pIpAddr--;
  1356. *pIpAddr++ = IpAddress;
  1357. *pIpAddr = (ULONG)-1;
  1358. //
  1359. // update the number of addresses in the list so far
  1360. //
  1361. pNameAddr->MaxDomainAddrLength += INITIAL_DOM_SIZE;
  1362. pNameAddr->CurrentLength += sizeof(ULONG);
  1363. pNameAddr->Verify = REMOTE_NAME;
  1364. }
  1365. }
  1366. }
  1367. }
  1368. //
  1369. // check if we found the name or we need to add a new name
  1370. //
  1371. if (!pNameAddr)
  1372. {
  1373. //
  1374. // create a new name for the domain list
  1375. //
  1376. if (pNameAddr = NbtAllocMem (sizeof(tNAMEADDR), NBT_TAG2('09')))
  1377. {
  1378. CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
  1379. pIpAddr = NbtAllocMem (INITIAL_DOM_SIZE, NBT_TAG2('10'));
  1380. if (pIpAddr)
  1381. {
  1382. CTEMemCopy(pNameAddr->Name,pName,NETBIOS_NAME_SIZE);
  1383. pNameAddr->pLmhSvcGroupList = pIpAddr;
  1384. *pIpAddr++ = IpAddress;
  1385. *pIpAddr = (ULONG)-1;
  1386. pNameAddr->NameTypeState = NAMETYPE_INET_GROUP;
  1387. pNameAddr->MaxDomainAddrLength = INITIAL_DOM_SIZE;
  1388. pNameAddr->CurrentLength = 2*sizeof(ULONG);
  1389. pNameAddr->Verify = REMOTE_NAME;
  1390. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE);
  1391. InsertHeadList(pDomainHead,&pNameAddr->Linkage);
  1392. }
  1393. else
  1394. {
  1395. CTEMemFree(pNameAddr);
  1396. pNameAddr = NULL;
  1397. }
  1398. }
  1399. }
  1400. if (pNameAddr && fPreload)
  1401. {
  1402. pNameAddr->fPreload = TRUE;
  1403. }
  1404. return(STATUS_SUCCESS);
  1405. }
  1406. //----------------------------------------------------------------------------
  1407. tNAMEADDR *
  1408. FindInDomainList (
  1409. IN PUCHAR pName,
  1410. IN PLIST_ENTRY pDomainHead
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. This function finds a name in the domain list passed in.
  1415. Arguments:
  1416. name to find
  1417. head of list to look on
  1418. Return Value:
  1419. ptr to pNameaddr
  1420. --*/
  1421. {
  1422. PLIST_ENTRY pHead;
  1423. PLIST_ENTRY pEntry;
  1424. tNAMEADDR *pNameAddr;
  1425. pHead = pEntry = pDomainHead;
  1426. while ((pEntry = pEntry->Flink) != pHead)
  1427. {
  1428. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  1429. if (strncmp(pNameAddr->Name,pName,NETBIOS_NAME_SIZE) == 0)
  1430. {
  1431. return(pNameAddr);
  1432. }
  1433. }
  1434. return(NULL);
  1435. }
  1436. //----------------------------------------------------------------------------
  1437. VOID
  1438. MakeNewListCurrent (
  1439. PLIST_ENTRY pTmpDomainList
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. This function frees the old entries on the DomainList and hooks up the
  1444. new entries
  1445. Arguments:
  1446. pTmpDomainList - list entry to the head of a new domain list
  1447. Return Value:
  1448. --*/
  1449. {
  1450. CTELockHandle OldIrq;
  1451. tNAMEADDR *pNameAddr;
  1452. PLIST_ENTRY pEntry;
  1453. PLIST_ENTRY pHead;
  1454. NTSTATUS status;
  1455. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1456. if (!IsListEmpty(pTmpDomainList))
  1457. {
  1458. //
  1459. // free the old list elements
  1460. //
  1461. pHead = &DomainNames.DomainList;
  1462. pEntry = pHead->Flink;
  1463. while (pEntry != pHead)
  1464. {
  1465. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  1466. pEntry = pEntry->Flink;
  1467. RemoveEntryList(&pNameAddr->Linkage);
  1468. //
  1469. // initialize linkage so that if the nameaddr is being
  1470. // referenced now, when it does get freed in a subsequent
  1471. // call to NBT_DEREFERENCE_NAMEADDR it will not
  1472. // remove it from any lists
  1473. //
  1474. InitializeListHead(&pNameAddr->Linkage);
  1475. //
  1476. // Since the name could be in use now we must dereference rather
  1477. // than just free it outright
  1478. //
  1479. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  1480. }
  1481. //
  1482. // See if any of the new names has to be preloaded!
  1483. //
  1484. pEntry = pTmpDomainList->Flink;
  1485. while (pEntry != pTmpDomainList)
  1486. {
  1487. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  1488. pEntry = pEntry->Flink;
  1489. if (pNameAddr->fPreload)
  1490. {
  1491. RemoveEntryList(&pNameAddr->Linkage);
  1492. InitializeListHead(&pNameAddr->Linkage);
  1493. status = AddToHashTable (NbtConfig.pRemoteHashTbl,
  1494. pNameAddr->Name,
  1495. NbtConfig.pScope,
  1496. 0,
  1497. 0,
  1498. pNameAddr,
  1499. &pNameAddr,
  1500. NULL,
  1501. NAME_RESOLVED_BY_LMH_P | NAME_ADD_INET_GROUP);
  1502. if ((status == STATUS_SUCCESS) ||
  1503. ((status == STATUS_PENDING) &&
  1504. (!(pNameAddr->NameTypeState & PRELOADED))))
  1505. {
  1506. //
  1507. // this prevents the name from being deleted by the Hash Timeout code
  1508. //
  1509. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_PRELOADED);
  1510. pNameAddr->Ttl = 0xFFFFFFFF;
  1511. pNameAddr->NameTypeState |= PRELOADED | STATE_RESOLVED;
  1512. pNameAddr->NameTypeState &= ~STATE_CONFLICT;
  1513. pNameAddr->AdapterMask = (CTEULONGLONG)-1;
  1514. }
  1515. }
  1516. }
  1517. DomainNames.DomainList.Flink = pTmpDomainList->Flink;
  1518. DomainNames.DomainList.Blink = pTmpDomainList->Blink;
  1519. pTmpDomainList->Flink->Blink = &DomainNames.DomainList;
  1520. pTmpDomainList->Blink->Flink = &DomainNames.DomainList;
  1521. }
  1522. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1523. }
  1524. //----------------------------------------------------------------------------
  1525. NTSTATUS
  1526. NtProcessLmHSvcIrp(
  1527. IN tDEVICECONTEXT *pDeviceContext,
  1528. IN PVOID *pBuffer,
  1529. IN LONG Size,
  1530. IN PCTE_IRP pIrp,
  1531. IN enum eNbtLmhRequestType RequestType
  1532. )
  1533. /*++
  1534. Routine Description:
  1535. This function is used by LmHsvc Dll to collect requests for
  1536. Pinging IP addresses or querying through DNS.
  1537. The request is sent to LmhSvc in the buffer associated with
  1538. this request.
  1539. Arguments:
  1540. Return Value:
  1541. STATUS_PENDING if the buffer is to be held on to, the normal case.
  1542. Notes:
  1543. --*/
  1544. {
  1545. NTSTATUS status;
  1546. NTSTATUS Locstatus;
  1547. CTELockHandle OldIrq;
  1548. tIPADDR_BUFFER_DNS *pIpAddrBuf;
  1549. PVOID pClientCompletion;
  1550. PVOID pClientContext;
  1551. tDGRAM_SEND_TRACKING *pTracker;
  1552. ULONG IpAddrsList[MAX_IPADDRS_PER_HOST+1];
  1553. NBT_WORK_ITEM_CONTEXT *pContext;
  1554. BOOLEAN CompletingAnotherQuery = FALSE;
  1555. tLMHSVC_REQUESTS *pLmhRequest;
  1556. tDEVICECONTEXT *pDeviceContextRequest;
  1557. pIpAddrBuf = (tIPADDR_BUFFER_DNS *)pBuffer;
  1558. switch (RequestType)
  1559. {
  1560. case NBT_PING_IP_ADDRS:
  1561. {
  1562. pLmhRequest = &CheckAddr;
  1563. break;
  1564. }
  1565. case NBT_RESOLVE_WITH_DNS:
  1566. {
  1567. pLmhRequest = &DnsQueries;
  1568. break;
  1569. }
  1570. default:
  1571. {
  1572. ASSERTMSG ("Nbt.NtProcessLmHSvcIrp: ERROR - Invalid Request from LmhSvc Dll\n", 0);
  1573. return STATUS_UNSUCCESSFUL;
  1574. }
  1575. }
  1576. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1577. //
  1578. // If we already have an Irp posted, return this Irp -- Bug # 311924
  1579. //
  1580. if ((pLmhRequest->QueryIrp) &&
  1581. (!pLmhRequest->ResolvingNow))
  1582. {
  1583. CTESpinFree (&NbtConfig.JointLock,OldIrq);
  1584. KdPrint (("Nbt.NtProcessLmHSvcIrp: ERROR -- duplicate request Irp!\n"));
  1585. NTIoComplete (pIrp, STATUS_OBJECT_PATH_INVALID, 0);
  1586. NbtTrace(NBT_TRACE_NAMESRV, ("%!FUNC! duplicate Lmhosts request"));
  1587. return STATUS_OBJECT_PATH_INVALID;
  1588. }
  1589. IoMarkIrpPending(pIrp);
  1590. pLmhRequest->QueryIrp = pIrp;
  1591. status = STATUS_PENDING;
  1592. if (pLmhRequest->ResolvingNow)
  1593. {
  1594. //
  1595. // if the client got tired of waiting for DNS, the NbtCancelWaitForLmhSvcIrp
  1596. // in ntisol.c will have cleared the pContext value when cancelling the
  1597. // irp, so check for that here.
  1598. //
  1599. if (pLmhRequest->Context)
  1600. {
  1601. pContext = (NBT_WORK_ITEM_CONTEXT *) pLmhRequest->Context;
  1602. pLmhRequest->Context = NULL;
  1603. pDeviceContextRequest = pContext->pDeviceContext;
  1604. if (NBT_REFERENCE_DEVICE (pDeviceContextRequest, REF_DEV_LMH, TRUE))
  1605. {
  1606. NbtCancelCancelRoutine (((tDGRAM_SEND_TRACKING *) (pContext->pClientContext))->pClientIrp);
  1607. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1608. ASSERT(sizeof(pIpAddrBuf->pwName) == DNS_NAME_BUFFER_LENGTH * sizeof(pIpAddrBuf->pwName[0]));
  1609. pIpAddrBuf->pwName[DNS_NAME_BUFFER_LENGTH-1] = 0;
  1610. NbtCompleteLmhSvcRequest (pContext,
  1611. pIpAddrBuf->IpAddrsList,
  1612. RequestType,
  1613. pIpAddrBuf->NameLen,
  1614. pIpAddrBuf->pwName,
  1615. (BOOLEAN)pIpAddrBuf->Resolved);
  1616. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1617. NBT_DEREFERENCE_DEVICE (pDeviceContextRequest, REF_DEV_LMH, TRUE);
  1618. }
  1619. else
  1620. {
  1621. ASSERT (0);
  1622. }
  1623. }
  1624. else
  1625. {
  1626. IF_DBG(NBT_DEBUG_NAMESRV)
  1627. KdPrint(("Nbt.NtProcessLmHSvcIrp[%s]: No Context!! *******\r\n",
  1628. (RequestType == NBT_RESOLVE_WITH_DNS ? "NBT_RESOLVE_WITH_DNS" : "NBT_PING_IP_ADDRS")));
  1629. }
  1630. pLmhRequest->ResolvingNow = FALSE;
  1631. //
  1632. // are there any more name query requests to process?
  1633. //
  1634. while (!IsListEmpty(&pLmhRequest->ToResolve))
  1635. {
  1636. PLIST_ENTRY pEntry;
  1637. pEntry = RemoveHeadList(&pLmhRequest->ToResolve);
  1638. pContext = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
  1639. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1640. Locstatus = NbtProcessLmhSvcRequest (pContext, RequestType);
  1641. if (NT_SUCCESS(Locstatus))
  1642. {
  1643. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1644. CompletingAnotherQuery = TRUE;
  1645. break;
  1646. }
  1647. //
  1648. // if it failed then complete the irp now
  1649. //
  1650. IF_DBG(NBT_DEBUG_NAMESRV)
  1651. KdPrint(("Nbt.NtProcessLmHSvcIrp[%s]: NbtProcessLmhSvcRequest failed with %x\r\n",
  1652. (RequestType==NBT_RESOLVE_WITH_DNS ? "NBT_RESOLVE_WITH_DNS":"NBT_PING_IP_ADDRS"),
  1653. Locstatus));
  1654. pClientCompletion = pContext->ClientCompletion;
  1655. pClientContext = pContext->pClientContext;
  1656. pTracker = pContext->pTracker;
  1657. //
  1658. // Clear the Cancel Routine now
  1659. //
  1660. (VOID)NbtCancelCancelRoutine(((tDGRAM_SEND_TRACKING *)pClientContext)->pClientIrp);
  1661. if (pTracker)
  1662. {
  1663. if (pTracker->pNameAddr)
  1664. {
  1665. SetNameState (pTracker->pNameAddr, NULL, FALSE);
  1666. pTracker->pNameAddr = NULL;
  1667. }
  1668. //
  1669. // pTracker is NULL for Ping requests, hence this dereference is
  1670. // done only for Dns requests
  1671. //
  1672. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  1673. }
  1674. CompleteClientReq(pClientCompletion, pClientContext, STATUS_BAD_NETWORK_PATH);
  1675. CTEMemFree(pContext);
  1676. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1677. }
  1678. }
  1679. //
  1680. // We are holding onto the Irp, so set the cancel routine.
  1681. // (Since we may have released the lock earlier, we also need
  1682. // to ensure that no other Query has completed the Irp!)
  1683. //
  1684. if ((!CompletingAnotherQuery) &&
  1685. (!pLmhRequest->ResolvingNow) &&
  1686. (pLmhRequest->QueryIrp == pIrp))
  1687. {
  1688. status = NTCheckSetCancelRoutine(pIrp, NbtCancelLmhSvcIrp, pDeviceContext);
  1689. if (!NT_SUCCESS(status))
  1690. {
  1691. // the irp got cancelled so complete it now
  1692. //
  1693. pLmhRequest->QueryIrp = NULL;
  1694. pLmhRequest->pIpAddrBuf = NULL;
  1695. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1696. NTIoComplete(pIrp,status,0);
  1697. }
  1698. else
  1699. {
  1700. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1701. status = STATUS_PENDING;
  1702. }
  1703. }
  1704. else
  1705. {
  1706. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1707. }
  1708. return(status);
  1709. }
  1710. //----------------------------------------------------------------------------
  1711. NTSTATUS
  1712. NbtProcessLmhSvcRequest(
  1713. IN NBT_WORK_ITEM_CONTEXT *pContext,
  1714. IN enum eNbtLmhRequestType RequestType
  1715. )
  1716. /*++
  1717. Routine Description:
  1718. This function is called to pass a NBT request to ping IP addrs
  1719. or query DNS to the LmhSvc Dll
  1720. Arguments:
  1721. Return Value:
  1722. STATUS_PENDING if the buffer is to be held on to , the normal case.
  1723. Notes:
  1724. --*/
  1725. {
  1726. NTSTATUS status = STATUS_SUCCESS;
  1727. tIPADDR_BUFFER_DNS *pIpAddrBuf;
  1728. PCTE_IRP pIrp;
  1729. tDGRAM_SEND_TRACKING *pTracker;
  1730. tDGRAM_SEND_TRACKING *pClientTracker;
  1731. CTELockHandle OldIrq;
  1732. PCHAR pDestName;
  1733. ULONG NameLen, NumAddrs;
  1734. tLMHSVC_REQUESTS *pLmhRequest;
  1735. switch (RequestType)
  1736. {
  1737. case NBT_PING_IP_ADDRS:
  1738. {
  1739. pLmhRequest = &CheckAddr;
  1740. break;
  1741. }
  1742. case NBT_RESOLVE_WITH_DNS:
  1743. {
  1744. pLmhRequest = &DnsQueries;
  1745. break;
  1746. }
  1747. default:
  1748. {
  1749. ASSERTMSG ("Nbt.NbtProcessLmHSvcRequest: ERROR - Invalid Request type\n", 0);
  1750. return STATUS_UNSUCCESSFUL;
  1751. }
  1752. }
  1753. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1754. pContext->TimedOut = FALSE;
  1755. if ((!NBT_VERIFY_HANDLE (pContext->pDeviceContext, NBT_VERIFY_DEVCONTEXT)) ||
  1756. (!pLmhRequest->QueryIrp))
  1757. {
  1758. //
  1759. // Either the device is going away, or
  1760. // the irp either never made it down here, or it was cancelled,
  1761. // so pretend the name query timed out.
  1762. //
  1763. IF_DBG(NBT_DEBUG_NAMESRV)
  1764. KdPrint(("Nbt.NbtProcessLmhSvcRequest[%s]: QueryIrp is NULL, returning\r\n",
  1765. (RequestType == NBT_RESOLVE_WITH_DNS ? "NBT_RESOLVE_WITH_DNS" : "NBT_PING_IP_ADDRS")));
  1766. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1767. if (pLmhRequest->QueryIrp) {
  1768. NbtTrace(NBT_TRACE_NAMESRV, ("return STATUS_BAD_NETWORK_PATH because the device is going away"));
  1769. } else {
  1770. NbtTrace(NBT_TRACE_NAMESRV, ("LmHost services didn't start"));
  1771. }
  1772. return(STATUS_BAD_NETWORK_PATH);
  1773. }
  1774. else if (!pLmhRequest->ResolvingNow)
  1775. {
  1776. pIrp = pLmhRequest->QueryIrp;
  1777. if ((!pLmhRequest->pIpAddrBuf) &&
  1778. (!(pLmhRequest->pIpAddrBuf = (tIPADDR_BUFFER_DNS *)
  1779. MmGetSystemAddressForMdlSafe (pIrp->MdlAddress, HighPagePriority))))
  1780. {
  1781. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1782. NbtTrace(NBT_TRACE_NAMESRV, ("%!FUNC! returns STATUS_UNSUCCESSFUL"));
  1783. return(STATUS_UNSUCCESSFUL);
  1784. }
  1785. pIpAddrBuf = pLmhRequest->pIpAddrBuf;
  1786. pLmhRequest->ResolvingNow = TRUE;
  1787. pLmhRequest->Context = pContext;
  1788. pTracker = pContext->pTracker; // this is the name query tracker (for Dns queries only)
  1789. pClientTracker = (tDGRAM_SEND_TRACKING *)pContext->pClientContext; // session setup tracker
  1790. switch (RequestType)
  1791. {
  1792. case NBT_PING_IP_ADDRS:
  1793. {
  1794. ASSERT(pTracker == NULL);
  1795. //
  1796. // copy the IP addrs for lmhsvc to ping (upto MAX_IPADDRS_PER_HOST) ...
  1797. //
  1798. NumAddrs = pClientTracker->NumAddrs > MAX_IPADDRS_PER_HOST ?
  1799. MAX_IPADDRS_PER_HOST : pClientTracker->NumAddrs;
  1800. CTEMemCopy(pIpAddrBuf->IpAddrsList, pClientTracker->IpList, NumAddrs * sizeof(ULONG));
  1801. pIpAddrBuf->IpAddrsList[NumAddrs] = 0;
  1802. break;
  1803. }
  1804. case NBT_RESOLVE_WITH_DNS:
  1805. {
  1806. WCHAR *UnicodeDestName;
  1807. UnicodeDestName = pClientTracker? pClientTracker->UnicodeDestName: NULL;
  1808. //
  1809. // whenever dest. name is 16 bytes long (or smaller), we have no
  1810. // way of knowing if its a netbios name or a dns name, so we presume
  1811. // it's netbios name, go to wins, broadcast etc. and then come to dns
  1812. // In this case, the name query tracker will be setup, so be non-null
  1813. //
  1814. if (pTracker)
  1815. {
  1816. pDestName = pTracker->pNameAddr->Name;
  1817. NameLen = NETBIOS_NAME_SIZE;
  1818. }
  1819. //
  1820. // if the dest name is longer than 16 bytes, it's got to be dns name so
  1821. // we bypass wins etc. and come straight to dns. In this case, we didn't
  1822. // set up a name query tracker so it will be null. Use the session setup
  1823. // tracker (i.e. pClientTracker) to get the dest name
  1824. //
  1825. else
  1826. {
  1827. ASSERT(pClientTracker);
  1828. pDestName = pClientTracker->pDestName;
  1829. NameLen = pClientTracker->RemoteNameLength;
  1830. }
  1831. if ((NameLen == NETBIOS_NAME_SIZE) &&
  1832. (!(IsValidDnsNameTag (pDestName[NETBIOS_NAME_SIZE-1]))))
  1833. {
  1834. NbtTrace(NBT_TRACE_NAMESRV, ("%!FUNC! returns STATUS_BAD_NETWORK_PATH %02x",
  1835. (unsigned)pDestName[NETBIOS_NAME_SIZE-1]));
  1836. status = STATUS_BAD_NETWORK_PATH;
  1837. }
  1838. else
  1839. {
  1840. //
  1841. // Ignore the 16th byte only if it is a non-DNS name character (we should be
  1842. // safe below 0x20). This will allow queries to DNS names which are exactly 16
  1843. // characters long.
  1844. //
  1845. if (NameLen == NETBIOS_NAME_SIZE)
  1846. {
  1847. if ((pDestName[NETBIOS_NAME_SIZE-1] <= 0x20 ) ||
  1848. (pDestName[NETBIOS_NAME_SIZE-1] >= 0x7f ))
  1849. {
  1850. NameLen = NETBIOS_NAME_SIZE-1; // ignore 16th byte
  1851. }
  1852. }
  1853. else if (NameLen > DNS_MAX_NAME_LENGTH)
  1854. {
  1855. NameLen = DNS_MAX_NAME_LENGTH;
  1856. }
  1857. //
  1858. // copy the name to the Irps return buffer for lmhsvc to resolve with
  1859. // a gethostbyname call
  1860. //
  1861. if (UnicodeDestName) {
  1862. int len;
  1863. len = pClientTracker->UnicodeRemoteNameLength;
  1864. if (len > sizeof(pIpAddrBuf->pwName - sizeof(WCHAR))) {
  1865. len = sizeof(pIpAddrBuf->pwName) - sizeof(WCHAR);
  1866. }
  1867. ASSERT((len % sizeof(WCHAR)) == 0);
  1868. CTEMemCopy(pIpAddrBuf->pwName, UnicodeDestName, len);
  1869. pIpAddrBuf->pwName[len/sizeof(WCHAR)] = 0;
  1870. pIpAddrBuf->NameLen = len;
  1871. pIpAddrBuf->bUnicode = TRUE;
  1872. } else {
  1873. //
  1874. // I would like to maintain only UNICODE interface between NetBT and LmhSVC.
  1875. // But I cannot do RtlAnsiStringToUnicodeString here due to IRQ level here.
  1876. //
  1877. pIpAddrBuf->bUnicode = FALSE;
  1878. CTEMemCopy(pIpAddrBuf->pName, pDestName, NameLen);
  1879. pIpAddrBuf->pName[NameLen] = 0;
  1880. pIpAddrBuf->NameLen = NameLen;
  1881. }
  1882. }
  1883. break;
  1884. }
  1885. default:
  1886. {
  1887. //
  1888. // This code path should never be hit!
  1889. //
  1890. ASSERT(0);
  1891. }
  1892. } // switch
  1893. //
  1894. // Since datagrams are buffered there is no client irp to get cancelled
  1895. // since the client's irp is returned immediately -so this check
  1896. // is only for connections being setup or QueryFindname or
  1897. // nodestatus, where we allow the irp to
  1898. // be cancelled.
  1899. //
  1900. if ((NT_SUCCESS(status)) &&
  1901. (pClientTracker->pClientIrp))
  1902. {
  1903. //
  1904. // allow the client to cancel the name query Irp - no need to check
  1905. // if the client irp was already cancelled or not since the DNS query
  1906. // will complete and find no client request and stop.
  1907. //
  1908. status = NTCheckSetCancelRoutine(pClientTracker->pClientIrp, NbtCancelWaitForLmhSvcIrp,NULL);
  1909. }
  1910. //
  1911. // pass the irp up to lmhsvc.dll to do a gethostbyname call to
  1912. // sockets
  1913. // The Irp will return to NtDnsNameResolve, above
  1914. //
  1915. if (NT_SUCCESS(status))
  1916. {
  1917. pLmhRequest->pIpAddrBuf = NULL;
  1918. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1919. NTIoComplete(pLmhRequest->QueryIrp,STATUS_SUCCESS,0);
  1920. return (STATUS_PENDING);
  1921. }
  1922. //
  1923. // We failed to set the cancel routine, so undo setting up the
  1924. // the pLmhRequest structure.
  1925. //
  1926. NbtTrace(NBT_TRACE_NAMESRV, ("%!FUNC! returns %!status!", status));
  1927. IF_DBG(NBT_DEBUG_NAMESRV)
  1928. KdPrint(("Nbt.NbtProcessLmhSvcRequest[%s]: CheckSet (submitting) failed with %x\r\n",
  1929. (RequestType == NBT_RESOLVE_WITH_DNS ? "NBT_RESOLVE_WITH_DNS" : "NBT_PING_IP_ADDRS"),status));
  1930. pLmhRequest->ResolvingNow = FALSE;
  1931. pLmhRequest->Context = NULL;
  1932. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1933. }
  1934. else
  1935. {
  1936. pClientTracker = (tDGRAM_SEND_TRACKING *)pContext->pClientContext;
  1937. //
  1938. // Since datagrams are buffered there is no client irp to get cancelled
  1939. // since the client's irp is returned immediately -so this check
  1940. // is only for connections being setup, where we allow the irp to
  1941. // be cancelled.
  1942. //
  1943. //
  1944. // allow the client to cancel the name query Irp
  1945. //
  1946. if (pClientTracker->pClientIrp) // check if this is the session setup tracker
  1947. {
  1948. status = NTCheckSetCancelRoutine(pClientTracker->pClientIrp, NbtCancelWaitForLmhSvcIrp,NULL);
  1949. }
  1950. if (NT_SUCCESS(status))
  1951. {
  1952. // the irp is busy resolving another name, so wait for it to return
  1953. // down here again, mean while, Queue the name query
  1954. //
  1955. InsertTailList(&pLmhRequest->ToResolve, &pContext->Item.List);
  1956. }
  1957. else
  1958. {
  1959. IF_DBG(NBT_DEBUG_NAMESRV)
  1960. KdPrint(("Nbt.NbtProcessLmhSvcRequest[%s]: CheckSet (queuing) failed with %x\r\n",
  1961. (RequestType == NBT_RESOLVE_WITH_DNS ? "NBT_RESOLVE_WITH_DNS" : "NBT_PING_IP_ADDRS"),status));
  1962. NbtTrace(NBT_TRACE_NAMESRV, ("%!FUNC! returns %!status!", status));
  1963. }
  1964. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1965. }
  1966. if (NT_SUCCESS(status))
  1967. {
  1968. status = STATUS_PENDING;
  1969. }
  1970. return(status);
  1971. }
  1972. //----------------------------------------------------------------------------
  1973. extern
  1974. VOID
  1975. SetNameState(
  1976. IN tNAMEADDR *pNameAddr,
  1977. IN PULONG pIpList,
  1978. IN BOOLEAN IpAddrResolved
  1979. )
  1980. /*++
  1981. Routine Description:
  1982. This function dereferences the pNameAddr and sets the state to Released
  1983. just incase the dereference does not delete the entry right away, due to
  1984. another outstanding reference against the name.
  1985. Arguments:
  1986. Context -
  1987. Return Value:
  1988. none
  1989. --*/
  1990. {
  1991. CTELockHandle OldIrq;
  1992. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1993. if (IpAddrResolved)
  1994. {
  1995. pNameAddr->IpAddress = pIpList[0];
  1996. }
  1997. else
  1998. {
  1999. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  2000. pNameAddr->NameTypeState |= STATE_RELEASED;
  2001. pNameAddr->pTracker = NULL;
  2002. }
  2003. ASSERT (pNameAddr->RefCount == 1);
  2004. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  2005. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2006. }
  2007. //----------------------------------------------------------------------------
  2008. VOID
  2009. NbtCompleteLmhSvcRequest(
  2010. IN NBT_WORK_ITEM_CONTEXT *Context,
  2011. IN ULONG *IpList,
  2012. IN enum eNbtLmhRequestType RequestType,
  2013. IN ULONG lNameLength,
  2014. IN PWSTR pwsName, // The rosolved name return by LmhSvc
  2015. IN BOOLEAN IpAddrResolved
  2016. )
  2017. /*++
  2018. Routine Description:
  2019. If the destination name is of the form 11.101.4.25 or is a dns name (i.e. of
  2020. the form ftp.microsoft.com) then we come to this function. In addition to
  2021. doing some house keeping, if the name did resolve then we also send out
  2022. a nodestatus request to find out the server name for that ipaddr
  2023. Arguments:
  2024. Context - (NBT_WORK_ITEM_CONTEXT)
  2025. IpList - Array of ipaddrs if resolved (i.e. IpAddrResolved is TRUE)
  2026. IpAddrResolved - TRUE if ipaddr could be resolved, FALSE otherwise
  2027. Return Value:
  2028. Nothing
  2029. Notes:
  2030. --*/
  2031. {
  2032. NTSTATUS status;
  2033. PVOID pClientCompletion;
  2034. tDGRAM_SEND_TRACKING *pTracker;
  2035. tDGRAM_SEND_TRACKING *pClientTracker;
  2036. ULONG TdiAddressType = TDI_ADDRESS_TYPE_NETBIOS;
  2037. ULONG IpAddrsList[MAX_IPADDRS_PER_HOST+1];
  2038. tDEVICECONTEXT *pDeviceContext;
  2039. int i;
  2040. tCONNECTELE *pConnEle;
  2041. CTEPagedCode();
  2042. IF_DBG(NBT_DEBUG_NAMESRV)
  2043. KdPrint(("Nbt.NbtCompleteLmhSvcRequest: Entered ...\n"));
  2044. pTracker = Context->pTracker;
  2045. pClientCompletion = Context->ClientCompletion;
  2046. pClientTracker = (tDGRAM_SEND_TRACKING *) Context->pClientContext;
  2047. pDeviceContext = pClientTracker->pDeviceContext;
  2048. // whether or not name resolved, we don't need this nameaddr anymore
  2049. // (if name resolved, then we do a node status to that addr and create
  2050. // a new nameaddr for the server name in ExtractServerName)
  2051. // pTracker is null if we went straight to dns (without wins etc)
  2052. if (pTracker)
  2053. {
  2054. //
  2055. // Set some info in case some client is still resolving the name
  2056. //
  2057. SetNameState (pTracker->pNameAddr, IpList, IpAddrResolved);
  2058. pTracker->pNameAddr = NULL;
  2059. }
  2060. (VOID)NbtCancelCancelRoutine (pClientTracker->pClientIrp);
  2061. pClientTracker->pTrackerWorker = NULL; // The original NameQuery Tracker will be dereferenced below
  2062. status = STATUS_BAD_NETWORK_PATH;
  2063. if (RequestType == NBT_RESOLVE_WITH_DNS)
  2064. {
  2065. TdiAddressType = ((pTracker == NULL) ? pClientTracker->AddressType: TDI_ADDRESS_TYPE_NETBIOS);
  2066. }
  2067. //
  2068. // If we failed to resolve it, set the state approriately!
  2069. //
  2070. if (!IpAddrResolved)
  2071. {
  2072. if ((TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) &&
  2073. (pConnEle = pClientTracker->pConnEle)) // NULL if request was to send Datagram!
  2074. {
  2075. pConnEle->RemoteNameDoesNotExistInDNS = TRUE;
  2076. }
  2077. }
  2078. else if (NBT_VERIFY_HANDLE(pDeviceContext, NBT_VERIFY_DEVCONTEXT)) // check if this Device is still up!
  2079. {
  2080. // the name was resolved successfully!
  2081. switch (RequestType)
  2082. {
  2083. case NBT_RESOLVE_WITH_DNS:
  2084. {
  2085. // bug #20697, #95241
  2086. if (pwsName && pClientTracker->pNetbiosUnicodeEX &&
  2087. (pClientTracker->pNetbiosUnicodeEX->NameBufferType == NBT_READWRITE ||
  2088. pClientTracker->pNetbiosUnicodeEX->NameBufferType == NBT_WRITEONLY)) {
  2089. UNICODE_STRING temp;
  2090. temp = pClientTracker->pNetbiosUnicodeEX->RemoteName;
  2091. //
  2092. // Has the buffer changed?
  2093. //
  2094. if (memcmp(&temp, &pClientTracker->ucRemoteName, sizeof(UNICODE_STRING)) == 0) {
  2095. ASSERT(lNameLength <= (DNS_NAME_BUFFER_LENGTH-1) * sizeof(pwsName[0]));
  2096. ASSERT((lNameLength%sizeof(WCHAR)) == 0);
  2097. //
  2098. // Make sure we don't overrun the buffer
  2099. //
  2100. if (lNameLength > temp.MaximumLength - sizeof(WCHAR)) {
  2101. // Don't return STATUS_BUFFER_OVERFLOW since it is just a warning instead of error
  2102. status = STATUS_BUFFER_TOO_SMALL;
  2103. break;
  2104. }
  2105. CTEMemCopy(temp.Buffer, pwsName, lNameLength);
  2106. temp.Buffer[lNameLength/sizeof(WCHAR)] = 0;
  2107. temp.Length = (USHORT)lNameLength;
  2108. pClientTracker->pNetbiosUnicodeEX->NameBufferType = NBT_WRITTEN;
  2109. pClientTracker->pNetbiosUnicodeEX->RemoteName = temp;
  2110. IF_DBG(NBT_DEBUG_NETBIOS_EX)
  2111. KdPrint(("netbt!NbtCompleteLmhSvcRequest: Update Unicode Name at %d of %s\n"
  2112. "\t\tDNS return (%ws)\n",
  2113. __LINE__, __FILE__, pwsName));
  2114. }
  2115. }
  2116. if ((TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS) &&
  2117. (!IsDeviceNetbiosless(pDeviceContext))) // Can't do a NodeStatus on the SMB port
  2118. {
  2119. for (i=0; i<MAX_IPADDRS_PER_HOST; i++)
  2120. {
  2121. IpAddrsList[i] = IpList[i];
  2122. if (IpAddrsList[i] == 0)
  2123. {
  2124. break;
  2125. }
  2126. }
  2127. IpAddrsList[MAX_IPADDRS_PER_HOST] = 0;
  2128. pClientTracker->Flags |= NBT_DNS_SERVER; // Set this so that the completion will know
  2129. pClientTracker->CompletionRoutine = pClientCompletion;
  2130. status = NbtSendNodeStatus(pDeviceContext,
  2131. NULL,
  2132. IpAddrsList,
  2133. pClientTracker,
  2134. ExtractServerNameCompletion);
  2135. //
  2136. // If we succeeded in sending a Node status, exit now,
  2137. // without calling the completion routine
  2138. //
  2139. if (NT_SUCCESS(status))
  2140. {
  2141. // pTracker is null if we went straight to dns (without wins etc) or
  2142. // if this was a Ping request
  2143. if (pTracker)
  2144. {
  2145. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  2146. }
  2147. CTEMemFree(Context);
  2148. return;
  2149. }
  2150. break;
  2151. }
  2152. //
  2153. // The Address is of type TDI_ADDRESS_TYPE_NETBIOS_EX,
  2154. // so now handle this scenario in the same way as for
  2155. // for a Ping request!
  2156. //
  2157. // NO break!
  2158. }
  2159. case NBT_PING_IP_ADDRS:
  2160. {
  2161. //
  2162. // add this server name to the remote hashtable
  2163. // Call into IP to determine the outgoing interface for this address
  2164. //
  2165. pDeviceContext = GetDeviceFromInterface (htonl(IpList[0]), TRUE);
  2166. status = LockAndAddToHashTable(NbtConfig.pRemoteHashTbl,
  2167. pClientTracker->pDestName,
  2168. NbtConfig.pScope,
  2169. IpList[0],
  2170. NBT_UNIQUE,
  2171. NULL,
  2172. NULL,
  2173. pDeviceContext,
  2174. (USHORT) ((RequestType == NBT_RESOLVE_WITH_DNS) ?
  2175. NAME_RESOLVED_BY_DNS :
  2176. NAME_RESOLVED_BY_WINS | NAME_RESOLVED_BY_BCAST));
  2177. if (pDeviceContext)
  2178. {
  2179. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_OUT_FROM_IP, FALSE);
  2180. }
  2181. //
  2182. // STATUS_PENDING will be returned if the name already existed
  2183. // in the hashtable
  2184. //
  2185. if (status == STATUS_PENDING)
  2186. {
  2187. status = STATUS_SUCCESS;
  2188. }
  2189. IF_DBG(NBT_DEBUG_NAMESRV)
  2190. KdPrint(("Nbt.NbtCompleteLmhSvcRequest: AddRecordToHashTable Status %lx\n",status));
  2191. break;
  2192. }
  2193. default:
  2194. {
  2195. ASSERT(0);
  2196. }
  2197. } // switch
  2198. }
  2199. // pTracker is null if we went straight to dns (without wins etc) or
  2200. // if this was a Ping request
  2201. if (pTracker)
  2202. {
  2203. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  2204. }
  2205. NbtTrace(NBT_TRACE_NAMESRV, ("%!FUNC! complete client request with %!status!", status));
  2206. CompleteClientReq(pClientCompletion, pClientTracker, status);
  2207. CTEMemFree(Context);
  2208. }
  2209. #endif // !VXD
  2210. //----------------------------------------------------------------------------
  2211. NTSTATUS
  2212. PreloadEntry(
  2213. IN PUCHAR name,
  2214. IN tIPADDRESS inaddr
  2215. )
  2216. /*++
  2217. Routine Description:
  2218. This function adds an lmhosts entry to nbt's name cache. For each
  2219. lmhosts entry, NSUFFIXES unique cache entries are created.
  2220. Even when some cache entries can't be created, this function doesn't
  2221. attempt to remove any that were successfully added to the cache.
  2222. Arguments:
  2223. name - the unencoded NetBIOS name specified in lmhosts
  2224. inaddr - the ip address, in host byte order
  2225. Return Value:
  2226. The number of new name cache entries created.
  2227. --*/
  2228. {
  2229. NTSTATUS status;
  2230. tNAMEADDR *pNameAddr;
  2231. LONG nentries;
  2232. LONG Len;
  2233. CHAR temp[NETBIOS_NAME_SIZE+1];
  2234. CTELockHandle OldIrq;
  2235. LONG NumberToAdd;
  2236. tDEVICECONTEXT *pDeviceContext;
  2237. // if all 16 bytes are present then only add that name exactly as it
  2238. // is.
  2239. //
  2240. Len = strlen(name);
  2241. //
  2242. // if this string is exactly 16 characters long, do not expand
  2243. // into 0x00, 0x03,0x20 names. Just add the single name as it is.
  2244. //
  2245. if (Len == NETBIOS_NAME_SIZE)
  2246. {
  2247. NumberToAdd = 1;
  2248. }
  2249. else
  2250. {
  2251. NumberToAdd = NSUFFIXES;
  2252. }
  2253. for (nentries = 0; nentries < NumberToAdd; nentries++)
  2254. {
  2255. // for names less than 16 bytes, expand out to 16 and put a 16th byte
  2256. // on according to the suffix array
  2257. //
  2258. if (Len != NETBIOS_NAME_SIZE)
  2259. {
  2260. LmExpandName(temp, name, Suffix[nentries]);
  2261. }
  2262. else
  2263. {
  2264. CTEMemCopy(temp,name,NETBIOS_NAME_SIZE);
  2265. }
  2266. pDeviceContext = GetDeviceFromInterface (htonl(inaddr), TRUE);
  2267. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2268. status = AddToHashTable (NbtConfig.pRemoteHashTbl,
  2269. temp,
  2270. NbtConfig.pScope,
  2271. inaddr,
  2272. NBT_UNIQUE,
  2273. NULL,
  2274. &pNameAddr,
  2275. pDeviceContext,
  2276. NAME_RESOLVED_BY_LMH_P);
  2277. // if the name is already in the hash table, the status code is
  2278. // status pending. This could happen if the preloads are purged
  2279. // when one is still being referenced by another part of the code,
  2280. // and was therefore not deleted. We do not want to add the name
  2281. // twice, so we just change the ip address to agree with the preload
  2282. // value
  2283. //
  2284. if ((status == STATUS_SUCCESS) ||
  2285. ((status == STATUS_PENDING) &&
  2286. (!(pNameAddr->NameTypeState & PRELOADED))))
  2287. {
  2288. //
  2289. // this prevents the name from being deleted by the Hash Timeout code
  2290. //
  2291. pNameAddr->NameTypeState |= PRELOADED | STATE_RESOLVED;
  2292. pNameAddr->NameTypeState &= ~STATE_CONFLICT;
  2293. pNameAddr->Ttl = 0xFFFFFFFF;
  2294. pNameAddr->Verify = REMOTE_NAME;
  2295. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_PRELOADED);
  2296. if (pDeviceContext)
  2297. {
  2298. pNameAddr->AdapterMask |= pDeviceContext->AdapterMask;
  2299. }
  2300. }
  2301. else if (status == STATUS_PENDING)
  2302. {
  2303. pNameAddr->IpAddress = inaddr;
  2304. }
  2305. if (pDeviceContext)
  2306. {
  2307. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_OUT_FROM_IP, TRUE);
  2308. }
  2309. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2310. }
  2311. return(STATUS_SUCCESS);
  2312. } // PreloadEntry
  2313. //----------------------------------------------------------------------------
  2314. extern
  2315. VOID
  2316. RemovePreloads (
  2317. )
  2318. /*++
  2319. Routine Description:
  2320. This function removes preloaded entries from the remote hash table.
  2321. If it finds any of the preloaded entries are active with a ref count
  2322. above the base level of 2, then it returns true.
  2323. Arguments:
  2324. none
  2325. Return Value:
  2326. none
  2327. --*/
  2328. {
  2329. tNAMEADDR *pNameAddr;
  2330. PLIST_ENTRY pHead,pEntry;
  2331. CTELockHandle OldIrq;
  2332. tHASHTABLE *pHashTable;
  2333. BOOLEAN FoundActivePreload=FALSE;
  2334. LONG i;
  2335. //
  2336. // go through the remote table deleting names that have the PRELOAD
  2337. // bit set.
  2338. //
  2339. pHashTable = NbtConfig.pRemoteHashTbl;
  2340. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2341. for (i=0;i < pHashTable->lNumBuckets ;i++ )
  2342. {
  2343. pHead = &pHashTable->Bucket[i];
  2344. pEntry = pHead->Flink;
  2345. while (pEntry != pHead)
  2346. {
  2347. pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
  2348. pEntry = pEntry->Flink;
  2349. //
  2350. // Delete preloaded entries that are not in use by some other
  2351. // part of the code now. Note that preloaded entries start with
  2352. // a ref count of 2 so that the normal remote hashtimeout code
  2353. // will not delete them
  2354. //
  2355. if ((pNameAddr->NameTypeState & PRELOADED) &&
  2356. (pNameAddr->RefCount == 2))
  2357. {
  2358. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_PRELOADED, TRUE);
  2359. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_REMOTE, TRUE);
  2360. }
  2361. }
  2362. }
  2363. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2364. return;
  2365. }
  2366. //----------------------------------------------------------------------------
  2367. LONG
  2368. PrimeCache(
  2369. IN PUCHAR path,
  2370. IN PUCHAR ignored,
  2371. IN CHAR RecurseDepth,
  2372. OUT BOOLEAN *ignored2
  2373. )
  2374. /*++
  2375. Routine Description:
  2376. This function is called to prime the cache with entries in the lmhosts
  2377. file that are marked as preload entries.
  2378. Arguments:
  2379. path - a fully specified path to a lmhosts file
  2380. ignored - unused
  2381. RecurseDepth- the depth to which we can resurse -- 0 => no more recursion
  2382. Return Value:
  2383. Number of new cache entries that were added, or -1 if there was an
  2384. i/o error.
  2385. --*/
  2386. {
  2387. int nentries;
  2388. PUCHAR buffer;
  2389. PLM_FILE pfile;
  2390. NTSTATUS status;
  2391. int count, nwords;
  2392. unsigned long temp;
  2393. INCLUDE_STATE incstate;
  2394. PUCHAR token[MaxTokens];
  2395. ULONG inaddr;
  2396. LINE_CHARACTERISTICS current;
  2397. UCHAR Name[NETBIOS_NAME_SIZE+1];
  2398. ULONG IpAddr;
  2399. LIST_ENTRY TmpDomainList;
  2400. int domtoklen;
  2401. CTEPagedCode();
  2402. if (!NbtConfig.EnableLmHosts)
  2403. {
  2404. return(STATUS_SUCCESS);
  2405. }
  2406. InitializeListHead(&TmpDomainList);
  2407. //
  2408. // Check for infinitely recursive name lookup in a #INCLUDE.
  2409. //
  2410. if (LmpBreakRecursion(path, "", 1) == TRUE)
  2411. {
  2412. return (-1);
  2413. }
  2414. pfile = LmOpenFile(path);
  2415. if (!pfile)
  2416. {
  2417. return(-1);
  2418. }
  2419. nentries = 0;
  2420. incstate = MustInclude;
  2421. domtoklen = strlen(DOMAIN_TOKEN);
  2422. while (buffer = LmFgets(pfile, &count))
  2423. {
  2424. #ifndef VXD
  2425. if ((NbtConfig.MaxPreloadEntries - nentries) < 3)
  2426. {
  2427. break;
  2428. }
  2429. #else
  2430. if ( nentries >= (NbtConfig.MaxPreloadEntries - 3) )
  2431. {
  2432. break;
  2433. }
  2434. #endif
  2435. nwords = MaxTokens;
  2436. current = LmpGetTokens(buffer, token, &nwords);
  2437. // if there is and error or no name on the line, then continue
  2438. // to the next line.
  2439. //
  2440. if (current.l_category == ErrorLine)
  2441. {
  2442. IF_DBG(NBT_DEBUG_LMHOST)
  2443. KdPrint(("Nbt.PrimeCache: Error line in Lmhost file\n"));
  2444. continue;
  2445. }
  2446. if (current.l_category != BeginAlternate && current.l_category != EndAlternate) {
  2447. if (token[NbName] == NULL) {
  2448. IF_DBG(NBT_DEBUG_LMHOST)
  2449. KdPrint(("Nbt.PrimeCache: Error line in Lmhost file\n"));
  2450. continue;
  2451. }
  2452. }
  2453. if (current.l_preload)
  2454. {
  2455. status = ConvertDottedDecimalToUlong(token[IpAddress],&inaddr);
  2456. if (NT_SUCCESS(status))
  2457. {
  2458. status = PreloadEntry (token[NbName], inaddr);
  2459. if (NT_SUCCESS(status))
  2460. {
  2461. nentries++;
  2462. }
  2463. }
  2464. }
  2465. switch ((ULONG)current.l_category)
  2466. {
  2467. case Domain:
  2468. if ((nwords - 1) < GroupName)
  2469. {
  2470. continue;
  2471. }
  2472. //
  2473. // and add '1C' on the end
  2474. //
  2475. LmExpandName(Name, token[GroupName]+ domtoklen, SPECIAL_GROUP_SUFFIX);
  2476. status = ConvertDottedDecimalToUlong(token[IpAddress],&IpAddr);
  2477. if (NT_SUCCESS(status))
  2478. {
  2479. AddToDomainList (Name, IpAddr, &TmpDomainList, (BOOLEAN)current.l_preload);
  2480. }
  2481. continue;
  2482. case Include:
  2483. if (!RecurseDepth || ((incstate == SkipInclude) || (nwords < 2)))
  2484. {
  2485. continue;
  2486. }
  2487. #ifdef VXD
  2488. //
  2489. // the buffer which we read into is reused for the next file: we
  2490. // need the contents when we get back: back it up!
  2491. // if we can't allocate memory, just skip this include
  2492. //
  2493. if ( !BackupCurrentData(pfile) )
  2494. {
  2495. continue;
  2496. }
  2497. #endif
  2498. temp = LmInclude(token[1], PrimeCache, NULL, (CHAR) (RecurseDepth-1), NULL);
  2499. #ifdef VXD
  2500. //
  2501. // going back to previous file: restore the backed up data
  2502. //
  2503. RestoreOldData(pfile);
  2504. #endif
  2505. if (temp != -1)
  2506. {
  2507. if (incstate == TryToInclude)
  2508. {
  2509. incstate = SkipInclude;
  2510. }
  2511. nentries += temp;
  2512. continue;
  2513. }
  2514. continue;
  2515. case BeginAlternate:
  2516. ASSERT(nwords == 1);
  2517. incstate = TryToInclude;
  2518. continue;
  2519. case EndAlternate:
  2520. ASSERT(nwords == 1);
  2521. incstate = MustInclude;
  2522. continue;
  2523. default:
  2524. continue;
  2525. }
  2526. }
  2527. status = LmCloseFile(pfile);
  2528. ASSERT(status == STATUS_SUCCESS);
  2529. //
  2530. // make this the new domain list
  2531. //
  2532. MakeNewListCurrent(&TmpDomainList);
  2533. ASSERT(nentries >= 0);
  2534. return(nentries);
  2535. } // LmPrimeCache
  2536. //----------------------------------------------------------------------------
  2537. extern
  2538. VOID
  2539. GetContext(
  2540. IN OUT NBT_WORK_ITEM_CONTEXT **ppContext
  2541. )
  2542. /*++
  2543. Routine Description:
  2544. This function is called to get the context value to check if a name
  2545. query has been cancelled or not.
  2546. Arguments:
  2547. Context -
  2548. Return Value:
  2549. none
  2550. --*/
  2551. {
  2552. CTELockHandle OldIrq;
  2553. NBT_WORK_ITEM_CONTEXT *pContext;
  2554. //
  2555. // remove the Context value and return it.
  2556. //
  2557. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2558. if (pContext = LmHostQueries.Context)
  2559. {
  2560. if ((*ppContext) &&
  2561. (*ppContext != pContext))
  2562. {
  2563. pContext = NULL;
  2564. }
  2565. #ifndef VXD
  2566. else if (NbtCancelCancelRoutine(((tDGRAM_SEND_TRACKING *)(pContext->pClientContext))->pClientIrp)
  2567. == STATUS_CANCELLED)
  2568. {
  2569. pContext = NULL;
  2570. }
  2571. else
  2572. #endif // VXD
  2573. {
  2574. LmHostQueries.Context = NULL;
  2575. }
  2576. }
  2577. *ppContext = pContext;
  2578. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2579. }
  2580. //----------------------------------------------------------------------------
  2581. extern
  2582. NTSTATUS
  2583. ChangeStateOfName (
  2584. IN tIPADDRESS IpAddress,
  2585. IN NBT_WORK_ITEM_CONTEXT *pContext,
  2586. IN OUT NBT_WORK_ITEM_CONTEXT **ppContext,
  2587. IN USHORT NameAddFlags
  2588. )
  2589. /*++
  2590. Routine Description:
  2591. This function changes the state of a name and nulls the Context
  2592. value in lmhostqueries.
  2593. Arguments:
  2594. pContext - The Context value if it has been removed from the
  2595. LmHostQueries.Context ptr.
  2596. ppContext - The Context we are processing
  2597. Return Value:
  2598. none
  2599. --*/
  2600. {
  2601. NTSTATUS status;
  2602. CTELockHandle OldIrq;
  2603. tDEVICECONTEXT *pDeviceContext;
  2604. pDeviceContext = GetDeviceFromInterface(htonl(IpAddress), TRUE);
  2605. if (pContext == NULL)
  2606. {
  2607. //
  2608. // See if the name query is still active
  2609. //
  2610. pContext = *ppContext;
  2611. GetContext (&pContext);
  2612. }
  2613. if (pContext)
  2614. {
  2615. // convert broadcast addresses to zero since NBT interprets zero
  2616. // to be broadcast
  2617. //
  2618. if (IpAddress == (ULONG)-1)
  2619. {
  2620. IpAddress = 0;
  2621. }
  2622. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2623. status = AddToHashTable (NbtConfig.pRemoteHashTbl,
  2624. pContext->pTracker->pNameAddr->Name,
  2625. NbtConfig.pScope,
  2626. IpAddress,
  2627. NBT_UNIQUE,
  2628. NULL,
  2629. NULL,
  2630. pDeviceContext,
  2631. NameAddFlags);
  2632. //
  2633. // this will free the pNameAddr, so do not access this after this point
  2634. //
  2635. NBT_DEREFERENCE_NAMEADDR (pContext->pTracker->pNameAddr, REF_NAME_QUERY_ON_NET, TRUE);
  2636. pContext->pTracker->pNameAddr = NULL;
  2637. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2638. *ppContext = pContext;
  2639. }
  2640. else
  2641. {
  2642. *ppContext = NULL;
  2643. }
  2644. if (pDeviceContext)
  2645. {
  2646. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_OUT_FROM_IP, FALSE);
  2647. }
  2648. return (STATUS_SUCCESS);
  2649. }
  2650. //----------------------------------------------------------------------------
  2651. VOID
  2652. RemoveLmHRequests(
  2653. IN tLMHSVC_REQUESTS *pLmHRequest,
  2654. IN PLIST_ENTRY pTmpHead,
  2655. IN tTIMERQENTRY *pTimerQEntry,
  2656. IN tDEVICECONTEXT *pDeviceContext
  2657. )
  2658. /*++
  2659. Routine Description:
  2660. This routine is called to find timed out entries in the queue of
  2661. lmhost or dns name queries.
  2662. Arguments:
  2663. Return Value:
  2664. The function value is the status of the operation.
  2665. --*/
  2666. {
  2667. PLIST_ENTRY pEntry;
  2668. NBT_WORK_ITEM_CONTEXT *pWiContext;
  2669. BOOLEAN fRestartTimer = FALSE;
  2670. //
  2671. // check the currently processing LMHOSTS entry
  2672. //
  2673. if (pLmHRequest->Context)
  2674. {
  2675. pWiContext = (NBT_WORK_ITEM_CONTEXT *) pLmHRequest->Context;
  2676. if ((pWiContext->TimedOut) || (pWiContext->pDeviceContext == pDeviceContext))
  2677. {
  2678. pLmHRequest->Context = NULL;
  2679. InsertTailList(pTmpHead, &pWiContext->Item.List);
  2680. #ifndef VXD
  2681. // Not for win95, MohsinA, 05-Dec-96.
  2682. NbtCancelCancelRoutine(((tDGRAM_SEND_TRACKING *) (pWiContext->pClientContext))->pClientIrp);
  2683. #endif
  2684. }
  2685. else
  2686. {
  2687. //
  2688. // restart the timer
  2689. //
  2690. fRestartTimer = TRUE;
  2691. pWiContext->TimedOut = TRUE;
  2692. }
  2693. }
  2694. //
  2695. // Check the list of queued entries
  2696. //
  2697. if (!IsListEmpty(&pLmHRequest->ToResolve))
  2698. {
  2699. //
  2700. // restart the timer
  2701. //
  2702. fRestartTimer = TRUE;
  2703. pEntry = pLmHRequest->ToResolve.Flink;
  2704. while (pEntry != &pLmHRequest->ToResolve)
  2705. {
  2706. pWiContext = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
  2707. pEntry = pEntry->Flink;
  2708. if ((pWiContext->TimedOut) || (pWiContext->pDeviceContext == pDeviceContext))
  2709. {
  2710. //
  2711. // save on a temporary list and complete below
  2712. //
  2713. RemoveEntryList(&pWiContext->Item.List);
  2714. InsertTailList(pTmpHead, &pWiContext->Item.List);
  2715. }
  2716. else
  2717. {
  2718. pWiContext->TimedOut = TRUE;
  2719. }
  2720. }
  2721. }
  2722. if ((fRestartTimer) && (pTimerQEntry))
  2723. {
  2724. pTimerQEntry->Flags |= TIMER_RESTART;
  2725. }
  2726. }
  2727. //----------------------------------------------------------------------------
  2728. VOID
  2729. TimeoutLmHRequests(
  2730. IN tTIMERQENTRY *pTimerQEntry,
  2731. IN tDEVICECONTEXT *pDeviceContext,
  2732. IN BOOLEAN fLocked,
  2733. IN CTELockHandle *pJointLockOldIrq
  2734. )
  2735. {
  2736. PLIST_ENTRY pHead;
  2737. PLIST_ENTRY pEntry;
  2738. NBT_WORK_ITEM_CONTEXT *pWiContext;
  2739. LIST_ENTRY TmpHead;
  2740. InitializeListHead(&TmpHead);
  2741. if (!fLocked)
  2742. {
  2743. CTESpinLock(&NbtConfig.JointLock,*pJointLockOldIrq);
  2744. }
  2745. //
  2746. // check the currently processing LMHOSTS entry
  2747. //
  2748. RemoveLmHRequests (&LmHostQueries, &TmpHead, pTimerQEntry, pDeviceContext);
  2749. RemoveLmHRequests (&CheckAddr, &TmpHead, pTimerQEntry, pDeviceContext);
  2750. #ifndef VXD
  2751. RemoveLmHRequests (&DnsQueries, &TmpHead, pTimerQEntry, pDeviceContext);
  2752. #endif
  2753. CTESpinFree(&NbtConfig.JointLock,*pJointLockOldIrq);
  2754. if (!IsListEmpty(&TmpHead))
  2755. {
  2756. pHead = &TmpHead;
  2757. pEntry = pHead->Flink;
  2758. while (pEntry != pHead)
  2759. {
  2760. pWiContext = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
  2761. pEntry = pEntry->Flink;
  2762. RemoveEntryList(&pWiContext->Item.List);
  2763. IF_DBG(NBT_DEBUG_LMHOST)
  2764. KdPrint(("Nbt.TimeoutLmHRequests: Context=<%p>, pDeviceContext=<%p>\n",
  2765. pWiContext, pDeviceContext));
  2766. RemoveNameAndCompleteReq(pWiContext,STATUS_TIMEOUT);
  2767. }
  2768. }
  2769. if (fLocked)
  2770. {
  2771. CTESpinLock(&NbtConfig.JointLock,*pJointLockOldIrq);
  2772. }
  2773. }
  2774. //----------------------------------------------------------------------------
  2775. VOID
  2776. LmHostTimeout(
  2777. PVOID pContext,
  2778. PVOID pContext2,
  2779. tTIMERQENTRY *pTimerQEntry
  2780. )
  2781. /*++
  2782. Routine Description:
  2783. This routine is called by the timer code when the timer expires. It
  2784. marks all items in Lmhosts/Dns q as timed out and completes any that have
  2785. already timed out with status timeout.
  2786. Arguments:
  2787. Return Value:
  2788. The function value is the status of the operation.
  2789. --*/
  2790. {
  2791. CTELockHandle OldIrq;
  2792. //
  2793. // If the timer is NULL, it means that the Timer is currently
  2794. // being stopped (usually at Unload time), so don't do anything!
  2795. //
  2796. if (!pTimerQEntry)
  2797. {
  2798. LmHostQueries.pTimer = NULL;
  2799. return;
  2800. }
  2801. TimeoutLmHRequests (pTimerQEntry, NULL, FALSE, &OldIrq);
  2802. // null the timer if we are not going to restart it.
  2803. //
  2804. if (!(pTimerQEntry->Flags & TIMER_RESTART))
  2805. {
  2806. LmHostQueries.pTimer = NULL;
  2807. }
  2808. }
  2809. //----------------------------------------------------------------------------
  2810. extern
  2811. VOID
  2812. StartLmHostTimer(
  2813. IN NBT_WORK_ITEM_CONTEXT *pContext,
  2814. IN BOOLEAN fLockedOnEntry
  2815. )
  2816. /*++
  2817. Routine Description
  2818. This routine handles setting up a timer to time the Lmhost entry.
  2819. The Joint Spin Lock may be held when this routine is called
  2820. Arguments:
  2821. Return Values:
  2822. VOID
  2823. --*/
  2824. {
  2825. NTSTATUS status;
  2826. tTIMERQENTRY *pTimerEntry;
  2827. CTELockHandle OldIrq;
  2828. if (!fLockedOnEntry)
  2829. {
  2830. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2831. }
  2832. pContext->TimedOut = FALSE;
  2833. //
  2834. // start the timer if it is not running
  2835. //
  2836. if (!LmHostQueries.pTimer)
  2837. {
  2838. status = StartTimer(LmHostTimeout,
  2839. NbtConfig.LmHostsTimeout,
  2840. NULL, // context value
  2841. NULL, // context2 value
  2842. NULL,
  2843. NULL,
  2844. NULL,
  2845. &pTimerEntry,
  2846. 0,
  2847. TRUE);
  2848. IF_DBG(NBT_DEBUG_NAMESRV)
  2849. KdPrint(("Nbt.StartLmHostTimer: Start Timer to time Lmhost Qing for pContext= %x,\n", pContext));
  2850. if (NT_SUCCESS(status))
  2851. {
  2852. LmHostQueries.pTimer = pTimerEntry;
  2853. }
  2854. else
  2855. {
  2856. // we failed to get a timer, but that is not
  2857. // then end of the world. The lmhost query will just
  2858. // not timeout in 30 seconds. It may take longer if
  2859. // it tries to include a remove file on a dead machine.
  2860. //
  2861. LmHostQueries.pTimer = NULL;
  2862. }
  2863. }
  2864. if (!fLockedOnEntry)
  2865. {
  2866. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2867. }
  2868. }
  2869. //----------------------------------------------------------------------------
  2870. NTSTATUS
  2871. LmHostQueueRequest(
  2872. IN tDGRAM_SEND_TRACKING *pTracker,
  2873. IN PVOID pClientContext,
  2874. IN PVOID ClientCompletion,
  2875. IN PVOID pDeviceContext
  2876. )
  2877. /*++
  2878. Routine Description:
  2879. This routine exists so that LmHost requests will not take up more than
  2880. one executive worker thread. If a thread is busy performing an Lmhost
  2881. request, new requests are queued otherwise we could run out of worker
  2882. threads and lock up the system.
  2883. The Joint Spin Lock is held when this routine is called
  2884. Arguments:
  2885. pTracker - the tracker block for context
  2886. DelayedWorkerRoutine - the routine for the Workerthread to call
  2887. pDeviceContext - dev context that initiated this
  2888. Return Value:
  2889. --*/
  2890. {
  2891. NTSTATUS status = STATUS_UNSUCCESSFUL;
  2892. NBT_WORK_ITEM_CONTEXT *pContext;
  2893. tDGRAM_SEND_TRACKING *pTrackClient;
  2894. PCTE_IRP pIrp;
  2895. BOOLEAN OnList;
  2896. if (pContext = (NBT_WORK_ITEM_CONTEXT *)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('V')))
  2897. {
  2898. pContext->pTracker = pTracker;
  2899. pContext->pClientContext = pClientContext;
  2900. pContext->ClientCompletion = ClientCompletion;
  2901. pContext->pDeviceContext = pDeviceContext;
  2902. pContext->TimedOut = FALSE;
  2903. if (LmHostQueries.ResolvingNow)
  2904. {
  2905. // Lmhosts is busy resolving another name, so wait for it to return
  2906. // mean while, Queue the name query
  2907. //
  2908. InsertTailList(&LmHostQueries.ToResolve,&pContext->Item.List);
  2909. OnList = TRUE;
  2910. }
  2911. else
  2912. {
  2913. LmHostQueries.Context = pContext;
  2914. LmHostQueries.ResolvingNow = TRUE;
  2915. OnList = FALSE;
  2916. if (!NT_SUCCESS (CTEQueueForNonDispProcessing (DelayedScanLmHostFile,
  2917. pTracker,
  2918. pClientContext,
  2919. ClientCompletion,
  2920. pDeviceContext,
  2921. TRUE)))
  2922. {
  2923. LmHostQueries.Context = NULL;
  2924. LmHostQueries.ResolvingNow = FALSE;
  2925. CTEMemFree(pContext);
  2926. return (STATUS_UNSUCCESSFUL);
  2927. }
  2928. }
  2929. //
  2930. // To prevent this name query from languishing on the Lmhost Q when
  2931. // a #include on a dead machine is trying to be openned, start the
  2932. // connection setup timer
  2933. //
  2934. StartLmHostTimer(pContext, TRUE);
  2935. //
  2936. // this is the session setup tracker
  2937. //
  2938. #ifndef VXD
  2939. pTrackClient = (tDGRAM_SEND_TRACKING *)pClientContext;
  2940. if (pIrp = pTrackClient->pClientIrp)
  2941. {
  2942. //
  2943. // allow the client to cancel the name query Irp
  2944. //
  2945. // but do not call NTSetCancel... since it takes need to run
  2946. // at non DPC level, and it calls the completion routine
  2947. // which takes the JointLock that we already have.
  2948. //
  2949. status = NTCheckSetCancelRoutine(pTrackClient->pClientIrp, NbtCancelWaitForLmhSvcIrp,NULL);
  2950. if (status == STATUS_CANCELLED)
  2951. {
  2952. //
  2953. // since the name query is cancelled do not let lmhost processing
  2954. // handle it.
  2955. //
  2956. if (OnList)
  2957. {
  2958. RemoveEntryList(&pContext->Item.List);
  2959. }
  2960. else
  2961. {
  2962. //
  2963. // do not set resolving now to False since the work item
  2964. // has been queued to the worker thread
  2965. //
  2966. LmHostQueries.Context = NULL;
  2967. LmHostQueries.ResolvingNow = FALSE;
  2968. }
  2969. CTEMemFree(pContext);
  2970. }
  2971. return(status);
  2972. }
  2973. #endif
  2974. status = STATUS_SUCCESS;
  2975. }
  2976. return(status);
  2977. }
  2978. //----------------------------------------------------------------------------
  2979. extern
  2980. NBT_WORK_ITEM_CONTEXT *
  2981. GetNameToFind(
  2982. OUT PUCHAR pName
  2983. )
  2984. /*++
  2985. Routine Description:
  2986. This function is called to get the name to query from the LmHostQueries
  2987. list.
  2988. Arguments:
  2989. Context -
  2990. Return Value:
  2991. none
  2992. --*/
  2993. {
  2994. tDGRAM_SEND_TRACKING *pTracker;
  2995. CTELockHandle OldIrq;
  2996. NBT_WORK_ITEM_CONTEXT *Context;
  2997. PLIST_ENTRY pEntry;
  2998. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2999. // if the context value has been cleared then that name query has been
  3000. // cancelled, so check for another one.
  3001. //
  3002. if (!(Context = LmHostQueries.Context))
  3003. {
  3004. //
  3005. // the current name query got canceled so see if there are any more
  3006. // to service
  3007. //
  3008. if (!IsListEmpty(&LmHostQueries.ToResolve))
  3009. {
  3010. pEntry = RemoveHeadList(&LmHostQueries.ToResolve);
  3011. Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
  3012. LmHostQueries.Context = Context;
  3013. }
  3014. else
  3015. {
  3016. //
  3017. // no more names to resolve, so clear the flag
  3018. //
  3019. LmHostQueries.ResolvingNow = FALSE;
  3020. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3021. return(NULL);
  3022. }
  3023. }
  3024. pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
  3025. CTEMemCopy(pName,pTracker->pNameAddr->Name,NETBIOS_NAME_SIZE);
  3026. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3027. return(Context);
  3028. }
  3029. //----------------------------------------------------------------------------
  3030. extern
  3031. VOID
  3032. RemoveNameAndCompleteReq (
  3033. IN NBT_WORK_ITEM_CONTEXT *pContext,
  3034. IN NTSTATUS status
  3035. )
  3036. /*++
  3037. Routine Description:
  3038. This function removes the name, cleans up the tracker
  3039. and then completes the clients request.
  3040. Arguments:
  3041. Context -
  3042. Return Value:
  3043. none
  3044. --*/
  3045. {
  3046. tDGRAM_SEND_TRACKING *pTracker;
  3047. PVOID pClientContext;
  3048. PVOID pClientCompletion;
  3049. CTELockHandle OldIrq;
  3050. // if pContext is null the name query was cancelled during the
  3051. // time it took to go read the lmhosts file, so don't do this
  3052. // stuff
  3053. //
  3054. if (pContext)
  3055. {
  3056. pTracker = pContext->pTracker;
  3057. pClientCompletion = pContext->ClientCompletion;
  3058. pClientContext = pContext->pClientContext;
  3059. CTEMemFree(pContext);
  3060. #ifndef VXD
  3061. //
  3062. // clear out the cancel routine if there is an irp involved
  3063. //
  3064. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  3065. NbtCancelCancelRoutine( ((tDGRAM_SEND_TRACKING *)(pClientContext))->pClientIrp );
  3066. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3067. #endif
  3068. // remove the name from the hash table, since it did not resolve
  3069. if (pTracker)
  3070. {
  3071. if ((status != STATUS_SUCCESS) &&
  3072. (pTracker->pNameAddr))
  3073. {
  3074. SetNameState (pTracker->pNameAddr, NULL, FALSE);
  3075. pTracker->pNameAddr = NULL;
  3076. }
  3077. // free the tracker and call the completion routine.
  3078. //
  3079. NBT_DEREFERENCE_TRACKER(pTracker, FALSE);
  3080. }
  3081. if (pClientCompletion)
  3082. {
  3083. CompleteClientReq(pClientCompletion, pClientContext, status);
  3084. }
  3085. }
  3086. }
  3087. //----------------------------------------------------------------------------
  3088. //
  3089. // Alternative to the c-runtime
  3090. //
  3091. #ifndef VXD
  3092. PCHAR
  3093. Nbtstrcat( PUCHAR pch, PUCHAR pCat, LONG Len )
  3094. {
  3095. STRING StringIn;
  3096. STRING StringOut;
  3097. RtlInitAnsiString(&StringIn, pCat);
  3098. RtlInitAnsiString(&StringOut, pch);
  3099. StringOut.MaximumLength = (USHORT)Len;
  3100. //
  3101. // increment to include the null on the end of the string since
  3102. // we want that on the end of the final product
  3103. //
  3104. StringIn.Length++;
  3105. RtlAppendStringToString(&StringOut,&StringIn);
  3106. return(pch);
  3107. }
  3108. #else
  3109. #define Nbtstrcat( a,b,c ) strcat( a,b )
  3110. #endif