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.

5705 lines
167 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: PKT.C
  6. //
  7. // Contents: This module implements the Partition Knowledge Table routines
  8. // for the Dfs driver.
  9. //
  10. // Functions: PktInitialize -
  11. // PktInitializeLocalPartition -
  12. // RemoveLastComponent -
  13. // PktCreateEntry -
  14. // PktCreateDomainEntry -
  15. // PktCreateSubordinateEntry -
  16. // PktLookupEntryById -
  17. // PktEntryModifyPrefix -
  18. // PktLookupEntryByPrefix -
  19. // PktLookupEntryByUid -
  20. // PktLookupReferralEntry -
  21. // PktTrimSubordinates -
  22. // PktpRecoverLocalPartition -
  23. // PktpValidateLocalPartition -
  24. // PktCreateEntryFromReferral -
  25. // PktExpandSpecialEntryFromReferral -
  26. // PktCreateSpecialEntryTableFromReferral -
  27. // PktGetSpecialReferralTable -
  28. // PktpAddEntry -
  29. // PktExpandSpecialName -
  30. // PktParsePath -
  31. // PktLookupSpecialNameEntry -
  32. // PktCreateSpecialNameEntry -
  33. // PktGetReferral -
  34. // DfspSetActiveServiceByServerName -
  35. //
  36. // History: 5 May 1992 PeterCo Created.
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include "dfsprocs.h"
  40. #include <smbtypes.h>
  41. #include <smbtrans.h>
  42. #include "dnr.h"
  43. #include "log.h"
  44. #include "know.h"
  45. #include "mupwml.h"
  46. #include "wincred.h"
  47. #include <netevent.h>
  48. #define Dbg (DEBUG_TRACE_PKT)
  49. //
  50. // These should come from ntos\inc\ps.h, but
  51. // there are #define conflicts
  52. //
  53. BOOLEAN
  54. PsDisableImpersonation(
  55. IN PETHREAD Thread,
  56. IN PSE_IMPERSONATION_STATE ImpersonationState);
  57. VOID
  58. PsRestoreImpersonation(
  59. IN PETHREAD Thread,
  60. IN PSE_IMPERSONATION_STATE ImpersonationState);
  61. BOOLEAN
  62. DfspIsSysVolShare(
  63. PUNICODE_STRING ShareName);
  64. //
  65. // Local procedure prototypes
  66. //
  67. NTSTATUS
  68. PktpCheckReferralSyntax(
  69. IN PUNICODE_STRING ReferralPath,
  70. IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
  71. IN DWORD ReferralSize);
  72. NTSTATUS
  73. PktpCheckReferralString(
  74. IN LPWSTR String,
  75. IN PCHAR ReferralBuffer,
  76. IN PCHAR ReferralBufferEnd);
  77. NTSTATUS
  78. PktpCheckReferralNetworkAddress(
  79. IN PWCHAR Address,
  80. IN ULONG MaxLength);
  81. NTSTATUS
  82. PktpCreateEntryIdFromReferral(
  83. IN PRESP_GET_DFS_REFERRAL Ref,
  84. IN PUNICODE_STRING ReferralPath,
  85. OUT ULONG *MatchingLength,
  86. OUT PDFS_PKT_ENTRY_ID Peid);
  87. NTSTATUS
  88. PktpAddEntry (
  89. IN PDFS_PKT Pkt,
  90. IN PDFS_PKT_ENTRY_ID EntryId,
  91. IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
  92. IN ULONG CreateDisposition,
  93. IN PDFS_TARGET_INFO pDfsTargetInfo,
  94. OUT PDFS_PKT_ENTRY *ppPktEntry);
  95. PDS_MACHINE
  96. PktpGetDSMachine(
  97. IN PUNICODE_STRING ServerName);
  98. VOID
  99. PktShuffleServiceList(
  100. PDFS_PKT_ENTRY_INFO pInfo);
  101. NTSTATUS
  102. DfspSetServiceListToDc(
  103. PDFS_PKT_ENTRY pktEntry);
  104. VOID
  105. PktShuffleSpecialEntryList(
  106. PDFS_SPECIAL_ENTRY pSpecialEntry);
  107. VOID
  108. PktSetSpecialEntryListToDc(
  109. PDFS_SPECIAL_ENTRY pSpecialEntry);
  110. VOID
  111. PktShuffleGroup(
  112. PDFS_PKT_ENTRY_INFO pInfo,
  113. ULONG nStart,
  114. ULONG nEnd);
  115. NTSTATUS
  116. PktGetReferral(
  117. IN PUNICODE_STRING MachineName,
  118. IN PUNICODE_STRING DomainName,
  119. IN PUNICODE_STRING ShareName,
  120. IN BOOLEAN CSCAgentCreate);
  121. NTSTATUS
  122. DfspSetActiveServiceByServerName(
  123. PUNICODE_STRING ServerName,
  124. PDFS_PKT_ENTRY pktEntry);
  125. BOOLEAN
  126. DfspIsDupPktEntry(
  127. PDFS_PKT_ENTRY ExistingEntry,
  128. ULONG EntryType,
  129. PDFS_PKT_ENTRY_ID EntryId,
  130. PDFS_PKT_ENTRY_INFO EntryInfo);
  131. BOOLEAN
  132. DfspIsDupSvc(
  133. PDFS_SERVICE pS1,
  134. PDFS_SERVICE pS2);
  135. VOID
  136. PktFlushChildren(
  137. PDFS_PKT_ENTRY pEntry);
  138. BOOLEAN
  139. DfspDnsNameToFlatName(
  140. PUNICODE_STRING DnsName,
  141. PUNICODE_STRING FlatName);
  142. NTSTATUS
  143. DfsGetLMRTargetInfo(
  144. HANDLE IpcHandle,
  145. PDFS_TARGET_INFO *ppTargetInfo );
  146. NTSTATUS
  147. PktCreateTargetInfo(
  148. PUNICODE_STRING pDomainName,
  149. PUNICODE_STRING pShareName,
  150. BOOLEAN SpecialName,
  151. PDFS_TARGET_INFO *ppDfsTargetInfo );
  152. DWORD PktLastReferralStatus = 0;
  153. #ifdef ALLOC_PRAGMA
  154. #pragma alloc_text( INIT, PktInitialize )
  155. #pragma alloc_text( PAGE, PktUninitialize )
  156. #pragma alloc_text( PAGE, RemoveLastComponent )
  157. #pragma alloc_text( PAGE, PktCreateEntry )
  158. #pragma alloc_text( PAGE, PktCreateDomainEntry )
  159. #pragma alloc_text( PAGE, PktEntryModifyPrefix )
  160. #pragma alloc_text( PAGE, PktLookupEntryByPrefix )
  161. #pragma alloc_text( PAGE, PktLookupEntryByUid )
  162. #pragma alloc_text( PAGE, PktLookupReferralEntry )
  163. #pragma alloc_text( PAGE, PktCreateEntryFromReferral )
  164. #pragma alloc_text( PAGE, PktExpandSpecialEntryFromReferral )
  165. #pragma alloc_text( PAGE, PktpCheckReferralSyntax )
  166. #pragma alloc_text( PAGE, PktpCheckReferralString )
  167. #pragma alloc_text( PAGE, PktpCheckReferralNetworkAddress )
  168. #pragma alloc_text( PAGE, PktpCreateEntryIdFromReferral )
  169. #pragma alloc_text( PAGE, PktpAddEntry )
  170. #pragma alloc_text( PAGE, PktExpandSpecialName )
  171. #pragma alloc_text( PAGE, PktpGetDSMachine )
  172. #pragma alloc_text( PAGE, PktShuffleServiceList )
  173. #pragma alloc_text( PAGE, DfspSetServiceListToDc )
  174. #pragma alloc_text( PAGE, PktShuffleSpecialEntryList )
  175. #pragma alloc_text( PAGE, PktSetSpecialEntryListToDc )
  176. #pragma alloc_text( PAGE, PktShuffleGroup )
  177. #pragma alloc_text( PAGE, PktParsePath )
  178. #pragma alloc_text( PAGE, PktLookupSpecialNameEntry )
  179. #pragma alloc_text( PAGE, PktCreateSpecialNameEntry )
  180. #pragma alloc_text( PAGE, PktGetSpecialReferralTable )
  181. #pragma alloc_text( PAGE, PktCreateSpecialEntryTableFromReferral )
  182. #pragma alloc_text( PAGE, DfspSetActiveServiceByServerName )
  183. #pragma alloc_text( PAGE, DfspIsDupPktEntry )
  184. #pragma alloc_text( PAGE, DfspIsDupSvc )
  185. #pragma alloc_text( PAGE, DfspDnsNameToFlatName )
  186. #pragma alloc_text( PAGE, PktpUpdateSpecialTable)
  187. #pragma alloc_text( PAGE, PktFindEntryByPrefix )
  188. #endif // ALLOC_PRAGMA
  189. //
  190. // declare the global null guid
  191. //
  192. GUID _TheNullGuid;
  193. //
  194. // If we are in a workgroup, there's no use in trying to contact the DC!
  195. //
  196. BOOLEAN MupInAWorkGroup = FALSE;
  197. #define SpcIsRecoverableError(x) ( (x) == STATUS_IO_TIMEOUT || \
  198. (x) == STATUS_REMOTE_NOT_LISTENING || \
  199. (x) == STATUS_VIRTUAL_CIRCUIT_CLOSED || \
  200. (x) == STATUS_BAD_NETWORK_PATH || \
  201. (x) == STATUS_NETWORK_BUSY || \
  202. (x) == STATUS_INVALID_NETWORK_RESPONSE || \
  203. (x) == STATUS_UNEXPECTED_NETWORK_ERROR || \
  204. (x) == STATUS_NETWORK_NAME_DELETED || \
  205. (x) == STATUS_BAD_NETWORK_NAME || \
  206. (x) == STATUS_REQUEST_NOT_ACCEPTED || \
  207. (x) == STATUS_DISK_OPERATION_FAILED || \
  208. (x) == STATUS_NETWORK_UNREACHABLE || \
  209. (x) == STATUS_INSUFFICIENT_RESOURCES || \
  210. (x) == STATUS_SHARING_PAUSED || \
  211. (x) == STATUS_DFS_UNAVAILABLE || \
  212. (x) == STATUS_DEVICE_OFF_LINE || \
  213. (x) == STATUS_NETLOGON_NOT_STARTED \
  214. )
  215. //+-------------------------------------------------------------------------
  216. //
  217. // Function: PktInitialize, public
  218. //
  219. // Synopsis: PktInitialize initializes the partition knowledge table.
  220. //
  221. // Arguments: [Pkt] - pointer to an uninitialized PKT
  222. //
  223. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  224. //
  225. // Notes: This routine is called only at driver init time.
  226. //
  227. //--------------------------------------------------------------------------
  228. NTSTATUS
  229. PktInitialize(
  230. IN PDFS_PKT Pkt
  231. ) {
  232. PDFS_SPECIAL_TABLE pSpecialTable = &Pkt->SpecialTable;
  233. DfsDbgTrace(+1, Dbg, "PktInitialize: Entered\n", 0);
  234. //
  235. // initialize the NULL GUID.
  236. //
  237. RtlZeroMemory(&_TheNullGuid, sizeof(GUID));
  238. //
  239. // Always zero the pkt first
  240. //
  241. RtlZeroMemory(Pkt, sizeof(DFS_PKT));
  242. //
  243. // do basic initialization
  244. //
  245. Pkt->NodeTypeCode = DSFS_NTC_PKT;
  246. Pkt->NodeByteSize = sizeof(DFS_PKT);
  247. ExInitializeResourceLite(&Pkt->Resource);
  248. InitializeListHead(&Pkt->EntryList);
  249. DfsInitializeUnicodePrefix(&Pkt->PrefixTable);
  250. DfsInitializeUnicodePrefix(&Pkt->ShortPrefixTable);
  251. RtlInitializeUnicodePrefix(&Pkt->DSMachineTable);
  252. Pkt->EntryTimeToLive = MAX_REFERRAL_LIFE_TIME;
  253. InitializeListHead(&pSpecialTable->SpecialEntryList);
  254. DfsDbgTrace(-1, Dbg, "PktInitialize: Exit -> VOID\n", 0 );
  255. return STATUS_SUCCESS;
  256. }
  257. //+-------------------------------------------------------------------------
  258. //
  259. // Function: PktUninitialize, public
  260. //
  261. // Synopsis: PktUninitialize uninitializes the partition knowledge table.
  262. //
  263. // Arguments: [Pkt] - pointer to an initialized PKT
  264. //
  265. // Returns: None
  266. //
  267. // Notes: This routine is called only at driver unload time
  268. //
  269. //--------------------------------------------------------------------------
  270. VOID
  271. PktUninitialize(
  272. IN PDFS_PKT Pkt
  273. )
  274. {
  275. DfsFreePrefixTable(&Pkt->PrefixTable);
  276. DfsFreePrefixTable(&Pkt->ShortPrefixTable);
  277. ExDeleteResourceLite(&Pkt->Resource);
  278. }
  279. //+-------------------------------------------------------------------------
  280. //
  281. // Function: RemoveLastComponent, public
  282. //
  283. // Synopsis: Removes the last component of the string passed.
  284. //
  285. // Arguments: [Prefix] -- The prefix whose last component is to be returned.
  286. // [newPrefix] -- The new Prefix with the last component removed.
  287. //
  288. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  289. //
  290. // Notes: On return, the newPrefix points to the same memory buffer
  291. // as Prefix.
  292. //
  293. //--------------------------------------------------------------------------
  294. void
  295. RemoveLastComponent(
  296. PUNICODE_STRING Prefix,
  297. PUNICODE_STRING newPrefix
  298. )
  299. {
  300. PWCHAR pwch;
  301. USHORT i=0;
  302. *newPrefix = *Prefix;
  303. pwch = newPrefix->Buffer;
  304. pwch += (Prefix->Length/sizeof(WCHAR)) - 1;
  305. while ((*pwch != UNICODE_PATH_SEP) && (pwch != newPrefix->Buffer)) {
  306. i += sizeof(WCHAR);
  307. pwch--;
  308. }
  309. newPrefix->Length = newPrefix->Length - i;
  310. }
  311. //+-------------------------------------------------------------------------
  312. //
  313. // Function: PktCreateEntry, public
  314. //
  315. // Synopsis: PktCreateEntry creates a new partition table entry or
  316. // updates an existing one. The PKT must be acquired
  317. // exclusively for this operation.
  318. //
  319. // Arguments: [Pkt] - pointer to an initialized (and exclusively acquired) PKT
  320. // [PktEntryType] - the type of entry to create/update.
  321. // [PktEntryId] - pointer to the Id of the entry to create
  322. // [PktEntryInfo] - pointer to the guts of the entry
  323. // [CreateDisposition] - specifies whether to overwrite if
  324. // an entry already exists, etc.
  325. // [ppPktEntry] - the new entry is placed here.
  326. //
  327. // Returns: [STATUS_SUCCESS] - if all is well.
  328. //
  329. // [DFS_STATUS_NO_SUCH_ENTRY] - the create disposition was
  330. // set to PKT_REPLACE_ENTRY and no entry of the specified
  331. // Id exists to replace.
  332. //
  333. // [DFS_STATUS_ENTRY_EXISTS] - a create disposition of
  334. // PKT_CREATE_ENTRY was specified and an entry of the
  335. // specified Id already exists.
  336. //
  337. // [DFS_STATUS_LOCAL_ENTRY] - creation of the entry would
  338. // required the invalidation of a local entry or exit point.
  339. //
  340. // [STATUS_INVALID_PARAMETER] - the Id specified for the
  341. // new entry is invalid.
  342. //
  343. // [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was
  344. // available to complete the operation.
  345. //
  346. // Notes: The PktEntryId and PktEntryInfo structures are MOVED (not
  347. // COPIED) to the new entry. The memory used for UNICODE_STRINGS
  348. // and DFS_SERVICE arrays is used by the new entry. The
  349. // associated fields in the PktEntryId and PktEntryInfo
  350. // structures passed as arguments are Zero'd to indicate that
  351. // the memory has been "deallocated" from these strutures and
  352. // reallocated to the newly created PktEntry. Note that this
  353. // routine does not deallocate the PktEntryId structure or
  354. // the PktEntryInfo structure itself. On successful return from
  355. // this function, the PktEntryId structure will be modified
  356. // to have a NULL Prefix entry, and the PktEntryInfo structure
  357. // will be modified to have zero services and a null ServiceList
  358. // entry.
  359. //
  360. //--------------------------------------------------------------------------
  361. NTSTATUS
  362. PktCreateEntry(
  363. IN PDFS_PKT Pkt,
  364. IN ULONG PktEntryType,
  365. IN PDFS_PKT_ENTRY_ID PktEntryId,
  366. IN PDFS_PKT_ENTRY_INFO PktEntryInfo OPTIONAL,
  367. IN ULONG CreateDisposition,
  368. IN PDFS_TARGET_INFO pDfsTargetInfo,
  369. OUT PDFS_PKT_ENTRY *ppPktEntry)
  370. {
  371. NTSTATUS status = STATUS_SUCCESS;
  372. PDFS_PKT_ENTRY pfxMatchEntry = NULL;
  373. PDFS_PKT_ENTRY uidMatchEntry = NULL;
  374. PDFS_PKT_ENTRY entryToUpdate = NULL;
  375. PDFS_PKT_ENTRY entryToInvalidate = NULL;
  376. PDFS_PKT_ENTRY SupEntry = NULL;
  377. UNICODE_STRING remainingPath, newRemainingPath;
  378. ASSERT(ARGUMENT_PRESENT(Pkt) &&
  379. ARGUMENT_PRESENT(PktEntryId) &&
  380. ARGUMENT_PRESENT(ppPktEntry));
  381. DfsDbgTrace(+1, Dbg, "PktCreateEntry: Entered\n", 0);
  382. RtlZeroMemory(&remainingPath, sizeof(UNICODE_STRING));
  383. RtlZeroMemory(&newRemainingPath, sizeof(UNICODE_STRING));
  384. //
  385. // We're pessimistic at first...
  386. //
  387. *ppPktEntry = NULL;
  388. //
  389. // See if there exists an entry with this prefix. The prefix
  390. // must match exactly (i.e. No remaining path).
  391. //
  392. pfxMatchEntry = PktLookupEntryByPrefix(Pkt,
  393. &PktEntryId->Prefix,
  394. &remainingPath);
  395. if (remainingPath.Length > 0) {
  396. SupEntry = pfxMatchEntry;
  397. pfxMatchEntry = NULL;
  398. } else {
  399. UNICODE_STRING newPrefix;
  400. RemoveLastComponent(&PktEntryId->Prefix, &newPrefix);
  401. SupEntry = PktLookupEntryByPrefix(Pkt,
  402. &newPrefix,
  403. &newRemainingPath);
  404. }
  405. //
  406. // Now search for an entry that has the same Uid.
  407. //
  408. uidMatchEntry = PktLookupEntryByUid(Pkt, &PktEntryId->Uid);
  409. //
  410. // Now we must determine if during this create, we are going to be
  411. // updating or invalidating any existing entries. If an existing
  412. // entry is found that has the same Uid as the one we are trying to
  413. // create, the entry becomes a target for "updating". If the Uid
  414. // passed in is NULL, then we check to see if an entry exists that
  415. // has a NULL Uid AND a Prefix that matches. If this is the case,
  416. // that entry becomes the target for "updating".
  417. //
  418. // To determine if there is an entry to invalidate, we look for an
  419. // entry with the same Prefix as the one we are trying to create, BUT,
  420. // which has a different Uid. If we detect such a situation, we
  421. // we make the entry with the same Prefix the target for invalidation
  422. // (we do not allow two entries with the same Prefix, and we assume
  423. // that the new entry takes precedence).
  424. //
  425. if (uidMatchEntry != NULL) {
  426. entryToUpdate = uidMatchEntry;
  427. if (pfxMatchEntry != uidMatchEntry)
  428. entryToInvalidate = pfxMatchEntry;
  429. } else if ((pfxMatchEntry != NULL) &&
  430. NullGuid(&pfxMatchEntry->Id.Uid)) {
  431. //
  432. // This should go away once we don't have any NULL guids at all in
  433. // the driver.
  434. //
  435. entryToUpdate = pfxMatchEntry;
  436. } else {
  437. entryToInvalidate = pfxMatchEntry;
  438. }
  439. //
  440. // Now we check to make sure that our create disposition is
  441. // consistent with what we are about to do.
  442. //
  443. if ((CreateDisposition & PKT_ENTRY_CREATE) && entryToUpdate != NULL) {
  444. *ppPktEntry = entryToUpdate;
  445. status = DFS_STATUS_ENTRY_EXISTS;
  446. } else if ((CreateDisposition & PKT_ENTRY_REPLACE) && entryToUpdate==NULL) {
  447. status = DFS_STATUS_NO_SUCH_ENTRY;
  448. }
  449. //
  450. // if we have an error here we can get out now!
  451. //
  452. if (!NT_SUCCESS(status)) {
  453. DfsDbgTrace(-1, Dbg, "PktCreateEntry: Exit -> %08lx\n", ULongToPtr(status) );
  454. return status;
  455. }
  456. #if DBG
  457. if (MupVerbose)
  458. DbgPrint(" #####CreateDisposition=0x%x, entryToUpdate=[%wZ], PktEntryInfo=0x%x\n",
  459. CreateDisposition,
  460. &entryToUpdate->Id.Prefix,
  461. PktEntryInfo);
  462. #endif
  463. //
  464. // If this entry is a dup of the one we will want to replace,
  465. // simply up the timeout on the existing, destroy the new,
  466. // then return.
  467. //
  468. if (DfspIsDupPktEntry(entryToUpdate, PktEntryType, PktEntryId, PktEntryInfo) == TRUE) {
  469. #if DBG
  470. if (MupVerbose)
  471. DbgPrint(" ****DUPLICATE PKT ENTRY!!\n");
  472. #endif
  473. PktEntryIdDestroy(PktEntryId, FALSE);
  474. PktEntryInfoDestroy(PktEntryInfo, FALSE);
  475. entryToUpdate->ExpireTime = 60;
  476. entryToUpdate->TimeToLive = 60;
  477. DfspSetServiceListToDc(entryToUpdate);
  478. (*ppPktEntry) = entryToUpdate;
  479. DfsDbgTrace(-1, Dbg, "PktCreateEntry: Exit -> %08lx\n", ULongToPtr(status) );
  480. return status;
  481. }
  482. //
  483. // At this point we must insure that we are not going to
  484. // be invalidating any local partition entries.
  485. //
  486. if ((entryToInvalidate != NULL) &&
  487. (!(entryToInvalidate->Type & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM) ) &&
  488. (entryToInvalidate->Type &
  489. (PKT_ENTRY_TYPE_LOCAL |
  490. PKT_ENTRY_TYPE_LOCAL_XPOINT |
  491. PKT_ENTRY_TYPE_PERMANENT))) {
  492. DfsDbgTrace(-1, Dbg, "PktCreateEntry: Exit -> %08lx\n",
  493. ULongToPtr(DFS_STATUS_LOCAL_ENTRY) );
  494. return DFS_STATUS_LOCAL_ENTRY;
  495. }
  496. //
  497. // We go up the links till we reach a REFERRAL entry type. Actually
  498. // we may never go up since we always link to a REFERRAL entry. Anyway
  499. // no harm done!
  500. //
  501. while ((SupEntry != NULL) &&
  502. !(SupEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC)) {
  503. SupEntry = SupEntry->ClosestDC;
  504. }
  505. //
  506. // If we had success then we need to see if we have to
  507. // invalidate an entry.
  508. //
  509. if (NT_SUCCESS(status) && entryToInvalidate != NULL) {
  510. if (entryToInvalidate->UseCount != 0) {
  511. DbgPrint("PktEntryReassemble: Destroying in use pkt entry %x, usecount %x\n",
  512. entryToInvalidate, entryToInvalidate->UseCount);
  513. }
  514. PktEntryDestroy(entryToInvalidate, Pkt, (BOOLEAN)TRUE);
  515. }
  516. //
  517. // If we are not updating an entry we must construct a new one
  518. // from scratch. Otherwise we need to update.
  519. //
  520. if (entryToUpdate != NULL) {
  521. status = PktEntryReassemble(entryToUpdate,
  522. Pkt,
  523. PktEntryType,
  524. PktEntryId,
  525. PktEntryInfo,
  526. pDfsTargetInfo);
  527. if (NT_SUCCESS(status)) {
  528. (*ppPktEntry) = entryToUpdate;
  529. PktEntryLinkChild(SupEntry, entryToUpdate);
  530. }
  531. } else {
  532. //
  533. // Now we are going to create a new entry. So we have to set
  534. // the ClosestDC Entry pointer while creating this entry. The
  535. // ClosestDC entry value is already in SupEntry.
  536. //
  537. PDFS_PKT_ENTRY newEntry;
  538. newEntry = (PDFS_PKT_ENTRY) ExAllocatePoolWithTag(
  539. PagedPool,
  540. sizeof(DFS_PKT_ENTRY),
  541. ' puM');
  542. if (newEntry == NULL) {
  543. status = STATUS_INSUFFICIENT_RESOURCES;
  544. } else {
  545. status = PktEntryAssemble(newEntry,
  546. Pkt,
  547. PktEntryType,
  548. PktEntryId,
  549. PktEntryInfo,
  550. pDfsTargetInfo);
  551. if (!NT_SUCCESS(status)) {
  552. ExFreePool(newEntry);
  553. } else {
  554. (*ppPktEntry) = newEntry;
  555. PktEntryLinkChild(SupEntry, newEntry);
  556. }
  557. }
  558. }
  559. DfsDbgTrace(-1, Dbg, "PktCreateEntry: Exit -> %08lx\n", ULongToPtr(status) );
  560. return status;
  561. }
  562. //+----------------------------------------------------------------------------
  563. //
  564. // Function: PktCreateDomainEntry
  565. //
  566. // Synopsis: Given a name that is thought to be a domain name, this routine
  567. // will create a Pkt Entry for the root of the domain's Dfs.
  568. // The domain must exist, must have a Dfs root, and must be
  569. // reachable for this routine to succeed.
  570. //
  571. // Arguments: [DomainName] -- Name of domain/machine thought to support a Dfs
  572. // [ShareName] -- Name of FtDfs or dfs share
  573. // [CSCAgentCreate] -- TRUE if this is a CSC agent create
  574. //
  575. // Returns: [STATUS_SUCCESS] -- Successfully completed operation.
  576. //
  577. // Status from PktGetReferral
  578. //
  579. //-----------------------------------------------------------------------------
  580. NTSTATUS
  581. PktCreateDomainEntry(
  582. IN PUNICODE_STRING DomainName,
  583. IN PUNICODE_STRING ShareName,
  584. IN BOOLEAN CSCAgentCreate)
  585. {
  586. NTSTATUS status;
  587. PUNICODE_STRING MachineName;
  588. PDFS_SPECIAL_ENTRY pSpecialEntry = NULL;
  589. ULONG EntryIdx;
  590. ULONG Start;
  591. LARGE_INTEGER StartTime;
  592. LARGE_INTEGER EndTime;
  593. DfsDbgTrace(+1, Dbg, "PktCreateDomainEntry: DomainName %wZ \n", DomainName);
  594. DfsDbgTrace( 0, Dbg, " ShareName %wZ \n", ShareName);
  595. KeQuerySystemTime(&StartTime);
  596. #if DBG
  597. if (MupVerbose) {
  598. KeQuerySystemTime(&EndTime);
  599. DbgPrint("[%d] PktCreateDomainEntry(%wZ,%wZ)\n",
  600. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  601. DomainName,
  602. ShareName);
  603. }
  604. #endif
  605. //
  606. // See if machine name is really a domain name, if so
  607. // turn it into a DC name
  608. //
  609. status = PktExpandSpecialName(DomainName, &pSpecialEntry);
  610. if (NT_SUCCESS(status)) {
  611. //
  612. // Step through the DC list trying for a referral
  613. // Check the status returned - only continue on recoverable errors
  614. //
  615. Start = pSpecialEntry->Active;
  616. for (EntryIdx = Start; EntryIdx < pSpecialEntry->ExpandedCount; EntryIdx++) {
  617. MachineName = &pSpecialEntry->ExpandedNames[EntryIdx].ExpandedName;
  618. status = PktGetReferral(MachineName, DomainName, ShareName, CSCAgentCreate);
  619. if (!NT_SUCCESS(status) && SpcIsRecoverableError(status)) {
  620. continue;
  621. }
  622. break;
  623. }
  624. if (status != STATUS_NO_SUCH_DEVICE && !NT_SUCCESS(status) && Start > 0) {
  625. for (EntryIdx = 0; EntryIdx < Start; EntryIdx++) {
  626. MachineName = &pSpecialEntry->ExpandedNames[EntryIdx].ExpandedName;
  627. status = PktGetReferral(MachineName, DomainName, ShareName, CSCAgentCreate);
  628. if (!NT_SUCCESS(status) && SpcIsRecoverableError(status)) {
  629. continue;
  630. }
  631. break;
  632. }
  633. }
  634. if (NT_SUCCESS(status) || status == STATUS_NO_SUCH_DEVICE) {
  635. pSpecialEntry->Active = EntryIdx;
  636. }
  637. InterlockedDecrement(&pSpecialEntry->UseCount);
  638. } else {
  639. status = PktGetReferral(DomainName, DomainName, ShareName, CSCAgentCreate);
  640. PktLastReferralStatus = status;
  641. }
  642. KeQuerySystemTime(&EndTime);
  643. DfsDbgTrace(-1, Dbg, "PktCreateDomainEntry: Exit -> %08lx\n", ULongToPtr(status) );
  644. #if DBG
  645. if (MupVerbose)
  646. DbgPrint(" [%d] DfsCreateDomainEntry returned %08lx\n",
  647. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  648. status);
  649. #endif
  650. return status;
  651. }
  652. //+----------------------------------------------------------------------------
  653. //
  654. // Function: PktGetReferral -- helper for PktCreateDomainEntry
  655. //
  656. // Synopsis: Ask [MachineName] for referral for \DomainName\ShareName
  657. //
  658. // Arguments: [MachineName] -- Name of machine to submit referral request to
  659. // [DomainName] -- Name of domain/machine thought to support a Dfs
  660. // [ShareName] -- Name of FtDfs or dfs share
  661. // [CSCAgentCreate] -- TRUE if this is a CSC agent create
  662. //
  663. // Returns: [STATUS_SUCCESS] -- Successfully completed operation.
  664. //
  665. // [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate memory.
  666. // [BAD_NETWORK_PATH] -- Unable to allocate provider
  667. // [STATUS_INVALID_NETWORK_RESPONSE] -- Bad referral
  668. //
  669. //-----------------------------------------------------------------------------
  670. NTSTATUS
  671. _PktGetReferral(
  672. IN PUNICODE_STRING MachineName, // Machine to direct referral to
  673. IN PUNICODE_STRING DomainName, // the machine or domain name to use
  674. IN PUNICODE_STRING ShareName, // the ftdfs or dfs name
  675. IN BOOLEAN CSCAgentCreate) // the CSC agent create flag
  676. {
  677. NTSTATUS status;
  678. HANDLE hServer = NULL;
  679. DFS_SERVICE service;
  680. PPROVIDER_DEF provider;
  681. PREQ_GET_DFS_REFERRAL ref = NULL;
  682. ULONG refSize = 0;
  683. ULONG type, matchLength;
  684. UNICODE_STRING refPath;
  685. IO_STATUS_BLOCK iosb;
  686. PDFS_PKT_ENTRY pktEntry;
  687. BOOLEAN attachedToSystemProcess = FALSE;
  688. BOOLEAN pktLocked;
  689. KAPC_STATE ApcState;
  690. ULONG MaxReferralLength;
  691. ULONG i;
  692. SE_IMPERSONATION_STATE DisabledImpersonationState;
  693. BOOLEAN RestoreImpersonationState = FALSE;
  694. LARGE_INTEGER StartTime;
  695. LARGE_INTEGER EndTime;
  696. PDFS_TARGET_INFO pDfsTargetInfo = NULL;
  697. DfsDbgTrace(+1, Dbg, "PktGetReferral: MachineName %wZ \n", MachineName);
  698. DfsDbgTrace( 0, Dbg, " DomainName %wZ \n", DomainName);
  699. DfsDbgTrace( 0, Dbg, " ShareName %wZ \n", ShareName);
  700. KeQuerySystemTime(&StartTime);
  701. #if DBG
  702. if (MupVerbose) {
  703. KeQuerySystemTime(&EndTime);
  704. DbgPrint(" [%d] PktGetReferral([%wZ]->[\\%wZ\\%wZ]\n",
  705. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  706. MachineName,
  707. DomainName,
  708. ShareName);
  709. }
  710. #endif
  711. //
  712. // Get a provider (LM rdr) and service (connection to a machine) describing the remote server.
  713. //
  714. provider = ReplLookupProvider( PROV_ID_MUP_RDR );
  715. if (provider == NULL) {
  716. DfsDbgTrace(-1, Dbg, "Unable to open LM Rdr!\n", 0);
  717. #if DBG
  718. if (MupVerbose)
  719. DbgPrint("Unable to open LM Rdr returning STATUS_BAD_NETWORK_PATH\n", 0);
  720. #endif
  721. if (DfsEventLog > 0)
  722. LogWriteMessage(LM_REDIR_FAILURE, 0, 0, NULL);
  723. status = STATUS_BAD_NETWORK_PATH;
  724. MUP_TRACE_HIGH(ERROR, _PktGetReferral_Error_UnableToOpenRdr,
  725. LOGUSTR(*MachineName)
  726. LOGUSTR(*DomainName)
  727. LOGUSTR(*ShareName)
  728. LOGBOOLEAN(CSCAgentCreate)
  729. LOGSTATUS(status));
  730. return STATUS_BAD_NETWORK_PATH;
  731. }
  732. RtlZeroMemory( &service, sizeof(DFS_SERVICE) );
  733. status = PktServiceConstruct(
  734. &service,
  735. DFS_SERVICE_TYPE_MASTER | DFS_SERVICE_TYPE_REFERRAL,
  736. PROV_DFS_RDR,
  737. STATUS_SUCCESS,
  738. PROV_ID_MUP_RDR,
  739. MachineName,
  740. NULL);
  741. DfsDbgTrace(0, Dbg, "PktServiceConstruct returned %08lx\n", ULongToPtr(status) );
  742. //
  743. // Build a connection to this machine
  744. //
  745. if (NT_SUCCESS(status)) {
  746. PktAcquireShared( TRUE, &pktLocked );
  747. if (PsGetCurrentProcess() != DfsData.OurProcess) {
  748. KeStackAttachProcess( DfsData.OurProcess, &ApcState );
  749. attachedToSystemProcess = TRUE;
  750. }
  751. RestoreImpersonationState = PsDisableImpersonation(
  752. PsGetCurrentThread(),
  753. &DisabledImpersonationState);
  754. status = DfsCreateConnection(
  755. &service,
  756. provider,
  757. CSCAgentCreate,
  758. &hServer);
  759. #if DBG
  760. if (MupVerbose) {
  761. KeQuerySystemTime(&EndTime);
  762. DbgPrint(" [%d] DfsCreateConnection returned 0x%x\n",
  763. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  764. status);
  765. }
  766. #endif
  767. if (!NT_SUCCESS(status) && DfsEventLog > 0)
  768. LogWriteMessage(DFS_CONNECTION_FAILURE, status, 1, MachineName);
  769. DfsDbgTrace(0, Dbg, "DfsCreateConnection returned %08lx\n", ULongToPtr(status) );
  770. if (status == STATUS_SUCCESS)
  771. {
  772. status = PktGetTargetInfo( hServer,
  773. DomainName,
  774. ShareName,
  775. &pDfsTargetInfo );
  776. }
  777. PktRelease();
  778. pktLocked = FALSE;
  779. }
  780. MaxReferralLength = MAX_REFERRAL_LENGTH;
  781. Retry:
  782. RtlZeroMemory( &refPath, sizeof(UNICODE_STRING) );
  783. //
  784. // Build the referral request (\DomainName\ShareName)
  785. //
  786. if (NT_SUCCESS(status)) {
  787. ULONG ReferralSize = 0;
  788. refPath.Length = 0;
  789. refPath.MaximumLength = sizeof(UNICODE_PATH_SEP) +
  790. DomainName->Length +
  791. sizeof(UNICODE_PATH_SEP) +
  792. ShareName->Length +
  793. sizeof(UNICODE_NULL);
  794. ReferralSize = refPath.MaximumLength + sizeof(REQ_GET_DFS_REFERRAL);
  795. if (ReferralSize > MAX_REFERRAL_MAX) {
  796. status = STATUS_INVALID_PARAMETER;
  797. }
  798. else if (MaxReferralLength < ReferralSize)
  799. {
  800. MaxReferralLength = ReferralSize;
  801. }
  802. if (NT_SUCCESS(status)) {
  803. refPath.Buffer = ExAllocatePoolWithTag( NonPagedPool,
  804. refPath.MaximumLength + MaxReferralLength,
  805. ' puM');
  806. if (refPath.Buffer != NULL) {
  807. ref = (PREQ_GET_DFS_REFERRAL)&refPath.Buffer[refPath.MaximumLength / sizeof(WCHAR)];
  808. RtlAppendUnicodeToString( &refPath, UNICODE_PATH_SEP_STR);
  809. RtlAppendUnicodeStringToString( &refPath, DomainName);
  810. RtlAppendUnicodeToString( &refPath, UNICODE_PATH_SEP_STR);
  811. RtlAppendUnicodeStringToString( &refPath, ShareName );
  812. refPath.Buffer[ refPath.Length / sizeof(WCHAR) ] = UNICODE_NULL;
  813. ref->MaxReferralLevel = 3;
  814. RtlMoveMemory(
  815. &ref->RequestFileName[0],
  816. refPath.Buffer,
  817. refPath.Length + sizeof(WCHAR));
  818. DfsDbgTrace(0, Dbg, "Referral Path : %ws\n", ref->RequestFileName);
  819. refSize = sizeof(USHORT) + refPath.Length + sizeof(WCHAR);
  820. DfsDbgTrace(0, Dbg, "Referral Size is %d bytes\n", ULongToPtr(refSize) );
  821. } else {
  822. DfsDbgTrace(0, Dbg, "Unable to allocate %d bytes\n",
  823. ULongToPtr(refPath.MaximumLength + MaxReferralLength));
  824. status = STATUS_INSUFFICIENT_RESOURCES;
  825. MUP_TRACE_HIGH(ERROR, _PktGetReferral_Error_ExallocatePoolWithTag,
  826. LOGUSTR(*MachineName)
  827. LOGUSTR(*DomainName)
  828. LOGUSTR(*ShareName)
  829. LOGBOOLEAN(CSCAgentCreate)
  830. LOGSTATUS(status));
  831. }
  832. }
  833. }
  834. //
  835. // Send the referral out
  836. //
  837. if (NT_SUCCESS(status)) {
  838. DfsDbgTrace(0, Dbg, "Ref Buffer @%08lx\n", ref);
  839. status = ZwFsControlFile(
  840. hServer, // Target
  841. NULL, // Event
  842. NULL, // APC Routine
  843. NULL, // APC Context,
  844. &iosb, // Io Status block
  845. FSCTL_DFS_GET_REFERRALS, // FS Control code
  846. (PVOID) ref, // Input Buffer
  847. refSize, // Input Buffer Length
  848. (PVOID) ref, // Output Buffer
  849. MaxReferralLength); // Output Buffer Length
  850. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, _PktGetReferral_Error_ZwFsControlFile,
  851. LOGUSTR(*MachineName)
  852. LOGUSTR(*DomainName)
  853. LOGUSTR(*ShareName)
  854. LOGBOOLEAN(CSCAgentCreate)
  855. LOGSTATUS(status));
  856. DfsDbgTrace(0, Dbg, "Fscontrol returned %08lx\n", ULongToPtr(status) );
  857. KeQuerySystemTime(&EndTime);
  858. #if DBG
  859. if (MupVerbose) {
  860. KeQuerySystemTime(&EndTime);
  861. DbgPrint(" [%d] ZwFsControlFile returned %08lx\n",
  862. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  863. status);
  864. }
  865. #endif
  866. }
  867. //
  868. // ...and handle the response
  869. //
  870. if (NT_SUCCESS(status)) {
  871. status = PktCreateEntryFromReferral(
  872. &DfsData.Pkt,
  873. &refPath,
  874. (ULONG)iosb.Information,
  875. (PRESP_GET_DFS_REFERRAL) ref,
  876. PKT_ENTRY_SUPERSEDE,
  877. pDfsTargetInfo,
  878. &matchLength,
  879. &type,
  880. &pktEntry);
  881. DfsDbgTrace(0, Dbg, "PktCreateEntryFromReferral returned %08lx\n", ULongToPtr(status) );
  882. #if DBG
  883. if (MupVerbose)
  884. DbgPrint(" PktCreateEntryFromReferral returned %08lx\n", status);
  885. #endif
  886. } else if (status == STATUS_BUFFER_OVERFLOW && (refPath.Buffer != NULL) && MaxReferralLength < MAX_REFERRAL_MAX) {
  887. //
  888. // The referral didn't fit in the buffer supplied. Make it bigger and try
  889. // again.
  890. //
  891. DfsDbgTrace(0, Dbg, "PktGetSpecialReferralTable: MaxReferralLength %d too small\n",
  892. ULongToPtr(MaxReferralLength) );
  893. ExFreePool(refPath.Buffer);
  894. refPath.Buffer = NULL;
  895. MaxReferralLength *= 2;
  896. if (MaxReferralLength > MAX_REFERRAL_MAX)
  897. MaxReferralLength = MAX_REFERRAL_MAX;
  898. status = STATUS_SUCCESS;
  899. goto Retry;
  900. } else if (status == STATUS_NO_SUCH_DEVICE) {
  901. UNICODE_STRING ustr;
  902. UNICODE_STRING RemPath;
  903. WCHAR *wCp = NULL;
  904. ULONG Size;
  905. PDFS_PKT_ENTRY pEntry = NULL;
  906. PDFS_PKT Pkt;
  907. BOOLEAN pktLocked;
  908. //
  909. // Check if there is a pkt entry (probably stale) that needs to be removed
  910. //
  911. #if DBG
  912. if (MupVerbose)
  913. DbgPrint(" PktGetReferral: remove PKT entry for \\%wZ\\%wZ\n",
  914. DomainName,
  915. ShareName);
  916. #endif
  917. Size = sizeof(WCHAR) +
  918. DomainName->Length +
  919. sizeof(WCHAR) +
  920. ShareName->Length;
  921. ustr.Buffer = ExAllocatePoolWithTag(
  922. PagedPool,
  923. Size,
  924. ' puM');
  925. if (ustr.Buffer == NULL) {
  926. status = STATUS_INSUFFICIENT_RESOURCES;
  927. } else {
  928. wCp = ustr.Buffer;
  929. ustr.Length = (USHORT)Size;
  930. *wCp++ = UNICODE_PATH_SEP;
  931. RtlCopyMemory(wCp, DomainName->Buffer, DomainName->Length);
  932. wCp += DomainName->Length/sizeof(WCHAR);
  933. *wCp++ = UNICODE_PATH_SEP;
  934. RtlCopyMemory(wCp, ShareName->Buffer, ShareName->Length);
  935. Pkt = _GetPkt();
  936. PktAcquireExclusive(TRUE, &pktLocked);
  937. #if DBG
  938. if (MupVerbose)
  939. DbgPrint("Looking up %wZ\n", &ustr);
  940. #endif
  941. pEntry = PktLookupEntryByPrefix(
  942. &DfsData.Pkt,
  943. &ustr,
  944. &RemPath);
  945. #if DBG
  946. if (MupVerbose)
  947. DbgPrint("pEntry=0x%x\n", pEntry);
  948. #endif
  949. if (pEntry != NULL && (pEntry->Type & PKT_ENTRY_TYPE_PERMANENT) == 0) {
  950. PktFlushChildren(pEntry);
  951. if (pEntry->UseCount == 0) {
  952. PktEntryDestroy(pEntry, Pkt, (BOOLEAN) TRUE);
  953. } else {
  954. pEntry->Type |= PKT_ENTRY_TYPE_DELETE_PENDING;
  955. pEntry->ExpireTime = 0;
  956. DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(pEntry->Id.Prefix));
  957. DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(pEntry->Id.ShortPrefix));
  958. }
  959. }
  960. ExFreePool(ustr.Buffer);
  961. PktRelease();
  962. }
  963. }
  964. if (!NT_SUCCESS(status) && DfsEventLog > 0 && refPath.Buffer != NULL) {
  965. UNICODE_STRING puStr[2];
  966. puStr[0] = refPath;
  967. puStr[1] = *MachineName;
  968. LogWriteMessage(DFS_REFERRAL_FAILURE, status, 2, puStr);
  969. }
  970. if (NT_SUCCESS(status) && DfsEventLog > 1 && refPath.Buffer != NULL) {
  971. UNICODE_STRING puStr[2];
  972. puStr[0] = refPath;
  973. puStr[1] = *MachineName;
  974. LogWriteMessage(DFS_REFERRAL_SUCCESS, status, 2, puStr);
  975. }
  976. //
  977. // Well, we are done. Cleanup all the things we allocated...
  978. //
  979. PktServiceDestroy( &service, FALSE );
  980. if (pDfsTargetInfo != NULL)
  981. {
  982. PktReleaseTargetInfo( pDfsTargetInfo );
  983. }
  984. if (hServer != NULL) {
  985. ZwClose( hServer );
  986. }
  987. if (refPath.Buffer != NULL) {
  988. ExFreePool( refPath.Buffer );
  989. }
  990. if (RestoreImpersonationState) {
  991. PsRestoreImpersonation(
  992. PsGetCurrentThread(),
  993. &DisabledImpersonationState);
  994. }
  995. if (attachedToSystemProcess) {
  996. KeUnstackDetachProcess(&ApcState);
  997. }
  998. DfsDbgTrace(-1, Dbg, "PktGetReferral returning %08lx\n", ULongToPtr(status) );
  999. #if DBG
  1000. if (MupVerbose) {
  1001. KeQuerySystemTime(&EndTime);
  1002. DbgPrint(" [%d] PktGetReferral returning %08lx\n",
  1003. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  1004. status);
  1005. }
  1006. #endif
  1007. return( status );
  1008. }
  1009. //+-------------------------------------------------------------------------
  1010. //
  1011. // Function: PktLookupEntryByPrefix, public
  1012. //
  1013. // Synopsis: PktLookupEntryByPrefix finds an entry that has a
  1014. // specified prefix. The PKT must be acquired for
  1015. // this operation.
  1016. //
  1017. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  1018. // [Prefix] - the partitions prefix to lookup.
  1019. // [Remaining] - any remaining path. Points within
  1020. // the Prefix to where any trailing (nonmatched)
  1021. // characters are.
  1022. //
  1023. // Returns: The PKT_ENTRY that has the exact same prefix, or NULL,
  1024. // if none exists or is marked for delete.
  1025. //
  1026. // Notes:
  1027. //
  1028. //--------------------------------------------------------------------------
  1029. PDFS_PKT_ENTRY
  1030. PktLookupEntryByPrefix(
  1031. IN PDFS_PKT Pkt,
  1032. IN PUNICODE_STRING Prefix,
  1033. OUT PUNICODE_STRING Remaining
  1034. )
  1035. {
  1036. PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
  1037. PDFS_PKT_ENTRY pktEntry;
  1038. DfsDbgTrace(+1, Dbg, "PktLookupEntryByPrefix: Entered\n", 0);
  1039. //
  1040. // If there really is a prefix to lookup, use the prefix table
  1041. // to initially find an entry
  1042. //
  1043. if ((Prefix->Length != 0) &&
  1044. (pfxEntry = DfsFindUnicodePrefix(&Pkt->PrefixTable,Prefix,Remaining))) {
  1045. USHORT pfxLength;
  1046. //
  1047. // reset a pointer to the corresponding entry
  1048. //
  1049. pktEntry = CONTAINING_RECORD(pfxEntry,
  1050. DFS_PKT_ENTRY,
  1051. PrefixTableEntry);
  1052. if (!(pktEntry->Type & PKT_ENTRY_TYPE_DELETE_PENDING)) {
  1053. pfxLength = pktEntry->Id.Prefix.Length;
  1054. //
  1055. // Now calculate the remaining path and return
  1056. // the entry we found. Note that we bump the length
  1057. // up by one char so that we skip any path separater.
  1058. //
  1059. if ((pfxLength < Prefix->Length) &&
  1060. (Prefix->Buffer[pfxLength/sizeof(WCHAR)] == UNICODE_PATH_SEP))
  1061. pfxLength += sizeof(WCHAR);
  1062. if (pfxLength < Prefix->Length) {
  1063. Remaining->Length = (USHORT)(Prefix->Length - pfxLength);
  1064. Remaining->Buffer = &Prefix->Buffer[pfxLength/sizeof(WCHAR)];
  1065. Remaining->MaximumLength = (USHORT)(Prefix->MaximumLength - pfxLength);
  1066. DfsDbgTrace( 0, Dbg, "PktLookupEntryByPrefix: Remaining = %wZ\n",
  1067. Remaining);
  1068. } else {
  1069. Remaining->Length = Remaining->MaximumLength = 0;
  1070. Remaining->Buffer = NULL;
  1071. DfsDbgTrace( 0, Dbg, "PktLookupEntryByPrefix: No Remaining\n", 0);
  1072. }
  1073. DfsDbgTrace(-1, Dbg, "PktLookupEntryByPrefix: Exit -> %08lx\n",
  1074. pktEntry);
  1075. return pktEntry;
  1076. }
  1077. }
  1078. DfsDbgTrace(-1, Dbg, "PktLookupEntryByPrefix: Exit -> %08lx\n", NULL);
  1079. return NULL;
  1080. }
  1081. //+-------------------------------------------------------------------------
  1082. //
  1083. // Function: PktLookupEntryByShortPrefix, public
  1084. //
  1085. // Synopsis: PktLookupEntryByShortPrefix finds an entry that has a
  1086. // specified prefix. The PKT must be acquired for
  1087. // this operation.
  1088. //
  1089. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  1090. // [Prefix] - the partitions prefix to lookup.
  1091. // [Remaining] - any remaining path. Points within
  1092. // the Prefix to where any trailing (nonmatched)
  1093. // characters are.
  1094. //
  1095. // Returns: The PKT_ENTRY that has the exact same prefix, or NULL,
  1096. // if none exists or is marked for delete.
  1097. //
  1098. // Notes:
  1099. //
  1100. //--------------------------------------------------------------------------
  1101. PDFS_PKT_ENTRY
  1102. PktLookupEntryByShortPrefix(
  1103. IN PDFS_PKT Pkt,
  1104. IN PUNICODE_STRING Prefix,
  1105. OUT PUNICODE_STRING Remaining
  1106. )
  1107. {
  1108. PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
  1109. PDFS_PKT_ENTRY pktEntry;
  1110. DfsDbgTrace(+1, Dbg, "PktLookupEntryByShortPrefix: Entered\n", 0);
  1111. //
  1112. // If there really is a prefix to lookup, use the prefix table
  1113. // to initially find an entry
  1114. //
  1115. if ((Prefix->Length != 0) &&
  1116. (pfxEntry = DfsFindUnicodePrefix(&Pkt->ShortPrefixTable,Prefix,Remaining))) {
  1117. USHORT pfxLength;
  1118. //
  1119. // reset a pointer to the corresponding entry
  1120. //
  1121. pktEntry = CONTAINING_RECORD(pfxEntry,
  1122. DFS_PKT_ENTRY,
  1123. PrefixTableEntry);
  1124. if (!(pktEntry->Type & PKT_ENTRY_TYPE_DELETE_PENDING)) {
  1125. pfxLength = pktEntry->Id.ShortPrefix.Length;
  1126. //
  1127. // Now calculate the remaining path and return
  1128. // the entry we found. Note that we bump the length
  1129. // up by one char so that we skip any path separater.
  1130. //
  1131. if ((pfxLength < Prefix->Length) &&
  1132. (Prefix->Buffer[pfxLength/sizeof(WCHAR)] == UNICODE_PATH_SEP))
  1133. pfxLength += sizeof(WCHAR);
  1134. if (pfxLength < Prefix->Length) {
  1135. Remaining->Length = (USHORT)(Prefix->Length - pfxLength);
  1136. Remaining->Buffer = &Prefix->Buffer[pfxLength/sizeof(WCHAR)];
  1137. Remaining->MaximumLength = (USHORT)(Prefix->MaximumLength - pfxLength);
  1138. DfsDbgTrace( 0, Dbg, "PktLookupEntryByShortPrefix: Remaining = %wZ\n",
  1139. Remaining);
  1140. } else {
  1141. Remaining->Length = Remaining->MaximumLength = 0;
  1142. Remaining->Buffer = NULL;
  1143. DfsDbgTrace( 0, Dbg, "PktLookupEntryByShortPrefix: No Remaining\n", 0);
  1144. }
  1145. DfsDbgTrace(-1, Dbg, "PktLookupEntryByShortPrefix: Exit -> %08lx\n",
  1146. pktEntry);
  1147. return pktEntry;
  1148. }
  1149. }
  1150. DfsDbgTrace(-1, Dbg, "PktLookupEntryByShortPrefix: Exit -> %08lx\n", NULL);
  1151. return NULL;
  1152. }
  1153. //+-------------------------------------------------------------------------
  1154. //
  1155. // Function: PktLookupEntryByUid, public
  1156. //
  1157. // Synopsis: PktLookupEntryByUid finds an entry that has a
  1158. // specified Uid. The PKT must be acquired for this operation.
  1159. //
  1160. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  1161. // [Uid] - a pointer to the partitions Uid to lookup.
  1162. //
  1163. // Returns: A pointer to the PKT_ENTRY that has the exact same
  1164. // Uid, or NULL, if none exists.
  1165. //
  1166. // Notes: The input Uid cannot be the Null GUID.
  1167. //
  1168. // On a DC where there may be *lots* of entries in the PKT,
  1169. // we may want to consider using some other algorithm for
  1170. // looking up by ID.
  1171. //
  1172. //--------------------------------------------------------------------------
  1173. PDFS_PKT_ENTRY
  1174. PktLookupEntryByUid(
  1175. IN PDFS_PKT Pkt,
  1176. IN GUID *Uid
  1177. ) {
  1178. PDFS_PKT_ENTRY entry;
  1179. DfsDbgTrace(+1, Dbg, "PktLookupEntryByUid: Entered\n", 0);
  1180. //
  1181. // We don't lookup NULL Uids
  1182. //
  1183. if (NullGuid(Uid)) {
  1184. DfsDbgTrace(0, Dbg, "PktLookupEntryByUid: NULL Guid\n", NULL);
  1185. entry = NULL;
  1186. } else {
  1187. entry = PktFirstEntry(Pkt);
  1188. }
  1189. while (entry != NULL) {
  1190. if (GuidEqual(&entry->Id.Uid, Uid))
  1191. break;
  1192. entry = PktNextEntry(Pkt, entry);
  1193. }
  1194. //
  1195. // Don't return the entry if it is marked for delete
  1196. //
  1197. if (entry != NULL && (entry->Type & PKT_ENTRY_TYPE_DELETE_PENDING) != 0) {
  1198. entry = NULL;
  1199. }
  1200. DfsDbgTrace(-1, Dbg, "PktLookupEntryByUid: Exit -> %08lx\n", entry);
  1201. return entry;
  1202. }
  1203. //+-------------------------------------------------------------------------
  1204. //
  1205. // Function: PktLookupReferralEntry, public
  1206. //
  1207. // Synopsis: Given a PKT Entry pointer it returns the closest referral
  1208. // entry in the PKT to this entry.
  1209. //
  1210. // Arguments: [Pkt] - A pointer to the PKT that is being manipulated.
  1211. // [Entry] - The PKT entry passed in by caller.
  1212. //
  1213. // Returns: The pointer to the referral entry that was requested.
  1214. // This could have a NULL value if we could not get anything
  1215. // at all - The caller's responsibility to do whatever he wants
  1216. // with it.
  1217. //
  1218. // Note: If the data structures in the PKT are not linked up right
  1219. // this function might return a pointer to the DOMAIN_SERVICE
  1220. // entry on the DC. If DNR uses this to do an FSCTL we will have
  1221. // a deadlock. However, this should never happen. If it does we
  1222. // have a BUG somewhere in our code. I cannot even have an
  1223. // assert out here.
  1224. //
  1225. //--------------------------------------------------------------------------
  1226. PDFS_PKT_ENTRY
  1227. PktLookupReferralEntry(
  1228. PDFS_PKT Pkt,
  1229. PDFS_PKT_ENTRY Entry
  1230. ) {
  1231. UNICODE_STRING FileName;
  1232. UNICODE_STRING RemPath;
  1233. USHORT i, j;
  1234. DfsDbgTrace(+1, Dbg, "PktLookupReferralEntry: Entered\n", 0);
  1235. if (Entry == NULL) {
  1236. DfsDbgTrace(-1, Dbg, "PktLookupReferralEntry: Exit -> NULL\n", 0);
  1237. return( NULL );
  1238. }
  1239. FileName = Entry->Id.Prefix;
  1240. #if DBG
  1241. if (MupVerbose)
  1242. DbgPrint(" PktLookupReferralEntry(1): FileName=[%wZ]\n", &FileName);
  1243. #endif
  1244. //
  1245. // We want to work with the \Server\Share part of the FileName only,
  1246. // so count up to 3 backslashes, then stop.
  1247. //
  1248. for (i = j = 0; i < FileName.Length/sizeof(WCHAR) && j < 3; i++) {
  1249. if (FileName.Buffer[i] == UNICODE_PATH_SEP) {
  1250. j++;
  1251. }
  1252. }
  1253. FileName.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
  1254. #if DBG
  1255. if (MupVerbose)
  1256. DbgPrint(" PktLookupReferralEntry(2): FileName=[%wZ]\n", &FileName);
  1257. #endif
  1258. //
  1259. // Now find the pkt entry
  1260. //
  1261. Entry = PktLookupEntryByPrefix(
  1262. Pkt,
  1263. &FileName,
  1264. &RemPath);
  1265. #if DBG
  1266. if (MupVerbose)
  1267. if (Entry != NULL)
  1268. DbgPrint(" Parent Entry=[%wZ]\n", &Entry->Id.Prefix);
  1269. else
  1270. DbgPrint(" Parent Entry=NULL\n");
  1271. #endif
  1272. //
  1273. // Make sure that we found an entry for machine that can give out a referral
  1274. //
  1275. if (
  1276. Entry != NULL
  1277. &&
  1278. (
  1279. (Entry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC) == 0
  1280. ||
  1281. (Entry->Type & PKT_ENTRY_TYPE_DELETE_PENDING) != 0
  1282. )
  1283. ) {
  1284. Entry = NULL;
  1285. }
  1286. DfsDbgTrace(-1, Dbg, "PktLookupReferralEntry: Exit -> %08lx\n", Entry);
  1287. #if DBG
  1288. if (MupVerbose)
  1289. DbgPrint(" PktLookupReferralEntry: Exit -> %08lx\n", Entry);
  1290. #endif
  1291. return(Entry);
  1292. }
  1293. //+-------------------------------------------------------------------------
  1294. //
  1295. // Function: PktCreateEntryFromReferral, public
  1296. //
  1297. // Synopsis: PktCreateEntryFromReferral creates a new partition
  1298. // table entry from a referral and places it in the table.
  1299. // The PKT must be aquired exclusively for this operation.
  1300. //
  1301. // Arguments: [Pkt] -- pointer to a initialized (and exclusively
  1302. // acquired) PKT
  1303. // [ReferralPath] -- Path for which this referral was obtained.
  1304. // [ReferralSize] -- size (in bytes) of the referral buffer.
  1305. // [ReferralBuffer] -- pointer to a referral buffer
  1306. // [CreateDisposition] -- specifies whether to overwrite if
  1307. // an entry already exists, etc.
  1308. // [MatchingLength] -- The length in bytes of referralPath that
  1309. // matched.
  1310. // [ReferralType] - On successful return, this is set to
  1311. // DFS_STORAGE_REFERRAL or DFS_REFERRAL_REFERRAL
  1312. // depending on the type of referral we just processed.
  1313. // [ppPktEntry] - the new entry is placed here.
  1314. //
  1315. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  1316. //
  1317. // Notes:
  1318. //
  1319. //--------------------------------------------------------------------------
  1320. NTSTATUS
  1321. PktCreateEntryFromReferral(
  1322. IN PDFS_PKT Pkt,
  1323. IN PUNICODE_STRING ReferralPath,
  1324. IN ULONG ReferralSize,
  1325. IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
  1326. IN ULONG CreateDisposition,
  1327. IN PDFS_TARGET_INFO pDfsTargetInfo,
  1328. OUT ULONG *MatchingLength,
  1329. OUT ULONG *ReferralType,
  1330. OUT PDFS_PKT_ENTRY *ppPktEntry
  1331. )
  1332. {
  1333. DFS_PKT_ENTRY_ID EntryId;
  1334. UNICODE_STRING RemainingPath;
  1335. ULONG RefListSize;
  1336. NTSTATUS Status;
  1337. BOOLEAN bPktAcquired = FALSE;
  1338. UNREFERENCED_PARAMETER(Pkt);
  1339. DfsDbgTrace(+1, Dbg, "PktCreateEntryFromReferral: Entered\n", 0);
  1340. try {
  1341. RtlZeroMemory(&EntryId, sizeof(EntryId));
  1342. //
  1343. // Do some parameter validation
  1344. //
  1345. Status = PktpCheckReferralSyntax(
  1346. ReferralPath,
  1347. ReferralBuffer,
  1348. ReferralSize);
  1349. if (!NT_SUCCESS(Status)) {
  1350. try_return(Status);
  1351. }
  1352. Status = PktpCreateEntryIdFromReferral(
  1353. ReferralBuffer,
  1354. ReferralPath,
  1355. MatchingLength,
  1356. &EntryId);
  1357. if (!NT_SUCCESS(Status)) {
  1358. try_return(Status);
  1359. }
  1360. //
  1361. // Create/Update the prefix entry
  1362. //
  1363. PktAcquireExclusive(TRUE, &bPktAcquired);
  1364. Status = PktpAddEntry(&DfsData.Pkt,
  1365. &EntryId,
  1366. ReferralBuffer,
  1367. CreateDisposition,
  1368. pDfsTargetInfo,
  1369. ppPktEntry);
  1370. PktRelease();
  1371. bPktAcquired = FALSE;
  1372. //
  1373. // We have to tell the caller as to what kind of referral was just
  1374. // received through ReferralType.
  1375. //
  1376. if (ReferralBuffer->StorageServers == 1) {
  1377. *ReferralType = DFS_STORAGE_REFERRAL;
  1378. } else {
  1379. *ReferralType = DFS_REFERRAL_REFERRAL;
  1380. }
  1381. try_exit: NOTHING;
  1382. } finally {
  1383. DebugUnwind(PktCreateEntryFromReferral);
  1384. if (bPktAcquired)
  1385. PktRelease();
  1386. if (AbnormalTermination())
  1387. Status = STATUS_INVALID_USER_BUFFER;
  1388. PktEntryIdDestroy( &EntryId, FALSE );
  1389. }
  1390. DfsDbgTrace(-1, Dbg, "PktCreateEntryFromReferral: Exit -> %08lx\n", ULongToPtr(Status) );
  1391. return Status;
  1392. }
  1393. //+-------------------------------------------------------------------------
  1394. //
  1395. // Function: PktExpandSpecialEntryFromReferral, public
  1396. //
  1397. // Synopsis: Creates a special list corresponding to the list of names
  1398. // in a referral.
  1399. //
  1400. // Arguments: [Pkt] -- pointer to a initialized (and exclusively
  1401. // acquired) PKT
  1402. // [ReferralPath] -- Path for which this referral was obtained.
  1403. // [ReferralSize] -- size (in bytes) of the referral buffer.
  1404. // [ReferralBuffer] -- pointer to a referral buffer
  1405. // [pSpecialEntry] - the entry to expand
  1406. //
  1407. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  1408. //
  1409. // Notes:
  1410. //
  1411. //--------------------------------------------------------------------------
  1412. NTSTATUS
  1413. PktExpandSpecialEntryFromReferral(
  1414. IN PDFS_PKT Pkt,
  1415. IN PUNICODE_STRING ReferralPath,
  1416. IN ULONG ReferralSize,
  1417. IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
  1418. IN PDFS_SPECIAL_ENTRY pSpecialEntry
  1419. )
  1420. {
  1421. PUNICODE_STRING ustrExpandedName;
  1422. NTSTATUS Status = STATUS_SUCCESS;
  1423. PDFS_REFERRAL_V3 v3;
  1424. PDFS_EXPANDED_NAME pExpandedNames;
  1425. LPWSTR wzSpecialName;
  1426. LPWSTR wzExpandedName;
  1427. ULONG TimeToLive = 0;
  1428. ULONG i, j;
  1429. DfsDbgTrace(+1, Dbg, "PktExpandSpecialEntryFromReferral(%wZ): Entered\n", ReferralPath);
  1430. //
  1431. // We can't update if another thread is using this entry
  1432. //
  1433. if (pSpecialEntry->UseCount > 1) {
  1434. return STATUS_SUCCESS;
  1435. }
  1436. //
  1437. // Do some parameter validation
  1438. //
  1439. try {
  1440. Status = PktpCheckReferralSyntax(
  1441. ReferralPath,
  1442. ReferralBuffer,
  1443. ReferralSize);
  1444. } except (EXCEPTION_EXECUTE_HANDLER) {
  1445. Status = STATUS_INVALID_USER_BUFFER;
  1446. }
  1447. if (!NT_SUCCESS(Status)) {
  1448. DfsDbgTrace(-1, Dbg, "PktExpandSpecialEntryFromReferral exit 0x%x\n", ULongToPtr(Status) );
  1449. return( Status);
  1450. }
  1451. v3 = &ReferralBuffer->Referrals[0].v3;
  1452. if (v3->NumberOfExpandedNames > 0) {
  1453. pExpandedNames = ExAllocatePoolWithTag(
  1454. PagedPool,
  1455. sizeof(DFS_EXPANDED_NAME) * v3->NumberOfExpandedNames,
  1456. ' puM');
  1457. if (pExpandedNames == NULL) {
  1458. if (pSpecialEntry->NeedsExpansion == FALSE) {
  1459. pSpecialEntry->Stale = FALSE;
  1460. Status = STATUS_SUCCESS;
  1461. } else {
  1462. Status = STATUS_INSUFFICIENT_RESOURCES;
  1463. }
  1464. DfsDbgTrace( 0, Dbg, "Unable to allocate ExpandedNames\n", 0);
  1465. DfsDbgTrace(-1, Dbg, "PktExpandSpecialEntryFromReferral: Exit -> %08lx\n", ULongToPtr(Status) );
  1466. return (Status);
  1467. }
  1468. RtlZeroMemory(
  1469. pExpandedNames,
  1470. sizeof(DFS_EXPANDED_NAME) * v3->NumberOfExpandedNames);
  1471. //
  1472. // Loop over the referral, filling in the expanded names
  1473. // If we fail an allocate request, we simply go on.
  1474. //
  1475. wzExpandedName = (LPWSTR) (( (PCHAR) v3) + v3->ExpandedNameOffset);
  1476. for (i = j = 0; i < v3->NumberOfExpandedNames; i++) {
  1477. TimeToLive = v3->TimeToLive;
  1478. //
  1479. // Strip leading '\'
  1480. //
  1481. if (*wzExpandedName == UNICODE_PATH_SEP)
  1482. wzExpandedName++;
  1483. DfsDbgTrace( 0, Dbg, "%ws\n", wzExpandedName);
  1484. ustrExpandedName = &pExpandedNames[j].ExpandedName;
  1485. if (wcslen(wzExpandedName) > 0) {
  1486. ustrExpandedName->Length = wcslen(wzExpandedName) * sizeof(WCHAR);
  1487. ustrExpandedName->MaximumLength = ustrExpandedName->Length + sizeof(WCHAR);
  1488. ustrExpandedName->Buffer = ExAllocatePoolWithTag(
  1489. PagedPool,
  1490. ustrExpandedName->MaximumLength,
  1491. ' puM');
  1492. if (ustrExpandedName->Buffer != NULL) {
  1493. RtlCopyMemory(
  1494. ustrExpandedName->Buffer,
  1495. wzExpandedName,
  1496. ustrExpandedName->MaximumLength);
  1497. j++;
  1498. } else {
  1499. ustrExpandedName->Length = ustrExpandedName->MaximumLength = 0;
  1500. }
  1501. }
  1502. wzExpandedName += wcslen(wzExpandedName) + 1;
  1503. }
  1504. if (j > 0) {
  1505. if (pSpecialEntry->ExpandedNames != NULL) {
  1506. PUNICODE_STRING pustr;
  1507. for (i = 0; i < pSpecialEntry->ExpandedCount; i++) {
  1508. pustr = &pSpecialEntry->ExpandedNames[i].ExpandedName;
  1509. if (pustr->Buffer) {
  1510. ExFreePool(pustr->Buffer);
  1511. }
  1512. }
  1513. ExFreePool(pSpecialEntry->ExpandedNames);
  1514. pSpecialEntry->ExpandedNames = NULL;
  1515. pSpecialEntry->ExpandedCount = 0;
  1516. }
  1517. pSpecialEntry->ExpandedCount = j;
  1518. pSpecialEntry->Active = 0;
  1519. pSpecialEntry->ExpandedNames = pExpandedNames;
  1520. pSpecialEntry->NeedsExpansion = FALSE;
  1521. pSpecialEntry->Stale = FALSE;
  1522. // PktShuffleSpecialEntryList(pSpecialEntry);
  1523. PktSetSpecialEntryListToDc(pSpecialEntry);
  1524. } else {
  1525. ExFreePool(pExpandedNames);
  1526. }
  1527. }
  1528. DfsDbgTrace(-1, Dbg, "PktExpandSpecialEntryFromReferral: Exit -> %08lx\n", ULongToPtr(Status) );
  1529. return Status;
  1530. }
  1531. NTSTATUS
  1532. PktCreateSpecialEntryTableFromReferral(
  1533. IN PDFS_PKT Pkt,
  1534. IN PUNICODE_STRING ReferralPath,
  1535. IN ULONG ReferralSize,
  1536. IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
  1537. IN PUNICODE_STRING DCName)
  1538. {
  1539. PUNICODE_STRING ustrSpecialName;
  1540. PUNICODE_STRING ustrExpandedName;
  1541. PDFS_EXPANDED_NAME pExpandedNames;
  1542. PDFS_SPECIAL_ENTRY pSpecialEntry;
  1543. PDFS_REFERRAL_V3 v3;
  1544. LPWSTR wzSpecialName;
  1545. LPWSTR wzExpandedName;
  1546. NTSTATUS Status = STATUS_SUCCESS;
  1547. ULONG TimeToLive = 0;
  1548. ULONG i, j, n;
  1549. DfsDbgTrace(+1, Dbg, "PktCreateSpecialEntryTableFromReferral(%wZ): Entered\n", ReferralPath);
  1550. //
  1551. // Do some parameter validation
  1552. //
  1553. try {
  1554. Status = PktpCheckReferralSyntax(
  1555. ReferralPath,
  1556. ReferralBuffer,
  1557. ReferralSize);
  1558. } except (EXCEPTION_EXECUTE_HANDLER) {
  1559. Status = STATUS_INVALID_USER_BUFFER;
  1560. }
  1561. if (!NT_SUCCESS(Status)) {
  1562. DfsDbgTrace(-1, Dbg, "PktCreateSpecialEntryTableFromReferral exit 0x%x\n", ULongToPtr(Status) );
  1563. return( Status);
  1564. }
  1565. //
  1566. // Loop over referrals
  1567. //
  1568. v3 = &ReferralBuffer->Referrals[0].v3;
  1569. for (n = 0; n < ReferralBuffer->NumberOfReferrals; n++) {
  1570. //
  1571. // Create the entry itself
  1572. //
  1573. pSpecialEntry = ExAllocatePoolWithTag(
  1574. PagedPool,
  1575. sizeof(DFS_SPECIAL_ENTRY),
  1576. ' puM');
  1577. if (pSpecialEntry == NULL) {
  1578. Status = STATUS_INSUFFICIENT_RESOURCES;
  1579. DfsDbgTrace( 0, Dbg, "Unable to allocate SpecialEntry\n", 0);
  1580. DfsDbgTrace(-1, Dbg, "PktCreateSpecialEntryTableFromReferral: Exit -> %08lx\n", ULongToPtr(Status) );
  1581. return (Status);
  1582. }
  1583. //
  1584. // Mundate initialization
  1585. //
  1586. RtlZeroMemory(pSpecialEntry, sizeof(DFS_SPECIAL_ENTRY));
  1587. pSpecialEntry->NodeTypeCode = DSFS_NTC_SPECIAL_ENTRY;
  1588. pSpecialEntry->NodeByteSize = sizeof(DFS_SPECIAL_ENTRY);
  1589. pSpecialEntry->USN = 1;
  1590. pSpecialEntry->UseCount = 0;
  1591. pSpecialEntry->ExpandedCount = 0;
  1592. pSpecialEntry->Active = 0;
  1593. pSpecialEntry->ExpandedNames = NULL;
  1594. pSpecialEntry->NeedsExpansion = TRUE;
  1595. pSpecialEntry->Stale = FALSE;
  1596. //
  1597. // Set gotdcreferral to false. This gets set to true only when
  1598. // we have already been asked (via an fsctl) to get the
  1599. // trusted domainlist for the domain represented by this special entry
  1600. //
  1601. pSpecialEntry->GotDCReferral = FALSE;
  1602. //
  1603. // Fill in the Special Name, without the leading '\'
  1604. //
  1605. wzSpecialName = (PWCHAR) (((PCHAR) v3) + v3->SpecialNameOffset);
  1606. if (*wzSpecialName == UNICODE_PATH_SEP) {
  1607. wzSpecialName++;
  1608. }
  1609. ustrSpecialName = &pSpecialEntry->SpecialName;
  1610. ustrSpecialName->Length = wcslen(wzSpecialName) * sizeof(WCHAR);
  1611. ustrSpecialName->MaximumLength = ustrSpecialName->Length + sizeof(WCHAR);
  1612. ustrSpecialName->Buffer = ExAllocatePoolWithTag(
  1613. PagedPool,
  1614. ustrSpecialName->MaximumLength,
  1615. ' puM');
  1616. if (ustrSpecialName->Buffer == NULL) {
  1617. ExFreePool(pSpecialEntry);
  1618. Status = STATUS_INSUFFICIENT_RESOURCES;
  1619. DfsDbgTrace( 0, Dbg, "Unable to allocate SpecialName\n", 0);
  1620. DfsDbgTrace(-1, Dbg, "PktCreateSpecialEntryTableFromReferral: Exit -> %08lx\n", ULongToPtr(Status) );
  1621. return (Status);
  1622. }
  1623. RtlCopyMemory(
  1624. ustrSpecialName->Buffer,
  1625. wzSpecialName,
  1626. ustrSpecialName->MaximumLength);
  1627. // If the DCName is non-null, copy it into the special entry.
  1628. // We store null dcname for all the special entries that get to use
  1629. // the global pkt->dcname.
  1630. if (DCName != NULL) {
  1631. pSpecialEntry->DCName.Buffer = ExAllocatePoolWithTag(
  1632. PagedPool,
  1633. DCName->MaximumLength,
  1634. ' puM');
  1635. if (pSpecialEntry->DCName.Buffer == NULL) {
  1636. ExFreePool(pSpecialEntry->SpecialName.Buffer);
  1637. ExFreePool(pSpecialEntry);
  1638. Status = STATUS_INSUFFICIENT_RESOURCES;
  1639. DfsDbgTrace( 0, Dbg, "Unable to allocate DCName\n", 0);
  1640. DfsDbgTrace(-1, Dbg, "PktCreateSpecialEntryTableFromReferral: Exit -> %08lx\n", ULongToPtr(Status) );
  1641. return (Status);
  1642. }
  1643. pSpecialEntry->DCName.MaximumLength = DCName->MaximumLength;
  1644. RtlCopyUnicodeString(&pSpecialEntry->DCName, DCName);
  1645. }
  1646. //
  1647. // Clip the UNICODE_NULL off the end
  1648. //
  1649. if (ustrSpecialName->Buffer[(ustrSpecialName->Length/sizeof(WCHAR))-1] == UNICODE_NULL) {
  1650. ustrSpecialName->Length -= sizeof(WCHAR);
  1651. }
  1652. DfsDbgTrace( 0, Dbg, "SpecialName %wZ\n", ustrSpecialName);
  1653. TimeToLive = v3->TimeToLive;
  1654. if (v3->NumberOfExpandedNames > 0) {
  1655. pExpandedNames = ExAllocatePoolWithTag(
  1656. PagedPool,
  1657. sizeof(DFS_EXPANDED_NAME) * v3->NumberOfExpandedNames,
  1658. ' puM');
  1659. if (pExpandedNames == NULL) {
  1660. DfsDbgTrace( 0, Dbg, "Unable to allocate ExpandedNames\n", 0);
  1661. DfsDbgTrace(-1, Dbg, "PktCreateSpecialEntryTableFromReferral: Exit -> %08lx\n",
  1662. ULongToPtr(Status) );
  1663. }
  1664. if (pExpandedNames != NULL) {
  1665. RtlZeroMemory(
  1666. pExpandedNames,
  1667. sizeof(DFS_EXPANDED_NAME) * v3->NumberOfExpandedNames);
  1668. //
  1669. // Loop over the referral, filling in the expanded names
  1670. // If we fail an allocate request, we simply go on.
  1671. //
  1672. wzExpandedName = (LPWSTR) (( (PCHAR) v3) + v3->ExpandedNameOffset);
  1673. for (i = j = 0; i < v3->NumberOfExpandedNames; i++) {
  1674. //
  1675. // Strip leading '\'
  1676. //
  1677. if (*wzExpandedName == UNICODE_PATH_SEP)
  1678. wzExpandedName++;
  1679. DfsDbgTrace( 0, Dbg, "..expands to %ws\n", wzExpandedName);
  1680. ustrExpandedName = &pExpandedNames[j].ExpandedName;
  1681. if (wcslen(wzExpandedName) > 0) {
  1682. ustrExpandedName->Length = wcslen(wzExpandedName) * sizeof(WCHAR);
  1683. ustrExpandedName->MaximumLength = ustrExpandedName->Length + sizeof(WCHAR);
  1684. ustrExpandedName->Buffer = ExAllocatePoolWithTag(
  1685. PagedPool,
  1686. ustrExpandedName->MaximumLength,
  1687. ' puM');
  1688. if (ustrExpandedName->Buffer != NULL) {
  1689. RtlCopyMemory(
  1690. ustrExpandedName->Buffer,
  1691. wzExpandedName,
  1692. ustrExpandedName->MaximumLength);
  1693. j++;
  1694. } else {
  1695. ustrExpandedName->Length = ustrExpandedName->MaximumLength = 0;
  1696. }
  1697. }
  1698. wzExpandedName += wcslen(wzExpandedName) + 1;
  1699. }
  1700. if (j > 0) {
  1701. pSpecialEntry->ExpandedCount = j;
  1702. pSpecialEntry->Active = 0;
  1703. pSpecialEntry->ExpandedNames = pExpandedNames;
  1704. pSpecialEntry->NeedsExpansion = FALSE;
  1705. pSpecialEntry->Stale = FALSE;
  1706. // PktShuffleSpecialEntryList(pSpecialEntry);
  1707. PktSetSpecialEntryListToDc(pSpecialEntry);
  1708. } else {
  1709. ExFreePool(pExpandedNames);
  1710. }
  1711. }
  1712. }
  1713. //
  1714. // If we got a referral with a TimeToLive, use the TimeToLive we got
  1715. //
  1716. if (TimeToLive != 0) {
  1717. Pkt->SpecialTable.TimeToLive = TimeToLive;
  1718. }
  1719. //
  1720. // Put it in the pkt!!
  1721. //
  1722. PktCreateSpecialNameEntry(pSpecialEntry);
  1723. v3 = (PDFS_REFERRAL_V3) (((PUCHAR) v3) + v3->Size);
  1724. }
  1725. DfsDbgTrace(-1, Dbg, "PktCreateSpecialEntryTableFromReferral: Exit -> %08lx\n", ULongToPtr(Status) );
  1726. return Status;
  1727. }
  1728. //+----------------------------------------------------------------------------
  1729. //
  1730. // Function: PktpCheckReferralSyntax
  1731. //
  1732. // Synopsis: Does some validation of a Referral
  1733. //
  1734. // Arguments: [ReferralPath] -- The Path for which a referral was obtained
  1735. // [ReferralBuffer] -- Pointer to RESP_GET_DFS_REFERRAL Buffer
  1736. // [ReferralSize] -- Size of ReferralBuffer
  1737. //
  1738. // Returns: [STATUS_SUCCESS] -- Referral looks ok.
  1739. //
  1740. // [STATUS_INVALID_USER_BUFFER] -- Buffer looks hoky.
  1741. //
  1742. //-----------------------------------------------------------------------------
  1743. NTSTATUS
  1744. PktpCheckReferralSyntax(
  1745. IN PUNICODE_STRING ReferralPath,
  1746. IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
  1747. IN DWORD ReferralSize)
  1748. {
  1749. NTSTATUS status = STATUS_SUCCESS;
  1750. ULONG i, sizeRemaining;
  1751. PDFS_REFERRAL_V1 ref;
  1752. PCHAR ReferralBufferEnd = (((PCHAR) ReferralBuffer) + ReferralSize);
  1753. DfsDbgTrace(+1, Dbg, "PktpCheckReferralSyntax: Entered\n", 0);
  1754. if (ReferralBuffer->PathConsumed > ReferralPath->Length) {
  1755. DfsDbgTrace( 0, Dbg, " PathConsumed=0x%x\n", ReferralBuffer->PathConsumed);
  1756. DfsDbgTrace( 0, Dbg, " Length=0x%x\n", ReferralPath->Length);
  1757. DfsDbgTrace(-1, Dbg, "PktpCheckReferralSyntax: INVALID_USER_BUFFER(1)\n", 0);
  1758. // return( STATUS_INVALID_USER_BUFFER );
  1759. }
  1760. if (ReferralBuffer->NumberOfReferrals == 0) {
  1761. status = STATUS_INVALID_USER_BUFFER;
  1762. DfsDbgTrace(-1, Dbg, "PktpCheckReferralSyntax: INVALID_USER_BUFFER(2)\n", 0);
  1763. MUP_TRACE_HIGH(ERROR, PktpCheckReferralSyntax_Error_InvalidBuffer2,
  1764. LOGSTATUS(status)
  1765. LOGUSTR(*ReferralPath));
  1766. return( status );
  1767. }
  1768. if (ReferralBuffer->NumberOfReferrals * sizeof(DFS_REFERRAL_V1) > ReferralSize) {
  1769. DfsDbgTrace(-1, Dbg, "PktpCheckReferralSyntax: INVALID_USER_BUFFER(3)\n", 0);
  1770. status = STATUS_INVALID_USER_BUFFER;
  1771. MUP_TRACE_HIGH(ERROR, PktpCheckReferralSyntax_Error_InvalidBuffer3,
  1772. LOGSTATUS(status)
  1773. LOGUSTR(*ReferralPath));
  1774. return( status );
  1775. }
  1776. for (i = 0,
  1777. ref = &ReferralBuffer->Referrals[0].v1,
  1778. status = STATUS_SUCCESS,
  1779. sizeRemaining = ReferralSize -
  1780. FIELD_OFFSET(RESP_GET_DFS_REFERRAL, Referrals);
  1781. i < ReferralBuffer->NumberOfReferrals;
  1782. i++) {
  1783. ULONG lenAddress;
  1784. if ((ref->VersionNumber < 1 || ref->VersionNumber > 3) ||
  1785. ref->Size > sizeRemaining) {
  1786. DfsDbgTrace( 0, Dbg, "PktpCheckReferralSyntax: INVALID_USER_BUFFER(4)\n", 0);
  1787. status = STATUS_INVALID_USER_BUFFER;
  1788. MUP_TRACE_HIGH(ERROR, PktpCheckReferralSyntax_Error_InvalidBuffer4,
  1789. LOGSTATUS(status)
  1790. LOGUSTR(*ReferralPath));
  1791. break;
  1792. }
  1793. //
  1794. // Check the network address syntax
  1795. //
  1796. switch (ref->VersionNumber) {
  1797. case 1:
  1798. {
  1799. status = PktpCheckReferralString(
  1800. (LPWSTR) ref->ShareName,
  1801. (PCHAR) ReferralBuffer,
  1802. ReferralBufferEnd);
  1803. if (NT_SUCCESS(status)) {
  1804. lenAddress = ref->Size -
  1805. FIELD_OFFSET(DFS_REFERRAL_V1, ShareName);
  1806. lenAddress /= sizeof(WCHAR);
  1807. status = PktpCheckReferralNetworkAddress(
  1808. (LPWSTR) ref->ShareName,
  1809. lenAddress);
  1810. }
  1811. }
  1812. break;
  1813. case 2:
  1814. {
  1815. PDFS_REFERRAL_V2 refV2 = (PDFS_REFERRAL_V2) ref;
  1816. PWCHAR dfsPath, dfsAlternatePath, networkAddress;
  1817. dfsPath =
  1818. (PWCHAR) (((PCHAR) refV2) + refV2->DfsPathOffset);
  1819. dfsAlternatePath =
  1820. (PWCHAR) (((PCHAR) refV2) + refV2->DfsAlternatePathOffset);
  1821. networkAddress =
  1822. (PWCHAR) (((PCHAR) refV2) + refV2->NetworkAddressOffset);
  1823. status = PktpCheckReferralString(
  1824. dfsPath,
  1825. (PCHAR) ReferralBuffer,
  1826. ReferralBufferEnd);
  1827. if (NT_SUCCESS(status)) {
  1828. status = PktpCheckReferralString(
  1829. dfsAlternatePath,
  1830. (PCHAR) ReferralBuffer,
  1831. ReferralBufferEnd);
  1832. }
  1833. if (NT_SUCCESS(status)) {
  1834. status = PktpCheckReferralString(
  1835. networkAddress,
  1836. (PCHAR) ReferralBuffer,
  1837. ReferralBufferEnd);
  1838. }
  1839. if (NT_SUCCESS(status)) {
  1840. lenAddress = (ULONG)(((ULONG_PTR) ReferralBufferEnd) -
  1841. ((ULONG_PTR) networkAddress));
  1842. lenAddress /= sizeof(WCHAR);
  1843. status = PktpCheckReferralNetworkAddress(
  1844. networkAddress,
  1845. lenAddress);
  1846. }
  1847. }
  1848. break;
  1849. case 3:
  1850. {
  1851. PDFS_REFERRAL_V3 refV3 = (PDFS_REFERRAL_V3) ref;
  1852. if (refV3->NameListReferral != 0) {
  1853. PWCHAR dfsSpecialName, dfsExpandedNames;
  1854. ULONG i;
  1855. dfsSpecialName =
  1856. (PWCHAR) (((PCHAR) refV3) + refV3->SpecialNameOffset);
  1857. dfsExpandedNames =
  1858. (PWCHAR) (((PCHAR) refV3) + refV3->ExpandedNameOffset);
  1859. status = PktpCheckReferralString(
  1860. dfsSpecialName,
  1861. (PCHAR) ReferralBuffer,
  1862. ReferralBufferEnd);
  1863. if (!NT_SUCCESS(status)) {
  1864. DfsDbgTrace(0,
  1865. Dbg,
  1866. "PktpCheckReferralSyntax: INVALID_USER_BUFFER(5)\n",
  1867. 0);
  1868. }
  1869. if (NT_SUCCESS(status)) {
  1870. for (i = 0; i < refV3->NumberOfExpandedNames; i++) {
  1871. status = PktpCheckReferralString(
  1872. dfsSpecialName,
  1873. (PCHAR) ReferralBuffer,
  1874. ReferralBufferEnd);
  1875. if (!NT_SUCCESS(status)) {
  1876. DfsDbgTrace(0,
  1877. Dbg,
  1878. "PktpCheckReferralSyntax: INVALID_USER_BUFFER(6)\n",
  1879. 0);
  1880. break;
  1881. }
  1882. dfsSpecialName += wcslen(dfsSpecialName) + 1;
  1883. }
  1884. }
  1885. } else {
  1886. PWCHAR dfsPath, dfsAlternatePath, networkAddress;
  1887. dfsPath =
  1888. (PWCHAR) (((PCHAR) refV3) + refV3->DfsPathOffset);
  1889. dfsAlternatePath =
  1890. (PWCHAR) (((PCHAR) refV3) + refV3->DfsAlternatePathOffset);
  1891. networkAddress =
  1892. (PWCHAR) (((PCHAR) refV3) + refV3->NetworkAddressOffset);
  1893. status = PktpCheckReferralString(
  1894. dfsPath,
  1895. (PCHAR) ReferralBuffer,
  1896. ReferralBufferEnd);
  1897. if (NT_SUCCESS(status)) {
  1898. status = PktpCheckReferralString(
  1899. dfsAlternatePath,
  1900. (PCHAR) ReferralBuffer,
  1901. ReferralBufferEnd);
  1902. }
  1903. if (NT_SUCCESS(status)) {
  1904. status = PktpCheckReferralString(
  1905. networkAddress,
  1906. (PCHAR) ReferralBuffer,
  1907. ReferralBufferEnd);
  1908. }
  1909. if (NT_SUCCESS(status)) {
  1910. lenAddress = (ULONG)(((ULONG_PTR) ReferralBufferEnd) -
  1911. ((ULONG_PTR) networkAddress));
  1912. lenAddress /= sizeof(WCHAR);
  1913. status = PktpCheckReferralNetworkAddress(
  1914. networkAddress,
  1915. lenAddress);
  1916. }
  1917. }
  1918. }
  1919. break;
  1920. default:
  1921. ASSERT(FALSE && "bad ref->VersionNumber\n");
  1922. status = STATUS_INVALID_USER_BUFFER;
  1923. break;
  1924. }
  1925. //
  1926. // This ref is ok. Go on to the next one...
  1927. //
  1928. sizeRemaining -= ref->Size;
  1929. ref = (PDFS_REFERRAL_V1) (((PUCHAR) ref) + ref->Size);
  1930. }
  1931. DfsDbgTrace(-1, Dbg, "PktpCheckReferralSyntax: Exit -> %08lx\n", ULongToPtr(status) );
  1932. return( status );
  1933. }
  1934. //+----------------------------------------------------------------------------
  1935. //
  1936. // Function: PktpCheckReferralString
  1937. //
  1938. // Synopsis: Validates part of a Referral as being a valid "string"
  1939. //
  1940. // Arguments: [String] -- Pointer to buffer thought to contain string.
  1941. // [ReferralBuffer] -- Start of Referral Buffer
  1942. // [ReferralBufferEnd] -- End of Referral Buffer
  1943. //
  1944. // Returns: [STATUS_SUCCESS] -- Valid string at String.
  1945. //
  1946. // [STATUS_INVALID_USER_BUFFER] -- String doesn't check out.
  1947. //
  1948. //-----------------------------------------------------------------------------
  1949. NTSTATUS
  1950. PktpCheckReferralString(
  1951. IN LPWSTR String,
  1952. IN PCHAR ReferralBuffer,
  1953. IN PCHAR ReferralBufferEnd)
  1954. {
  1955. NTSTATUS status = STATUS_SUCCESS;
  1956. ULONG i, length;
  1957. if ( (((ULONG_PTR) String) & 0x1) != 0 ) {
  1958. //
  1959. // Strings should always start at word aligned addresses!
  1960. //
  1961. status = STATUS_INVALID_USER_BUFFER;
  1962. MUP_TRACE_HIGH(ERROR, PktpCheckReferralString_Error_StringNotWordAlligned,
  1963. LOGSTATUS(status)
  1964. LOGWSTR(String));
  1965. return( status );
  1966. }
  1967. if ( (((ULONG_PTR) String) >= ((ULONG_PTR) ReferralBuffer)) &&
  1968. (((ULONG_PTR) String) < ((ULONG_PTR) ReferralBufferEnd)) ) {
  1969. length = (ULONG)(( ((ULONG_PTR) ReferralBufferEnd) - ((ULONG_PTR) String) )) /
  1970. sizeof(WCHAR);
  1971. for (i = 0; (i < length) && (String[i] != UNICODE_NULL); i++) {
  1972. NOTHING;
  1973. }
  1974. if (i >= length)
  1975. status = STATUS_INVALID_USER_BUFFER;
  1976. } else {
  1977. status = STATUS_INVALID_USER_BUFFER;
  1978. }
  1979. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, PktpCheckReferralString_Error,
  1980. LOGWSTR(String)
  1981. LOGSTATUS(status));
  1982. return( status );
  1983. }
  1984. //+----------------------------------------------------------------------------
  1985. //
  1986. // Function: PktpCheckReferralNetworkAddress
  1987. //
  1988. // Synopsis: Checks to see if a NetworkAddress inside a referral
  1989. // is of a valid form
  1990. //
  1991. // Arguments: [Address] -- Pointer to buffer containing network addresss
  1992. //
  1993. // [MaxLength] -- Maximum length, in wchars, that Address can be.
  1994. //
  1995. // Returns: [STATUS_SUCCESS] -- Network address checks out
  1996. //
  1997. // [STATUS_INVALID_USER_BUFFER] -- Network address looks bogus
  1998. //
  1999. //-----------------------------------------------------------------------------
  2000. NTSTATUS
  2001. PktpCheckReferralNetworkAddress(
  2002. IN PWCHAR Address,
  2003. IN ULONG MaxLength)
  2004. {
  2005. ULONG j;
  2006. BOOLEAN foundShare;
  2007. NTSTATUS status;
  2008. //
  2009. // Address must be atleast \a\b followed by a NULL
  2010. //
  2011. if (MaxLength < 5) {
  2012. status = STATUS_INVALID_USER_BUFFER;
  2013. MUP_TRACE_HIGH(ERROR, PktpCheckReferralNetworkAddress_Error_TooShortToBeValid,
  2014. LOGWSTR(Address)
  2015. LOGSTATUS(status));
  2016. return(STATUS_INVALID_USER_BUFFER);
  2017. }
  2018. //
  2019. // Make sure the server name part is not NULL
  2020. //
  2021. if (Address[0] != UNICODE_PATH_SEP ||
  2022. Address[1] == UNICODE_PATH_SEP) {
  2023. status = STATUS_INVALID_USER_BUFFER;
  2024. MUP_TRACE_HIGH(ERROR, PktpCheckReferralNetworkAddress_Error_NullServerName,
  2025. LOGWSTR(Address)
  2026. LOGSTATUS(status));
  2027. return(STATUS_INVALID_USER_BUFFER);
  2028. }
  2029. //
  2030. // Find the backslash after the server name
  2031. //
  2032. for (j = 2, foundShare = FALSE;
  2033. j < MaxLength && !foundShare;
  2034. j++) {
  2035. if (Address[j] == UNICODE_PATH_SEP)
  2036. foundShare = TRUE;
  2037. }
  2038. if (foundShare) {
  2039. //
  2040. // We found the second backslash. Make sure the share name
  2041. // part is not 0 length.
  2042. //
  2043. if (j == MaxLength) {
  2044. status = STATUS_INVALID_USER_BUFFER;
  2045. MUP_TRACE_HIGH(ERROR, PktpCheckReferralNetworkAddress_Error_ZeroLengthShareName,
  2046. LOGWSTR(Address)
  2047. LOGSTATUS(status));
  2048. return(status);
  2049. }
  2050. else {
  2051. ASSERT(Address[j-1] == UNICODE_PATH_SEP);
  2052. if (Address[j] == UNICODE_PATH_SEP ||
  2053. Address[j] == UNICODE_NULL) {
  2054. status = STATUS_INVALID_USER_BUFFER;
  2055. MUP_TRACE_HIGH(ERROR, PktpCheckReferralNetworkAddress_Error_ShareNameZeroLength,
  2056. LOGWSTR(Address)
  2057. LOGSTATUS(status));
  2058. return(status);
  2059. }
  2060. }
  2061. } else {
  2062. status = STATUS_INVALID_USER_BUFFER;
  2063. MUP_TRACE_HIGH(ERROR, PktpCheckReferralNetworkAddress_Error_ShareNameNotFound,
  2064. LOGWSTR(Address)
  2065. LOGSTATUS(status));
  2066. return(status);
  2067. }
  2068. return( STATUS_SUCCESS );
  2069. }
  2070. //+--------------------------------------------------------------------
  2071. //
  2072. // Function: PktpAddEntry
  2073. //
  2074. // Synopsis: This function is called to create an entry which was obtained
  2075. // in the form of a referral from a DC. This method should only
  2076. // be called for adding entries which were obtained through
  2077. // referrals. It sets an expire time on all these entries.
  2078. //
  2079. // Arguments: [Pkt] --
  2080. // [EntryId] --
  2081. // [ReferralBuffer] --
  2082. // [CreateDisposition] --
  2083. // [ppPktEntry] --
  2084. //
  2085. // Returns: NTSTATUS
  2086. //
  2087. //---------------------------------------------------------------------
  2088. NTSTATUS
  2089. PktpAddEntry (
  2090. IN PDFS_PKT Pkt,
  2091. IN PDFS_PKT_ENTRY_ID EntryId,
  2092. IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
  2093. IN ULONG CreateDisposition,
  2094. IN PDFS_TARGET_INFO pDfsTargetInfo,
  2095. OUT PDFS_PKT_ENTRY *ppPktEntry
  2096. )
  2097. {
  2098. NTSTATUS status;
  2099. DFS_PKT_ENTRY_INFO pktEntryInfo;
  2100. ULONG Type = 0;
  2101. ULONG n;
  2102. PDFS_SERVICE service;
  2103. PDFS_REFERRAL_V1 ref;
  2104. LPWSTR shareName;
  2105. PDS_MACHINE pMachine;
  2106. ULONG TimeToLive = 0;
  2107. BOOLEAN ShuffleList = TRUE;
  2108. UNICODE_STRING ServerName;
  2109. ULONG i;
  2110. BOOLEAN DomainDfsService = FALSE;
  2111. DfsDbgTrace(+1, Dbg, "PktpAddEntry: Entered\n", 0);
  2112. RtlZeroMemory(&pktEntryInfo, sizeof(DFS_PKT_ENTRY_INFO));
  2113. DfsDbgTrace( 0, Dbg, "PktpAddEntry: Id.Prefix = %wZ\n", &EntryId->Prefix);
  2114. //
  2115. // Now we go about the business of creating the entry Info structure.
  2116. //
  2117. pktEntryInfo.ServiceCount = ReferralBuffer->NumberOfReferrals;
  2118. if (pktEntryInfo.ServiceCount > 0) {
  2119. //
  2120. // Allocate the service list.
  2121. //
  2122. n = pktEntryInfo.ServiceCount;
  2123. pktEntryInfo.ServiceList = (PDFS_SERVICE) ExAllocatePoolWithTag(
  2124. PagedPool,
  2125. sizeof(DFS_SERVICE) * n,
  2126. ' puM');
  2127. if (pktEntryInfo.ServiceList == NULL) {
  2128. status = STATUS_INSUFFICIENT_RESOURCES;
  2129. goto Cleanup;
  2130. }
  2131. RtlZeroMemory(pktEntryInfo.ServiceList, sizeof(DFS_SERVICE) * n);
  2132. //
  2133. // initialize temporary pointers
  2134. //
  2135. service = pktEntryInfo.ServiceList;
  2136. ref = &ReferralBuffer->Referrals[0].v1;
  2137. //
  2138. // Cycle through the list of referrals initializing
  2139. // service structures on the way.
  2140. //
  2141. while (n--) {
  2142. if (ref->ServerType == 1) {
  2143. service->Type = DFS_SERVICE_TYPE_MASTER;
  2144. service->Capability = PROV_DFS_RDR;
  2145. service->ProviderId = PROV_ID_DFS_RDR;
  2146. } else {
  2147. service->Type = DFS_SERVICE_TYPE_MASTER |
  2148. DFS_SERVICE_TYPE_DOWN_LEVEL;
  2149. service->Capability = PROV_STRIP_PREFIX;
  2150. service->ProviderId = PROV_ID_MUP_RDR;
  2151. }
  2152. switch (ref->VersionNumber) {
  2153. case 1:
  2154. shareName = (LPWSTR) (ref->ShareName); break;
  2155. case 2:
  2156. {
  2157. PDFS_REFERRAL_V2 refV2 = (PDFS_REFERRAL_V2) ref;
  2158. service->Cost = refV2->Proximity;
  2159. TimeToLive = refV2->TimeToLive;
  2160. shareName =
  2161. (LPWSTR) (((PCHAR) refV2) + refV2->NetworkAddressOffset);
  2162. }
  2163. break;
  2164. case 3:
  2165. {
  2166. PDFS_REFERRAL_V3 refV3 = (PDFS_REFERRAL_V3) ref;
  2167. service->Cost = 0;
  2168. TimeToLive = refV3->TimeToLive;
  2169. shareName =
  2170. (LPWSTR) (((PCHAR) refV3) + refV3->NetworkAddressOffset);
  2171. //
  2172. // Don't shuffle v3 referral list - it's ordered for us
  2173. // using site information
  2174. //
  2175. ShuffleList = FALSE;
  2176. }
  2177. break;
  2178. default:
  2179. ASSERT(FALSE && "Bad ref->VersionNumber\n");
  2180. break;
  2181. }
  2182. //
  2183. // Now try and figure out the server name
  2184. //
  2185. {
  2186. USHORT plen;
  2187. WCHAR *pbuf;
  2188. ASSERT( shareName[0] == UNICODE_PATH_SEP );
  2189. pbuf = wcschr( &shareName[1], UNICODE_PATH_SEP );
  2190. if(pbuf) {
  2191. plen = (USHORT) (((ULONG_PTR)pbuf) - ((ULONG_PTR)&shareName[1]));
  2192. } else {
  2193. plen = 0;
  2194. }
  2195. service->Name.Length = plen;
  2196. service->Name.MaximumLength = plen + sizeof(WCHAR);
  2197. service->Name.Buffer = (PWCHAR) ExAllocatePoolWithTag(
  2198. PagedPool,
  2199. plen + sizeof(WCHAR),
  2200. ' puM');
  2201. if (service->Name.Buffer == NULL) {
  2202. status = STATUS_INSUFFICIENT_RESOURCES;
  2203. goto Cleanup;
  2204. }
  2205. RtlMoveMemory(service->Name.Buffer, &shareName[1], plen);
  2206. service->Name.Buffer[ service->Name.Length / sizeof(WCHAR) ] =
  2207. UNICODE_NULL;
  2208. if ((DomainDfsService != TRUE) &&
  2209. PktLookupSpecialNameEntry(&service->Name) != NULL)
  2210. {
  2211. DomainDfsService = TRUE;
  2212. }
  2213. }
  2214. //
  2215. // Next, try and copy the address...
  2216. //
  2217. service->Address.Length = (USHORT) wcslen(shareName) *
  2218. sizeof(WCHAR);
  2219. service->Address.MaximumLength = service->Address.Length +
  2220. sizeof(WCHAR);
  2221. service->Address.Buffer = (PWCHAR) ExAllocatePoolWithTag(
  2222. PagedPool,
  2223. service->Address.MaximumLength,
  2224. ' puM');
  2225. if (service->Address.Buffer == NULL) {
  2226. status = STATUS_INSUFFICIENT_RESOURCES;
  2227. goto Cleanup;
  2228. }
  2229. RtlMoveMemory(service->Address.Buffer,
  2230. shareName,
  2231. service->Address.MaximumLength);
  2232. DfsDbgTrace( 0, Dbg, "PktpAddEntry: service->Address = %wZ\n",
  2233. &service->Address);
  2234. //
  2235. // Get the Machine Address structure for this server...
  2236. //
  2237. pMachine = PktpGetDSMachine( &service->Name );
  2238. if (pMachine == NULL) {
  2239. status = STATUS_INSUFFICIENT_RESOURCES;
  2240. goto Cleanup;
  2241. }
  2242. service->pMachEntry = ExAllocatePoolWithTag(
  2243. PagedPool, sizeof(DFS_MACHINE_ENTRY),
  2244. ' puM');
  2245. if (service->pMachEntry == NULL) {
  2246. DfsDbgTrace( 0, Dbg, "PktpAddEntry: Unable to allocate DFS_MACHINE_ENTRY\n", 0);
  2247. status = STATUS_INSUFFICIENT_RESOURCES;
  2248. goto Cleanup;
  2249. }
  2250. RtlZeroMemory( (PVOID) service->pMachEntry, sizeof(DFS_MACHINE_ENTRY));
  2251. service->pMachEntry->pMachine = pMachine;
  2252. service->pMachEntry->UseCount = 1;
  2253. //
  2254. // Now we need to advance to the next referral, and to
  2255. // the next service structure.
  2256. //
  2257. ref = (PDFS_REFERRAL_V1) (((PUCHAR)ref) + ref->Size);
  2258. service++;
  2259. }
  2260. //
  2261. // Finally, if needed, we shuffle the services so that we achieve load balancing
  2262. // while still maintaining site-cost based replica selection.
  2263. //
  2264. // Note: we only shuffle v1 and v2 referrals. V3 referrals are ordered by site.
  2265. //
  2266. if (ShuffleList == TRUE) {
  2267. PktShuffleServiceList( &pktEntryInfo );
  2268. }
  2269. }
  2270. //
  2271. // Now we have to figure out the type for this entry.
  2272. //
  2273. //
  2274. // Ignore the storage server bit from the server.
  2275. // Bug: 332061.
  2276. //
  2277. //if (ReferralBuffer->StorageServers == 0) {
  2278. //
  2279. // ASSERT(ReferralBuffer->ReferralServers == 1);
  2280. //
  2281. // Type = PKT_ENTRY_TYPE_OUTSIDE_MY_DOM;
  2282. //
  2283. // } else {
  2284. //
  2285. // Type = PKT_ENTRY_TYPE_DFS;
  2286. //
  2287. //}
  2288. Type = 0;
  2289. if (DomainDfsService == TRUE)
  2290. {
  2291. Type |= PKT_ENTRY_TYPE_OUTSIDE_MY_DOM;
  2292. }
  2293. else {
  2294. Type = PKT_ENTRY_TYPE_DFS;
  2295. if (ReferralBuffer->ReferralServers == 1)
  2296. {
  2297. Type |= PKT_ENTRY_TYPE_REFERRAL_SVC;
  2298. }
  2299. }
  2300. //
  2301. // At this point we have everything we need to create an entry, so
  2302. // try to add the entry.
  2303. //
  2304. status = PktCreateEntry(
  2305. Pkt,
  2306. Type,
  2307. EntryId,
  2308. &pktEntryInfo,
  2309. CreateDisposition,
  2310. pDfsTargetInfo,
  2311. ppPktEntry);
  2312. if (!NT_SUCCESS(status)) {
  2313. //
  2314. // Since we failed to add the entry, at least we need to release
  2315. // all the memory before we return back.
  2316. //
  2317. goto Cleanup;
  2318. }
  2319. //
  2320. // Set the active service, if possible
  2321. //
  2322. ServerName = (*ppPktEntry)->Id.Prefix;
  2323. //
  2324. // Skip any leading leading '\'
  2325. //
  2326. if (ServerName.Buffer != NULL) {
  2327. if (*ServerName.Buffer == UNICODE_PATH_SEP) {
  2328. ServerName.Buffer++;
  2329. ServerName.Length -= sizeof(WCHAR);
  2330. }
  2331. //
  2332. // Find the first '\' or end
  2333. //
  2334. for (i = 0;
  2335. i < ServerName.Length/sizeof(WCHAR) &&
  2336. ServerName.Buffer[i] != UNICODE_PATH_SEP;
  2337. i++) {
  2338. NOTHING;
  2339. }
  2340. ServerName.Length = ServerName.MaximumLength = (USHORT) (i * sizeof(WCHAR));
  2341. //
  2342. // Ignore the return value - for FtDfs names using \\domainname\ftdfsname,
  2343. // there will be no services with the domain name.
  2344. //
  2345. #if 0
  2346. DfspSetActiveServiceByServerName(
  2347. &ServerName,
  2348. *ppPktEntry);
  2349. #endif
  2350. }
  2351. //
  2352. // If one of the services is our DC, we try to make it the active service
  2353. // DONT DO THIS! Screws up site selection!
  2354. #if 0
  2355. DfspSetServiceListToDc(*ppPktEntry);
  2356. #endif
  2357. //
  2358. // We set the ExpireTime in this entry to
  2359. // Pkt->EntryTimeToLive. After these many number of seconds this
  2360. // entry will get deleted from the PKT. Do this only for non-permanent
  2361. // entries.
  2362. //
  2363. if (TimeToLive != 0) {
  2364. (*ppPktEntry)->ExpireTime = TimeToLive;
  2365. (*ppPktEntry)->TimeToLive = TimeToLive;
  2366. } else {
  2367. (*ppPktEntry)->ExpireTime = Pkt->EntryTimeToLive;
  2368. (*ppPktEntry)->TimeToLive = Pkt->EntryTimeToLive;
  2369. }
  2370. #if DBG
  2371. if (MupVerbose)
  2372. DbgPrint(" Setting expiretime/timetolive = %d/%d\n",
  2373. (*ppPktEntry)->ExpireTime,
  2374. (*ppPktEntry)->TimeToLive);
  2375. #endif
  2376. #if DBG
  2377. if (MupVerbose >= 2) {
  2378. DbgPrint(" Setting expiretime and timetolive to 10\n");
  2379. (*ppPktEntry)->ExpireTime = 10;
  2380. (*ppPktEntry)->TimeToLive = 10;
  2381. }
  2382. #endif
  2383. DfsDbgTrace(-1, Dbg, "PktpAddEntry: Exit -> %08lx\n", ULongToPtr(status) );
  2384. return status;
  2385. Cleanup:
  2386. if (pktEntryInfo.ServiceCount > 0) {
  2387. n = pktEntryInfo.ServiceCount;
  2388. if (pktEntryInfo.ServiceList != NULL) {
  2389. service = pktEntryInfo.ServiceList;
  2390. while (n--) {
  2391. if (service->Name.Buffer != NULL)
  2392. DfsFree(service->Name.Buffer);
  2393. if (service->Address.Buffer != NULL)
  2394. DfsFree(service->Address.Buffer);
  2395. if (service->pMachEntry != NULL) {
  2396. DfsDecrementMachEntryCount( service->pMachEntry, TRUE);
  2397. }
  2398. service++;
  2399. }
  2400. ExFreePool(pktEntryInfo.ServiceList);
  2401. }
  2402. }
  2403. DfsDbgTrace(-1, Dbg, "PktpAddEntry: Exit -> %08lx\n", ULongToPtr(status) );
  2404. return status;
  2405. }
  2406. //+----------------------------------------------------------------------------
  2407. //
  2408. // Function: PktpCreateEntryIdFromReferral
  2409. //
  2410. // Synopsis: Given a dfs referral, this routine constructs a PKT_ENTRY_ID
  2411. // from the referral buffer which can then be used to create
  2412. // the Pkt Entry.
  2413. //
  2414. // Arguments: [Ref] -- The referral buffer
  2415. // [ReferralPath] -- The path for which the referral was obtained
  2416. // [MatchingLength] -- The length in bytes of ReferralPath that
  2417. // matched.
  2418. // [Peid] -- On successful return, the entry id is returned
  2419. // here.
  2420. //
  2421. // Returns: [STATUS_SUCCESS] -- Successfully create entry id.
  2422. //
  2423. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition
  2424. //
  2425. //-----------------------------------------------------------------------------
  2426. NTSTATUS
  2427. PktpCreateEntryIdFromReferral(
  2428. IN PRESP_GET_DFS_REFERRAL Ref,
  2429. IN PUNICODE_STRING ReferralPath,
  2430. OUT ULONG *MatchingLength,
  2431. OUT PDFS_PKT_ENTRY_ID Peid)
  2432. {
  2433. NTSTATUS status = STATUS_SUCCESS;
  2434. PDFS_REFERRAL_V2 pv2;
  2435. PDFS_REFERRAL_V3 pv3;
  2436. UNICODE_STRING prefix, shortPrefix;
  2437. DfsDbgTrace(+1, Dbg, "PktpCreateIdFromReferral: Entered\n", 0);
  2438. Peid->Prefix.Buffer = NULL;
  2439. Peid->ShortPrefix.Buffer = NULL;
  2440. pv2 = &Ref->Referrals[0].v2;
  2441. switch (pv2->VersionNumber) {
  2442. case 1:
  2443. {
  2444. //
  2445. // A version 1 referral only has the number of characters that
  2446. // matched, and it does not have short names.
  2447. //
  2448. prefix = *ReferralPath;
  2449. prefix.Length = Ref->PathConsumed;
  2450. if (prefix.Buffer[ prefix.Length/sizeof(WCHAR) - 1 ] ==
  2451. UNICODE_PATH_SEP) {
  2452. prefix.Length -= sizeof(WCHAR);
  2453. }
  2454. prefix.MaximumLength = prefix.Length + sizeof(WCHAR);
  2455. shortPrefix = prefix;
  2456. *MatchingLength = prefix.Length;
  2457. }
  2458. break;
  2459. case 2:
  2460. {
  2461. LPWSTR volPrefix;
  2462. LPWSTR volShortPrefix;
  2463. volPrefix = (LPWSTR) (((PCHAR) pv2) + pv2->DfsPathOffset);
  2464. volShortPrefix = (LPWSTR) (((PCHAR) pv2) + pv2->DfsAlternatePathOffset);
  2465. RtlInitUnicodeString(&prefix, volPrefix);
  2466. RtlInitUnicodeString(&shortPrefix, volShortPrefix);
  2467. *MatchingLength = Ref->PathConsumed;
  2468. }
  2469. break;
  2470. case 3:
  2471. {
  2472. LPWSTR volPrefix;
  2473. LPWSTR volShortPrefix;
  2474. pv3 = &Ref->Referrals[0].v3;
  2475. volPrefix = (LPWSTR) (((PCHAR) pv3) + pv3->DfsPathOffset);
  2476. volShortPrefix = (LPWSTR) (((PCHAR) pv3) + pv3->DfsAlternatePathOffset);
  2477. RtlInitUnicodeString(&prefix, volPrefix);
  2478. RtlInitUnicodeString(&shortPrefix, volShortPrefix);
  2479. *MatchingLength = Ref->PathConsumed;
  2480. }
  2481. break;
  2482. default:
  2483. // Fix for 440914 (prefix bug). Remove assert and return so that
  2484. // we are not dealing with uninitialized variables.
  2485. status = STATUS_INVALID_PARAMETER;
  2486. return status;
  2487. }
  2488. Peid->Prefix.Buffer = ExAllocatePoolWithTag(
  2489. PagedPool,
  2490. prefix.MaximumLength,
  2491. ' puM');
  2492. if (Peid->Prefix.Buffer == NULL)
  2493. status = STATUS_INSUFFICIENT_RESOURCES;
  2494. if (NT_SUCCESS(status)) {
  2495. Peid->ShortPrefix.Buffer = ExAllocatePoolWithTag(
  2496. PagedPool,
  2497. shortPrefix.MaximumLength,
  2498. ' puM');
  2499. if (Peid->ShortPrefix.Buffer == NULL) {
  2500. status = STATUS_INSUFFICIENT_RESOURCES;
  2501. }
  2502. }
  2503. if (NT_SUCCESS(status)) {
  2504. Peid->Prefix.Length = prefix.Length;
  2505. Peid->Prefix.MaximumLength = prefix.MaximumLength;
  2506. RtlCopyMemory(
  2507. Peid->Prefix.Buffer,
  2508. prefix.Buffer,
  2509. prefix.Length);
  2510. Peid->Prefix.Buffer[Peid->Prefix.Length/sizeof(WCHAR)] =
  2511. UNICODE_NULL;
  2512. Peid->ShortPrefix.Length = shortPrefix.Length;
  2513. Peid->ShortPrefix.MaximumLength = shortPrefix.MaximumLength;
  2514. RtlCopyMemory(
  2515. Peid->ShortPrefix.Buffer,
  2516. shortPrefix.Buffer,
  2517. shortPrefix.Length);
  2518. Peid->ShortPrefix.Buffer[Peid->ShortPrefix.Length/sizeof(WCHAR)] =
  2519. UNICODE_NULL;
  2520. }
  2521. if (!NT_SUCCESS(status)) {
  2522. if (Peid->Prefix.Buffer != NULL) {
  2523. ExFreePool( Peid->Prefix.Buffer );
  2524. Peid->Prefix.Buffer = NULL;
  2525. }
  2526. if (Peid->ShortPrefix.Buffer != NULL) {
  2527. ExFreePool( Peid->ShortPrefix.Buffer );
  2528. Peid->ShortPrefix.Buffer = NULL;
  2529. }
  2530. }
  2531. DfsDbgTrace(-1, Dbg, "PktpCreateIdFromReferral: Exit -> 0x%x\n", ULongToPtr(status) );
  2532. return( status );
  2533. }
  2534. //+----------------------------------------------------------------------------
  2535. //
  2536. // Function: PktpGetDSMachine
  2537. //
  2538. // Synopsis: Builds a DS_MACHINE with a single NetBIOS address
  2539. //
  2540. // Arguments: [ServerName] -- Name of server.
  2541. //
  2542. // Returns: If successful, a pointer to a newly allocate DS_MACHINE,
  2543. // otherwise, NULL
  2544. //
  2545. //-----------------------------------------------------------------------------
  2546. PDS_MACHINE
  2547. PktpGetDSMachine(
  2548. IN PUNICODE_STRING ServerName)
  2549. {
  2550. PDS_MACHINE pMachine = NULL;
  2551. PDS_TRANSPORT pdsTransport;
  2552. PTDI_ADDRESS_NETBIOS ptdiNB;
  2553. ANSI_STRING astrNetBios;
  2554. //
  2555. // Allocate the DS_MACHINE structure
  2556. //
  2557. pMachine = ExAllocatePoolWithTag(PagedPool, sizeof(DS_MACHINE), ' puM');
  2558. if (pMachine == NULL) {
  2559. goto Cleanup;
  2560. }
  2561. RtlZeroMemory(pMachine, sizeof(DS_MACHINE));
  2562. //
  2563. // Allocate the array of principal names
  2564. //
  2565. pMachine->cPrincipals = 1;
  2566. pMachine->prgpwszPrincipals = (LPWSTR *) ExAllocatePoolWithTag(
  2567. PagedPool,
  2568. sizeof(LPWSTR),
  2569. ' puM');
  2570. if (pMachine->prgpwszPrincipals == NULL) {
  2571. goto Cleanup;
  2572. }
  2573. //
  2574. // Allocate the principal name
  2575. //
  2576. pMachine->prgpwszPrincipals[0] = (PWCHAR) ExAllocatePoolWithTag(
  2577. PagedPool,
  2578. ServerName->MaximumLength,
  2579. ' puM');
  2580. if (pMachine->prgpwszPrincipals[0] == NULL) {
  2581. goto Cleanup;
  2582. }
  2583. RtlMoveMemory(
  2584. pMachine->prgpwszPrincipals[0],
  2585. ServerName->Buffer,
  2586. ServerName->MaximumLength);
  2587. //
  2588. // Allocate a single DS_TRANSPORT
  2589. //
  2590. pMachine->cTransports = 1;
  2591. pMachine->rpTrans[0] = (PDS_TRANSPORT) ExAllocatePoolWithTag(
  2592. PagedPool,
  2593. sizeof(DS_TRANSPORT) + sizeof(TDI_ADDRESS_NETBIOS),
  2594. ' puM');
  2595. if (pMachine->rpTrans[0] == NULL) {
  2596. goto Cleanup;
  2597. }
  2598. //
  2599. // Initialize the DS_TRANSPORT
  2600. //
  2601. pdsTransport = pMachine->rpTrans[0];
  2602. pdsTransport->usFileProtocol = FSP_SMB;
  2603. pdsTransport->iPrincipal = 0;
  2604. pdsTransport->grfModifiers = 0;
  2605. //
  2606. // Build the TA_ADDRESS_NETBIOS
  2607. //
  2608. pdsTransport->taddr.AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
  2609. pdsTransport->taddr.AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  2610. ptdiNB = (PTDI_ADDRESS_NETBIOS) &pdsTransport->taddr.Address[0];
  2611. ptdiNB->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  2612. RtlFillMemory( &ptdiNB->NetbiosName[0], 16, ' ' );
  2613. astrNetBios.Length = 0;
  2614. astrNetBios.MaximumLength = 16;
  2615. astrNetBios.Buffer = ptdiNB->NetbiosName;
  2616. RtlUnicodeStringToAnsiString(&astrNetBios, ServerName, FALSE);
  2617. return( pMachine );
  2618. Cleanup:
  2619. if (pMachine) {
  2620. PktDSMachineDestroy( pMachine, TRUE );
  2621. pMachine = NULL;
  2622. }
  2623. return( pMachine );
  2624. }
  2625. //+----------------------------------------------------------------------------
  2626. //
  2627. // Function: PktShuffleServiceList
  2628. //
  2629. // Synopsis: Randomizes a service list for proper load balancing. This
  2630. // routine assumes that the service list is ordered based on
  2631. // site costs. For each equivalent cost group, this routine
  2632. // shuffles the service list.
  2633. //
  2634. // Arguments: [pInfo] -- Pointer to PktEntryInfo whose service list needs to
  2635. // be shuffled.
  2636. //
  2637. // Returns: Nothing, unless rand() fails!
  2638. //
  2639. //-----------------------------------------------------------------------------
  2640. VOID
  2641. PktShuffleServiceList(
  2642. PDFS_PKT_ENTRY_INFO pInfo)
  2643. {
  2644. PktShuffleGroup(pInfo, 0, pInfo->ServiceCount);
  2645. }
  2646. //+----------------------------------------------------------------------------
  2647. //
  2648. // Function: PktShuffleGroup
  2649. //
  2650. // Synopsis: Shuffles a cost equivalent group of services around for load
  2651. // balancing. Uses the classic card shuffling algorithm - for
  2652. // each card in the deck, exchange it with a random card in the
  2653. // deck.
  2654. //
  2655. // Arguments:
  2656. //
  2657. // Returns:
  2658. //
  2659. //-----------------------------------------------------------------------------
  2660. VOID
  2661. PktShuffleGroup(
  2662. PDFS_PKT_ENTRY_INFO pInfo,
  2663. ULONG nStart,
  2664. ULONG nEnd)
  2665. {
  2666. ULONG i;
  2667. LARGE_INTEGER seed;
  2668. ASSERT( nStart < pInfo->ServiceCount );
  2669. ASSERT( nEnd <= pInfo->ServiceCount );
  2670. KeQuerySystemTime( &seed );
  2671. for (i = nStart; i < nEnd; i++) {
  2672. DFS_SERVICE TempService;
  2673. ULONG j;
  2674. ASSERT (nEnd - nStart != 0);
  2675. j = (RtlRandom( &seed.LowPart ) % (nEnd - nStart)) + nStart;
  2676. ASSERT( j >= nStart && j <= nEnd );
  2677. TempService = pInfo->ServiceList[i];
  2678. pInfo->ServiceList[i] = pInfo->ServiceList[j];
  2679. pInfo->ServiceList[j] = TempService;
  2680. }
  2681. }
  2682. //+----------------------------------------------------------------------------
  2683. //
  2684. // Function: DfspSetServiceListToDc
  2685. //
  2686. // Synopsis: If this is a sysvol service list, try to set the
  2687. // DC to the one we got from DsGetDcName().
  2688. //
  2689. // Arguments: [pInfo] -- Pointer to DFS_PKT_ENTRY whose service list is to
  2690. // be set.
  2691. //
  2692. //-----------------------------------------------------------------------------
  2693. NTSTATUS
  2694. DfspSetServiceListToDc(
  2695. PDFS_PKT_ENTRY pktEntry)
  2696. {
  2697. PDFS_PKT Pkt;
  2698. UNICODE_STRING DCNameShort;
  2699. PDFS_PKT_ENTRY_INFO pInfo = &pktEntry->Info;
  2700. ULONG i, pathSepCount;
  2701. UNICODE_STRING ShareName;
  2702. ShareName = (pktEntry)->Id.Prefix;
  2703. pathSepCount = 2; // 2 \ before we reach the sharename.
  2704. for (i = 0;
  2705. i < ShareName.Length/sizeof(WCHAR) && pathSepCount;
  2706. i++) {
  2707. if (ShareName.Buffer[i] == UNICODE_PATH_SEP) {
  2708. pathSepCount--;
  2709. }
  2710. }
  2711. if (pathSepCount == 0 && ShareName.Length > i) {
  2712. ShareName.Buffer += i;
  2713. ShareName.Length -= (USHORT)(i * sizeof(WCHAR));
  2714. for (i = 0;
  2715. i < ShareName.Length/sizeof(WCHAR) &&
  2716. ShareName.Buffer[i] != UNICODE_PATH_SEP;
  2717. i++) {
  2718. NOTHING;
  2719. }
  2720. ShareName.Length = (USHORT)i * sizeof(WCHAR);
  2721. ShareName.MaximumLength = ShareName.Length;
  2722. if (DfspIsSysVolShare(&ShareName) == FALSE) {
  2723. return STATUS_INVALID_PARAMETER;
  2724. }
  2725. } else {
  2726. return STATUS_INVALID_PARAMETER;
  2727. }
  2728. //
  2729. // We simply scan the list and try to match on the DC name. If we get
  2730. // a hit, set the active service pointer
  2731. //
  2732. Pkt = _GetPkt();
  2733. if ( Pkt->DCName.Length > 0 && pInfo != NULL) {
  2734. DfspDnsNameToFlatName(&Pkt->DCName, &DCNameShort);
  2735. for (i = 0; i < pInfo->ServiceCount; i++) {
  2736. if (
  2737. RtlCompareUnicodeString(&pInfo->ServiceList[i].Name, &Pkt->DCName, TRUE) == 0
  2738. ||
  2739. RtlCompareUnicodeString(&pInfo->ServiceList[i].Name, &DCNameShort, TRUE) == 0
  2740. ) {
  2741. pktEntry->ActiveService = &pInfo->ServiceList[i];
  2742. return STATUS_SUCCESS;
  2743. }
  2744. }
  2745. }
  2746. return STATUS_INVALID_PARAMETER;
  2747. }
  2748. //+----------------------------------------------------------------------------
  2749. //
  2750. // Function: PktShuffleSpecialEntryList
  2751. //
  2752. // Synopsis: Shuffles the Special Entries
  2753. //
  2754. // Arguments:
  2755. //
  2756. // Returns:
  2757. //
  2758. //-----------------------------------------------------------------------------
  2759. VOID
  2760. PktShuffleSpecialEntryList(
  2761. PDFS_SPECIAL_ENTRY pSpecialEntry)
  2762. {
  2763. ULONG i;
  2764. LARGE_INTEGER seed;
  2765. if (pSpecialEntry->ExpandedCount < 2)
  2766. return;
  2767. KeQuerySystemTime( &seed );
  2768. for (i = 0; i < pSpecialEntry->ExpandedCount; i++) {
  2769. DFS_EXPANDED_NAME TempExpandedName;
  2770. ULONG j;
  2771. j = RtlRandom( &seed.LowPart ) % pSpecialEntry->ExpandedCount;
  2772. ASSERT( j < pSpecialEntry->ExpandedCount );
  2773. TempExpandedName = pSpecialEntry->ExpandedNames[i];
  2774. pSpecialEntry->ExpandedNames[i] = pSpecialEntry->ExpandedNames[j];
  2775. pSpecialEntry->ExpandedNames[j] = TempExpandedName;
  2776. }
  2777. }
  2778. //+----------------------------------------------------------------------------
  2779. //
  2780. // Function: PktSetSpecialEntryListToDc
  2781. //
  2782. // Synopsis: Sets the Special list active selection to the DC we got
  2783. // from DsGetDcName()
  2784. //
  2785. // Arguments:
  2786. //
  2787. // Returns:
  2788. //
  2789. //-----------------------------------------------------------------------------
  2790. VOID
  2791. PktSetSpecialEntryListToDc(
  2792. PDFS_SPECIAL_ENTRY pSpecialEntry)
  2793. {
  2794. PDFS_PKT Pkt;
  2795. //
  2796. // Set the 'active' entry to be the DC that DsGetDcName() gave us, if this is
  2797. // the current domain.
  2798. //
  2799. Pkt = _GetPkt();
  2800. //
  2801. // If in our domain, start with DC last fetched by DsGetDcName()
  2802. //
  2803. if (
  2804. Pkt->DCName.Length > 0
  2805. &&
  2806. Pkt->DomainNameFlat.Length > 0
  2807. &&
  2808. Pkt->DomainNameDns.Length > 0
  2809. &&
  2810. (RtlCompareUnicodeString(&pSpecialEntry->SpecialName, &Pkt->DomainNameFlat, TRUE) == 0
  2811. ||
  2812. RtlCompareUnicodeString(&pSpecialEntry->SpecialName, &Pkt->DomainNameDns, TRUE) == 0)
  2813. ) {
  2814. UNICODE_STRING DCNameShort;
  2815. PUNICODE_STRING pExpandedName;
  2816. ULONG EntryIdx;
  2817. #if DBG
  2818. if (MupVerbose)
  2819. DbgPrint(" PktSetSpecialEntryListToDc(SpecialName=[%wZ] Flat=[%wZ] Dns=[%wZ])\n",
  2820. &pSpecialEntry->SpecialName,
  2821. &Pkt->DomainNameFlat,
  2822. &Pkt->DomainNameDns);
  2823. #endif
  2824. DfspDnsNameToFlatName(&Pkt->DCName, &DCNameShort);
  2825. for (EntryIdx = 0; EntryIdx < pSpecialEntry->ExpandedCount; EntryIdx++) {
  2826. pExpandedName = &pSpecialEntry->ExpandedNames[EntryIdx].ExpandedName;
  2827. if (
  2828. RtlCompareUnicodeString(&Pkt->DCName, pExpandedName, TRUE) == 0
  2829. ||
  2830. RtlCompareUnicodeString(&DCNameShort, pExpandedName, TRUE) == 0
  2831. ) {
  2832. pSpecialEntry->Active = EntryIdx;
  2833. #if DBG
  2834. if (MupVerbose)
  2835. DbgPrint(" EntryIdx=%d\n", EntryIdx);
  2836. #endif
  2837. break;
  2838. }
  2839. }
  2840. }
  2841. }
  2842. //+----------------------------------------------------------------------------
  2843. //
  2844. // Function: PktParsePrefix
  2845. //
  2846. // Synopsis: Helper routine to break a path into domain, share, remainder
  2847. //
  2848. // Arguments: [Path] -- PUNICODE string of path to parse
  2849. //
  2850. // Returns: [MachineName] -- UNICODE_STRING containing MachineName, if present
  2851. // [ShareName] -- UNICODE_STRING containing ShareName, if present
  2852. // [Remainder] -- UNICODE_STRING containing remainder of Path
  2853. //
  2854. //-----------------------------------------------------------------------------
  2855. VOID
  2856. PktParsePath(
  2857. IN PUNICODE_STRING PathName,
  2858. OUT PUNICODE_STRING MachineName,
  2859. OUT PUNICODE_STRING ShareName,
  2860. OUT PUNICODE_STRING Remainder OPTIONAL)
  2861. {
  2862. LPWSTR ustrp, ustart, uend;
  2863. DfsDbgTrace(+1, Dbg, "PktParsePath(%wZ)\n", PathName);
  2864. RtlInitUnicodeString(MachineName, NULL);
  2865. RtlInitUnicodeString(ShareName, NULL);
  2866. if (ARGUMENT_PRESENT(Remainder)) {
  2867. RtlInitUnicodeString(Remainder, NULL);
  2868. }
  2869. // Be sure there's something to do
  2870. if (PathName->Length == 0) {
  2871. DfsDbgTrace(-1, Dbg, "PathName is empty\n",0 );
  2872. return;
  2873. }
  2874. // Skip leading '\'s
  2875. ustart = ustrp = PathName->Buffer;
  2876. uend = &PathName->Buffer[PathName->Length / sizeof(WCHAR)] - 1;
  2877. // strip trailing nulls
  2878. while (uend >= ustart && *uend == UNICODE_NULL)
  2879. uend--;
  2880. while (ustrp <= uend && *ustrp == UNICODE_PATH_SEP)
  2881. ustrp++;
  2882. // MachineName
  2883. ustart = ustrp;
  2884. while (ustrp <= uend && *ustrp != UNICODE_PATH_SEP)
  2885. ustrp++;
  2886. if (ustrp != ustart) {
  2887. MachineName->Buffer = ustart;
  2888. MachineName->Length = (USHORT)(ustrp - ustart) * sizeof(WCHAR);
  2889. MachineName->MaximumLength = MachineName->Length;
  2890. // ShareName
  2891. ustart = ++ustrp;
  2892. while (ustrp <= uend && *ustrp != UNICODE_PATH_SEP)
  2893. ustrp++;
  2894. if (ustrp != ustart) {
  2895. ShareName->Buffer = ustart;
  2896. ShareName->Length = (USHORT)(ustrp - ustart) * sizeof(WCHAR);
  2897. ShareName->MaximumLength = ShareName->Length;
  2898. // Remainder is whatever's left
  2899. ustart = ++ustrp;
  2900. while (ustrp <= uend)
  2901. ustrp++;
  2902. if (ustrp != ustart && ARGUMENT_PRESENT(Remainder)) {
  2903. Remainder->Buffer = ustart;
  2904. Remainder->Length = (USHORT)(ustrp - ustart) * sizeof(WCHAR);
  2905. Remainder->MaximumLength = Remainder->Length;
  2906. }
  2907. }
  2908. }
  2909. DfsDbgTrace( 0, Dbg, "PktParsePath: MachineName -> %wZ\n", MachineName);
  2910. if (!ARGUMENT_PRESENT(Remainder)) {
  2911. DfsDbgTrace(-1, Dbg, " ShareName -> %wZ\n", ShareName);
  2912. } else {
  2913. DfsDbgTrace( 0, Dbg, " ShareName -> %wZ\n", ShareName);
  2914. DfsDbgTrace(-1, Dbg, " Remainder -> %wZ\n", Remainder);
  2915. }
  2916. }
  2917. //+--------------------------------------------------------------------
  2918. //
  2919. // Function: PktExpandSpecialName
  2920. //
  2921. // Synopsis: This function is called to expand a Special name into a list
  2922. // of Names. It returns a pointer to an array of DFS_SPECIAL_ENTRY's
  2923. //
  2924. // Arguments: Name - Name to expand
  2925. // ppSpecialEntry - pointer to pointer for results
  2926. //
  2927. // Returns: STATUS_SUCCESS
  2928. // STATUS_BAD_NETWORK_PATH
  2929. // STATUS_INSUFFICIENT_RESOURCES
  2930. //
  2931. //---------------------------------------------------------------------
  2932. NTSTATUS
  2933. _PktExpandSpecialName(
  2934. PUNICODE_STRING Name,
  2935. PDFS_SPECIAL_ENTRY *ppSpecialEntry)
  2936. {
  2937. NTSTATUS status;
  2938. HANDLE hServer = NULL;
  2939. DFS_SERVICE service;
  2940. PPROVIDER_DEF provider;
  2941. PREQ_GET_DFS_REFERRAL ref = NULL;
  2942. ULONG refSize = 0;
  2943. UNICODE_STRING refPath;
  2944. IO_STATUS_BLOCK iosb;
  2945. BOOLEAN attachedToSystemProcess = FALSE;
  2946. PDFS_SPECIAL_ENTRY pSpecialEntry;
  2947. PDFS_PKT Pkt;
  2948. BOOLEAN pktLocked;
  2949. PDFS_SPECIAL_TABLE pSpecial = &DfsData.Pkt.SpecialTable;
  2950. LARGE_INTEGER now;
  2951. KAPC_STATE ApcState;
  2952. ULONG MaxReferralLength;
  2953. SE_IMPERSONATION_STATE DisabledImpersonationState;
  2954. BOOLEAN RestoreImpersonationState = FALSE;
  2955. LARGE_INTEGER StartTime;
  2956. LARGE_INTEGER EndTime;
  2957. PUNICODE_STRING origDCName;
  2958. UNICODE_STRING DCName;
  2959. DfsDbgTrace(+1, Dbg, "PktExpandSpecialName(%wZ)\n", Name);
  2960. DCName.Buffer = NULL;
  2961. KeQuerySystemTime(&StartTime);
  2962. #if DBG
  2963. if (MupVerbose) {
  2964. KeQuerySystemTime(&EndTime);
  2965. DbgPrint("[%d] PktExpandSpecialName: Name %wZ \n",
  2966. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  2967. Name);
  2968. }
  2969. #endif
  2970. *ppSpecialEntry = NULL;
  2971. Pkt = _GetPkt();
  2972. PktAcquireShared(TRUE, &pktLocked);
  2973. if (Pkt->SpecialTable.SpecialEntryCount == 0) {
  2974. PktRelease();
  2975. pktLocked = FALSE;
  2976. status = STATUS_BAD_NETWORK_PATH;
  2977. MUP_TRACE_HIGH(ERROR, _PktExpandSpecialName_Error_NoSpecialReferralTable,
  2978. LOGSTATUS(status)
  2979. LOGUSTR(*Name));
  2980. DfsDbgTrace( 0, Dbg, "No special referral table.\n", 0);
  2981. DfsDbgTrace(-1, Dbg, "PktExpandSpecialName returning %08lx\n", ULongToPtr(status) );
  2982. return (status);
  2983. }
  2984. pSpecialEntry = PktLookupSpecialNameEntry(Name);
  2985. //
  2986. // We don't have any expansion for this name
  2987. //
  2988. if (pSpecialEntry == NULL) {
  2989. PktRelease();
  2990. pktLocked = FALSE;
  2991. status = STATUS_BAD_NETWORK_PATH;
  2992. MUP_TRACE_HIGH(ERROR, _PktExpandSpecialName_Error_NotInSpecialReferralTable,
  2993. LOGUSTR(*Name)
  2994. LOGSTATUS(status));
  2995. DfsDbgTrace( 0, Dbg, "... not in SpecialName table(cache miss)\n", 0);
  2996. DfsDbgTrace(-1, Dbg, "PktExpandSpecialName returning %08lx\n", ULongToPtr(status) );
  2997. return (status);
  2998. }
  2999. origDCName = &pSpecialEntry->DCName;
  3000. if (origDCName->Buffer == NULL) {
  3001. origDCName = &Pkt->DCName;
  3002. }
  3003. DfsDbgTrace( 0, Dbg, "Expanded Referral DCName = %wZ\n", origDCName);
  3004. //
  3005. // We have a (potential) expansion
  3006. //
  3007. if (origDCName->Buffer == NULL) {
  3008. status = STATUS_BAD_NETWORK_PATH;
  3009. MUP_TRACE_HIGH(ERROR, _PktExpandSpecialName_Error_DCNameNotInitialized,
  3010. LOGSTATUS(status)
  3011. LOGUSTR(*Name));
  3012. DfsDbgTrace( 0, Dbg, "PktExpandSpecialName:DCName not initialized - \n", 0);
  3013. DfsDbgTrace(-1, Dbg, "PktExpandSpecialName returning %08lx\n", ULongToPtr(status) );
  3014. PktRelease();
  3015. pktLocked = FALSE;
  3016. return (status);
  3017. }
  3018. InterlockedIncrement(&pSpecialEntry->UseCount);
  3019. if (pSpecialEntry->Stale == FALSE && pSpecialEntry->NeedsExpansion == FALSE) {
  3020. PktRelease();
  3021. pktLocked = FALSE;
  3022. *ppSpecialEntry = pSpecialEntry;
  3023. status = STATUS_SUCCESS;
  3024. DfsDbgTrace( 0, Dbg, "... found in Special Name table (cache hit 1)\n", 0);
  3025. DfsDbgTrace(-1, Dbg, "PktExpandSpecialName returning %08lx\n", ULongToPtr(status) );
  3026. return (status);
  3027. }
  3028. //
  3029. // It's in the special name table, but needs to be expanded or refreshed
  3030. //
  3031. ASSERT(pSpecialEntry->NeedsExpansion == TRUE || pSpecialEntry->Stale == TRUE);
  3032. // Now copy the DC we are going to use before releasing the lock.
  3033. DCName.Buffer = ExAllocatePoolWithTag(
  3034. PagedPool,
  3035. origDCName->MaximumLength,
  3036. ' puM');
  3037. if (DCName.Buffer == NULL) {
  3038. status = STATUS_INSUFFICIENT_RESOURCES;
  3039. MUP_TRACE_HIGH(ERROR, _PktExpandSpecialName_Error_ExAllocatePoolWithTag,
  3040. LOGSTATUS(status)
  3041. LOGUSTR(*Name));
  3042. DfsDbgTrace(-1, Dbg, "PktExpandSpecialName returning %08lx\n", ULongToPtr(status) );
  3043. PktRelease();
  3044. pktLocked = FALSE;
  3045. return (status);
  3046. }
  3047. DCName.Length = origDCName->Length;
  3048. DCName.MaximumLength = origDCName->MaximumLength;
  3049. RtlCopyMemory(
  3050. DCName.Buffer,
  3051. origDCName->Buffer,
  3052. origDCName->MaximumLength);
  3053. PktRelease();
  3054. pktLocked = FALSE;
  3055. DfsDbgTrace( 0, Dbg, "... in special name table (cache hit 2)\n", 0);
  3056. //
  3057. // get a provider and service describing the remote server.
  3058. //
  3059. provider = ReplLookupProvider( PROV_ID_DFS_RDR );
  3060. if (provider == NULL) {
  3061. DfsDbgTrace(-1, Dbg, "Unable to open LM Rdr!\n", 0);
  3062. status = STATUS_BAD_NETWORK_PATH;
  3063. MUP_TRACE_HIGH(ERROR, _PktExpandSpecialName_Error_UnableToOpenRdr,
  3064. LOGSTATUS(status)
  3065. LOGUSTR(*Name));
  3066. goto Cleanup;
  3067. }
  3068. RtlZeroMemory( &service, sizeof(DFS_SERVICE) );
  3069. status = PktServiceConstruct(
  3070. &service,
  3071. DFS_SERVICE_TYPE_MASTER | DFS_SERVICE_TYPE_REFERRAL,
  3072. PROV_DFS_RDR,
  3073. STATUS_SUCCESS,
  3074. PROV_ID_DFS_RDR,
  3075. &DCName,
  3076. NULL);
  3077. DfsDbgTrace(0, Dbg, "PktServiceConstruct returned %08lx\n", ULongToPtr(status) );
  3078. //
  3079. // Next, we build a connection to this machine and ask it for a referral.
  3080. //
  3081. if (NT_SUCCESS(status)) {
  3082. PktAcquireShared( TRUE, &pktLocked );
  3083. if (PsGetCurrentProcess() != DfsData.OurProcess) {
  3084. KeStackAttachProcess( DfsData.OurProcess, &ApcState );
  3085. attachedToSystemProcess = TRUE;
  3086. }
  3087. RestoreImpersonationState = PsDisableImpersonation(
  3088. PsGetCurrentThread(),
  3089. &DisabledImpersonationState);
  3090. status = DfsCreateConnection(
  3091. &service,
  3092. provider,
  3093. FALSE,
  3094. &hServer);
  3095. #if DBG
  3096. if (MupVerbose) {
  3097. KeQuerySystemTime(&EndTime);
  3098. DbgPrint(" [%d] DfsCreateConnection to %wZ returned 0x%x\n",
  3099. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  3100. &DCName,
  3101. status);
  3102. }
  3103. #endif
  3104. if (!NT_SUCCESS(status) && DfsEventLog > 0)
  3105. LogWriteMessage(DFS_CONNECTION_FAILURE, status, 1, &DCName);
  3106. PktRelease();
  3107. pktLocked = FALSE;
  3108. DfsDbgTrace(0, Dbg, "DfsCreateConnection returned %08lx\n", ULongToPtr(status) );
  3109. }
  3110. MaxReferralLength = MAX_REFERRAL_LENGTH;
  3111. Retry:
  3112. RtlZeroMemory( &refPath, sizeof(UNICODE_STRING) );
  3113. if (NT_SUCCESS(status)) {
  3114. ULONG ReferralSize = 0;
  3115. refPath.Length = 0;
  3116. refPath.MaximumLength = sizeof(UNICODE_PATH_SEP) +
  3117. Name->Length +
  3118. sizeof(UNICODE_NULL);
  3119. ReferralSize = refPath.MaximumLength + sizeof(REQ_GET_DFS_REFERRAL);
  3120. if (ReferralSize > MAX_REFERRAL_MAX) {
  3121. status = STATUS_INVALID_PARAMETER;
  3122. }
  3123. else if (MaxReferralLength < ReferralSize)
  3124. {
  3125. MaxReferralLength = ReferralSize;
  3126. }
  3127. if (NT_SUCCESS(status)) {
  3128. refPath.Buffer = ExAllocatePoolWithTag( NonPagedPool,
  3129. refPath.MaximumLength + MaxReferralLength,
  3130. ' puM');
  3131. if (refPath.Buffer != NULL) {
  3132. ref = (PREQ_GET_DFS_REFERRAL)
  3133. &refPath.Buffer[refPath.MaximumLength / sizeof(WCHAR)];
  3134. RtlAppendUnicodeToString( &refPath, UNICODE_PATH_SEP_STR);
  3135. RtlAppendUnicodeStringToString( &refPath, Name);
  3136. refPath.Buffer[ refPath.Length / sizeof(WCHAR) ] = UNICODE_NULL;
  3137. ref->MaxReferralLevel = 3;
  3138. RtlMoveMemory(&ref->RequestFileName[0],
  3139. refPath.Buffer,
  3140. refPath.Length + sizeof(WCHAR));
  3141. DfsDbgTrace(0, Dbg, "Referral Path : %ws\n", ref->RequestFileName);
  3142. refSize = sizeof(USHORT) + refPath.Length + sizeof(WCHAR);
  3143. DfsDbgTrace(0, Dbg, "Referral Size is %d bytes\n", ULongToPtr(refSize) );
  3144. } else {
  3145. DfsDbgTrace(0, Dbg, "Unable to allocate %d bytes\n",
  3146. ULongToPtr(refPath.MaximumLength + MaxReferralLength));
  3147. status = STATUS_INSUFFICIENT_RESOURCES;
  3148. }
  3149. }
  3150. }
  3151. if (NT_SUCCESS(status)) {
  3152. DfsDbgTrace(0, Dbg, "Ref Buffer @%08lx\n", ref);
  3153. status = ZwFsControlFile(
  3154. hServer, // Target
  3155. NULL, // Event
  3156. NULL, // APC Routine
  3157. NULL, // APC Context,
  3158. &iosb, // Io Status block
  3159. FSCTL_DFS_GET_REFERRALS, // FS Control code
  3160. (PVOID) ref, // Input Buffer
  3161. refSize, // Input Buffer Length
  3162. (PVOID) ref, // Output Buffer
  3163. MaxReferralLength); // Output Buffer Length
  3164. MUP_TRACE_ERROR_HIGH(status, ALL_ERROR, _PktExpandSpecialName_Error_ZwFsControlFile,
  3165. LOGUSTR(*Name)
  3166. LOGSTATUS(status));
  3167. DfsDbgTrace(0, Dbg, "Fscontrol returned %08lx\n", ULongToPtr(status) );
  3168. #if DBG
  3169. if (MupVerbose) {
  3170. KeQuerySystemTime(&EndTime);
  3171. DbgPrint(" [%d] ZwFsControlFile returned 0x%x\n",
  3172. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  3173. status);
  3174. }
  3175. #endif
  3176. }
  3177. //
  3178. // Use the referral to expand the entry
  3179. //
  3180. if (NT_SUCCESS(status)) {
  3181. PktAcquireExclusive(TRUE, &pktLocked );
  3182. status = PktExpandSpecialEntryFromReferral(
  3183. &DfsData.Pkt,
  3184. &refPath,
  3185. (ULONG)iosb.Information,
  3186. (PRESP_GET_DFS_REFERRAL) ref,
  3187. pSpecialEntry);
  3188. DfsDbgTrace(0, Dbg, "PktExpandSpecialEntryFromReferral returned %08lx\n",
  3189. ULongToPtr(status) );
  3190. } else if (status == STATUS_BUFFER_OVERFLOW && (refPath.Buffer != NULL) && MaxReferralLength < MAX_REFERRAL_MAX) {
  3191. //
  3192. // The referral didn't fit in the buffer supplied. Make it bigger and try
  3193. // again.
  3194. //
  3195. DfsDbgTrace(0, Dbg, "PktGetSpecialReferralTable: MaxReferralLength %d too small\n",
  3196. ULongToPtr(MaxReferralLength) );
  3197. ExFreePool(refPath.Buffer);
  3198. refPath.Buffer = NULL;
  3199. MaxReferralLength *= 2;
  3200. if (MaxReferralLength > MAX_REFERRAL_MAX)
  3201. MaxReferralLength = MAX_REFERRAL_MAX;
  3202. status = STATUS_SUCCESS;
  3203. goto Retry;
  3204. }
  3205. if (NT_SUCCESS(status) ||
  3206. ((pSpecialEntry->NeedsExpansion == FALSE) &&
  3207. (status != STATUS_NO_SUCH_DEVICE))) {
  3208. *ppSpecialEntry = pSpecialEntry;
  3209. status = STATUS_SUCCESS;
  3210. } else {
  3211. InterlockedDecrement(&pSpecialEntry->UseCount);
  3212. }
  3213. if (pktLocked) {
  3214. PktRelease();
  3215. pktLocked = FALSE;
  3216. }
  3217. //
  3218. // Well, we are done. Cleanup all the things we allocated...
  3219. //
  3220. PktServiceDestroy( &service, FALSE );
  3221. if (hServer != NULL) {
  3222. ZwClose( hServer );
  3223. }
  3224. if (refPath.Buffer != NULL) {
  3225. ExFreePool( refPath.Buffer );
  3226. }
  3227. if (attachedToSystemProcess) {
  3228. KeUnstackDetachProcess(&ApcState);
  3229. }
  3230. if (RestoreImpersonationState) {
  3231. PsRestoreImpersonation(
  3232. PsGetCurrentThread(),
  3233. &DisabledImpersonationState);
  3234. }
  3235. if (status != STATUS_SUCCESS && status != STATUS_INSUFFICIENT_RESOURCES) {
  3236. status = STATUS_BAD_NETWORK_PATH;
  3237. }
  3238. #if DBG
  3239. if (MupVerbose) {
  3240. KeQuerySystemTime(&EndTime);
  3241. DbgPrint("[%d] PktExpandSpecialName exit 0x%x\n",
  3242. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  3243. status);
  3244. }
  3245. #endif
  3246. Cleanup:
  3247. if (DCName.Buffer != NULL)
  3248. ExFreePool( DCName.Buffer );
  3249. DfsDbgTrace(-1, Dbg, "PktExpandSpecialName returning %08lx\n", ULongToPtr(status) );
  3250. return( status );
  3251. }
  3252. //+--------------------------------------------------------------------
  3253. //
  3254. // Function: PktGetSpecialReferralTable
  3255. //
  3256. // Synopsis: This function is called to load the special name table.
  3257. //
  3258. // Arguments: [machine] - Machine to contact
  3259. // [systemDC] - true if the table uses the pkt->dcname.
  3260. //
  3261. // Returns: STATUS_SUCCESS
  3262. // STATUS_BAD_NETWORK_PATH
  3263. // STATUS_INSUFFICIENT_RESOURCES
  3264. //
  3265. //---------------------------------------------------------------------
  3266. NTSTATUS
  3267. _PktGetSpecialReferralTable(
  3268. PUNICODE_STRING Machine,
  3269. BOOLEAN SystemDC)
  3270. {
  3271. NTSTATUS status;
  3272. HANDLE hServer = NULL;
  3273. DFS_SERVICE service;
  3274. PPROVIDER_DEF provider;
  3275. PREQ_GET_DFS_REFERRAL ref = NULL;
  3276. ULONG refSize = 0;
  3277. UNICODE_STRING refPath;
  3278. IO_STATUS_BLOCK iosb;
  3279. BOOLEAN attachedToSystemProcess = FALSE;
  3280. PDFS_SPECIAL_ENTRY pSpecialEntry;
  3281. PDFS_PKT Pkt;
  3282. BOOLEAN pktLocked = FALSE;
  3283. PDFS_SPECIAL_TABLE pSpecial = &DfsData.Pkt.SpecialTable;
  3284. LARGE_INTEGER now;
  3285. KAPC_STATE ApcState;
  3286. ULONG MaxReferralLength;
  3287. SE_IMPERSONATION_STATE DisabledImpersonationState;
  3288. BOOLEAN RestoreImpersonationState = FALSE;
  3289. LARGE_INTEGER StartTime;
  3290. LARGE_INTEGER EndTime;
  3291. DfsDbgTrace(+1, Dbg, "PktGetSpecialReferralTable(%wZ)\n", Machine);
  3292. KeQuerySystemTime(&StartTime);
  3293. #if DBG
  3294. if (MupVerbose) {
  3295. KeQuerySystemTime(&EndTime);
  3296. DbgPrint("[%d] PktGetSpecialReferralTable(%wZ)\n",
  3297. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  3298. Machine);
  3299. }
  3300. #endif
  3301. provider = ReplLookupProvider( PROV_ID_DFS_RDR );
  3302. if (provider == NULL) {
  3303. DfsDbgTrace(-1, Dbg, "Unable to open LM Rdr!\n", 0);
  3304. return( STATUS_BAD_NETWORK_PATH );
  3305. }
  3306. RtlZeroMemory( &service, sizeof(DFS_SERVICE) );
  3307. status = PktServiceConstruct(
  3308. &service,
  3309. DFS_SERVICE_TYPE_MASTER | DFS_SERVICE_TYPE_REFERRAL,
  3310. PROV_DFS_RDR,
  3311. STATUS_SUCCESS,
  3312. PROV_ID_DFS_RDR,
  3313. Machine,
  3314. NULL);
  3315. DfsDbgTrace(0, Dbg, "PktServiceConstruct returned %08lx\n", ULongToPtr(status) );
  3316. //
  3317. // Next, we build a connection to this machine and ask it for a referral.
  3318. //
  3319. if (NT_SUCCESS(status)) {
  3320. PktAcquireShared( TRUE, &pktLocked );
  3321. if (PsGetCurrentProcess() != DfsData.OurProcess) {
  3322. KeStackAttachProcess( DfsData.OurProcess, &ApcState );
  3323. attachedToSystemProcess = TRUE;
  3324. }
  3325. RestoreImpersonationState = PsDisableImpersonation(
  3326. PsGetCurrentThread(),
  3327. &DisabledImpersonationState);
  3328. status = DfsCreateConnection(
  3329. &service,
  3330. provider,
  3331. FALSE,
  3332. &hServer);
  3333. #if DBG
  3334. if (MupVerbose) {
  3335. KeQuerySystemTime(&EndTime);
  3336. DbgPrint(" [%d] DfsCreateConnection returned 0x%x\n",
  3337. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  3338. status);
  3339. }
  3340. #endif
  3341. if (!NT_SUCCESS(status) && DfsEventLog > 0)
  3342. LogWriteMessage(DFS_CONNECTION_FAILURE, status, 1, Machine);
  3343. PktRelease();
  3344. pktLocked = FALSE;
  3345. DfsDbgTrace(0, Dbg, "DfsCreateConnection returned %08lx\n", ULongToPtr(status) );
  3346. }
  3347. MaxReferralLength = MAX_REFERRAL_LENGTH;
  3348. Retry:
  3349. RtlZeroMemory( &refPath, sizeof(UNICODE_STRING) );
  3350. if (NT_SUCCESS(status)) {
  3351. ULONG ReferralSize = 0;
  3352. refPath.Length = 0;
  3353. refPath.MaximumLength = sizeof(UNICODE_NULL);
  3354. ReferralSize = refPath.MaximumLength + sizeof(REQ_GET_DFS_REFERRAL);
  3355. if (ReferralSize > MAX_REFERRAL_MAX) {
  3356. status = STATUS_INVALID_PARAMETER;
  3357. }
  3358. else if (MaxReferralLength < ReferralSize)
  3359. {
  3360. MaxReferralLength = ReferralSize;
  3361. }
  3362. if (NT_SUCCESS(status)) {
  3363. refPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
  3364. refPath.MaximumLength + MaxReferralLength,
  3365. ' puM');
  3366. if (refPath.Buffer != NULL) {
  3367. ref = (PREQ_GET_DFS_REFERRAL)
  3368. &refPath.Buffer[refPath.MaximumLength / sizeof(WCHAR)];
  3369. refPath.Buffer[ refPath.Length / sizeof(WCHAR) ] = UNICODE_NULL;
  3370. ref->MaxReferralLevel = 3;
  3371. RtlMoveMemory(&ref->RequestFileName[0],
  3372. refPath.Buffer,
  3373. refPath.Length + sizeof(WCHAR));
  3374. DfsDbgTrace(0, Dbg, "Referral Path : (%ws)\n", ref->RequestFileName);
  3375. refSize = sizeof(USHORT) + refPath.Length + sizeof(WCHAR);
  3376. DfsDbgTrace(0, Dbg, "Referral Size is %d bytes\n", ULongToPtr(refSize) );
  3377. } else {
  3378. DfsDbgTrace(0, Dbg, "Unable to allocate %d bytes\n",
  3379. ULongToPtr(refPath.MaximumLength + MaxReferralLength));
  3380. status = STATUS_INSUFFICIENT_RESOURCES;
  3381. }
  3382. }
  3383. }
  3384. if (NT_SUCCESS(status)) {
  3385. DfsDbgTrace(0, Dbg, "Ref Buffer @%08lx\n", ref);
  3386. status = ZwFsControlFile(
  3387. hServer, // Target
  3388. NULL, // Event
  3389. NULL, // APC Routine
  3390. NULL, // APC Context,
  3391. &iosb, // Io Status block
  3392. FSCTL_DFS_GET_REFERRALS, // FS Control code
  3393. (PVOID) ref, // Input Buffer
  3394. refSize, // Input Buffer Length
  3395. (PVOID) ref, // Output Buffer
  3396. MaxReferralLength); // Output Buffer Length
  3397. DfsDbgTrace(0, Dbg, "Fscontrol returned %08lx\n", ULongToPtr(status) );
  3398. #if DBG
  3399. if (MupVerbose) {
  3400. KeQuerySystemTime(&EndTime);
  3401. DbgPrint(" [%d] ZwFsControlFile returned 0x%x\n",
  3402. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  3403. status);
  3404. }
  3405. #endif
  3406. }
  3407. //
  3408. // Use the referral to expand the entry
  3409. //
  3410. if (NT_SUCCESS(status)) {
  3411. PktAcquireExclusive( TRUE, &pktLocked );
  3412. status = PktCreateSpecialEntryTableFromReferral(
  3413. &DfsData.Pkt,
  3414. &refPath,
  3415. (ULONG)iosb.Information,
  3416. (PRESP_GET_DFS_REFERRAL) ref,
  3417. (SystemDC == TRUE) ? NULL : Machine);
  3418. DfsDbgTrace(0, Dbg, "PktGetSpecialReferralTable returned %08lx\n",
  3419. ULongToPtr(status) );
  3420. } else if (status == STATUS_BUFFER_OVERFLOW && (refPath.Buffer!= NULL) && MaxReferralLength < MAX_REFERRAL_MAX) {
  3421. //
  3422. // The referral didn't fit in the buffer supplied. Make it bigger and try
  3423. // again.
  3424. //
  3425. DfsDbgTrace(0, Dbg, "PktGetSpecialReferralTable: MaxReferralLength %d too small\n",
  3426. ULongToPtr(MaxReferralLength) );
  3427. ExFreePool(refPath.Buffer);
  3428. refPath.Buffer = NULL;
  3429. MaxReferralLength *= 2;
  3430. if (MaxReferralLength > MAX_REFERRAL_MAX)
  3431. MaxReferralLength = MAX_REFERRAL_MAX;
  3432. status = STATUS_SUCCESS;
  3433. goto Retry;
  3434. }
  3435. if (!NT_SUCCESS(status) && DfsEventLog > 0)
  3436. LogWriteMessage(DFS_SPECIAL_REFERRAL_FAILURE, status, 1, Machine);
  3437. if (pktLocked) {
  3438. PktRelease();
  3439. pktLocked = FALSE;
  3440. }
  3441. //
  3442. // Well, we are done. Cleanup all the things we allocated...
  3443. //
  3444. PktServiceDestroy( &service, FALSE );
  3445. if (hServer != NULL) {
  3446. ZwClose( hServer );
  3447. }
  3448. if (refPath.Buffer != NULL) {
  3449. ExFreePool( refPath.Buffer );
  3450. }
  3451. if (attachedToSystemProcess) {
  3452. KeUnstackDetachProcess(&ApcState);
  3453. }
  3454. if (RestoreImpersonationState) {
  3455. PsRestoreImpersonation(
  3456. PsGetCurrentThread(),
  3457. &DisabledImpersonationState);
  3458. }
  3459. DfsDbgTrace(-1, Dbg, "PktGetSpecialReferralTable returning %08lx\n", ULongToPtr(status) );
  3460. #if DBG
  3461. if (MupVerbose) {
  3462. KeQuerySystemTime(&EndTime);
  3463. DbgPrint("[%d] PktGetSpecialReferralTable exit 0x%x\n",
  3464. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  3465. status);
  3466. }
  3467. #endif
  3468. return( status );
  3469. }
  3470. //+--------------------------------------------------------------------
  3471. //
  3472. // Function: PktLookupSpecialEntry
  3473. //
  3474. // Synopsis: Looks up a PDFS_SPECIAL_ENTRY by name in the pkt
  3475. //
  3476. // Arguments: Name - Name to search on
  3477. //
  3478. // Returns: [pointer] PDFS_SPECIAL_ENTRY, if found
  3479. // [pointer] NULL, if not found
  3480. //
  3481. //---------------------------------------------------------------------
  3482. PDFS_SPECIAL_ENTRY
  3483. PktLookupSpecialNameEntry(
  3484. PUNICODE_STRING Name)
  3485. {
  3486. PDFS_SPECIAL_ENTRY pSpecialEntry;
  3487. PDFS_SPECIAL_TABLE pSpecialTable;
  3488. PDFS_PKT Pkt;
  3489. ULONG i;
  3490. DfsDbgTrace(+1, Dbg, "PktLookupSpecialNameEntry(%wZ)\n", Name);
  3491. Pkt = _GetPkt();
  3492. pSpecialTable = &Pkt->SpecialTable;
  3493. if (pSpecialTable->SpecialEntryCount == 0) {
  3494. return (NULL);
  3495. }
  3496. DfsDbgTrace( 0, Dbg, "Cache contains %d entries...\n", ULongToPtr(pSpecialTable->SpecialEntryCount) );
  3497. pSpecialEntry = CONTAINING_RECORD(
  3498. pSpecialTable->SpecialEntryList.Flink,
  3499. DFS_SPECIAL_ENTRY,
  3500. Link);
  3501. for (i = 0; i < pSpecialTable->SpecialEntryCount; i++) {
  3502. DfsDbgTrace( 0, Dbg, "Comparing with %wZ\n", &pSpecialEntry->SpecialName);
  3503. if (RtlCompareUnicodeString(Name, &pSpecialEntry->SpecialName, TRUE) == 0) {
  3504. DfsDbgTrace( 0, Dbg, "Cache hit\n", 0);
  3505. DfsDbgTrace(-1, Dbg, "returning 0x%x\n", pSpecialEntry);
  3506. return (pSpecialEntry);
  3507. }
  3508. pSpecialEntry = CONTAINING_RECORD(
  3509. pSpecialEntry->Link.Flink,
  3510. DFS_SPECIAL_ENTRY,
  3511. Link);
  3512. }
  3513. //
  3514. // Nothing found
  3515. //
  3516. DfsDbgTrace(-1, Dbg, "PktLookupSpecialNameEntry: returning NULL\n", 0);
  3517. return (NULL);
  3518. }
  3519. //+--------------------------------------------------------------------
  3520. //
  3521. // Function: PktCreateSpecialNameEntry
  3522. //
  3523. // Synopsis: Inserts a DFS_SPECIAL_ENTRY into the pkt, on a best-effort
  3524. // basis.
  3525. //
  3526. // Arguments: pSpecialEntry - Entry to insert
  3527. //
  3528. // Returns: STATUS_SUCCESS
  3529. //
  3530. //---------------------------------------------------------------------
  3531. NTSTATUS
  3532. PktCreateSpecialNameEntry(
  3533. PDFS_SPECIAL_ENTRY pSpecialEntry)
  3534. {
  3535. PDFS_PKT Pkt;
  3536. PDFS_SPECIAL_TABLE pSpecialTable;
  3537. PDFS_SPECIAL_ENTRY pExistingEntry;
  3538. Pkt = _GetPkt();
  3539. pSpecialTable = &Pkt->SpecialTable;
  3540. DfsDbgTrace(+1, Dbg, "PktCreateSpecialNameEntry entered\n", 0);
  3541. pExistingEntry = PktLookupSpecialNameEntry(&pSpecialEntry->SpecialName);
  3542. if (pExistingEntry == NULL) {
  3543. //
  3544. // Put the new one in
  3545. //
  3546. InsertHeadList(&pSpecialTable->SpecialEntryList, &pSpecialEntry->Link);
  3547. pSpecialTable->SpecialEntryCount++;
  3548. DfsDbgTrace(-1, Dbg, "added entry %d\n", ULongToPtr(pSpecialTable->SpecialEntryCount) );
  3549. } else { // entry already exists
  3550. if (pExistingEntry->UseCount == 0) {
  3551. if (pSpecialEntry->ExpandedCount > 0) {
  3552. //
  3553. // Unlink the entry
  3554. //
  3555. RemoveEntryList(&pExistingEntry->Link);
  3556. pSpecialTable->SpecialEntryCount--;
  3557. //
  3558. // And free it...
  3559. PktSpecialEntryDestroy(pExistingEntry);
  3560. //
  3561. // Now put the new one in
  3562. //
  3563. InsertHeadList(&pSpecialTable->SpecialEntryList, &pSpecialEntry->Link);
  3564. pSpecialTable->SpecialEntryCount++;
  3565. DfsDbgTrace(-1, Dbg, "added entry %d\n", ULongToPtr(pSpecialTable->SpecialEntryCount) );
  3566. } else {
  3567. pExistingEntry->Stale = TRUE;
  3568. PktSpecialEntryDestroy(pSpecialEntry);
  3569. DfsDbgTrace(-1, Dbg, "marked exising stale, dropping new entry on the floor\n", 0);
  3570. }
  3571. } else {
  3572. //
  3573. // Entry in use - can't replace, so free the replacement one
  3574. //
  3575. PktSpecialEntryDestroy(pSpecialEntry);
  3576. DfsDbgTrace(-1, Dbg, "dropped entry\n", 0);
  3577. }
  3578. }
  3579. return (STATUS_SUCCESS);
  3580. }
  3581. //+--------------------------------------------------------------------
  3582. //
  3583. // Function: PktEntryFromSpecialEntry
  3584. //
  3585. // Synopsis: Creates a DFS_PKT_ENTRY from a DFS_SPECIAL_ENTRY, used
  3586. // to support sysvols
  3587. //
  3588. // Arguments: pSpecialEntry - Entry to Convert
  3589. // pShareName - Name of share to append to address
  3590. // ppPktEntry - The result
  3591. //
  3592. // Returns: STATUS_SUCCESS
  3593. // STATUS_INSUFFICIENT_RESOURCES
  3594. //
  3595. //---------------------------------------------------------------------
  3596. NTSTATUS
  3597. PktEntryFromSpecialEntry(
  3598. IN PDFS_SPECIAL_ENTRY pSpecialEntry,
  3599. IN PUNICODE_STRING pShareName,
  3600. OUT PDFS_PKT_ENTRY *ppPktEntry)
  3601. {
  3602. NTSTATUS status;
  3603. PDFS_PKT_ENTRY pktEntry = NULL;
  3604. PDFS_SERVICE pServices = NULL;
  3605. PDS_MACHINE pMachine = NULL;
  3606. PDFS_EXPANDED_NAME pExpandedNames;
  3607. ULONG svc;
  3608. ULONG Size;
  3609. PWCHAR pwch;
  3610. if (pSpecialEntry->ExpandedCount == 0
  3611. ||
  3612. DfspIsSysVolShare(pShareName) == FALSE
  3613. ) {
  3614. return STATUS_BAD_NETWORK_PATH;
  3615. }
  3616. pktEntry = ExAllocatePoolWithTag(
  3617. PagedPool,
  3618. sizeof(DFS_PKT_ENTRY),
  3619. ' puM');
  3620. if (pktEntry == NULL) {
  3621. status = STATUS_INSUFFICIENT_RESOURCES;
  3622. goto Cleanup;
  3623. }
  3624. RtlZeroMemory( pktEntry, sizeof(DFS_PKT_ENTRY) );
  3625. pServices = ExAllocatePoolWithTag(
  3626. PagedPool,
  3627. sizeof(DFS_SERVICE) * pSpecialEntry->ExpandedCount,
  3628. ' puM');
  3629. if (pServices == NULL) {
  3630. status = STATUS_INSUFFICIENT_RESOURCES;
  3631. goto Cleanup;
  3632. }
  3633. RtlZeroMemory( pServices, sizeof(DFS_SERVICE) * pSpecialEntry->ExpandedCount);
  3634. pktEntry->NodeTypeCode = DSFS_NTC_PKT_ENTRY;
  3635. pktEntry->NodeByteSize = sizeof(DFS_PKT_ENTRY);
  3636. pktEntry->USN = 1;
  3637. pktEntry->Type = PKT_ENTRY_TYPE_NONDFS | PKT_ENTRY_TYPE_SYSVOL;
  3638. pktEntry->ExpireTime = 60 * 60;
  3639. pktEntry->TimeToLive = 60 * 60;
  3640. InitializeListHead(&pktEntry->Link);
  3641. InitializeListHead(&pktEntry->SubordinateList);
  3642. InitializeListHead(&pktEntry->ChildList);
  3643. //
  3644. // Create Prefix and ShortPrefix from SpecialName and ShareName
  3645. //
  3646. Size = sizeof(UNICODE_PATH_SEP) +
  3647. pSpecialEntry->SpecialName.Length +
  3648. sizeof(UNICODE_PATH_SEP) +
  3649. pShareName->Length;
  3650. pwch = ExAllocatePoolWithTag(
  3651. PagedPool,
  3652. Size,
  3653. ' puM');
  3654. if (pwch == NULL) {
  3655. status = STATUS_INSUFFICIENT_RESOURCES;
  3656. goto Cleanup;
  3657. }
  3658. pktEntry->Id.Prefix.Buffer = pwch;
  3659. pktEntry->Id.Prefix.Length = (USHORT) Size;
  3660. pktEntry->Id.Prefix.MaximumLength = (USHORT) Size;
  3661. *pwch++ = UNICODE_PATH_SEP;
  3662. RtlCopyMemory(
  3663. pwch,
  3664. pSpecialEntry->SpecialName.Buffer,
  3665. pSpecialEntry->SpecialName.Length);
  3666. pwch += pSpecialEntry->SpecialName.Length/sizeof(WCHAR);
  3667. *pwch++ = UNICODE_PATH_SEP;
  3668. RtlCopyMemory(
  3669. pwch,
  3670. pShareName->Buffer,
  3671. pShareName->Length);
  3672. pwch = ExAllocatePoolWithTag(
  3673. PagedPool,
  3674. Size,
  3675. ' puM');
  3676. if (pwch == NULL) {
  3677. status = STATUS_INSUFFICIENT_RESOURCES;
  3678. goto Cleanup;
  3679. }
  3680. pktEntry->Id.ShortPrefix.Buffer = pwch;
  3681. pktEntry->Id.ShortPrefix.Length = (USHORT) Size;
  3682. pktEntry->Id.ShortPrefix.MaximumLength = (USHORT) Size;
  3683. RtlCopyMemory(
  3684. pwch,
  3685. pktEntry->Id.Prefix.Buffer,
  3686. pktEntry->Id.Prefix.Length);
  3687. pktEntry->Info.ServiceCount = pSpecialEntry->ExpandedCount;
  3688. pktEntry->Info.ServiceList = pServices;
  3689. //
  3690. // Loop over the Expanded names, creating a Service for each
  3691. //
  3692. pExpandedNames = pSpecialEntry->ExpandedNames;
  3693. for (svc = 0; svc < pSpecialEntry->ExpandedCount; svc++) {
  3694. pServices[svc].Type = DFS_SERVICE_TYPE_MASTER | DFS_SERVICE_TYPE_DOWN_LEVEL;
  3695. pServices[svc].Capability = PROV_STRIP_PREFIX;
  3696. pServices[svc].ProviderId = PROV_ID_MUP_RDR;
  3697. //
  3698. // Machine name
  3699. //
  3700. Size = pExpandedNames[svc].ExpandedName.Length;
  3701. pwch = ExAllocatePoolWithTag(
  3702. PagedPool,
  3703. Size,
  3704. ' puM');
  3705. if (pwch == NULL) {
  3706. status = STATUS_INSUFFICIENT_RESOURCES;
  3707. goto Cleanup;
  3708. }
  3709. pServices[svc].Name.Buffer = pwch;
  3710. pServices[svc].Name.Length = (USHORT) Size;
  3711. pServices[svc].Name.MaximumLength = (USHORT) Size;
  3712. RtlCopyMemory(
  3713. pwch,
  3714. pExpandedNames[svc].ExpandedName.Buffer,
  3715. pExpandedNames[svc].ExpandedName.Length);
  3716. //
  3717. // Address (\machine\share)
  3718. //
  3719. Size = sizeof(UNICODE_PATH_SEP) +
  3720. pExpandedNames[svc].ExpandedName.Length +
  3721. sizeof(UNICODE_PATH_SEP) +
  3722. pShareName->Length;
  3723. pwch = ExAllocatePoolWithTag(
  3724. PagedPool,
  3725. Size,
  3726. ' puM');
  3727. if (pwch == NULL) {
  3728. status = STATUS_INSUFFICIENT_RESOURCES;
  3729. goto Cleanup;
  3730. }
  3731. pServices[svc].Address.Buffer = pwch;
  3732. pServices[svc].Address.Length = (USHORT) Size;
  3733. pServices[svc].Address.MaximumLength = (USHORT) Size;
  3734. *pwch++ = UNICODE_PATH_SEP;
  3735. RtlCopyMemory(
  3736. pwch,
  3737. pExpandedNames[svc].ExpandedName.Buffer,
  3738. pExpandedNames[svc].ExpandedName.Length);
  3739. pwch += pExpandedNames[svc].ExpandedName.Length/sizeof(WCHAR);
  3740. *pwch++ = UNICODE_PATH_SEP;
  3741. RtlCopyMemory(
  3742. pwch,
  3743. pShareName->Buffer,
  3744. pShareName->Length);
  3745. //
  3746. // Alloc and init a DSMachine struct
  3747. //
  3748. pMachine = PktpGetDSMachine( &pServices[svc].Name );
  3749. if (pMachine == NULL) {
  3750. status = STATUS_INSUFFICIENT_RESOURCES;
  3751. goto Cleanup;
  3752. }
  3753. pServices[svc].pMachEntry = ExAllocatePoolWithTag(
  3754. PagedPool, sizeof(DFS_MACHINE_ENTRY),
  3755. ' puM');
  3756. if (pServices[svc].pMachEntry == NULL) {
  3757. status = STATUS_INSUFFICIENT_RESOURCES;
  3758. goto Cleanup;
  3759. }
  3760. RtlZeroMemory( (PVOID) pServices[svc].pMachEntry, sizeof(DFS_MACHINE_ENTRY));
  3761. pServices[svc].pMachEntry->pMachine = pMachine;
  3762. pServices[svc].pMachEntry->UseCount = 1;
  3763. }
  3764. //
  3765. // Set active service to the same as the spc's active entry
  3766. //
  3767. pktEntry->ActiveService = &pServices[pSpecialEntry->Active];
  3768. *ppPktEntry = pktEntry;
  3769. return STATUS_SUCCESS;
  3770. Cleanup:
  3771. if (pServices != NULL) {
  3772. for (svc = 0; svc < pSpecialEntry->ExpandedCount; svc++) {
  3773. if (pServices[svc].Name.Buffer != NULL)
  3774. ExFreePool(pServices[svc].Name.Buffer);
  3775. if (pServices[svc].Address.Buffer != NULL)
  3776. ExFreePool(pServices[svc].Address.Buffer);
  3777. if (pServices[svc].pMachEntry != NULL) {
  3778. DfsDecrementMachEntryCount(pServices[svc].pMachEntry, TRUE);
  3779. }
  3780. }
  3781. ExFreePool(pServices);
  3782. }
  3783. //
  3784. // Cleanup on error
  3785. //
  3786. if (pktEntry != NULL) {
  3787. if (pktEntry->Id.Prefix.Buffer != NULL)
  3788. ExFreePool(pktEntry->Id.Prefix.Buffer);
  3789. if (pktEntry->Id.ShortPrefix.Buffer != NULL)
  3790. ExFreePool(pktEntry->Id.ShortPrefix.Buffer);
  3791. ExFreePool(pktEntry);
  3792. }
  3793. return status;
  3794. }
  3795. //+----------------------------------------------------------------------------
  3796. //
  3797. // Function: DfspSetActiveServiceByServerName
  3798. //
  3799. // Synopsis: Makes a given ServerName active
  3800. //
  3801. // Arguments:
  3802. //
  3803. // Returns:
  3804. //
  3805. //-----------------------------------------------------------------------------
  3806. NTSTATUS
  3807. DfspSetActiveServiceByServerName(
  3808. PUNICODE_STRING ServerName,
  3809. PDFS_PKT_ENTRY pktEntry)
  3810. {
  3811. UNICODE_STRING Server;
  3812. PDFS_SERVICE pService;
  3813. NTSTATUS NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  3814. ULONG i;
  3815. DfsDbgTrace(+1, Dbg, "DfspSetActiveServiceByServerName\n", 0);
  3816. for (i = 0; i < pktEntry->Info.ServiceCount && NtStatus != STATUS_SUCCESS; i++) {
  3817. LPWSTR wp;
  3818. pService = &pktEntry->Info.ServiceList[i];
  3819. DfsDbgTrace( 0, Dbg, "Examining %wZ\n", &pService->Address);
  3820. //
  3821. // Tease apart the address (of form \Server\Share) into Server and Share
  3822. //
  3823. RemoveLastComponent(&pService->Address, &Server);
  3824. //
  3825. // Remove leading & trailing '\'s
  3826. //
  3827. Server.Length -= 2* sizeof(WCHAR);
  3828. Server.MaximumLength = Server.Length;
  3829. Server.Buffer++;
  3830. //
  3831. // If ServerName doesn't match, then move on to the next service
  3832. //
  3833. if ( RtlCompareUnicodeString(ServerName, &Server, TRUE) ) {
  3834. continue;
  3835. }
  3836. DfsDbgTrace( 0, Dbg, "DfspSetActiveServiceByServerName: Server=%wZ\n", &Server);
  3837. //
  3838. // Make this the active share
  3839. //
  3840. pktEntry->ActiveService = pService;
  3841. NtStatus = STATUS_SUCCESS;
  3842. }
  3843. DfsDbgTrace(-1, Dbg, "DfspSetActiveServiceByServerName -> %08lx\n", ULongToPtr(NtStatus) );
  3844. return NtStatus;
  3845. }
  3846. //+----------------------------------------------------------------------------
  3847. //
  3848. // Function: DfspIsDupPktEntry
  3849. //
  3850. // Synopsis: Checks if a potential pkt entry is a dup of an existing one
  3851. //
  3852. // Arguments:
  3853. //
  3854. // Returns:
  3855. //
  3856. //-----------------------------------------------------------------------------
  3857. BOOLEAN
  3858. DfspIsDupPktEntry(
  3859. PDFS_PKT_ENTRY ExistingEntry,
  3860. ULONG EntryType,
  3861. PDFS_PKT_ENTRY_ID EntryId,
  3862. PDFS_PKT_ENTRY_INFO EntryInfo)
  3863. {
  3864. ULONG i;
  3865. ULONG j;
  3866. PDFS_SERVICE pNewSvc;
  3867. PDFS_SERVICE pExistSvc;
  3868. BOOLEAN FoundDup = FALSE;
  3869. if (
  3870. ExistingEntry == NULL
  3871. ||
  3872. EntryId == NULL
  3873. ||
  3874. EntryInfo == NULL
  3875. )
  3876. return FALSE;
  3877. #if DBG
  3878. if (MupVerbose)
  3879. DbgPrint(" DfspIsDupPktEntry([%wZ][%wZ])\n",
  3880. &EntryId->Prefix,
  3881. &ExistingEntry->Id.Prefix);
  3882. #endif
  3883. if (EntryType != ExistingEntry->Type) {
  3884. #if DBG
  3885. if (MupVerbose)
  3886. DbgPrint(" DfspIsDupPktEntry(1) returning FALSE\n");
  3887. #endif
  3888. return FALSE;
  3889. }
  3890. if (!GuidEqual(&EntryId->Uid, &ExistingEntry->Id.Uid)) {
  3891. #if DBG
  3892. if (MupVerbose)
  3893. DbgPrint(" DfspIsDupPktEntry(2) returning FALSE\n");
  3894. #endif
  3895. return FALSE;
  3896. }
  3897. if (
  3898. RtlCompareUnicodeString(&EntryId->Prefix, &ExistingEntry->Id.Prefix,TRUE) != 0
  3899. ||
  3900. RtlCompareUnicodeString(&EntryId->ShortPrefix, &ExistingEntry->Id.ShortPrefix,TRUE) != 0
  3901. ) {
  3902. #if DBG
  3903. if (MupVerbose)
  3904. DbgPrint(" DfspIsDupPktEntry(3) returning FALSE\n");
  3905. #endif
  3906. return FALSE;
  3907. }
  3908. //
  3909. // Now we have to compare all the services
  3910. //
  3911. if (EntryInfo->ServiceCount != ExistingEntry->Info.ServiceCount) {
  3912. #if DBG
  3913. if (MupVerbose)
  3914. DbgPrint(" DfspIsDupPktEntry(4) returning FALSE\n");
  3915. #endif
  3916. return FALSE;
  3917. }
  3918. for (i = 0; i < EntryInfo->ServiceCount; i++) {
  3919. FoundDup = FALSE;
  3920. pNewSvc = &EntryInfo->ServiceList[i];
  3921. for (j = 0; j < ExistingEntry->Info.ServiceCount; j++) {
  3922. pExistSvc = &ExistingEntry->Info.ServiceList[j];
  3923. if (DfspIsDupSvc(pExistSvc,pNewSvc) == TRUE) {
  3924. FoundDup = TRUE;
  3925. break;
  3926. }
  3927. }
  3928. if (FoundDup != TRUE) {
  3929. #if DBG
  3930. if (MupVerbose)
  3931. DbgPrint(" DfspIsDupPktEntry(5) returning FALSE\n");
  3932. #endif
  3933. return FALSE;
  3934. }
  3935. }
  3936. for (i = 0; i < ExistingEntry->Info.ServiceCount; i++) {
  3937. FoundDup = FALSE;
  3938. pExistSvc = &ExistingEntry->Info.ServiceList[i];
  3939. for (j = 0; j < EntryInfo->ServiceCount; j++) {
  3940. pNewSvc = &EntryInfo->ServiceList[j];
  3941. if (DfspIsDupSvc(pExistSvc,pNewSvc) == TRUE) {
  3942. FoundDup = TRUE;
  3943. break;
  3944. }
  3945. }
  3946. if (FoundDup != TRUE) {
  3947. #if DBG
  3948. if (MupVerbose)
  3949. DbgPrint(" DfspIsDupPktEntry(6) returning FALSE\n");
  3950. #endif
  3951. return FALSE;
  3952. }
  3953. }
  3954. #if DBG
  3955. if (MupVerbose)
  3956. DbgPrint(" DfspIsDupPktEntry returning TRUE\n");
  3957. #endif
  3958. return TRUE;
  3959. }
  3960. //+----------------------------------------------------------------------------
  3961. //
  3962. // Function: DfspIsDupSvc
  3963. //
  3964. // Synopsis: Checks if two services are, for all dfs purposes, identical
  3965. //
  3966. // Arguments:
  3967. //
  3968. // Returns:
  3969. //
  3970. //-----------------------------------------------------------------------------
  3971. BOOLEAN
  3972. DfspIsDupSvc(
  3973. PDFS_SERVICE pExistSvc,
  3974. PDFS_SERVICE pNewSvc)
  3975. {
  3976. #if DBG
  3977. if (MupVerbose & 0x80000000) {
  3978. DbgPrint("DfspIsDupSvc([%wZ][%wZ] vs [%wZ][%wZ])\n",
  3979. &pExistSvc->Name, &pExistSvc->Address,
  3980. &pNewSvc->Name, &pNewSvc->Address);
  3981. DbgPrint("Type: 0x%x vs 0x%x\n", pExistSvc->Type, pNewSvc->Type);
  3982. DbgPrint("Capability: 0x%x vs 0x%x\n", pExistSvc->Capability, pNewSvc->Capability);
  3983. DbgPrint("ProviderId: 0x%x vs 0x%x\n", pExistSvc->ProviderId, pNewSvc->ProviderId);
  3984. }
  3985. #endif
  3986. if (
  3987. pExistSvc->Capability != pNewSvc->Capability
  3988. ||
  3989. RtlCompareUnicodeString(&pExistSvc->Name, &pNewSvc->Name, TRUE) != 0
  3990. ||
  3991. RtlCompareUnicodeString(&pExistSvc->Address, &pNewSvc->Address, TRUE) != 0
  3992. ) {
  3993. #if DBG
  3994. if (MupVerbose & 0x80000000)
  3995. DbgPrint("...FALSE\n");
  3996. #endif
  3997. return FALSE;
  3998. }
  3999. #if DBG
  4000. if (MupVerbose & 0x80000000)
  4001. DbgPrint("...TRUE\n");
  4002. #endif
  4003. return TRUE;
  4004. }
  4005. BOOLEAN
  4006. DfspDnsNameToFlatName(
  4007. PUNICODE_STRING DnsName,
  4008. PUNICODE_STRING FlatName)
  4009. {
  4010. USHORT i;
  4011. *FlatName = *DnsName;
  4012. for (i = 1; i < (DnsName->Length/sizeof(WCHAR)); i++) {
  4013. if (FlatName->Buffer[i] == L'.') {
  4014. FlatName->Length = i * sizeof(WCHAR);
  4015. break;
  4016. }
  4017. }
  4018. #if DBG
  4019. if (MupVerbose)
  4020. DbgPrint(" DfspDnsNameToFlatName:[%wZ]->[%wZ]\n",
  4021. DnsName,
  4022. FlatName);
  4023. #endif
  4024. return TRUE;
  4025. }
  4026. #define MAX_SPECIAL_ENTRIES 500
  4027. //+----------------------------------------------------------------------------
  4028. //
  4029. // Function: PktpUpdateSpecialTable
  4030. //
  4031. // Synopsis: Adds entries to the special table, given a domain and a dcname.
  4032. // We contact the dc for a list of trusted domains either if we
  4033. // dont have the domain already in our list OR we have the domain
  4034. // but we haven't called this code atleast once with that domain
  4035. // name.
  4036. // Arguments: DomainName and DCName.
  4037. //
  4038. // Returns: Success or Failure status
  4039. //
  4040. //-----------------------------------------------------------------------------
  4041. NTSTATUS
  4042. PktpUpdateSpecialTable(
  4043. PUNICODE_STRING DomainName,
  4044. PUNICODE_STRING DCName
  4045. )
  4046. {
  4047. ULONG count = 0;
  4048. BOOLEAN needReferral = FALSE;
  4049. NTSTATUS status = STATUS_SUCCESS;
  4050. PDFS_SPECIAL_ENTRY pSpecialEntry;
  4051. BOOLEAN pktLocked = FALSE;
  4052. PDFS_PKT Pkt = _GetPkt();
  4053. DfsDbgTrace(+1, Dbg, "PktpUpdateSpecialTable -> Domain %wZ\n",
  4054. DomainName);
  4055. DfsDbgTrace(0, Dbg, "PktpUpdateSpecialTable -> DCname %wZ\n",
  4056. DCName);
  4057. if ((DomainName->Length ==0) || (DCName->Length == 0)) {
  4058. return STATUS_BAD_NETWORK_PATH;
  4059. }
  4060. PktAcquireExclusive(TRUE, &pktLocked);
  4061. pSpecialEntry = PktLookupSpecialNameEntry(DomainName);
  4062. // If we dont have the domain in our table, or we haven't checked
  4063. // against this domain atleast once AND the DC is not the dc that
  4064. // is stored in our pkt table, we decide we need a referral.
  4065. //
  4066. if (pSpecialEntry == NULL) {
  4067. needReferral = TRUE;
  4068. }
  4069. else {
  4070. if (pSpecialEntry->GotDCReferral == FALSE) {
  4071. pSpecialEntry->GotDCReferral = TRUE;
  4072. needReferral = TRUE;
  4073. }
  4074. }
  4075. if ((needReferral == TRUE) && (Pkt->DCName.Length != 0)) {
  4076. if (RtlEqualUnicodeString(&Pkt->DCName, DCName, TRUE)) {
  4077. needReferral = FALSE;
  4078. }
  4079. }
  4080. PktRelease();
  4081. if (needReferral) {
  4082. count = Pkt->SpecialTable.SpecialEntryCount;
  4083. if (Pkt->SpecialTable.SpecialEntryCount >= MAX_SPECIAL_ENTRIES) {
  4084. status = STATUS_DOMAIN_LIMIT_EXCEEDED;
  4085. }
  4086. else {
  4087. status = PktGetSpecialReferralTable(DCName, FALSE);
  4088. }
  4089. }
  4090. if (NT_SUCCESS(status)) {
  4091. DfsDbgTrace(0, Dbg, "PktpUpdateSpecialTable: added %d entries\n",
  4092. ULongToPtr( Pkt->SpecialTable.SpecialEntryCount - count ));
  4093. }
  4094. DfsDbgTrace(-1, Dbg, "PktpUpdateSpecialTable -> Status 0x%x\n",
  4095. ULongToPtr( status ));
  4096. return status;
  4097. }
  4098. PDFS_PKT_ENTRY
  4099. PktFindEntryByPrefix(
  4100. IN PDFS_PKT Pkt,
  4101. IN PUNICODE_STRING Prefix
  4102. )
  4103. {
  4104. PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
  4105. PDFS_PKT_ENTRY pktEntry = NULL;
  4106. UNICODE_STRING Remaining;
  4107. Remaining.Length = 0;
  4108. DfsDbgTrace(+1, Dbg, "PktFindEntryByPrefix: Entered\n", 0);
  4109. //
  4110. // If there really is a prefix to lookup, use the prefix table
  4111. // to initially find an entry
  4112. //
  4113. if ((Prefix->Length != 0) &&
  4114. (pfxEntry = DfsFindUnicodePrefix(&Pkt->PrefixTable,Prefix,&Remaining))) {
  4115. pktEntry = CONTAINING_RECORD(pfxEntry,
  4116. DFS_PKT_ENTRY,
  4117. PrefixTableEntry);
  4118. }
  4119. return pktEntry;
  4120. }
  4121. //
  4122. // Fix for bug: 29300.
  4123. // Do not attach the process to system thread. Instead, post the work to the
  4124. // system process.
  4125. //
  4126. typedef enum _TYPE_OF_REFERRAL {
  4127. REFERRAL_TYPE_GET_PKT,
  4128. REFERRAL_TYPE_EXPAND_SPECIAL_TABLE,
  4129. REFERRAL_TYPE_GET_REFERRAL_TABLE
  4130. } TYPE_OF_REFERRAL;
  4131. typedef struct _PKT_REFERRAL_CONTEXT {
  4132. UNICODE_STRING ContextName;
  4133. UNICODE_STRING DomainName;
  4134. UNICODE_STRING ShareName;
  4135. BOOLEAN ContextBool;
  4136. WORK_QUEUE_ITEM WorkQueueItem;
  4137. KEVENT Event;
  4138. TYPE_OF_REFERRAL Type;
  4139. ULONG RefCnt;
  4140. NTSTATUS Status;
  4141. PVOID Data;
  4142. } PKT_REFERRAL_CONTEXT, *PPKT_REFERRAL_CONTEXT;
  4143. VOID
  4144. PktWorkInSystemContext(
  4145. PPKT_REFERRAL_CONTEXT Context )
  4146. {
  4147. NTSTATUS Status;
  4148. switch (Context->Type) {
  4149. case REFERRAL_TYPE_GET_PKT:
  4150. Status = _PktGetReferral( &Context->ContextName,
  4151. &Context->DomainName,
  4152. &Context->ShareName,
  4153. Context->ContextBool );
  4154. break;
  4155. case REFERRAL_TYPE_EXPAND_SPECIAL_TABLE:
  4156. Status = _PktExpandSpecialName( &Context->ContextName,
  4157. (PDFS_SPECIAL_ENTRY *)&Context->Data );
  4158. break;
  4159. case REFERRAL_TYPE_GET_REFERRAL_TABLE:
  4160. Status = _PktGetSpecialReferralTable( &Context->ContextName,
  4161. Context->ContextBool );
  4162. break;
  4163. default:
  4164. Status = STATUS_INVALID_PARAMETER;
  4165. break;
  4166. }
  4167. Context->Status = Status;
  4168. KeSetEvent( &Context->Event, 0, FALSE );
  4169. if (InterlockedDecrement(&Context->RefCnt) == 0) {
  4170. ExFreePool(Context);
  4171. }
  4172. }
  4173. NTSTATUS
  4174. PktPostSystemWork(
  4175. PPKT_REFERRAL_CONTEXT pktContext,
  4176. PVOID *Data )
  4177. {
  4178. NTSTATUS Status;
  4179. KeInitializeEvent( &pktContext->Event,
  4180. SynchronizationEvent,
  4181. FALSE );
  4182. ExInitializeWorkItem( &pktContext->WorkQueueItem,
  4183. PktWorkInSystemContext,
  4184. pktContext );
  4185. ExQueueWorkItem( &pktContext->WorkQueueItem, CriticalWorkQueue );
  4186. Status = KeWaitForSingleObject( &pktContext->Event,
  4187. UserRequest,
  4188. KernelMode,
  4189. FALSE,
  4190. NULL);
  4191. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, PktPostSystemWork_Error_KeWaitForSingleObject,
  4192. LOGSTATUS(Status));
  4193. if (Status == STATUS_SUCCESS) {
  4194. Status = pktContext->Status;
  4195. }
  4196. if (Data != NULL) {
  4197. *Data = pktContext->Data;
  4198. }
  4199. if (InterlockedDecrement(&pktContext->RefCnt) == 0) {
  4200. ExFreePool(pktContext);
  4201. }
  4202. return Status;
  4203. }
  4204. NTSTATUS
  4205. PktGetReferral(
  4206. IN PUNICODE_STRING MachineName, // Machine to direct referral to
  4207. IN PUNICODE_STRING DomainName, // the machine or domain name to use
  4208. IN PUNICODE_STRING ShareName, // the ftdfs or dfs name
  4209. IN BOOLEAN CSCAgentCreate) // the CSC agent create flag
  4210. {
  4211. PPKT_REFERRAL_CONTEXT pktContext = NULL;
  4212. NTSTATUS Status;
  4213. ULONG NameSize = 0;
  4214. NameSize = MachineName->Length * sizeof(WCHAR);
  4215. NameSize += DomainName->Length * sizeof(WCHAR);
  4216. NameSize += ShareName->Length * sizeof(WCHAR);
  4217. if ((MupUseNullSessionForDfs == TRUE) &&
  4218. (PsGetCurrentProcess() != DfsData.OurProcess)) {
  4219. pktContext = ExAllocatePoolWithTag( NonPagedPool,
  4220. sizeof (PKT_REFERRAL_CONTEXT) + NameSize,
  4221. ' puM');
  4222. }
  4223. if (pktContext != NULL) {
  4224. pktContext->ContextName.MaximumLength = MachineName->Length;
  4225. pktContext->ContextName.Buffer = (WCHAR *)(pktContext + 1);
  4226. RtlCopyUnicodeString(&pktContext->ContextName, MachineName);
  4227. pktContext->DomainName.MaximumLength = DomainName->Length;
  4228. pktContext->DomainName.Buffer = pktContext->ContextName.Buffer + pktContext->ContextName.MaximumLength;
  4229. RtlCopyUnicodeString(&pktContext->DomainName, DomainName);
  4230. pktContext->ShareName.MaximumLength = ShareName->Length;
  4231. pktContext->ShareName.Buffer = pktContext->DomainName.Buffer + pktContext->DomainName.MaximumLength;
  4232. RtlCopyUnicodeString(&pktContext->ShareName, ShareName);
  4233. pktContext->ContextBool = CSCAgentCreate;
  4234. pktContext->Type = REFERRAL_TYPE_GET_PKT;
  4235. pktContext->RefCnt = 2;
  4236. Status = PktPostSystemWork( pktContext, NULL);
  4237. }
  4238. else {
  4239. Status = _PktGetReferral( MachineName,
  4240. DomainName,
  4241. ShareName,
  4242. CSCAgentCreate );
  4243. }
  4244. return Status;
  4245. }
  4246. NTSTATUS
  4247. PktExpandSpecialName(
  4248. IN PUNICODE_STRING Name,
  4249. PDFS_SPECIAL_ENTRY *ppSpecialEntry)
  4250. {
  4251. PPKT_REFERRAL_CONTEXT pktContext = NULL;
  4252. NTSTATUS Status;
  4253. ULONG NameSize = 0;
  4254. NameSize = Name->Length * sizeof(WCHAR);
  4255. if ((MupUseNullSessionForDfs == TRUE) &&
  4256. (PsGetCurrentProcess() != DfsData.OurProcess)) {
  4257. pktContext = ExAllocatePoolWithTag( NonPagedPool,
  4258. sizeof (PKT_REFERRAL_CONTEXT) + NameSize,
  4259. ' puM');
  4260. }
  4261. if (pktContext != NULL) {
  4262. pktContext->ContextName.MaximumLength = Name->Length;
  4263. pktContext->ContextName.Buffer = (WCHAR *)(pktContext + 1);
  4264. RtlCopyUnicodeString(&pktContext->ContextName, Name);
  4265. pktContext->Type = REFERRAL_TYPE_EXPAND_SPECIAL_TABLE;
  4266. pktContext->RefCnt = 2;
  4267. pktContext->Data = NULL;
  4268. Status = PktPostSystemWork( pktContext, (PVOID *)ppSpecialEntry );
  4269. }
  4270. else {
  4271. Status = _PktExpandSpecialName( Name,
  4272. ppSpecialEntry );
  4273. }
  4274. return Status;
  4275. }
  4276. NTSTATUS
  4277. PktGetSpecialReferralTable(
  4278. IN PUNICODE_STRING Machine,
  4279. BOOLEAN SystemDC)
  4280. {
  4281. PPKT_REFERRAL_CONTEXT pktContext = NULL;
  4282. NTSTATUS Status;
  4283. ULONG NameSize = 0;
  4284. NameSize = Machine->Length * sizeof(WCHAR);
  4285. if ((MupUseNullSessionForDfs == TRUE) &&
  4286. (PsGetCurrentProcess() != DfsData.OurProcess)) {
  4287. pktContext = ExAllocatePoolWithTag( NonPagedPool,
  4288. sizeof (PKT_REFERRAL_CONTEXT) + NameSize,
  4289. ' puM');
  4290. }
  4291. if (pktContext != NULL) {
  4292. pktContext->ContextName.MaximumLength = Machine->Length;
  4293. pktContext->ContextName.Buffer = (WCHAR *)(pktContext + 1);
  4294. RtlCopyUnicodeString(&pktContext->ContextName, Machine);
  4295. pktContext->ContextBool = SystemDC;
  4296. pktContext->Type = REFERRAL_TYPE_GET_REFERRAL_TABLE;
  4297. pktContext->RefCnt = 2;
  4298. Status = PktPostSystemWork( pktContext, NULL );
  4299. }
  4300. else {
  4301. Status = _PktGetSpecialReferralTable( Machine,
  4302. SystemDC );
  4303. }
  4304. return Status;
  4305. }
  4306. NTSTATUS
  4307. PktGetTargetInfo(
  4308. HANDLE IpcHandle,
  4309. PUNICODE_STRING pDomainName,
  4310. PUNICODE_STRING pShareName,
  4311. PDFS_TARGET_INFO *ppDfsTargetInfo )
  4312. {
  4313. BOOLEAN SpecialName;
  4314. PDFS_TARGET_INFO pDfsTargetInfo = NULL;
  4315. NTSTATUS Status;
  4316. SpecialName = (PktLookupSpecialNameEntry(pDomainName) == NULL) ? FALSE : TRUE;
  4317. if ((SpecialName == FALSE) &&
  4318. DfspIsSysVolShare(pShareName)) {
  4319. SpecialName = TRUE;
  4320. }
  4321. if (SpecialName)
  4322. {
  4323. Status = PktCreateTargetInfo( pDomainName,
  4324. pShareName,
  4325. SpecialName,
  4326. &pDfsTargetInfo );
  4327. }
  4328. else {
  4329. Status = DfsGetLMRTargetInfo( IpcHandle,
  4330. &pDfsTargetInfo );
  4331. if (Status != STATUS_SUCCESS)
  4332. {
  4333. Status = PktCreateTargetInfo( pDomainName,
  4334. pShareName,
  4335. SpecialName,
  4336. &pDfsTargetInfo );
  4337. }
  4338. }
  4339. if (Status == STATUS_SUCCESS)
  4340. {
  4341. pDfsTargetInfo->DfsHeader.Type = 'grTM';
  4342. pDfsTargetInfo->DfsHeader.UseCount=1;
  4343. *ppDfsTargetInfo = pDfsTargetInfo;
  4344. }
  4345. return Status;
  4346. }
  4347. #define MAX_TARGET_INFO_RETRIES 3
  4348. NTSTATUS
  4349. DfsGetLMRTargetInfo(
  4350. HANDLE IpcHandle,
  4351. PDFS_TARGET_INFO *ppTargetInfo )
  4352. {
  4353. ULONG TargetInfoSize, DfsTargetInfoSize;
  4354. PDFS_TARGET_INFO pDfsTargetInfo;
  4355. NTSTATUS Status = STATUS_SUCCESS;
  4356. IO_STATUS_BLOCK ioStatusBlock;
  4357. ULONG Retry = 0;
  4358. TargetInfoSize = sizeof(LMR_QUERY_TARGET_INFO) + MAX_PATH;
  4359. TargetInfoRetry:
  4360. DfsTargetInfoSize = TargetInfoSize + sizeof(DFS_TARGET_INFO_HEADER) + sizeof(ULONG);
  4361. pDfsTargetInfo = ExAllocatePoolWithTag( PagedPool,
  4362. DfsTargetInfoSize,
  4363. ' puM');
  4364. if (pDfsTargetInfo == NULL)
  4365. {
  4366. Status = STATUS_INSUFFICIENT_RESOURCES;
  4367. }
  4368. if (Status == STATUS_SUCCESS)
  4369. {
  4370. RtlZeroMemory( pDfsTargetInfo, DfsTargetInfoSize );
  4371. pDfsTargetInfo->LMRTargetInfo.BufferLength = TargetInfoSize;
  4372. Status = ZwFsControlFile(
  4373. IpcHandle,
  4374. NULL,
  4375. NULL,
  4376. NULL,
  4377. &ioStatusBlock,
  4378. FSCTL_LMR_QUERY_TARGET_INFO,
  4379. NULL,
  4380. 0,
  4381. &pDfsTargetInfo->LMRTargetInfo,
  4382. TargetInfoSize );
  4383. if (Status == STATUS_BUFFER_TOO_SMALL) {
  4384. TargetInfoSize = pDfsTargetInfo->LMRTargetInfo.BufferLength;
  4385. ExFreePool( pDfsTargetInfo );
  4386. pDfsTargetInfo = NULL;
  4387. if (Retry++ < MAX_TARGET_INFO_RETRIES)
  4388. {
  4389. Status = STATUS_SUCCESS;
  4390. goto TargetInfoRetry;
  4391. }
  4392. }
  4393. }
  4394. if (Status == STATUS_SUCCESS)
  4395. {
  4396. pDfsTargetInfo->DfsHeader.Flags = TARGET_INFO_LMR;
  4397. *ppTargetInfo = pDfsTargetInfo;
  4398. }
  4399. else
  4400. {
  4401. if (pDfsTargetInfo != NULL)
  4402. {
  4403. ExFreePool(pDfsTargetInfo);
  4404. }
  4405. }
  4406. return Status;
  4407. }
  4408. VOID
  4409. PktAcquireTargetInfo(
  4410. PDFS_TARGET_INFO pDfsTargetInfo)
  4411. {
  4412. ULONG Count;
  4413. if (pDfsTargetInfo != NULL)
  4414. {
  4415. Count = InterlockedIncrement( &pDfsTargetInfo->DfsHeader.UseCount);
  4416. }
  4417. return;
  4418. }
  4419. VOID
  4420. PktReleaseTargetInfo(
  4421. PDFS_TARGET_INFO pDfsTargetInfo)
  4422. {
  4423. LONG Count;
  4424. if (pDfsTargetInfo != NULL)
  4425. {
  4426. Count = InterlockedDecrement( &pDfsTargetInfo->DfsHeader.UseCount);
  4427. if (Count == 0)
  4428. {
  4429. ExFreePool(pDfsTargetInfo);
  4430. }
  4431. }
  4432. return;
  4433. }
  4434. NTSTATUS
  4435. PktCreateTargetInfo(
  4436. PUNICODE_STRING pDomainName,
  4437. PUNICODE_STRING pShareName,
  4438. BOOLEAN SpecialName,
  4439. PDFS_TARGET_INFO *ppDfsTargetInfo )
  4440. {
  4441. NTSTATUS Status = STATUS_SUCCESS;
  4442. ULONG TargetInfoSize;
  4443. PDFS_TARGET_INFO pDfsTargetInfo;
  4444. PCREDENTIAL_TARGET_INFORMATIONW pTargetInfo;
  4445. LPWSTR StringBuf;
  4446. TargetInfoSize = sizeof(DFS_TARGET_INFO) +
  4447. sizeof(UNICODE_PATH_SEP)+
  4448. pDomainName->Length +
  4449. sizeof(UNICODE_PATH_SEP) +
  4450. pShareName->Length +
  4451. sizeof(WCHAR) +
  4452. pDomainName->Length +
  4453. sizeof(WCHAR);
  4454. pDfsTargetInfo = ExAllocatePoolWithTag( PagedPool,
  4455. TargetInfoSize,
  4456. ' puM' );
  4457. if (pDfsTargetInfo == NULL)
  4458. {
  4459. Status = STATUS_INSUFFICIENT_RESOURCES;
  4460. }
  4461. else {
  4462. RtlZeroMemory(pDfsTargetInfo,
  4463. TargetInfoSize);
  4464. pDfsTargetInfo->DfsHeader.Flags = TARGET_INFO_DFS;
  4465. pTargetInfo = &pDfsTargetInfo->TargetInfo;
  4466. StringBuf = (LPWSTR)(pTargetInfo + 1);
  4467. pTargetInfo->TargetName = StringBuf;
  4468. RtlCopyMemory( StringBuf,
  4469. pDomainName->Buffer,
  4470. pDomainName->Length);
  4471. StringBuf += (pDomainName->Length / sizeof(WCHAR));
  4472. *StringBuf++ = UNICODE_PATH_SEP;
  4473. RtlCopyMemory( StringBuf,
  4474. pShareName->Buffer,
  4475. pShareName->Length);
  4476. StringBuf += (pShareName->Length / sizeof(WCHAR));
  4477. *StringBuf++ = 0;
  4478. pTargetInfo->DnsServerName = StringBuf;
  4479. RtlCopyMemory( StringBuf,
  4480. pDomainName->Buffer,
  4481. pDomainName->Length);
  4482. StringBuf += (pDomainName->Length / sizeof(WCHAR));
  4483. *StringBuf++ = 0;
  4484. //
  4485. // Add this flag AFTER lab03 RI's, to prevent failure
  4486. //
  4487. pTargetInfo->Flags = CRED_TI_CREATE_EXPLICIT_CRED;
  4488. pTargetInfo->Flags |= CRED_TI_SERVER_FORMAT_UNKNOWN;
  4489. if (SpecialName == TRUE)
  4490. {
  4491. pTargetInfo->DnsDomainName =
  4492. pTargetInfo->DnsServerName;
  4493. pTargetInfo->Flags |= CRED_TI_DOMAIN_FORMAT_UNKNOWN;
  4494. }
  4495. *ppDfsTargetInfo = pDfsTargetInfo;
  4496. }
  4497. return Status;
  4498. }
  4499. BOOLEAN
  4500. DfsIsSpecialName(
  4501. PUNICODE_STRING pName)
  4502. {
  4503. BOOLEAN pktLocked;
  4504. PDFS_PKT Pkt;
  4505. PDFS_SPECIAL_ENTRY pSpecialEntry;
  4506. BOOLEAN ReturnValue;
  4507. Pkt = _GetPkt();
  4508. PktAcquireShared(TRUE, &pktLocked);
  4509. pSpecialEntry = PktLookupSpecialNameEntry(pName);
  4510. PktRelease();
  4511. //
  4512. // We don't have any expansion for this name
  4513. //
  4514. if (pSpecialEntry == NULL)
  4515. {
  4516. ReturnValue = FALSE;
  4517. }
  4518. else
  4519. {
  4520. ReturnValue = TRUE;
  4521. }
  4522. return ReturnValue;
  4523. }