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.

1249 lines
32 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: PKTFSCTL.C
  6. //
  7. // Contents: This module contains the implementation for FS controls
  8. // which manipulate the PKT.
  9. //
  10. // Functions: PktFsctrlUpdateDomainKnowledge -
  11. // PktFsctrlGetRelationInfo -
  12. // PktFsctrlSetRelationInfo -
  13. // PktFsctrlIsChildnameLegal -
  14. // PktFsctrlCreateEntry -
  15. // PktFsctrlCreateSubordinateEntry -
  16. // PktFsctrlDestroyEntry -
  17. // PktFsctrlUpdateSiteCosts -
  18. // DfsFsctrlSetDCName -
  19. // DfsAgePktEntries - Flush PKT entries periodically
  20. //
  21. // Private Functions
  22. //
  23. // DfsCreateExitPathOnRoot
  24. // PktpHashSiteCostList
  25. // PktpLookupSiteCost
  26. // PktpUpdateSiteCosts
  27. // PktpSetActiveSpcService
  28. //
  29. // Debug Only Functions
  30. //
  31. // PktFsctrlFlushCache - Flush PKT entries on command
  32. // PktFsctrlFlushSpcCache - Flush SPC entries on command
  33. // PktFsctrlGetFirstSvc - Test hooks for testing replica
  34. // PktFsctrlGetNextSvc - selection.
  35. //
  36. // History: 12 Jul 1993 Alanw Created from localvol.c.
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include "dfsprocs.h"
  40. #include "dfserr.h"
  41. #include "fsctrl.h"
  42. #include "log.h"
  43. #include "dnr.h"
  44. #include "know.h"
  45. #include <stdlib.h>
  46. //
  47. // The local debug trace level
  48. //
  49. #define Dbg (DEBUG_TRACE_LOCALVOL)
  50. //
  51. // Local function prototypes
  52. //
  53. NTSTATUS
  54. DfspProtocolToService(
  55. IN PDS_TRANSPORT pdsTransport,
  56. IN PWSTR pwszPrincipalName,
  57. IN PWSTR pwszShareName,
  58. IN BOOLEAN fIsDfs,
  59. IN OUT PDFS_SERVICE pService);
  60. NTSTATUS
  61. PktFsctrlFlushCache(
  62. IN PIRP_CONTEXT IrpContext,
  63. IN PIRP Irp,
  64. IN PVOID InputBuffer,
  65. IN ULONG InputBufferLength
  66. );
  67. NTSTATUS
  68. PktFsctrlFlushSpcCache(
  69. IN PIRP_CONTEXT IrpContext,
  70. IN PIRP Irp,
  71. IN PVOID InputBuffer,
  72. IN ULONG InputBufferLength
  73. );
  74. VOID
  75. PktFlushChildren(
  76. PDFS_PKT_ENTRY pEntry
  77. );
  78. #ifdef ALLOC_PRAGMA
  79. #pragma alloc_text( PAGE, DfsAgePktEntries )
  80. #pragma alloc_text( PAGE, DfspProtocolToService )
  81. #pragma alloc_text( PAGE, DfsFsctrlSetDCName )
  82. #pragma alloc_text( PAGE, PktpSetActiveSpcService )
  83. #pragma alloc_text( PAGE, PktFlushChildren )
  84. #pragma alloc_text( PAGE, PktFsctrlFlushCache )
  85. #pragma alloc_text( PAGE, PktFsctrlFlushSpcCache )
  86. #endif // ALLOC_PRAGMA
  87. //+----------------------------------------------------------------------
  88. //
  89. // Function: DfsAgePktEntries, public
  90. //
  91. // Synopsis: This function gets called in the FSP to step through the PKT
  92. // entries and delete those entries which are old.
  93. //
  94. // Arguments: [TimerContext] -- This context block contains a busy flag
  95. // and a count of the number of ticks that
  96. // have elapsed.
  97. //
  98. // Returns: Nothing.
  99. //
  100. // Notes: In case the PKT cannot be acquired exclusive, the
  101. // routine just returns without doing anything. We
  102. // will have missed an aging interval, but aging is
  103. // a non-critical activity.
  104. //
  105. // History: 04/23/93 SudK Created.
  106. //
  107. //-----------------------------------------------------------------------
  108. VOID
  109. DfsAgePktEntries(PDFS_TIMER_CONTEXT DfsTimerContext)
  110. {
  111. PDFS_PKT pkt = _GetPkt();
  112. PDFS_PKT_ENTRY entry, nextEntry;
  113. PDFS_SPECIAL_ENTRY sentry, snextEntry;
  114. PLIST_ENTRY link;
  115. PDFS_CREDENTIALS creds;
  116. BOOLEAN pktLocked = FALSE;
  117. PDFS_SPECIAL_TABLE pSpecialTable;
  118. DfsDbgTrace(+1, Dbg, "DfsAgePktEntries called\n", 0);
  119. pSpecialTable = &pkt->SpecialTable;
  120. //
  121. // First we need to acquire a lock on the PKT and step through the PKT
  122. //
  123. //
  124. // If we can't get to the resource then let us return right away.
  125. // This is really not that critical. We can always try again.
  126. //
  127. PktAcquireExclusive(FALSE, &pktLocked);
  128. if (pktLocked == FALSE) {
  129. DfsTimerContext->TickCount = 0;
  130. DfsTimerContext->InUse = FALSE;
  131. DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan)\n", 0);
  132. return;
  133. }
  134. if (ExAcquireResourceExclusiveLite(&DfsData.Resource, FALSE) == FALSE) {
  135. PktRelease();
  136. DfsTimerContext->TickCount = 0;
  137. DfsTimerContext->InUse = FALSE;
  138. DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit (no scan 2)\n", 0);
  139. return;
  140. }
  141. //
  142. // Age all the Pkt entries
  143. //
  144. entry = PktFirstEntry(pkt);
  145. while (entry != NULL) {
  146. DfsDbgTrace(0, Dbg, "DfsAgePktEntries: Scanning %wZ\n", &entry->Id.Prefix);
  147. nextEntry = PktNextEntry(pkt, entry);
  148. if (entry->ExpireTime < DfsTimerContext->TickCount) {
  149. #if DBG
  150. if (MupVerbose)
  151. DbgPrint("DfsAgePktEntries:Setting expiretime on %wZ to 0\n",
  152. &entry->Id.Prefix);
  153. #endif
  154. entry->ExpireTime = 0;
  155. } else {
  156. entry->ExpireTime -= DfsTimerContext->TickCount;
  157. }
  158. entry = nextEntry;
  159. }
  160. //
  161. // Age the special table
  162. //
  163. if (pkt->SpecialTable.SpecialEntryCount > 0) {
  164. if (pkt->SpecialTable.TimeToLive >= DfsTimerContext->TickCount) {
  165. pkt->SpecialTable.TimeToLive -= DfsTimerContext->TickCount;
  166. } else { // make it zero
  167. pkt->SpecialTable.TimeToLive = 0;
  168. }
  169. }
  170. //
  171. // Check the deleted credentials queue...
  172. //
  173. for (link = DfsData.DeletedCredentials.Flink;
  174. link != &DfsData.DeletedCredentials;
  175. NOTHING) {
  176. creds = CONTAINING_RECORD(link, DFS_CREDENTIALS, Link);
  177. link = link->Flink;
  178. if (creds->RefCount == 0) {
  179. RemoveEntryList( &creds->Link );
  180. ExFreePool( creds );
  181. }
  182. }
  183. ExReleaseResourceLite( &DfsData.Resource );
  184. PktRelease();
  185. //
  186. // Finally we need to reset the count so that the Timer Routine can
  187. // work fine. We also release the context block by resetting the InUse
  188. // boolean. This will make sure that the next count towards the PKT
  189. // aging will start again.
  190. //
  191. DfsTimerContext->TickCount = 0;
  192. DfsTimerContext->InUse = FALSE;
  193. DfsDbgTrace(-1, Dbg, "DfsAgePktEntries Exit\n", 0);
  194. }
  195. //+----------------------------------------------------------------------------
  196. //
  197. // Function: DfspProtocolToService
  198. //
  199. // Synopsis: Given a NetBIOS protocol definition in a DS_PROTOCOL structure
  200. // this function creates a corresponding DFS_SERVICE structure.
  201. //
  202. // Arguments:
  203. //
  204. // Returns:
  205. //
  206. //-----------------------------------------------------------------------------
  207. NTSTATUS
  208. DfspProtocolToService(
  209. IN PDS_TRANSPORT pdsTransport,
  210. IN PWSTR pwszPrincipalName,
  211. IN PWSTR pwszShareName,
  212. IN BOOLEAN fIsDfs,
  213. IN OUT PDFS_SERVICE pService)
  214. {
  215. NTSTATUS status = STATUS_SUCCESS;
  216. PTA_ADDRESS pTaddr = &pdsTransport->taddr;
  217. PTDI_ADDRESS_NETBIOS pNBAddress;
  218. USHORT i;
  219. WCHAR NetBiosAddress[ TDI_ADDRESS_LENGTH_NETBIOS + 1];
  220. ULONG cbUnused;
  221. PUNICODE_STRING pServiceAddr;
  222. ULONG AllocLen;
  223. DfsDbgTrace(+1, Dbg, "DfspProtocolToService - entered\n", 0);
  224. //
  225. // Initialize the service to nulls
  226. //
  227. RtlZeroMemory(pService, sizeof(DFS_SERVICE));
  228. ASSERT(pTaddr->AddressType == TDI_ADDRESS_TYPE_NETBIOS);
  229. pNBAddress = (PTDI_ADDRESS_NETBIOS) pTaddr->Address;
  230. ASSERT(pTaddr->AddressLength == sizeof(TDI_ADDRESS_NETBIOS));
  231. RtlMultiByteToUnicodeN(
  232. NetBiosAddress,
  233. sizeof(NetBiosAddress),
  234. &cbUnused,
  235. pNBAddress->NetbiosName,
  236. 16);
  237. //
  238. // Process a NetBIOS name. Throw away char 16, then ignore the trailing
  239. // spaces
  240. //
  241. for (i = 14; i >= 0 && NetBiosAddress[i] == L' '; i--) {
  242. NOTHING;
  243. }
  244. NetBiosAddress[i+1] = UNICODE_NULL;
  245. DfsDbgTrace(0, Dbg, "NetBIOS address is %ws\n", NetBiosAddress);
  246. pService->Name.Length = wcslen(pwszPrincipalName) * sizeof(WCHAR);
  247. pService->Name.MaximumLength = pService->Name.Length +
  248. sizeof(UNICODE_NULL);
  249. pService->Name.Buffer = ExAllocatePoolWithTag(
  250. PagedPool,
  251. pService->Name.MaximumLength,
  252. ' puM');
  253. if (!pService->Name.Buffer) {
  254. DfsDbgTrace(0, Dbg, "Unable to create principal name!\n", 0);
  255. status = STATUS_INSUFFICIENT_RESOURCES;
  256. DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", ULongToPtr(status) );
  257. return(status);
  258. }
  259. RtlCopyMemory(pService->Name.Buffer, pwszPrincipalName, pService->Name.Length);
  260. AllocLen = sizeof(UNICODE_PATH_SEP) +
  261. pService->Name.Length +
  262. sizeof(UNICODE_PATH_SEP) +
  263. wcslen(pwszShareName) * sizeof(WCHAR) +
  264. sizeof(UNICODE_NULL);
  265. if (AllocLen <= MAXUSHORT) {
  266. pService->Address.MaximumLength = (USHORT) AllocLen;
  267. } else {
  268. DfsDbgTrace(0, Dbg, "Address too long!\n", 0);
  269. ExFreePool(pService->Name.Buffer);
  270. status = STATUS_NAME_TOO_LONG;
  271. DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", ULongToPtr(status) );
  272. return(status);
  273. }
  274. pService->Address.Buffer = ExAllocatePoolWithTag(
  275. PagedPool,
  276. pService->Address.MaximumLength,
  277. ' puM');
  278. if (!pService->Address.Buffer) {
  279. DfsDbgTrace(0, Dbg, "Unable to create address!\n", 0);
  280. ExFreePool(pService->Name.Buffer);
  281. pService->Name.Buffer = NULL;
  282. status = STATUS_INSUFFICIENT_RESOURCES;
  283. DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", ULongToPtr(status) );
  284. return(status);
  285. }
  286. pService->Address.Length = sizeof(UNICODE_PATH_SEP);
  287. pService->Address.Buffer[0] = UNICODE_PATH_SEP;
  288. DnrConcatenateFilePath(
  289. &pService->Address,
  290. pService->Name.Buffer,
  291. pService->Name.Length);
  292. DnrConcatenateFilePath(
  293. &pService->Address,
  294. pwszShareName,
  295. (USHORT) (wcslen(pwszShareName) * sizeof(WCHAR)));
  296. DfsDbgTrace(0, Dbg, "Server Name is %wZ\n", &pService->Name);
  297. DfsDbgTrace(0, Dbg, "Address is %wZ\n", &pService->Address);
  298. pService->Type = DFS_SERVICE_TYPE_MASTER;
  299. if (fIsDfs) {
  300. pService->Capability = PROV_DFS_RDR;
  301. pService->ProviderId = PROV_ID_DFS_RDR;
  302. } else {
  303. pService->Capability = PROV_STRIP_PREFIX;
  304. pService->ProviderId = PROV_ID_MUP_RDR;
  305. }
  306. pService->pProvider = NULL;
  307. DfsDbgTrace(-1, Dbg, "DfsProtocolToService returning %08lx\n", ULongToPtr(status) );
  308. return(status);
  309. }
  310. //+----------------------------------------------------------------------------
  311. //
  312. // Function: DfsFsctrlSetDCName
  313. //
  314. // Synopsis: Sets the DC to use for special referrals,
  315. // also tries for more referrals if the table is emty or old,
  316. // and also sets the preferred DC if a new DC is passed in.
  317. //
  318. // Arguments:
  319. //
  320. // Returns:
  321. //
  322. //-----------------------------------------------------------------------------
  323. NTSTATUS
  324. DfsFsctrlSetDCName(
  325. IN PIRP_CONTEXT IrpContext,
  326. IN PIRP Irp,
  327. IN PVOID InputBuffer,
  328. IN ULONG InputBufferLength
  329. )
  330. {
  331. NTSTATUS Status = STATUS_SUCCESS;
  332. PDFS_PKT Pkt = _GetPkt();
  333. BOOLEAN GotPkt = FALSE;
  334. BOOLEAN GotNewDc = FALSE;
  335. ULONG i;
  336. WCHAR *DCNameArg;
  337. UNICODE_STRING DomainNameDns;
  338. UNICODE_STRING DomainNameFlat;
  339. UNICODE_STRING DCNameFlat;
  340. UNICODE_STRING DCName;
  341. STD_FSCTRL_PROLOGUE(DfsFsctrlSetDCName, TRUE, FALSE, FALSE);
  342. DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDCName()\n", 0);
  343. RtlZeroMemory(&DomainNameDns, sizeof(UNICODE_STRING));
  344. RtlZeroMemory(&DomainNameFlat, sizeof(UNICODE_STRING));
  345. RtlZeroMemory(&DCName, sizeof(UNICODE_STRING));
  346. RtlZeroMemory(&DCNameFlat, sizeof(UNICODE_STRING));
  347. DCNameArg = (WCHAR *)InputBuffer;
  348. //
  349. // We expect a the buffer to be unicode, so it had better be
  350. // of even length
  351. //
  352. if ((InputBufferLength & 0x1) != 0) {
  353. Status = STATUS_INVALID_PARAMETER;
  354. goto Cleanup;
  355. }
  356. //
  357. // Verify there's a null someplace in the buffer
  358. //
  359. for (i = 0; i < InputBufferLength/sizeof(WCHAR) && DCNameArg[i]; i++)
  360. NOTHING;
  361. if (i >= InputBufferLength/sizeof(WCHAR)) {
  362. Status = STATUS_INVALID_PARAMETER;
  363. goto Cleanup;
  364. }
  365. //
  366. // Verify that the name given (with an added NULL) will fit
  367. // into a USHORT
  368. //
  369. if ((wcslen(DCNameArg) * sizeof(WCHAR)) > MAXUSHORT - sizeof(WCHAR)) {
  370. Status = STATUS_INVALID_PARAMETER;
  371. goto Cleanup;
  372. }
  373. GotNewDc = (i > 0) ? TRUE : FALSE;
  374. //
  375. // If we have a new DC name, switch to it
  376. //
  377. if (GotNewDc == TRUE) {
  378. UNICODE_STRING NewDCName;
  379. DfsDbgTrace(0, Dbg, "DCNameArg=%ws\n", DCNameArg);
  380. NewDCName.Length = wcslen(DCNameArg) * sizeof(WCHAR);
  381. NewDCName.MaximumLength = NewDCName.Length + sizeof(UNICODE_NULL);
  382. NewDCName.Buffer = ExAllocatePoolWithTag(PagedPool, NewDCName.MaximumLength, ' puM');
  383. if (NewDCName.Buffer == NULL) {
  384. Status = STATUS_INSUFFICIENT_RESOURCES;
  385. goto Cleanup;
  386. }
  387. PktAcquireExclusive(TRUE, &GotPkt);
  388. RtlCopyMemory(NewDCName.Buffer, DCNameArg, NewDCName.MaximumLength);
  389. if (Pkt->DCName.Buffer != NULL) {
  390. ExFreePool(Pkt->DCName.Buffer);
  391. }
  392. Pkt->DCName = NewDCName;
  393. }
  394. //
  395. // We need to reference the DCName in the Pkt even without the Pkt locked,
  396. // so we make a copy.
  397. //
  398. if (GotPkt == FALSE) {
  399. PktAcquireExclusive(TRUE, &GotPkt);
  400. }
  401. if (Pkt->DCName.Length > 0) {
  402. DFS_DUPLICATE_STRING(DCName,Pkt->DCName.Buffer, Status);
  403. if (!NT_SUCCESS(Status)) {
  404. goto Cleanup;
  405. }
  406. }
  407. if (GotNewDc == TRUE) {
  408. if (Pkt->DomainNameDns.Length > 0) {
  409. DFS_DUPLICATE_STRING(DomainNameDns,Pkt->DomainNameDns.Buffer, Status);
  410. if (!NT_SUCCESS(Status)) {
  411. goto CheckSpcTable;
  412. }
  413. }
  414. if (Pkt->DomainNameFlat.Length > 0) {
  415. DFS_DUPLICATE_STRING(DomainNameFlat,Pkt->DomainNameFlat.Buffer, Status);
  416. if (!NT_SUCCESS(Status)) {
  417. goto CheckSpcTable;
  418. }
  419. }
  420. PktRelease();
  421. GotPkt = FALSE;
  422. if (DCName.Length > 0 && DomainNameDns.Length > 0) {
  423. PktpSetActiveSpcService(
  424. &DomainNameDns,
  425. &DCName,
  426. FALSE);
  427. DCNameFlat = DCName;
  428. for (i = 0;
  429. i < DCNameFlat.Length / sizeof(WCHAR) && DCNameFlat.Buffer[i] != L'.';
  430. i++
  431. ) {
  432. NOTHING;
  433. }
  434. DCNameFlat.Length = (USHORT) (i * sizeof(WCHAR));
  435. if (DCNameFlat.Length > Pkt->DCName.Length)
  436. DCNameFlat.Length = Pkt->DCName.Length;
  437. }
  438. if (DCNameFlat.Length > 0 && DomainNameFlat.Length > 0) {
  439. PktpSetActiveSpcService(
  440. &DomainNameFlat,
  441. &DCNameFlat,
  442. FALSE);
  443. }
  444. }
  445. if (GotPkt == TRUE) {
  446. PktRelease();
  447. GotPkt = FALSE;
  448. }
  449. CheckSpcTable:
  450. if (NT_SUCCESS(Status) &&
  451. (Pkt->SpecialTable.SpecialEntryCount == 0 || Pkt->SpecialTable.TimeToLive == 0)) {
  452. if (DCName.Length > 0) {
  453. Status = PktGetSpecialReferralTable(&DCName, TRUE);
  454. } else {
  455. Status = STATUS_BAD_NETWORK_PATH;
  456. }
  457. }
  458. Cleanup:
  459. //
  460. // Free the local copies
  461. //
  462. if (DomainNameDns.Buffer != NULL)
  463. ExFreePool(DomainNameDns.Buffer);
  464. if (DomainNameFlat.Buffer != NULL)
  465. ExFreePool(DomainNameFlat.Buffer);
  466. if (DCName.Buffer != NULL)
  467. ExFreePool(DCName.Buffer);
  468. if (GotPkt == TRUE) {
  469. PktRelease();
  470. GotPkt = FALSE;
  471. }
  472. DfsCompleteRequest(IrpContext, Irp, Status);
  473. DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDCName exit 0x%x\n", ULongToPtr(Status) );
  474. return (Status);
  475. }
  476. //+----------------------------------------------------------------------------
  477. //
  478. // Function: DfsFsctrlSetDomainNameFlat
  479. //
  480. // Synopsis: Sets the DomainName (flat)
  481. //
  482. // Arguments:
  483. //
  484. // Returns:
  485. //
  486. //-----------------------------------------------------------------------------
  487. NTSTATUS
  488. DfsFsctrlSetDomainNameFlat(
  489. IN PIRP_CONTEXT IrpContext,
  490. IN PIRP Irp,
  491. IN PVOID InputBuffer,
  492. IN ULONG InputBufferLength
  493. )
  494. {
  495. NTSTATUS Status = STATUS_SUCCESS;
  496. PDFS_PKT Pkt = _GetPkt();
  497. BOOLEAN GotPkt;
  498. ULONG i;
  499. WCHAR *DomainNameFlat;
  500. STD_FSCTRL_PROLOGUE(DfsFsctrlSetDomainNameFlat, TRUE, FALSE, FALSE);
  501. DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDomainNameFlat()\n", 0);
  502. DomainNameFlat = (WCHAR *)InputBuffer;
  503. //
  504. // Verify there's a null someplace in the buffer
  505. //
  506. for (i = 0; i < InputBufferLength/sizeof(WCHAR) && DomainNameFlat[i]; i++)
  507. NOTHING;
  508. //
  509. // Zero-len is as bad as no terminating NULL
  510. //
  511. if (i == 0 || i >= InputBufferLength/sizeof(WCHAR)) {
  512. DfsCompleteRequest(IrpContext, Irp, Status);
  513. return STATUS_INVALID_PARAMETER;
  514. }
  515. //
  516. // Verify that the name given (with an added NULL) will fit
  517. // into a USHORT
  518. //
  519. if ((wcslen(DomainNameFlat) * sizeof(WCHAR)) > MAXUSHORT - sizeof(WCHAR)) {
  520. Status = STATUS_INVALID_PARAMETER;
  521. DfsCompleteRequest(IrpContext, Irp, Status);
  522. return STATUS_INVALID_PARAMETER;
  523. }
  524. PktAcquireExclusive(TRUE, &GotPkt);
  525. DfsDbgTrace(0, Dbg, "DomainNameFlat=%ws\n", DomainNameFlat);
  526. //
  527. // Replace old
  528. //
  529. if (Pkt->DomainNameFlat.Buffer) {
  530. ExFreePool(Pkt->DomainNameFlat.Buffer);
  531. }
  532. Pkt->DomainNameFlat.Length = wcslen(DomainNameFlat) * sizeof(WCHAR);
  533. Pkt->DomainNameFlat.MaximumLength = Pkt->DomainNameFlat.Length + sizeof(UNICODE_NULL);
  534. Pkt->DomainNameFlat.Buffer = ExAllocatePoolWithTag(
  535. PagedPool,
  536. Pkt->DomainNameFlat.MaximumLength,
  537. ' puM');
  538. if (Pkt->DomainNameFlat.Buffer != NULL) {
  539. RtlCopyMemory(
  540. Pkt->DomainNameFlat.Buffer,
  541. DomainNameFlat,
  542. Pkt->DomainNameFlat.MaximumLength);
  543. } else {
  544. Pkt->DomainNameFlat.Length = Pkt->DomainNameFlat.MaximumLength = 0;
  545. Status = STATUS_INSUFFICIENT_RESOURCES;
  546. }
  547. PktRelease();
  548. DfsCompleteRequest(IrpContext, Irp, Status);
  549. DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDomainNameFlat exit 0x%x\n", ULongToPtr(Status) );
  550. return (Status);
  551. }
  552. //+----------------------------------------------------------------------------
  553. //
  554. // Function: DfsFsctrlSetDomainNameDns
  555. //
  556. // Synopsis: Sets the DomainName (flat)
  557. //
  558. // Arguments:
  559. //
  560. // Returns:
  561. //
  562. //-----------------------------------------------------------------------------
  563. NTSTATUS
  564. DfsFsctrlSetDomainNameDns(
  565. IN PIRP_CONTEXT IrpContext,
  566. IN PIRP Irp,
  567. IN PVOID InputBuffer,
  568. IN ULONG InputBufferLength
  569. )
  570. {
  571. NTSTATUS Status = STATUS_SUCCESS;
  572. PDFS_PKT Pkt = _GetPkt();
  573. BOOLEAN GotPkt;
  574. ULONG i;
  575. WCHAR *DomainNameDns;
  576. STD_FSCTRL_PROLOGUE(DfsFsctrlSetDomainNameDns, TRUE, FALSE, FALSE);
  577. DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDomainNameDns()\n", 0);
  578. DomainNameDns = (WCHAR *)InputBuffer;
  579. //
  580. // Verify there's a null someplace in the buffer
  581. //
  582. for (i = 0; i < InputBufferLength/sizeof(WCHAR) && DomainNameDns[i]; i++)
  583. NOTHING;
  584. //
  585. // Zero-len is as bad as no terminating NULL
  586. //
  587. if (i == 0 || i >= InputBufferLength/sizeof(WCHAR)) {
  588. DfsCompleteRequest(IrpContext, Irp, Status);
  589. return STATUS_INVALID_PARAMETER;
  590. }
  591. //
  592. // Verify that the name given (with an added NULL) will fit
  593. // into a USHORT
  594. //
  595. if ((wcslen(DomainNameDns) * sizeof(WCHAR)) > MAXUSHORT - sizeof(WCHAR)) {
  596. Status = STATUS_INVALID_PARAMETER;
  597. DfsCompleteRequest(IrpContext, Irp, Status);
  598. return STATUS_INVALID_PARAMETER;
  599. }
  600. PktAcquireExclusive(TRUE, &GotPkt);
  601. DfsDbgTrace(0, Dbg, "DomainNameDns=%ws\n", DomainNameDns);
  602. //
  603. // Replace old
  604. //
  605. if (Pkt->DomainNameDns.Buffer) {
  606. ExFreePool(Pkt->DomainNameDns.Buffer);
  607. }
  608. Pkt->DomainNameDns.Length = wcslen(DomainNameDns) * sizeof(WCHAR);
  609. Pkt->DomainNameDns.MaximumLength = Pkt->DomainNameDns.Length + sizeof(UNICODE_NULL);
  610. Pkt->DomainNameDns.Buffer = ExAllocatePoolWithTag(
  611. PagedPool,
  612. Pkt->DomainNameDns.MaximumLength,
  613. ' puM');
  614. if (Pkt->DomainNameDns.Buffer != NULL) {
  615. RtlCopyMemory(
  616. Pkt->DomainNameDns.Buffer,
  617. DomainNameDns,
  618. Pkt->DomainNameDns.MaximumLength);
  619. } else {
  620. Pkt->DomainNameDns.Length = Pkt->DomainNameDns.MaximumLength = 0;
  621. Status = STATUS_INSUFFICIENT_RESOURCES;
  622. }
  623. PktRelease();
  624. DfsCompleteRequest(IrpContext, Irp, Status);
  625. DfsDbgTrace(+1, Dbg, "DfsFsctrlSetDomainNameDns exit 0x%x\n", ULongToPtr(Status) );
  626. return (Status);
  627. }
  628. //+-------------------------------------------------------------------------
  629. //
  630. // Function: PktFsctrlFlushCache, public
  631. //
  632. // Synopsis: This function will flush all entries which match the specified
  633. // input path.
  634. // However, this function will refuse to delete any Permanent
  635. // entries of the PKT.
  636. //
  637. // Arguments:
  638. //
  639. // Returns:
  640. //
  641. //--------------------------------------------------------------------------
  642. NTSTATUS
  643. PktFsctrlFlushCache(
  644. IN PIRP_CONTEXT IrpContext,
  645. IN PIRP Irp,
  646. IN PVOID InputBuffer,
  647. IN ULONG InputBufferLength
  648. )
  649. {
  650. NTSTATUS status = STATUS_SUCCESS;
  651. PDFS_PKT Pkt;
  652. PDFS_PKT_ENTRY curEntry;
  653. PDFS_PKT_ENTRY nextEntry;
  654. PDFS_PKT_ENTRY pEntry;
  655. BOOLEAN pktLocked;
  656. UNICODE_STRING ustrPrefix, RemainingPath;
  657. PWCHAR wCp = (PWCHAR) InputBuffer;
  658. STD_FSCTRL_PROLOGUE(PktFsctrlFlushCache, TRUE, FALSE, FALSE);
  659. DfsDbgTrace(+1,Dbg, "PktFsctrlFlushCache()\n", 0);
  660. //
  661. // If InputBufferLength == 2 and InputBuffer == '*', flush all entries
  662. //
  663. if (InputBufferLength == sizeof(WCHAR) && wCp[0] == L'*') {
  664. Pkt = _GetPkt();
  665. PktAcquireExclusive(TRUE, &pktLocked);
  666. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  667. curEntry = PktFirstEntry(Pkt);
  668. while (curEntry!=NULL) {
  669. nextEntry = PktNextEntry(Pkt, curEntry);
  670. if ( !(curEntry->Type & PKT_ENTRY_TYPE_PERMANENT) ) {
  671. if (curEntry->UseCount == 0) {
  672. PktEntryDestroy(curEntry, Pkt, (BOOLEAN) TRUE);
  673. } else if ( !(curEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC) ) {
  674. //
  675. // We can't delete this entry because it is in use, so
  676. // mark it DELETE_PENDING, set its timeout to zero
  677. // and remove from the prefix tables
  678. //
  679. curEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING;
  680. curEntry->ExpireTime = 0;
  681. curEntry->USN++;
  682. DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(curEntry->Id.Prefix));
  683. DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(curEntry->Id.ShortPrefix));
  684. }
  685. }
  686. curEntry = nextEntry;
  687. }
  688. PktRelease();
  689. ExReleaseResourceLite( &DfsData.Resource );
  690. DfsCompleteRequest( IrpContext, Irp, status );
  691. DfsDbgTrace(-1,Dbg, "PktFsctrlFlushCache: Exit -> %08lx\n", ULongToPtr(status) );
  692. return(status);
  693. }
  694. //
  695. // Verify the buffer contains at least a '\' and is of even length
  696. //
  697. if (InputBufferLength < sizeof(WCHAR)
  698. ||
  699. (InputBufferLength & 0x1) != 0
  700. ||
  701. wCp[0] != UNICODE_PATH_SEP) {
  702. status = STATUS_INVALID_PARAMETER;
  703. DfsCompleteRequest( IrpContext, Irp, status );
  704. return status;
  705. }
  706. //
  707. // Flush one entry
  708. //
  709. ustrPrefix.Length = (USHORT) InputBufferLength;
  710. ustrPrefix.MaximumLength = (USHORT) InputBufferLength;
  711. ustrPrefix.Buffer = (PWCHAR) InputBuffer;
  712. if (ustrPrefix.Length >= sizeof(WCHAR) * 2 &&
  713. ustrPrefix.Buffer[0] == UNICODE_PATH_SEP &&
  714. ustrPrefix.Buffer[1] == UNICODE_PATH_SEP
  715. ) {
  716. ustrPrefix.Buffer++;
  717. ustrPrefix.Length -= sizeof(WCHAR);
  718. }
  719. if (ustrPrefix.Buffer[ustrPrefix.Length/sizeof(WCHAR)-1] == UNICODE_NULL) {
  720. ustrPrefix.Length -= sizeof(WCHAR);
  721. }
  722. Pkt = _GetPkt();
  723. PktAcquireExclusive(TRUE, &pktLocked);
  724. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  725. pEntry = PktLookupEntryByPrefix(Pkt,
  726. &ustrPrefix,
  727. &RemainingPath);
  728. if (pEntry == NULL || RemainingPath.Length != 0) {
  729. status = STATUS_OBJECT_NAME_NOT_FOUND;
  730. } else {
  731. if ( !(pEntry->Type & PKT_ENTRY_TYPE_PERMANENT) ) {
  732. if (pEntry->UseCount == 0) {
  733. PktEntryDestroy(pEntry, Pkt, (BOOLEAN) TRUE);
  734. } else if ( !(pEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC) ) {
  735. //
  736. // We can't delete this entry because it is in use, so
  737. // mark it DELETE_PENDING, set its timeout to zero
  738. // and remove from the prefix tables
  739. //
  740. pEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING;
  741. pEntry->ExpireTime = 0;
  742. DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(pEntry->Id.Prefix));
  743. DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(pEntry->Id.ShortPrefix));
  744. }
  745. } else {
  746. status = STATUS_INVALID_PARAMETER;
  747. }
  748. }
  749. PktRelease();
  750. ExReleaseResourceLite( &DfsData.Resource );
  751. DfsCompleteRequest( IrpContext, Irp, status );
  752. DfsDbgTrace(-1,Dbg, "PktFsctrlFlushCache: Exit -> %08lx\n", ULongToPtr(status) );
  753. return status;
  754. }
  755. //+-------------------------------------------------------------------------
  756. //
  757. // Function: PktFsctrlFlushSpcCache, public
  758. //
  759. // Synopsis: This function will flush all entries which match the specified
  760. // input path.
  761. // However, this function will refuse to delete any Permanent
  762. // entries of the PKT.
  763. //
  764. // Arguments:
  765. //
  766. // Returns:
  767. //
  768. //--------------------------------------------------------------------------
  769. NTSTATUS
  770. PktFsctrlFlushSpcCache(
  771. IN PIRP_CONTEXT IrpContext,
  772. IN PIRP Irp,
  773. IN PVOID InputBuffer,
  774. IN ULONG InputBufferLength
  775. )
  776. {
  777. NTSTATUS status = STATUS_INVALID_PARAMETER;
  778. PDFS_PKT Pkt;
  779. BOOLEAN pktLocked;
  780. PDFS_SPECIAL_ENTRY pSpecialEntry;
  781. PDFS_SPECIAL_TABLE pSpecialTable;
  782. PWCHAR wCp = (PWCHAR) InputBuffer;
  783. ULONG i;
  784. STD_FSCTRL_PROLOGUE(PktFsctrlFlushSpcCache, TRUE, FALSE, FALSE);
  785. DfsDbgTrace(+1,Dbg, "PktFsctrlFlushSpcCache()\n", 0);
  786. //
  787. // InputBufferLength == 2 and InputBuffer == '*'
  788. //
  789. if (InputBufferLength == sizeof(WCHAR) && wCp[0] == L'*') {
  790. Pkt = _GetPkt();
  791. PktAcquireExclusive(TRUE, &pktLocked);
  792. pSpecialTable = &Pkt->SpecialTable;
  793. pSpecialTable->TimeToLive = 0;
  794. pSpecialEntry = CONTAINING_RECORD(
  795. pSpecialTable->SpecialEntryList.Flink,
  796. DFS_SPECIAL_ENTRY,
  797. Link);
  798. for (i = 0; i < pSpecialTable->SpecialEntryCount; i++) {
  799. pSpecialEntry->Stale = TRUE;
  800. pSpecialEntry = CONTAINING_RECORD(
  801. pSpecialEntry->Link.Flink,
  802. DFS_SPECIAL_ENTRY,
  803. Link);
  804. }
  805. PktRelease();
  806. status = STATUS_SUCCESS;
  807. } else {
  808. status = STATUS_INVALID_PARAMETER;
  809. }
  810. DfsCompleteRequest( IrpContext, Irp, status );
  811. DfsDbgTrace(-1,Dbg, "PktFsctrlFlushSpcCache: Exit -> %08lx\n", ULongToPtr(status) );
  812. return status;
  813. }
  814. //+-------------------------------------------------------------------------
  815. //
  816. // Function: PktFlushChildren
  817. //
  818. // Synopsis: This function will flush all entries which are children
  819. // of the entry passed in.
  820. // However, this function will refuse to delete any Permanent
  821. // entries of the PKT.
  822. //
  823. // Arguments:
  824. //
  825. // Returns:
  826. //
  827. //--------------------------------------------------------------------------
  828. VOID
  829. PktFlushChildren(
  830. PDFS_PKT_ENTRY pEntry
  831. )
  832. {
  833. NTSTATUS status = STATUS_SUCCESS;
  834. PDFS_PKT Pkt;
  835. PDFS_PKT_ENTRY curEntry;
  836. PDFS_PKT_ENTRY nextEntry;
  837. BOOLEAN pktLocked;
  838. DfsDbgTrace(+1,Dbg, "PktFlushChildren(%wZ)\n", &pEntry->Id.Prefix);
  839. #if DBG
  840. if (MupVerbose)
  841. DbgPrint("PktFlushChildren(%wZ)\n", &pEntry->Id.Prefix);
  842. #endif
  843. PktAcquireExclusive(TRUE, &pktLocked);
  844. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  845. Pkt = _GetPkt();
  846. curEntry = PktEntryFirstChild(pEntry);
  847. while (curEntry != NULL) {
  848. DfsDbgTrace(0, Dbg, "PktFlushChildren: examining %wZ\n",
  849. &curEntry->Id.Prefix);
  850. //
  851. // We may lose this entry due to deletion. Let us get the Next
  852. // entry before we go into the next stage.
  853. //
  854. nextEntry = PktEntryNextChild(pEntry,curEntry);
  855. //
  856. // Try to delete the entry.
  857. //
  858. if ( !(curEntry->Type & PKT_ENTRY_TYPE_PERMANENT) ) {
  859. if (curEntry->UseCount == 0) {
  860. PktEntryDestroy(curEntry, Pkt, (BOOLEAN) TRUE);
  861. } else if ( !(curEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC) ) {
  862. //
  863. // We can't delete this entry because it is in use, so
  864. // mark it DELETE_PENDING, set its timeout to zero
  865. // and remove from the prefix tables
  866. //
  867. curEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING;
  868. curEntry->ExpireTime = 0;
  869. DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(curEntry->Id.Prefix));
  870. DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(curEntry->Id.ShortPrefix));
  871. }
  872. }
  873. curEntry = nextEntry;
  874. }
  875. PktRelease();
  876. ExReleaseResourceLite( &DfsData.Resource );
  877. #if DBG
  878. if (MupVerbose)
  879. DbgPrint("PktFlushChildren returning VOID\n");
  880. #endif
  881. DfsDbgTrace(-1,Dbg, "PktFlushChildren returning VOID\n", 0);
  882. }
  883. //+-------------------------------------------------------------------------
  884. //
  885. // Function: PktpSetActiveSpcService
  886. //
  887. // Synopsis: This function will attempt to set the 'active' DC in the specified
  888. // domain
  889. //
  890. // Arguments:
  891. //
  892. // Returns: STATUS_SUCCESS or STATUS_NOT_FOUND
  893. //
  894. //--------------------------------------------------------------------------
  895. NTSTATUS
  896. PktpSetActiveSpcService(
  897. PUNICODE_STRING DomainName,
  898. PUNICODE_STRING DcName,
  899. BOOLEAN ResetTimeout)
  900. {
  901. NTSTATUS status = STATUS_NOT_FOUND;
  902. ULONG EntryIdx;
  903. USHORT i;
  904. PDFS_SPECIAL_ENTRY pSpecialEntry;
  905. UNICODE_STRING DcNameFlat;
  906. BOOLEAN pktLocked;
  907. if (DomainName != NULL && DomainName->Length > 0) {
  908. status = PktExpandSpecialName(DomainName, &pSpecialEntry);
  909. if (NT_SUCCESS(status)) {
  910. for (EntryIdx = 0; EntryIdx < pSpecialEntry->ExpandedCount; EntryIdx++) {
  911. if (RtlCompareUnicodeString(
  912. DcName,
  913. &pSpecialEntry->ExpandedNames[EntryIdx].ExpandedName,
  914. TRUE) == 0) {
  915. pSpecialEntry->Active = EntryIdx;
  916. //
  917. // Keep the spc table around for a while longer
  918. //
  919. if (ResetTimeout == TRUE) {
  920. PktAcquireExclusive(TRUE, &pktLocked);
  921. if (DfsData.Pkt.SpecialTable.TimeToLive < 60 * 15) {
  922. DfsData.Pkt.SpecialTable.TimeToLive += 60 * 15; // 15 min
  923. }
  924. PktRelease();
  925. }
  926. status = STATUS_SUCCESS;
  927. break;
  928. }
  929. status = STATUS_NOT_FOUND;
  930. }
  931. InterlockedDecrement(&pSpecialEntry->UseCount);
  932. } else {
  933. status = STATUS_NOT_FOUND;
  934. }
  935. }
  936. return status;
  937. }