Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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