Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3133 lines
85 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1996, Microsoft Corporation
  4. //
  5. // File: srv.c
  6. //
  7. // Contents: Support for interacting with the SMB server.
  8. //
  9. // Classes: None
  10. //
  11. // Functions: DfsSrvFsctrl
  12. // DfsFsctrlTranslatePath
  13. // DfsFsctrlGetReferrals
  14. // DfsFsctrlIsShareInDfs
  15. //
  16. //-----------------------------------------------------------------------------
  17. #include "dfsprocs.h"
  18. #include "srv.h"
  19. #include "smbtypes.h"
  20. #include "smbtrans.h"
  21. #include "know.h"
  22. #include "ftdfs.h"
  23. #include "sitesup.h"
  24. #include "ipsup.h"
  25. #include "spcsup.h"
  26. #include "dfslpc.h"
  27. #include "fsctrl.h"
  28. #include "dfswml.h"
  29. #include <ntlsa.h>
  30. #include <netevent.h>
  31. #define Dbg DEBUG_TRACE_REFERRALS
  32. #define MAXIMUM_DFS_REFERRALS 4096
  33. DFS_IPADDRESS ZeroIpAddress = {0};
  34. NTSTATUS
  35. DfspFormPrefix(
  36. IN PDFS_LOCAL_VOL_ENTRY LvEntry,
  37. IN PUNICODE_STRING ParentPath,
  38. IN PUNICODE_STRING DfsPathName,
  39. IN OUT PUNICODE_STRING Prefix);
  40. ULONG
  41. DfspGetV1ReferralSize(
  42. IN PDFS_PKT_ENTRY PktEntry,
  43. IN PUNICODE_STRING MachineName);
  44. ULONG
  45. DfspGetV2ReferralSize(
  46. IN PDFS_PKT_ENTRY PktEntry,
  47. IN PUNICODE_STRING MachineName);
  48. ULONG
  49. DfspGetV3ReferralSize(
  50. IN PDFS_PKT_ENTRY PktEntry,
  51. IN PUNICODE_STRING MachineName);
  52. VOID
  53. DfspGetV1Referral(
  54. IN PDFS_PKT_ENTRY PktEntry,
  55. IN PUNICODE_STRING MachineName,
  56. OUT PRESP_GET_DFS_REFERRAL Ref);
  57. NTSTATUS
  58. DfspGetV2Referral(
  59. IN PDFS_PKT_ENTRY PktEntry,
  60. IN PUNICODE_STRING MachineName,
  61. IN ULONG BufferSize,
  62. OUT PRESP_GET_DFS_REFERRAL Ref,
  63. OUT PULONG ReferralSize);
  64. NTSTATUS
  65. DfspGetV3Referral(
  66. IN PDFS_PKT_ENTRY PktEntry,
  67. IN PUNICODE_STRING MachineName,
  68. IN PDFS_IP_INFO pIpInfo,
  69. IN ULONG BufferSize,
  70. OUT PRESP_GET_DFS_REFERRAL Ref,
  71. OUT PULONG ReferralSize);
  72. NTSTATUS
  73. DfspGetOneV3SpecialReferral(
  74. IN PDFS_SPECIAL_INFO pSpcInfo,
  75. IN PUNICODE_STRING Name,
  76. IN PDFS_IP_INFO pIpInfo,
  77. OUT PRESP_GET_DFS_REFERRAL Ref,
  78. IN ULONG MaximumSize,
  79. PULONG ReturnedSize);
  80. NTSTATUS
  81. DfspGetAllV3SpecialReferral(
  82. IN PDFS_IP_INFO pIpInfo,
  83. OUT PRESP_GET_DFS_REFERRAL Ref,
  84. IN ULONG MaximumSize,
  85. PULONG ReturnedSize);
  86. NTSTATUS
  87. DfspGetV3FtDfsReferral(
  88. IN PUNICODE_STRING DomainName,
  89. IN PUNICODE_STRING ShareName,
  90. IN PDFS_IP_INFO pIpInfo,
  91. OUT PRESP_GET_DFS_REFERRAL Ref,
  92. IN ULONG MaximumSize,
  93. PULONG ReturnedSize);
  94. NTSTATUS
  95. DfsFsctrlTranslatePath(
  96. IN PVOID InputBuffer,
  97. IN ULONG InputBufferLength);
  98. NTSTATUS
  99. DfsFsctrlGetReferrals(
  100. IN PVOID InputBuffer,
  101. IN ULONG InputBufferLength,
  102. OUT PVOID OutputBuffer,
  103. IN ULONG OutputBufferLength,
  104. OUT PULONG ReturnedSize);
  105. NTSTATUS
  106. DfsFsctrlIsShareInDfs(
  107. IN PVOID InputBuffer,
  108. IN ULONG InputBufferLength);
  109. NTSTATUS
  110. DfsFsctrlFindShare(
  111. IN PVOID InputBuffer,
  112. IN ULONG InputBufferLength);
  113. VOID
  114. SrvShuffle(
  115. PDFS_REFERRAL_LIST pRefList,
  116. LONG nStart,
  117. LONG nEnd);
  118. ULONG
  119. DfsIpOrdering(
  120. IN PDFS_IP_INFO pIpInfo,
  121. IN ULONG RefCount,
  122. IN PDFS_REFERRAL_LIST pRefList);
  123. PDFS_SPECIAL_INFO
  124. DfspLookupSpcEntry(
  125. IN PUNICODE_STRING SpecialName);
  126. BOOLEAN
  127. DfspIsSpecialShare(
  128. PUNICODE_STRING ShareName);
  129. #define UNICODE_STRING_STRUCT(s) \
  130. {sizeof(s) - sizeof(WCHAR), sizeof(s) - sizeof(WCHAR), (s)}
  131. static UNICODE_STRING SpecialShares[] = {
  132. UNICODE_STRING_STRUCT(L"SYSVOL"),
  133. UNICODE_STRING_STRUCT(L"NETLOGON"),
  134. UNICODE_STRING_STRUCT(L"DEBUG")
  135. };
  136. #ifdef ALLOC_PRAGMA
  137. #pragma alloc_text( PAGE, DfsSrvFsctrl )
  138. #pragma alloc_text( PAGE, DfsFsctrlTranslatePath )
  139. #pragma alloc_text( PAGE, DfsFsctrlGetReferrals )
  140. #pragma alloc_text( PAGE, DfsFsctrlIsShareInDfs )
  141. #pragma alloc_text( PAGE, DfsFsctrlFindShare )
  142. #pragma alloc_text( PAGE, DfsIpOrdering )
  143. #pragma alloc_text( PAGE, DfspFormPrefix )
  144. #pragma alloc_text( PAGE, DfspGetV1ReferralSize )
  145. #pragma alloc_text( PAGE, DfspGetV2ReferralSize )
  146. #pragma alloc_text( PAGE, DfspGetV3ReferralSize )
  147. #pragma alloc_text( PAGE, DfspGetV1Referral )
  148. #pragma alloc_text( PAGE, DfspGetV2Referral )
  149. #pragma alloc_text( PAGE, DfspGetV3Referral )
  150. #pragma alloc_text( PAGE, DfspGetAllV3SpecialReferral )
  151. #pragma alloc_text( PAGE, DfspGetOneV3SpecialReferral )
  152. #pragma alloc_text( PAGE, DfspLookupSpcEntry )
  153. #endif // ALLOC_PRAGMA
  154. //+----------------------------------------------------------------------------
  155. //
  156. // Function: DfsSrvFsctrl
  157. //
  158. // Synopsis: Process fsctrls used by the server to communicate with Dfs.
  159. //
  160. // Arguments: [IoControlCode] -- The fsctrl code.
  161. // [InputBuffer] -- Input buffer for fsctrl.
  162. // [InputBufferLength] -- Length in bytes of InputBuffer
  163. // [OutputBuffer] -- Output buffer for fsctrl.
  164. // [OutputBufferLength] -- Length in bytes of OutputBuffer
  165. // [IoStatus] -- place to return status of fsctrl.
  166. //
  167. // Returns: [STATUS_SUCCESS] -- Fsctrl handled successfully.
  168. //
  169. // [STATUS_INVALID_DEVICE_REQUEST] -- Unrecognized fsctrl code.
  170. //
  171. // Status returned by the appropriate fsctrl handler.
  172. //
  173. //-----------------------------------------------------------------------------
  174. VOID DfsSrvFsctrl(
  175. IN ULONG IoControlCode,
  176. IN PVOID InputBuffer,
  177. IN ULONG InputBufferLength,
  178. OUT PVOID OutputBuffer,
  179. IN ULONG OutputBufferLength,
  180. OUT PIO_STATUS_BLOCK IoStatus)
  181. {
  182. KPROCESSOR_MODE PreviousMode;
  183. ULONG returnedSize = 0;
  184. if (IoControlCode == FSCTL_DFS_IS_ROOT) {
  185. if (DfsData.MachineState == DFS_ROOT_SERVER) {
  186. IoStatus->Status = STATUS_SUCCESS;
  187. } else {
  188. IoStatus->Status = STATUS_PATH_NOT_COVERED;
  189. DFS_TRACE_HIGH(ERROR, DfsSrvFsctrl_Error1, LOGSTATUS(IoStatus->Status));
  190. }
  191. return;
  192. } else if (IoControlCode == FSCTL_DFS_IS_SHARE_IN_DFS) {
  193. IoStatus->Status = DfsFsctrlIsShareInDfs(
  194. InputBuffer,
  195. InputBufferLength);
  196. return;
  197. }
  198. PreviousMode = ExGetPreviousMode();
  199. if (PreviousMode != KernelMode) {
  200. IoStatus->Status = STATUS_INVALID_PARAMETER;
  201. DFS_TRACE_HIGH(ERROR, DfsSrvFsctrl_Error2, LOGSTATUS(IoStatus->Status));
  202. return;
  203. }
  204. switch (IoControlCode) {
  205. case FSCTL_DFS_TRANSLATE_PATH:
  206. IoStatus->Status = DfsFsctrlTranslatePath(
  207. InputBuffer,
  208. InputBufferLength);
  209. break;
  210. case FSCTL_DFS_GET_REFERRALS:
  211. IoStatus->Status = DfsFsctrlGetReferrals(
  212. InputBuffer,
  213. InputBufferLength,
  214. OutputBuffer,
  215. OutputBufferLength,
  216. &returnedSize);
  217. IoStatus->Information = returnedSize;
  218. break;
  219. case FSCTL_DFS_REPORT_INCONSISTENCY:
  220. IoStatus->Status = STATUS_SUCCESS;
  221. break;
  222. case FSCTL_DFS_FIND_SHARE:
  223. IoStatus->Status = DfsFsctrlFindShare(
  224. InputBuffer,
  225. InputBufferLength);
  226. break;
  227. default:
  228. IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
  229. DFS_TRACE_HIGH(ERROR, DfsSrvFsctrl_Error3, LOGSTATUS(IoStatus->Status));
  230. break;
  231. }
  232. }
  233. //+----------------------------------------------------------------------------
  234. //
  235. // Function: DfsFsctrlTranslatePath
  236. //
  237. // Synopsis: Given a share path of the form \??\X:\foo\bar
  238. // and a full-blown Dfs prefix of the form \Root\Dfs\frum\bump,
  239. // this routine will determine the path relative to
  240. // \??\X:\foo\bar that maps to \Root\Dfs\frum\bump.
  241. //
  242. // In the above example, if \??\X:\foo\bar maps to
  243. // \Root\Dfs\frum, then this routine will return \bump.
  244. //
  245. // Since this fsctrl is intended for use by the server, the
  246. // input parameter \Root\Dfs\frum\bump will itself be truncated
  247. // to indicate the relative path.
  248. //
  249. // Arguments: [InputBuffer] -- Pointer to DFS_TRANSLATE_PATH_ARG.
  250. //
  251. // [InputBufferLength] -- Length in bytes of InputBuffer
  252. //
  253. // Returns: [STATUS_SUCCESS] -- Input path successfully translated.
  254. //
  255. // [STATUS_PATH_NOT_COVERED] -- The input path crossed a junction
  256. // point, or is not in the dfs at all.
  257. //
  258. //-----------------------------------------------------------------------------
  259. NTSTATUS
  260. DfsFsctrlTranslatePath(
  261. IN PVOID InputBuffer,
  262. IN ULONG InputBufferLength)
  263. {
  264. PDFS_TRANSLATE_PATH_ARG arg = (PDFS_TRANSLATE_PATH_ARG) InputBuffer;
  265. PDFS_PKT pkt;
  266. PDFS_PKT_ENTRY pktEntry, shortPktEntry;
  267. PUNICODE_PREFIX_TABLE_ENTRY lvPrefix;
  268. PDFS_LOCAL_VOL_ENTRY lvEntry;
  269. UNICODE_STRING lvName;
  270. WCHAR nameBuffer[MAX_PATH];
  271. UNICODE_STRING prefix;
  272. UNICODE_STRING lastComponent;
  273. UNICODE_STRING remPath, shortRemPath;
  274. NTSTATUS status = STATUS_SUCCESS;
  275. DebugTrace(+1, Dbg, "DfsFsctrlTranslatePath entered\n", 0);
  276. DFS_TRACE_NORM(EVENT, DfsFsctrlTranslatePath_Start,
  277. LOGSTATUS(status)
  278. LOGUSTR(arg->SubDirectory)
  279. LOGUSTR(arg->DfsPathName)
  280. LOGUSTR(arg->ParentPathName));
  281. lvName = arg->SubDirectory;
  282. DebugTrace( 0, Dbg, "lvName=%wZ\n", &lvName);
  283. RtlZeroMemory( &prefix, sizeof(prefix) );
  284. //
  285. // Lookup the localVol in the local volume prefix table.
  286. //
  287. pkt = _GetPkt();
  288. PktAcquireExclusive( pkt, TRUE );
  289. lvPrefix = DfsFindUnicodePrefix(
  290. &pkt->LocalVolTable,
  291. &lvName,
  292. &remPath);
  293. if (lvPrefix != NULL) {
  294. DebugTrace( 0, Dbg, "found lvPrefix=0x%x\n", lvPrefix);
  295. lvEntry = CONTAINING_RECORD(
  296. lvPrefix,
  297. DFS_LOCAL_VOL_ENTRY,
  298. PrefixTableEntry);
  299. if (lvEntry->LocalPath.Length == lvName.Length) {
  300. DebugTrace( 0, Dbg, "found path for a local vol\n", 0);
  301. DebugTrace( 0, Dbg, "lvEntry->LocalPath=%wZ\n", &lvEntry->LocalPath);
  302. //
  303. // Found an exact match for a local volume. Next, we check
  304. // whether the Dfs path crosses an exit point.
  305. //
  306. prefix.Length = 0;
  307. prefix.MaximumLength = sizeof( nameBuffer );
  308. prefix.Buffer = nameBuffer;
  309. status = DfspFormPrefix(
  310. lvEntry,
  311. &arg->ParentPathName,
  312. &arg->DfsPathName,
  313. &prefix);
  314. if (arg->Flags & DFS_TRANSLATE_STRIP_LAST_COMPONENT) {
  315. DebugTrace( 0, Dbg, "prefix=%wZ\n", &prefix);
  316. lastComponent = prefix;
  317. RemoveLastComponent( &lastComponent, &prefix );
  318. lastComponent.Length -= prefix.Length;
  319. lastComponent.MaximumLength -= prefix.Length;
  320. lastComponent.Buffer += (prefix.Length / sizeof(WCHAR));
  321. DebugTrace( 0, Dbg, "lastComponent=%wZ\n", &lastComponent);
  322. }
  323. if (NT_SUCCESS(status)) {
  324. pktEntry = PktLookupEntryByPrefix(pkt, &prefix, &remPath);
  325. shortPktEntry =
  326. PktLookupEntryByShortPrefix(pkt, &prefix, &shortRemPath);
  327. if (shortPktEntry != NULL) {
  328. if (pktEntry == NULL ||
  329. shortPktEntry->Id.Prefix.Length >
  330. pktEntry->Id.Prefix.Length) {
  331. pktEntry = shortPktEntry;
  332. remPath = shortRemPath;
  333. }
  334. }
  335. DebugTrace( 0, Dbg, "pktEntry=0x%x\n", pktEntry);
  336. if (pktEntry != NULL) {
  337. //
  338. // Found a pkt entry that matches. Is it the one belonging
  339. // to the local volume that matched?
  340. //
  341. if (pktEntry == lvEntry->PktEntry) {
  342. DebugTrace( 0, Dbg, "pktEntry===lvEntryPktEntry\n", 0);
  343. ASSERT( pktEntry->LocalService != NULL );
  344. //
  345. // For DfsPathName which is relative to some parent
  346. // path, we don't need to adjust the DfsPathName;
  347. // simply checking to see if we landed up with the
  348. // same Pkt Entry is all that is needed.
  349. //
  350. if (arg->ParentPathName.Length == 0) {
  351. if (arg->Flags & DFS_TRANSLATE_STRIP_LAST_COMPONENT) {
  352. DebugTrace( 0, Dbg, "STRIP_LAST on \n", 0);
  353. remPath.Length += lastComponent.Length;
  354. }
  355. arg->DfsPathName.Length = remPath.Length;
  356. RtlMoveMemory(
  357. arg->DfsPathName.Buffer,
  358. remPath.Buffer,
  359. remPath.Length);
  360. arg->DfsPathName.Buffer[
  361. remPath.Length/sizeof(WCHAR)] = UNICODE_NULL;
  362. DebugTrace( 0, Dbg, "arg->DfsPathName=%wZ\n", &arg->DfsPathName);
  363. }
  364. status = STATUS_SUCCESS;
  365. } else {
  366. //
  367. // Must have crossed a junction point (to another local
  368. // volume!)
  369. //
  370. status = STATUS_PATH_NOT_COVERED;
  371. }
  372. } else {
  373. //
  374. // We don't know anything about this Dfs path. The client
  375. // must be guessing...
  376. //
  377. status = STATUS_PATH_NOT_COVERED;
  378. }
  379. }
  380. } else {
  381. //
  382. // Didn't find an exact match for the given local volume name.
  383. //
  384. status = STATUS_PATH_NOT_COVERED;
  385. }
  386. } else {
  387. //
  388. // Didn't find a match for the given local volume at all!
  389. //
  390. status = STATUS_PATH_NOT_COVERED;
  391. }
  392. PktRelease( pkt );
  393. if (prefix.Buffer != NULL && prefix.Buffer != nameBuffer) {
  394. ExFreePool( prefix.Buffer );
  395. }
  396. DebugTrace( 0, Dbg, "DfsFsctrlTranslatePath exit 0x%x\n", ULongToPtr( status ));
  397. DebugTrace( 0, Dbg, "-->arg->SubDirectory=%wZ\n", &arg->SubDirectory);
  398. DebugTrace( 0, Dbg, "-->arg->ParentPathName=%wZ\n", &arg->ParentPathName);
  399. DebugTrace(-1, Dbg, "-->arg->DfsPathName=%wZ\n", &arg->DfsPathName);
  400. DFS_TRACE_ERROR_HIGH(status, ALL_ERROR, DfsFsctrlTranslatePath_Error1,
  401. LOGSTATUS(status)
  402. LOGUSTR(arg->SubDirectory)
  403. LOGUSTR(arg->ParentPathName)
  404. LOGUSTR(arg->DfsPathName));
  405. DFS_TRACE_NORM(EVENT, DfsFsctrlTranslatePath_End,
  406. LOGSTATUS(status)
  407. LOGUSTR(arg->SubDirectory)
  408. LOGUSTR(arg->DfsPathName)
  409. LOGUSTR(arg->ParentPathName));
  410. return( status );
  411. }
  412. //+----------------------------------------------------------------------------
  413. //
  414. // Function: DfspFormPrefix
  415. //
  416. // Synopsis: Helper routine that forms the arguments to
  417. // DfsFsctrlTranslatePath into a prefix appropriate for looking
  418. // up in the Pkt.
  419. //
  420. // Arguments: [LvEntry] -- The local volume entry on which the ParentPath
  421. // was opened.
  422. // [ParentPath] -- The path of the parent object, relative to
  423. // the dfs volume referenced by LvEntry. (equivalently,
  424. // it is also relative to the Share Path). If this is a 0
  425. // length string, then this is not a relative open.
  426. // [DfsPathName] -- The name of the file that is being translated.
  427. // [Prefix] -- The fully formed prefix is returned here. On
  428. // entry, this should be initialized to have a buffer of
  429. // some reasonable size; on return, the buffer might be
  430. // replaced with a bigger one if needed, in which case
  431. // the buffer should be freed using ExFreePool.
  432. //
  433. // Returns: [STATUS_SUCCESS] -- Successfully formed prefix.
  434. //
  435. // [STATUS_INSUFFICIENT_RESOURCES] -- Unable to form prefix.
  436. //
  437. //-----------------------------------------------------------------------------
  438. NTSTATUS
  439. DfspFormPrefix(
  440. IN PDFS_LOCAL_VOL_ENTRY LvEntry,
  441. IN PUNICODE_STRING ParentPath,
  442. IN PUNICODE_STRING DfsPathName,
  443. IN OUT PUNICODE_STRING Prefix)
  444. {
  445. NTSTATUS status;
  446. ULONG sizeRequired;
  447. DebugTrace(+1, Dbg, "DfspFormPrefix(LvEntry=0x%x)\n", LvEntry);
  448. DebugTrace( 0, Dbg, " ParentPath=%wZ\n", ParentPath);
  449. DebugTrace( 0, Dbg, " DfsPathName=%wZ\n", DfsPathName);
  450. ASSERT(Prefix->Buffer != NULL);
  451. sizeRequired = sizeof(UNICODE_PATH_SEP) +
  452. ParentPath->Length +
  453. sizeof(UNICODE_PATH_SEP) +
  454. DfsPathName->Length;
  455. if (ParentPath->Length > 0) {
  456. sizeRequired += LvEntry->PktEntry->Id.Prefix.Length;
  457. }
  458. if (sizeRequired > MAXUSHORT) {
  459. status = STATUS_INSUFFICIENT_RESOURCES;
  460. DFS_TRACE_HIGH(ERROR, DfspFormPrefix_Error1,
  461. LOGSTATUS(status)
  462. LOGUSTR(*ParentPath)
  463. LOGUSTR(*DfsPathName));
  464. return status;
  465. }
  466. if (sizeRequired > Prefix->MaximumLength) {
  467. Prefix->MaximumLength = (USHORT)sizeRequired;
  468. Prefix->Buffer = ExAllocatePoolWithTag(PagedPool, sizeRequired, ' sfD');
  469. }
  470. if (Prefix->Buffer != NULL) {
  471. if (ParentPath->Length > 0) {
  472. RtlAppendUnicodeStringToString(
  473. Prefix,
  474. &LvEntry->PktEntry->Id.Prefix);
  475. DfsConcatenateFilePath(
  476. Prefix,
  477. ParentPath->Buffer,
  478. (USHORT) (ParentPath->Length));
  479. } else {
  480. RtlAppendUnicodeToString(
  481. Prefix,
  482. UNICODE_PATH_SEP_STR);
  483. }
  484. DfsConcatenateFilePath(
  485. Prefix,
  486. DfsPathName->Buffer,
  487. DfsPathName->Length);
  488. status = STATUS_SUCCESS;
  489. } else {
  490. status = STATUS_INSUFFICIENT_RESOURCES;
  491. }
  492. DebugTrace( 0, Dbg, "on exit, Prefix=%wZ\n", Prefix);
  493. DebugTrace(-1, Dbg, "DfspFormPrefix exit 0x%x\n", ULongToPtr( status ));
  494. DFS_TRACE_ERROR_HIGH(status, ALL_ERROR, DfspFormPrefix_Error2,
  495. LOGSTATUS(status)
  496. LOGUSTR(*ParentPath)
  497. LOGUSTR(*DfsPathName));
  498. return( status );
  499. }
  500. //+----------------------------------------------------------------------------
  501. //
  502. // Function: DfsFsctrlGetReferrals
  503. //
  504. // Synopsis: Returns a referral buffer for the given prefix.
  505. //
  506. // Arguments: [InputBuffer] -- Pointer to DFS_GET_REFERRALS_INPUT_ARG
  507. // [InputBufferLength] -- Length of InputBuffer.
  508. // [OutputBuffer] -- On successful return, contains a
  509. // DFS_GET_REFERRALS_OUTPUT_BUFFER.
  510. // [OutputBufferLength] -- Length in bytes of OutputBuffer.
  511. // [ReturnedSize] -- On successful return, size of the returned
  512. // referral. If returning STATUS_BUFFER_OVERFLOW, this
  513. // variable contains the size of the buffer required to
  514. // fit the entire referral.
  515. //
  516. // Returns: [STATUS_SUCCESS] -- DFS_GET_REFERRALS_OUTPUT_BUFFER
  517. // successfully returned.
  518. //
  519. // [STATUS_BUFFER_OVERFLOW] -- Couldn't fit all the referrals
  520. // in the buffer; the required buffer length is returned
  521. // in ReturnedSize.
  522. //
  523. // [STATUS_NO_SUCH_DEVICE] -- Unable to find the Dfs volume in
  524. // the local pkt.
  525. //
  526. //-----------------------------------------------------------------------------
  527. NTSTATUS
  528. DfsFsctrlGetReferrals(
  529. IN PVOID InputBuffer,
  530. IN ULONG InputBufferLength,
  531. OUT PVOID OutputBuffer,
  532. IN ULONG OutputBufferLength,
  533. OUT PULONG ReturnedSize)
  534. {
  535. NTSTATUS status = STATUS_SUCCESS;
  536. PDFS_GET_REFERRALS_INPUT_ARG arg =
  537. (PDFS_GET_REFERRALS_INPUT_ARG) InputBuffer;
  538. PRESP_GET_DFS_REFERRAL ref =
  539. (PRESP_GET_DFS_REFERRAL) OutputBuffer;
  540. PDFS_PKT pkt;
  541. PDFS_PKT_ENTRY pktEntry, shortPfxEntry;
  542. PDFS_IPADDRESS pIpAddress = NULL;
  543. UNICODE_STRING prefix;
  544. UNICODE_STRING PrefixTail;
  545. UNICODE_STRING remPath;
  546. UNICODE_STRING DomainName;
  547. UNICODE_STRING ShareName;
  548. ULONG i, size, maxLevel;
  549. LPWSTR AltList;
  550. PDFS_IP_INFO pIpInfo = NULL;
  551. PDFS_SPECIAL_INFO pSpcInfo = NULL;
  552. PSPECIAL_HASH_TABLE pHashTable = DfsData.SpcHashTable;
  553. DFS_TRACE_NORM(EVENT, DfsFsctrlGetReferrals_Start,
  554. LOGSTATUS(status)
  555. LOGUSTR(arg->DfsPathName));
  556. //
  557. // If we're not started, then say so
  558. //
  559. if (DfsData.OperationalState != DFS_STATE_STARTED && DfsData.IsDC == FALSE) {
  560. status = STATUS_DFS_UNAVAILABLE;
  561. DFS_TRACE_HIGH(ERROR, DfsFsctrlGetReferrals_Error1, LOGSTATUS(status));
  562. //return( status );
  563. goto cleanup;
  564. }
  565. if (InputBufferLength == sizeof(DFS_GET_REFERRALS_INPUT_ARG)
  566. &&
  567. RtlCompareMemory(
  568. &ZeroIpAddress,
  569. &arg->IpAddress,
  570. sizeof(DFS_IPADDRESS)) != sizeof(DFS_IPADDRESS)) {
  571. pIpAddress = &arg->IpAddress;
  572. }
  573. prefix = arg->DfsPathName;
  574. if ((maxLevel = arg->MaxReferralLevel) > 3)
  575. maxLevel = 3;
  576. DebugTrace(0, Dbg, "DfsFsctrlGetReferrals(maxLevel=%d)\n", ULongToPtr( maxLevel ));
  577. // Create domain, sharename, remainder from prefix
  578. remPath.Length = remPath.MaximumLength = 0;
  579. DfspParsePath(&prefix, &DomainName, &ShareName, &remPath);
  580. // See if this is a special name referral
  581. if (DfsData.IsDC == TRUE) {
  582. if (maxLevel >= 3 &&
  583. (DomainName.Length == 0 ||
  584. (DomainName.Length > 0 && ShareName.Length == 0))) {
  585. DebugTrace(0, Dbg, "DfsFsctrlGetReferrals: case 1\n", 0);
  586. ref->PathConsumed = 0;
  587. if (DomainName.Length > 0) {
  588. pSpcInfo = DfspLookupSpcEntry(&DomainName);
  589. if (pSpcInfo != NULL && pSpcInfo->NameCount > 1) {
  590. pIpInfo = DfsLookupSiteByIpaddress(pIpAddress, TRUE);
  591. }
  592. status = DfspGetOneV3SpecialReferral(
  593. pSpcInfo,
  594. &DomainName,
  595. pIpInfo,
  596. ref,
  597. OutputBufferLength,
  598. ReturnedSize);
  599. if (pSpcInfo != NULL) {
  600. DfsReleaseSpcInfo(pHashTable, pSpcInfo);
  601. pSpcInfo = NULL;
  602. }
  603. } else {
  604. status = DfspGetAllV3SpecialReferral(
  605. pIpInfo,
  606. ref,
  607. OutputBufferLength,
  608. ReturnedSize);
  609. }
  610. DfsReleaseIpInfo(pIpInfo);
  611. if (DfsEventLog > 1)
  612. LogWriteMessage(DFS_REFERRAL_REQUEST, status, 1, &prefix);
  613. //return( status );
  614. goto cleanup;
  615. }
  616. }
  617. //
  618. // If we are going to hand out regular referrals,
  619. // check to see that we are a root server, and that the
  620. // referral request looks good.
  621. //
  622. pSpcInfo = DfspLookupSpcEntry(&DomainName);
  623. if (DfsData.MachineState == DFS_ROOT_SERVER
  624. &&
  625. DfsData.OperationalState == DFS_STATE_STARTED
  626. &&
  627. DfsData.LvState == LV_INITIALIZED
  628. &&
  629. DomainName.Length > 0
  630. &&
  631. ShareName.Length > 0
  632. &&
  633. (pSpcInfo == NULL || remPath.Length > 0)
  634. ) {
  635. DebugTrace(0, Dbg, "DfsFsctrlGetReferrals: case 2\n", 0);
  636. pkt = _GetPkt();
  637. if (maxLevel >= 3) {
  638. PktAcquireShared( pkt, TRUE );
  639. pktEntry = PktLookupEntryByPrefix( pkt, &prefix, &remPath);
  640. PktRelease( pkt );
  641. if (pktEntry != NULL && pktEntry->Info.ServiceCount > 1) {
  642. pIpInfo = DfsLookupSiteByIpaddress(pIpAddress, TRUE);
  643. }
  644. }
  645. PktAcquireShared( pkt, TRUE );
  646. //
  647. // Look up the name the client wants a referral for
  648. //
  649. if ((pktEntry = PktLookupEntryByPrefix( pkt, &prefix, &remPath)) != NULL) {
  650. //
  651. // See if there is a better match with an 8.3 prefix
  652. //
  653. shortPfxEntry = PktLookupEntryByShortPrefix( pkt, &prefix, &remPath );
  654. if ((maxLevel == 2 || maxLevel == 3) &&
  655. shortPfxEntry != NULL &&
  656. (shortPfxEntry->Id.Prefix.Length >
  657. pktEntry->Id.Prefix.Length)) {
  658. pktEntry = shortPfxEntry;
  659. RemoveFirstComponent(&pktEntry->Id.ShortPrefix, &PrefixTail);
  660. } else {
  661. RemoveFirstComponent(&pktEntry->Id.Prefix, &PrefixTail);
  662. }
  663. ref->PathConsumed = sizeof(UNICODE_PATH_SEP) +
  664. DomainName.Length +
  665. PrefixTail.Length;
  666. //
  667. // Found an entry for the requested path. First, size the referral,
  668. // then, if it will fit in the output buffer, marshal it in.
  669. //
  670. switch (maxLevel) {
  671. case 1:
  672. size = DfspGetV1ReferralSize(pktEntry, &DomainName); break;
  673. case 2:
  674. size = DfspGetV2ReferralSize(pktEntry, &DomainName); break;
  675. case 3:
  676. size = DfspGetV3ReferralSize(pktEntry, &DomainName); break;
  677. default:
  678. ASSERT(FALSE && "Invalid MaxLevel");
  679. }
  680. status = STATUS_SUCCESS;
  681. //
  682. // For level 1 referral, we fail if buffer is not big enough to
  683. // fit entire referral. For level 2 and 3, we try to fit as many
  684. // entries as possible into the refferal.
  685. switch (maxLevel) {
  686. case 1:
  687. if (size <= OutputBufferLength) {
  688. DfspGetV1Referral(pktEntry, &DomainName, ref);
  689. } else {
  690. status = STATUS_BUFFER_OVERFLOW;
  691. DFS_TRACE_HIGH(ERROR, DfsFsctrlGetReferals_Error1, LOGSTATUS(status));
  692. }
  693. break;
  694. case 2:
  695. status = DfspGetV2Referral(pktEntry, &DomainName, OutputBufferLength, ref, &size); break;
  696. case 3:
  697. status = DfspGetV3Referral(pktEntry, &DomainName, pIpInfo, OutputBufferLength, ref, &size); break;
  698. default:
  699. ASSERT(FALSE && "Invalid MaxLevel");
  700. }
  701. if (status == STATUS_SUCCESS) {
  702. *ReturnedSize = size;
  703. }
  704. PktRelease( pkt );
  705. DfsReleaseIpInfo(pIpInfo);
  706. if (DfsEventLog > 1)
  707. LogWriteMessage(DFS_REFERRAL_REQUEST, status, 1, &prefix);
  708. //return( status );
  709. goto cleanup;
  710. }
  711. PktRelease( pkt );
  712. }
  713. if (pSpcInfo != NULL) {
  714. DfsReleaseSpcInfo(pHashTable, pSpcInfo);
  715. }
  716. if (DfsData.IsDC == TRUE) {
  717. //
  718. // See if this is an FtDFS referral
  719. //
  720. if (maxLevel >= 3
  721. &&
  722. DomainName.Length > 0
  723. &&
  724. ShareName.Length > 0
  725. &&
  726. remPath.Length == 0
  727. ) {
  728. DebugTrace( 0, Dbg, "DfsFsctrlGetReferrals: case 3\n", 0);
  729. DebugTrace( 0, Dbg, " DomainName=%wZ\n", &DomainName);
  730. DebugTrace( 0, Dbg, " ShareName=%wZ\n", &ShareName);
  731. pIpInfo = DfsLookupSiteByIpaddress(pIpAddress, TRUE);
  732. status = DfspGetV3FtDfsReferral(
  733. &DomainName,
  734. &ShareName,
  735. pIpInfo,
  736. ref,
  737. OutputBufferLength,
  738. ReturnedSize);
  739. DebugTrace(-1, Dbg, "DfsFsctrlGetReferrals: exit->0x%x\n", ULongToPtr( status ));
  740. DfsReleaseIpInfo(pIpInfo);
  741. if (DfsEventLog > 1)
  742. LogWriteMessage(DFS_REFERRAL_REQUEST, status, 1, &prefix);
  743. //return( status );
  744. goto cleanup;
  745. }
  746. }
  747. //
  748. // Nobody claimed this referral
  749. //
  750. DfsReleaseIpInfo(pIpInfo);
  751. if (DfsEventLog > 1)
  752. LogWriteMessage(DFS_REFERRAL_REQUEST, STATUS_NO_SUCH_DEVICE, 1, &prefix);
  753. DebugTrace(-1, Dbg, "DfsFsctrlGetReferrals: exit STATUS_NO_SUCH_DEVICE\n", 0);
  754. status = STATUS_NO_SUCH_DEVICE;
  755. DFS_TRACE_HIGH(ERROR, DfsFsctrlGetReferals_Error2, LOGSTATUS(status));
  756. cleanup:
  757. DFS_TRACE_NORM(EVENT, DfsFsctrlGetReferrals_End,
  758. LOGSTATUS(status)
  759. LOGUSTR(arg->DfsPathName));
  760. return(status);
  761. }
  762. //+----------------------------------------------------------------------------
  763. //
  764. // Function: DfspGetV1ReferralSize, private
  765. //
  766. // Synopsis: Sizes a V1 referral given a PktEntry
  767. //
  768. // Arguments: [PktEntry] -- The pkt entry to be returned in the referral
  769. //
  770. // Returns: Size in bytes of a buffer required to hold the V1 referral
  771. // for this Pkt Entry
  772. //
  773. //-----------------------------------------------------------------------------
  774. ULONG
  775. DfspGetV1ReferralSize(
  776. IN PDFS_PKT_ENTRY PktEntry,
  777. IN PUNICODE_STRING MachineName)
  778. {
  779. ULONG i, size;
  780. size = sizeof( RESP_GET_DFS_REFERRAL );
  781. for (i = 0; i < PktEntry->Info.ServiceCount; i++) {
  782. size += sizeof(DFS_REFERRAL_V1) +
  783. PktEntry->Info.ServiceList[i].Address.Length +
  784. sizeof(UNICODE_NULL);
  785. }
  786. return( size );
  787. }
  788. //+----------------------------------------------------------------------------
  789. //
  790. // Function: DfspGetV2ReferralSize, private
  791. //
  792. // Synopsis: Sizes a V2 referral given a PktEntry
  793. //
  794. // Arguments: [PktEntry] -- The pkt entry to be returned in the referral
  795. //
  796. // Returns: Size in bytes of a buffer required to hold the V2 referral
  797. // for this Pkt Entry
  798. //
  799. //-----------------------------------------------------------------------------
  800. ULONG
  801. DfspGetV2ReferralSize(
  802. IN PDFS_PKT_ENTRY PktEntry,
  803. IN PUNICODE_STRING MachineName)
  804. {
  805. UNICODE_STRING PrefixTail;
  806. ULONG i, size;
  807. DebugTrace(+1, Dbg, "DfsPGetV2ReferralSize()\n", 0);
  808. size = sizeof( RESP_GET_DFS_REFERRAL );
  809. for (i = 0; i < PktEntry->Info.ServiceCount; i++) {
  810. size += sizeof(DFS_REFERRAL_V2) +
  811. PktEntry->Info.ServiceList[i].Address.Length +
  812. sizeof(UNICODE_NULL);
  813. }
  814. RemoveFirstComponent(&PktEntry->Id.Prefix, &PrefixTail);
  815. size += sizeof(UNICODE_PATH_SEP) +
  816. MachineName->Length +
  817. PrefixTail.Length +
  818. sizeof(UNICODE_NULL);
  819. RemoveFirstComponent(&PktEntry->Id.ShortPrefix, &PrefixTail);
  820. size += sizeof(UNICODE_PATH_SEP) +
  821. MachineName->Length +
  822. PrefixTail.Length +
  823. sizeof(UNICODE_NULL);
  824. DebugTrace(-1, Dbg, "DfspGetV2ReferralSize() -- returning 0x%x\n", ULongToPtr( size ));
  825. return( size );
  826. }
  827. //+----------------------------------------------------------------------------
  828. //
  829. // Function: DfspGetV3ReferralSize, private
  830. //
  831. // Synopsis: Sizes a V3 referral given a PktEntry
  832. //
  833. // Arguments: [PktEntry] -- The pkt entry to be returned in the referral
  834. //
  835. // Returns: Size in bytes of a buffer required to hold the V3 referral
  836. // for this Pkt Entry
  837. //
  838. //-----------------------------------------------------------------------------
  839. ULONG
  840. DfspGetV3ReferralSize(
  841. IN PDFS_PKT_ENTRY PktEntry,
  842. IN PUNICODE_STRING MachineName)
  843. {
  844. UNICODE_STRING PrefixTail;
  845. ULONG i, size;
  846. DebugTrace(+1, Dbg, "DfsPGetV3ReferralSize()\n", 0);
  847. size = sizeof( RESP_GET_DFS_REFERRAL );
  848. for (i = 0; i < PktEntry->Info.ServiceCount; i++) {
  849. size += sizeof(DFS_REFERRAL_V3) +
  850. PktEntry->Info.ServiceList[i].Address.Length +
  851. sizeof(UNICODE_NULL);
  852. }
  853. RemoveFirstComponent(&PktEntry->Id.Prefix, &PrefixTail);
  854. size += sizeof(UNICODE_PATH_SEP) +
  855. MachineName->Length +
  856. PrefixTail.Length +
  857. sizeof(UNICODE_NULL);
  858. RemoveFirstComponent(&PktEntry->Id.ShortPrefix, &PrefixTail);
  859. size += sizeof(UNICODE_PATH_SEP) +
  860. MachineName->Length +
  861. PrefixTail.Length +
  862. sizeof(UNICODE_NULL);
  863. DebugTrace(-1, Dbg, "DfspGetV3ReferralSize() -- returning 0x%x\n", ULongToPtr( size ));
  864. return( size );
  865. }
  866. //+----------------------------------------------------------------------------
  867. //
  868. // Function: DfspGetV1Referral, private
  869. //
  870. // Synopsis: Marshals a pkt entry into a RESP_GET_DFS_REFERRAL buffer with
  871. // V1 referrals
  872. //
  873. // Arguments:
  874. //
  875. // Returns:
  876. //
  877. //-----------------------------------------------------------------------------
  878. VOID
  879. DfspGetV1Referral(
  880. IN PDFS_PKT_ENTRY PktEntry,
  881. IN PUNICODE_STRING MachineName,
  882. OUT PRESP_GET_DFS_REFERRAL Ref)
  883. {
  884. PDFS_REFERRAL_V1 pv1;
  885. ULONG i;
  886. Ref->NumberOfReferrals = (USHORT) PktEntry->Info.ServiceCount;
  887. Ref->ReferralServers =
  888. (PktEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC ? 1 : 0);
  889. Ref->StorageServers = 1;
  890. for (i = 0, pv1 = &Ref->Referrals[0].v1;
  891. i < PktEntry->Info.ServiceCount;
  892. i++) {
  893. PDFS_SERVICE pSvc;
  894. pSvc = &PktEntry->Info.ServiceList[i];
  895. pv1->VersionNumber = 1;
  896. pv1->Size = sizeof(DFS_REFERRAL_V1) +
  897. pSvc->Address.Length +
  898. sizeof(UNICODE_NULL);
  899. pv1->ServerType =
  900. pSvc->Type & DFS_SERVICE_TYPE_DOWN_LEVEL ? 0 : 1;
  901. RtlCopyMemory(
  902. pv1->ShareName,
  903. pSvc->Address.Buffer,
  904. pSvc->Address.Length);
  905. pv1->ShareName[ pSvc->Address.Length / sizeof(WCHAR) ] =
  906. UNICODE_NULL;
  907. pv1 = (PDFS_REFERRAL_V1) ( ((PCHAR) pv1) + pv1->Size );
  908. }
  909. }
  910. //+----------------------------------------------------------------------------
  911. //
  912. // Function: DfspGetV2Referral, private
  913. //
  914. // Synopsis: Marshals a pkt entry into a RESP_GET_DFS_REFERRAL buffer with
  915. // V2 referrals
  916. //
  917. // Arguments:
  918. //
  919. // Returns:
  920. //
  921. //-----------------------------------------------------------------------------
  922. NTSTATUS
  923. DfspGetV2Referral(
  924. IN PDFS_PKT_ENTRY PktEntry,
  925. IN PUNICODE_STRING MachineName,
  926. IN ULONG BufferSize,
  927. OUT PRESP_GET_DFS_REFERRAL Ref,
  928. OUT PULONG ReferralSize)
  929. {
  930. PDFS_REFERRAL_V2 pv2;
  931. ULONG i;
  932. ULONG j;
  933. LPWSTR dfsPath, alternatePath, nextAddress;
  934. UNICODE_STRING PrefixTail;
  935. ULONG CumulativeSize, CurrentSize;
  936. ULONG optimalReferralCount;
  937. USHORT totalReferrals = 0;
  938. NTSTATUS status;
  939. // Setup the maximum number of referrals that we intend to return.
  940. if (DfsData.Pkt.MaxReferrals != 0) {
  941. optimalReferralCount = DfsData.Pkt.MaxReferrals;
  942. }
  943. else {
  944. optimalReferralCount = MAXIMUM_DFS_REFERRALS;
  945. }
  946. DebugTrace(+1, Dbg, "DfspGetV2Referral()\n", 0);
  947. // Calculate the size of the referral, and make sure our size does not
  948. // exceed the passed in buffer len.
  949. CumulativeSize = sizeof (RESP_GET_DFS_REFERRAL) +
  950. MachineName->Length + PktEntry->Id.Prefix.Length +
  951. sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL) +
  952. MachineName->Length + PktEntry->Id.ShortPrefix.Length +
  953. sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL);
  954. if (BufferSize < CumulativeSize) {
  955. status = STATUS_BUFFER_OVERFLOW;
  956. DFS_TRACE_HIGH(ERROR, DfspGetV2Referral_Error1,
  957. LOGSTATUS(status)
  958. LOGUSTR(*MachineName));
  959. return status;
  960. }
  961. Ref->NumberOfReferrals = (USHORT) PktEntry->Info.ServiceCount;
  962. Ref->ReferralServers =
  963. (PktEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC ? 1 : 0);
  964. Ref->StorageServers =
  965. (PktEntry->Type & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM ? 0 : 1);
  966. pv2 = &Ref->Referrals[0].v2;
  967. for (i = 0; i < Ref->NumberOfReferrals; i++) {
  968. PDFS_SERVICE pSvc;
  969. pSvc = &PktEntry->Info.ServiceList[i];
  970. if ((pSvc->Type & DFS_SERVICE_TYPE_OFFLINE) == 0) {
  971. totalReferrals++;
  972. }
  973. }
  974. for (i = j = 0; i < Ref->NumberOfReferrals; i++) {
  975. PDFS_SERVICE pSvc;
  976. pSvc = &PktEntry->Info.ServiceList[i];
  977. if ((pSvc->Type & DFS_SERVICE_TYPE_OFFLINE) == 0) {
  978. CurrentSize = sizeof(DFS_REFERRAL_V2) + pSvc->Address.Length + sizeof(UNICODE_NULL);
  979. if (((CumulativeSize + CurrentSize) >= BufferSize) || (j >= optimalReferralCount))
  980. break;
  981. j++;
  982. CumulativeSize += CurrentSize;
  983. }
  984. }
  985. // Adjust the number of referrals accordingly.
  986. Ref->NumberOfReferrals = (USHORT)i;
  987. //
  988. // Copy the volume prefix into the response buffer, just past the end
  989. // of all the V2 referrals
  990. //
  991. nextAddress = dfsPath = (LPWSTR) &pv2[j];
  992. *nextAddress++ = UNICODE_PATH_SEP;
  993. RtlCopyMemory(
  994. nextAddress,
  995. MachineName->Buffer,
  996. MachineName->Length);
  997. nextAddress += MachineName->Length/sizeof(WCHAR);
  998. RemoveFirstComponent(&PktEntry->Id.Prefix, &PrefixTail);
  999. RtlCopyMemory(
  1000. nextAddress,
  1001. PrefixTail.Buffer,
  1002. PrefixTail.Length);
  1003. nextAddress += PrefixTail.Length/sizeof(WCHAR);
  1004. *nextAddress++ = UNICODE_NULL;
  1005. //
  1006. // Copy the 8.3 volume prefix into the response buffer after the
  1007. // dfsPath
  1008. //
  1009. alternatePath = nextAddress;
  1010. *nextAddress++ = UNICODE_PATH_SEP;
  1011. RtlCopyMemory(
  1012. nextAddress,
  1013. MachineName->Buffer,
  1014. MachineName->Length);
  1015. nextAddress += MachineName->Length/sizeof(WCHAR);
  1016. RemoveFirstComponent(&PktEntry->Id.ShortPrefix, &PrefixTail);
  1017. RtlCopyMemory(
  1018. nextAddress,
  1019. PrefixTail.Buffer,
  1020. PrefixTail.Length);
  1021. nextAddress += PrefixTail.Length/sizeof(WCHAR);
  1022. *nextAddress++ = UNICODE_NULL;
  1023. //
  1024. // nextAddress is pointer into buffer where the individual service addresses
  1025. // will go.
  1026. //
  1027. for (i = j = 0; i < Ref->NumberOfReferrals; i++) {
  1028. PDFS_SERVICE pSvc;
  1029. //
  1030. // Only take online services
  1031. //
  1032. pSvc = &PktEntry->Info.ServiceList[i];
  1033. if ((pSvc->Type & DFS_SERVICE_TYPE_OFFLINE) == 0) {
  1034. pv2->VersionNumber = 2;
  1035. pv2->Size = sizeof(DFS_REFERRAL_V2);
  1036. pv2->ServerType =
  1037. pSvc->Type & DFS_SERVICE_TYPE_DOWN_LEVEL ? 0 : 1;
  1038. pv2->Proximity = 0;
  1039. pv2->TimeToLive = PktEntry->Info.Timeout;
  1040. pv2->DfsPathOffset = (USHORT) (((PCHAR) dfsPath) - ((PCHAR) pv2));
  1041. pv2->DfsAlternatePathOffset =
  1042. (USHORT) (((PCHAR) alternatePath) - ((PCHAR) pv2));
  1043. pv2->NetworkAddressOffset =
  1044. (USHORT) (((PCHAR) nextAddress) - ((PCHAR) pv2));
  1045. RtlCopyMemory(
  1046. nextAddress,
  1047. pSvc->Address.Buffer,
  1048. pSvc->Address.Length);
  1049. nextAddress[ pSvc->Address.Length/sizeof(WCHAR) ] = UNICODE_NULL;
  1050. nextAddress += pSvc->Address.Length/sizeof(WCHAR) + 1;
  1051. pv2++;
  1052. j++;
  1053. }
  1054. }
  1055. Ref->NumberOfReferrals = (USHORT) j;
  1056. //
  1057. // we have more than one service, but cannot fit any into the buffer
  1058. // return buffer overflow.
  1059. //
  1060. if ((totalReferrals > 0) && (Ref->NumberOfReferrals == 0)) {
  1061. status = STATUS_BUFFER_OVERFLOW;
  1062. DFS_TRACE_HIGH(ERROR, DfspGetV2Referral_Error2,
  1063. LOGSTATUS(status)
  1064. LOGUSTR(*MachineName));
  1065. return status;
  1066. }
  1067. *ReferralSize = (ULONG)((PUCHAR)nextAddress - (PUCHAR)Ref);
  1068. DebugTrace(-1, Dbg, "DfspGetV2Referral() -- exit\n", 0);
  1069. return STATUS_SUCCESS;
  1070. }
  1071. //+----------------------------------------------------------------------------
  1072. //
  1073. // Function: DfspGetV3Referral, private
  1074. //
  1075. // Synopsis: Marshals a pkt entry into a RESP_GET_DFS_REFERRAL buffer with
  1076. // V3 referrals
  1077. //
  1078. // Arguments:
  1079. //
  1080. // Returns:
  1081. //
  1082. //-----------------------------------------------------------------------------
  1083. NTSTATUS
  1084. DfspGetV3Referral(
  1085. IN PDFS_PKT_ENTRY PktEntry,
  1086. IN PUNICODE_STRING MachineName,
  1087. IN PDFS_IP_INFO pIpInfo,
  1088. IN ULONG BufferSize,
  1089. OUT PRESP_GET_DFS_REFERRAL Ref,
  1090. OUT PULONG ReferralSize)
  1091. {
  1092. PDFS_REFERRAL_V3 pv3;
  1093. ULONG i;
  1094. ULONG j;
  1095. LPWSTR dfsPath, alternatePath, nextAddress;
  1096. UNICODE_STRING PrefixTail;
  1097. PDFS_REFERRAL_LIST pRefList = NULL;
  1098. ULONG CumulativeSize, Ndx, CurrentSize;
  1099. USHORT totalReferrals;
  1100. ULONG InSite;
  1101. ULONG optimalReferralCount;
  1102. NTSTATUS status;
  1103. // Setup the maximum number of referrals that we intend to return.
  1104. if (DfsData.Pkt.MaxReferrals != 0) {
  1105. optimalReferralCount = DfsData.Pkt.MaxReferrals;
  1106. }
  1107. else {
  1108. optimalReferralCount = MAXIMUM_DFS_REFERRALS;
  1109. }
  1110. DebugTrace(+1, Dbg, "DfspGetV3Referral()\n", 0);
  1111. // Calculate the size of the referral, and make sure our size does not
  1112. // exceed the passed in buffer len.
  1113. CumulativeSize =
  1114. sizeof (RESP_GET_DFS_REFERRAL) +
  1115. MachineName->Length + PktEntry->Id.Prefix.Length +
  1116. sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL) +
  1117. MachineName->Length + PktEntry->Id.ShortPrefix.Length +
  1118. sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL);
  1119. if (BufferSize < CumulativeSize) {
  1120. status = STATUS_BUFFER_OVERFLOW;
  1121. DFS_TRACE_HIGH(ERROR, DfspGetV3Referral_Error1,
  1122. LOGSTATUS(status)
  1123. LOGUSTR(*MachineName));
  1124. return status;
  1125. }
  1126. Ref->NumberOfReferrals = (USHORT) PktEntry->Info.ServiceCount;
  1127. totalReferrals = Ref->NumberOfReferrals;
  1128. //
  1129. // Alloc and init a DFS_REFERRAL_LIST
  1130. //
  1131. if (Ref->NumberOfReferrals) {
  1132. pRefList = ExAllocatePoolWithTag(
  1133. PagedPool,
  1134. sizeof(DFS_REFERRAL_LIST) * Ref->NumberOfReferrals,
  1135. ' sfD');
  1136. if (pRefList == NULL) {
  1137. DebugTrace(-1,
  1138. Dbg,
  1139. "DfspGetV3Referral() exit STATUS_INSUFFICIENT_RESOURCES\n",
  1140. 0);
  1141. status = STATUS_INSUFFICIENT_RESOURCES;
  1142. DFS_TRACE_HIGH(ERROR, DfspGetV3Referral_Error2,
  1143. LOGSTATUS(status)
  1144. LOGUSTR(*MachineName));
  1145. return status;
  1146. }
  1147. }
  1148. //
  1149. // Initialize it
  1150. //
  1151. for (i = j = 0; i < Ref->NumberOfReferrals; i++) {
  1152. //
  1153. // Skip offline entries
  1154. //
  1155. if ((PktEntry->Info.ServiceList[i].Type & DFS_SERVICE_TYPE_OFFLINE) == 0) {
  1156. pRefList[j].pName = PktEntry->Info.ServiceList[i].Name;
  1157. pRefList[j].pAddress = PktEntry->Info.ServiceList[i].Address;
  1158. pRefList[j].Type = PktEntry->Info.ServiceList[i].Type;
  1159. j++;
  1160. }
  1161. }
  1162. Ref->NumberOfReferrals = (USHORT)j;
  1163. if (Ref->NumberOfReferrals) {
  1164. //
  1165. // Shuffle the list in case we don't have site info
  1166. //
  1167. SrvShuffle(pRefList, 0, Ref->NumberOfReferrals - 1);
  1168. //
  1169. // Determine client's site based on the IP address srv gave us.
  1170. //
  1171. if (pIpInfo != NULL) {
  1172. //
  1173. // Reorder by site
  1174. //
  1175. InSite = DfsIpOrdering(pIpInfo, Ref->NumberOfReferrals, pRefList);
  1176. if (PktEntry->Type & PKT_ENTRY_TYPE_INSITE_ONLY) {
  1177. Ref->NumberOfReferrals = (USHORT)InSite;
  1178. }
  1179. }
  1180. }
  1181. Ref->ReferralServers =
  1182. (PktEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC ? 1 : 0);
  1183. Ref->StorageServers =
  1184. (PktEntry->Type & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM ? 0 : 1);
  1185. totalReferrals = Ref->NumberOfReferrals;
  1186. pv3 = &Ref->Referrals[0].v3;
  1187. //
  1188. // Now, we have a shuffled list of referrals. see how many we can give back
  1189. // to the client in the buffer allocated.
  1190. // We pick the first entry, followed by the last entry, then the second
  1191. // entry followed by the last but one, and so on. The purpose of this
  1192. // logic is to ensure that we split the returned referrals between
  1193. // the "insite" referrals that are on the top of the list and the
  1194. // "outsite" referrals that are at the bottom
  1195. //
  1196. for (i = 0; i < Ref->NumberOfReferrals; i++) {
  1197. Ndx = i / 2;
  1198. if (i & 1) {
  1199. Ndx = Ref->NumberOfReferrals - Ndx - 1;
  1200. }
  1201. CurrentSize = sizeof(DFS_REFERRAL_V3) +
  1202. pRefList[Ndx].pAddress.Length + sizeof(UNICODE_NULL);
  1203. if (((CumulativeSize + CurrentSize) >= BufferSize) || (i >= optimalReferralCount))
  1204. break;
  1205. CumulativeSize += CurrentSize;
  1206. }
  1207. // Adjust the number of referrals accordingly.
  1208. Ref->NumberOfReferrals = (USHORT)i;
  1209. //
  1210. // Copy the volume prefix into the response buffer, just past the end
  1211. // of all the V3 referrals
  1212. //
  1213. nextAddress = dfsPath = (LPWSTR) &pv3[ Ref->NumberOfReferrals ];
  1214. *nextAddress++ = UNICODE_PATH_SEP;
  1215. RtlCopyMemory(
  1216. nextAddress,
  1217. MachineName->Buffer,
  1218. MachineName->Length);
  1219. nextAddress += MachineName->Length/sizeof(WCHAR);
  1220. RemoveFirstComponent(&PktEntry->Id.Prefix, &PrefixTail);
  1221. RtlCopyMemory(
  1222. nextAddress,
  1223. PrefixTail.Buffer,
  1224. PrefixTail.Length);
  1225. nextAddress += PrefixTail.Length/sizeof(WCHAR);
  1226. *nextAddress++ = UNICODE_NULL;
  1227. //
  1228. // Copy the 8.3 volume prefix into the response buffer after the
  1229. // dfsPath
  1230. //
  1231. alternatePath = nextAddress;
  1232. *nextAddress++ = UNICODE_PATH_SEP;
  1233. RtlCopyMemory(
  1234. nextAddress,
  1235. MachineName->Buffer,
  1236. MachineName->Length);
  1237. nextAddress += MachineName->Length/sizeof(WCHAR);
  1238. RemoveFirstComponent(&PktEntry->Id.ShortPrefix, &PrefixTail);
  1239. RtlCopyMemory(
  1240. nextAddress,
  1241. PrefixTail.Buffer,
  1242. PrefixTail.Length);
  1243. nextAddress += PrefixTail.Length/sizeof(WCHAR);
  1244. *nextAddress++ = UNICODE_NULL;
  1245. //
  1246. // nextAddress is pointer into buffer where the individual service addresses
  1247. // will go.
  1248. //
  1249. for (i = 0; i < Ref->NumberOfReferrals; i++) {
  1250. if (i < ((ULONG)Ref->NumberOfReferrals + 1) / 2) {
  1251. Ndx = i;
  1252. }
  1253. else {
  1254. Ndx = totalReferrals - Ref->NumberOfReferrals + i;
  1255. }
  1256. pv3->VersionNumber = 3;
  1257. pv3->Size = sizeof(DFS_REFERRAL_V3);
  1258. pv3->ServerType = pRefList[Ndx].Type & DFS_SERVICE_TYPE_DOWN_LEVEL ? 0 : 1;
  1259. pv3->StripPath = 0; // for now
  1260. pv3->NameListReferral = 0;
  1261. pv3->TimeToLive = PktEntry->Info.Timeout;
  1262. pv3->DfsPathOffset = (USHORT) (((PCHAR) dfsPath) - ((PCHAR) pv3));
  1263. pv3->DfsAlternatePathOffset =
  1264. (USHORT) (((PCHAR) alternatePath) - ((PCHAR) pv3));
  1265. pv3->NetworkAddressOffset =
  1266. (USHORT) (((PCHAR) nextAddress) - ((PCHAR) pv3));
  1267. RtlZeroMemory(
  1268. &pv3->ServiceSiteGuid,
  1269. sizeof (GUID));
  1270. RtlCopyMemory(
  1271. nextAddress,
  1272. pRefList[Ndx].pAddress.Buffer,
  1273. pRefList[Ndx].pAddress.Length);
  1274. nextAddress[ pRefList[Ndx].pAddress.Length/sizeof(WCHAR) ] = UNICODE_NULL;
  1275. nextAddress += pRefList[Ndx].pAddress.Length/sizeof(WCHAR) + 1;
  1276. pv3++;
  1277. }
  1278. if (pRefList) {
  1279. ExFreePool(pRefList);
  1280. }
  1281. //
  1282. // we have more than one service, but cannot fit any into the buffer
  1283. // return buffer overflow.
  1284. //
  1285. if ((totalReferrals > 0) && (Ref->NumberOfReferrals == 0)) {
  1286. return STATUS_BUFFER_OVERFLOW;
  1287. }
  1288. *ReferralSize = (ULONG)((PUCHAR)nextAddress - (PUCHAR)Ref);
  1289. DebugTrace(-1, Dbg, "DfspGetV3Referral() -- returning STATUS_SUCCESS\n", 0);
  1290. return STATUS_SUCCESS;
  1291. }
  1292. //+----------------------------------------------------------------------------
  1293. //
  1294. // Function: DfspGetOneV3SpecialReferral, private
  1295. //
  1296. // Synopsis: Marshals a special referral
  1297. //
  1298. //-----------------------------------------------------------------------------
  1299. NTSTATUS
  1300. DfspGetOneV3SpecialReferral(
  1301. IN PDFS_SPECIAL_INFO pSpcInfo,
  1302. IN PUNICODE_STRING Name,
  1303. IN PDFS_IP_INFO pIpInfo,
  1304. OUT PRESP_GET_DFS_REFERRAL Ref,
  1305. IN ULONG MaximumSize,
  1306. OUT PULONG ReturnedSize)
  1307. {
  1308. PDFS_REFERRAL_V3 pv3;
  1309. PDFS_REFERRAL_LIST pRefList;
  1310. LPWSTR pwName;
  1311. LONG i, j;
  1312. ULONG size;
  1313. NTSTATUS status;
  1314. DFS_REFERRAL_LIST MustKeep;
  1315. BOOLEAN FoundMustKeep;
  1316. ULONG CumulativeSize;
  1317. ULONG CurrentSize;
  1318. ULONG NameCount;
  1319. // ASSERT(Name->Length > 0);
  1320. DebugTrace(+1, Dbg, "DfspGetOneV3SpecialReferral(%ws)\n", Name->Buffer);
  1321. //
  1322. // Calculate the size
  1323. //
  1324. if (pSpcInfo == NULL) {
  1325. status = STATUS_NO_SUCH_DEVICE;
  1326. DebugTrace(-1, Dbg, "DfspGetOneV3SpecialReferral() -- exit STATUS_NO_SUCH_DEVICE\n", 0);
  1327. DFS_TRACE_HIGH(ERROR, DfspGetOneV3SpecialReferral_Error1,
  1328. LOGSTATUS(status)
  1329. LOGUSTR(*Name));
  1330. return status;
  1331. }
  1332. CumulativeSize = sizeof( RESP_GET_DFS_REFERRAL ) +
  1333. sizeof(DFS_REFERRAL_V3) +
  1334. pSpcInfo->SpecialName.Length +
  1335. sizeof(UNICODE_NULL) +
  1336. sizeof(UNICODE_NULL);
  1337. if (MaximumSize < CumulativeSize) {
  1338. *((PULONG) Ref) = CumulativeSize + sizeof(ULONG);
  1339. return STATUS_BUFFER_OVERFLOW;
  1340. }
  1341. //
  1342. // Alloc and init a DFS_REFERRAL_LIST
  1343. //
  1344. pRefList = ExAllocatePoolWithTag(
  1345. PagedPool,
  1346. sizeof(DFS_REFERRAL_LIST) * pSpcInfo->NameCount,
  1347. ' sfD');
  1348. if (pRefList == NULL) {
  1349. DebugTrace(-1,
  1350. Dbg,
  1351. "DfspGetOneV3SpecialReferral() exit STATUS_INSUFFICIENT_RESOURCES\n",
  1352. 0);
  1353. status = STATUS_INSUFFICIENT_RESOURCES;
  1354. DFS_TRACE_HIGH(ERROR, DfspGetOneV3SpecialRefferal_Error2,
  1355. LOGSTATUS(status)
  1356. LOGUSTR(*Name));
  1357. return status;
  1358. }
  1359. //
  1360. // Initialize it
  1361. //
  1362. for (j = 0; j < pSpcInfo->NameCount; j++) {
  1363. pRefList[j].pName = pSpcInfo->Name[j];
  1364. pRefList[j].pAddress = pSpcInfo->Name[j];
  1365. pRefList[j].Type = 0;
  1366. }
  1367. //
  1368. // Shuffle the list in case we don't have site info
  1369. //
  1370. SrvShuffle(pRefList, 1, pSpcInfo->NameCount - 1);
  1371. NameCount = 0;
  1372. if (pSpcInfo->NameCount > 0) {
  1373. MustKeep = pRefList[0];
  1374. CurrentSize = sizeof(UNICODE_PATH_SEP);
  1375. CurrentSize += MustKeep.pName.Length;
  1376. CurrentSize += sizeof(UNICODE_NULL);
  1377. CumulativeSize += CurrentSize;
  1378. }
  1379. //
  1380. // Determine client's site based on the IP address srv gave us.
  1381. //
  1382. if (pIpInfo != NULL) {
  1383. //
  1384. // Reorder by site
  1385. //
  1386. DfsIpOrdering(pIpInfo, pSpcInfo->NameCount, pRefList);
  1387. }
  1388. FoundMustKeep = FALSE;
  1389. for (j = 0; j < pSpcInfo->NameCount; j++) {
  1390. if ((FoundMustKeep == FALSE) &&
  1391. (MustKeep.pName.Buffer == pRefList[j].pName.Buffer)) {
  1392. FoundMustKeep = TRUE;
  1393. if (CumulativeSize >= MaximumSize) {
  1394. break;
  1395. }
  1396. }
  1397. else {
  1398. CurrentSize = sizeof(UNICODE_PATH_SEP);
  1399. CurrentSize += pRefList[j].pName.Length;
  1400. CurrentSize += sizeof(UNICODE_NULL);
  1401. if (CumulativeSize + CurrentSize >= MaximumSize) {
  1402. break;
  1403. }
  1404. CumulativeSize += CurrentSize;
  1405. }
  1406. }
  1407. if ((pSpcInfo->NameCount > 0) && (FoundMustKeep == FALSE)) {
  1408. if (CumulativeSize < MaximumSize) {
  1409. NameCount++;
  1410. pRefList[j] = MustKeep;
  1411. }
  1412. }
  1413. NameCount += j;
  1414. if ((NameCount == 0) && (pSpcInfo->NameCount > 0)) {
  1415. *ReturnedSize = CumulativeSize + CurrentSize;
  1416. ExFreePool(pRefList);
  1417. return STATUS_BUFFER_OVERFLOW;
  1418. }
  1419. //
  1420. // Fill in the referral
  1421. //
  1422. DebugTrace( 0, Dbg, "DfspGetOneV3SpecialReferral pSpcInfo = 0x%x\n", pSpcInfo);
  1423. Ref->NumberOfReferrals = 1;
  1424. Ref->StorageServers = Ref->ReferralServers = 0;
  1425. Ref->PathConsumed = 0;
  1426. pv3 = &Ref->Referrals[0].v3;
  1427. pv3->NumberOfExpandedNames = (USHORT) NameCount;
  1428. //
  1429. // Copy the Special Names right after the V3 referral
  1430. //
  1431. pwName = (LPWSTR) &pv3[1];
  1432. pv3->SpecialNameOffset = (USHORT) (((PCHAR) pwName) - ((PCHAR) pv3));
  1433. pv3->VersionNumber = 3;
  1434. pv3->Size = sizeof(DFS_REFERRAL_V3);
  1435. pv3->ServerType = 0;
  1436. pv3->StripPath = 0; // for now
  1437. pv3->NameListReferral = 1;
  1438. pv3->TimeToLive = DfsData.SpcHashTable->SpcTimeout;
  1439. *pwName++ = UNICODE_PATH_SEP;
  1440. RtlCopyMemory(
  1441. pwName,
  1442. pSpcInfo->SpecialName.Buffer,
  1443. pSpcInfo->SpecialName.Length);
  1444. pwName[ pSpcInfo->SpecialName.Length/sizeof(WCHAR) ] = UNICODE_NULL;
  1445. pwName += pSpcInfo->SpecialName.Length/sizeof(WCHAR) + 1;
  1446. pv3->ExpandedNameOffset = (USHORT) (((PCHAR) pwName) - ((PCHAR) pv3));
  1447. for (j = 0; j < pv3->NumberOfExpandedNames; j++) {
  1448. *pwName++ = UNICODE_PATH_SEP;
  1449. RtlCopyMemory(
  1450. pwName,
  1451. pRefList[j].pName.Buffer,
  1452. pRefList[j].pName.Length);
  1453. pwName[ pRefList[j].pName.Length/sizeof(WCHAR) ] = UNICODE_NULL;
  1454. pwName += pRefList[j].pName.Length/sizeof(WCHAR) + 1;
  1455. }
  1456. // Double UNICODE_NULL at end
  1457. *pwName++ = UNICODE_NULL;
  1458. *ReturnedSize = CumulativeSize;
  1459. ExFreePool(pRefList);
  1460. DebugTrace(-1, Dbg, "DfspGetOneV3SpecialReferral() -- exit\n", 0);
  1461. return STATUS_SUCCESS;
  1462. }
  1463. //+----------------------------------------------------------------------------
  1464. //
  1465. // Function: DfspGetAllV3SpecialReferral, private
  1466. //
  1467. //-----------------------------------------------------------------------------
  1468. NTSTATUS
  1469. DfspGetAllV3SpecialReferral(
  1470. IN PDFS_IP_INFO pIpInfo,
  1471. OUT PRESP_GET_DFS_REFERRAL Ref,
  1472. IN ULONG MaximumSize,
  1473. OUT PULONG ReturnedSize)
  1474. {
  1475. PDFS_REFERRAL_V3 pv3;
  1476. PDFS_SPECIAL_INFO pSpcInfo;
  1477. PSPECIAL_HASH_TABLE pHashTable = DfsData.SpcHashTable;
  1478. PDFS_REFERRAL_LIST pRefList;
  1479. LPWSTR pwName;
  1480. LONG i, j;
  1481. ULONG size;
  1482. ULONG SpcCount;
  1483. NTSTATUS status;
  1484. DebugTrace(+1, Dbg, "DfspGetAllV3SpecialReferral()\n", 0);
  1485. //
  1486. // return all special names, with DFS_SPECIAL_INFO_PRIMARY's expanded
  1487. //
  1488. size = sizeof( RESP_GET_DFS_REFERRAL );
  1489. DfsSpcInfoFindOpen(pHashTable);
  1490. for (SpcCount = 0, pSpcInfo = DfsSpcInfoFindFirst(pHashTable);
  1491. pSpcInfo != NULL;
  1492. pSpcInfo = DfsSpcInfoFindNext(pHashTable,pSpcInfo)) {
  1493. //
  1494. // Skip downlevel trusts - they can't have a SYSVOL or an FtDfs
  1495. // in them.
  1496. //
  1497. if (pSpcInfo->TrustType != TRUST_TYPE_UPLEVEL)
  1498. continue;
  1499. size += sizeof(DFS_REFERRAL_V3) +
  1500. sizeof(UNICODE_PATH_SEP) +
  1501. pSpcInfo->SpecialName.Length +
  1502. sizeof(UNICODE_NULL);
  1503. if ((pSpcInfo->TypeFlags & DFS_SPECIAL_INFO_PRIMARY) != 0) {
  1504. for (j = 0; j < pSpcInfo->NameCount; j++) {
  1505. size += sizeof(UNICODE_PATH_SEP) +
  1506. pSpcInfo->Name[j].Length +
  1507. sizeof(UNICODE_NULL);
  1508. }
  1509. }
  1510. //
  1511. // Double UNICODE_NULL at end
  1512. //
  1513. size += sizeof(WCHAR);
  1514. SpcCount++;
  1515. }
  1516. //
  1517. // If no entries to return say so
  1518. //
  1519. if (SpcCount == 0) {
  1520. DfsSpcInfoFindClose(pHashTable);
  1521. if (pIpInfo != NULL) {
  1522. DfsReleaseIpInfo(pIpInfo);
  1523. }
  1524. DebugTrace(-1, Dbg, "DfspGetAllV3SpecialReferral() -- exit STATUS_NO_SUCH_DEVICE\n", 0);
  1525. status = STATUS_NO_SUCH_DEVICE;
  1526. DFS_TRACE_HIGH(ERROR, DfspGetAllV3SpecialReferral_Error1, LOGSTATUS(status));
  1527. return status;
  1528. }
  1529. //
  1530. // See if it will fit - respond with needed size if it doesn't
  1531. //
  1532. if (size > MaximumSize) {
  1533. *((PULONG) Ref) = size;
  1534. *ReturnedSize = sizeof(ULONG);
  1535. DfsSpcInfoFindClose(pHashTable);
  1536. if (pIpInfo != NULL) {
  1537. DfsReleaseIpInfo(pIpInfo);
  1538. }
  1539. DebugTrace(-1, Dbg, "DfspGetAllV3SpecialReferral() -- exit STATUS_BUFFER_OVERFLOW\n", 0);
  1540. status = STATUS_BUFFER_OVERFLOW;
  1541. DFS_TRACE_HIGH(ERROR, DfspGetAllV3SpecialReferral_Error2, LOGSTATUS(status));
  1542. return STATUS_BUFFER_OVERFLOW;
  1543. }
  1544. *ReturnedSize = size;
  1545. Ref->NumberOfReferrals = (USHORT) SpcCount;
  1546. Ref->StorageServers = Ref->ReferralServers = 0;
  1547. Ref->PathConsumed = 0;
  1548. pv3 = &Ref->Referrals[0].v3;
  1549. //
  1550. // Copy the Special Names right after the V3 referrals
  1551. //
  1552. pwName = (LPWSTR) &pv3[SpcCount];
  1553. for (i = 0, pSpcInfo = DfsSpcInfoFindFirst(pHashTable);
  1554. pSpcInfo != NULL;
  1555. pSpcInfo = DfsSpcInfoFindNext(pHashTable,pSpcInfo)) {
  1556. //
  1557. // Skip downlevel trusts - they can't have a SYSVOL or an FtDfs
  1558. // in them.
  1559. //
  1560. if (pSpcInfo->TrustType != TRUST_TYPE_UPLEVEL)
  1561. continue;
  1562. pv3[i].SpecialNameOffset = (USHORT) (((PCHAR) pwName) - ((PCHAR) &pv3[i]));
  1563. pv3[i].VersionNumber = 3;
  1564. pv3[i].Size = sizeof(DFS_REFERRAL_V3);
  1565. pv3[i].ServerType = 0;
  1566. pv3[i].StripPath = 0; // for now
  1567. pv3[i].NameListReferral = 1;
  1568. pv3[i].TimeToLive = pHashTable->SpcTimeout;
  1569. *pwName++ = UNICODE_PATH_SEP;
  1570. RtlCopyMemory(
  1571. pwName,
  1572. pSpcInfo->SpecialName.Buffer,
  1573. pSpcInfo->SpecialName.Length);
  1574. pwName[ pSpcInfo->SpecialName.Length/sizeof(WCHAR) ] = UNICODE_NULL;
  1575. pwName += pSpcInfo->SpecialName.Length/sizeof(WCHAR) + 1;
  1576. if ((pSpcInfo->TypeFlags & DFS_SPECIAL_INFO_PRIMARY) != 0) {
  1577. //
  1578. // Alloc and init a DFS_REFERRAL_LIST
  1579. //
  1580. pRefList = ExAllocatePoolWithTag(
  1581. PagedPool,
  1582. sizeof(DFS_REFERRAL_LIST) * pSpcInfo->NameCount,
  1583. ' sfD');
  1584. if (pRefList == NULL) {
  1585. DfsSpcInfoFindClose(pHashTable);
  1586. if (pIpInfo != NULL) {
  1587. DfsReleaseIpInfo(pIpInfo);
  1588. }
  1589. DebugTrace(-1,
  1590. Dbg,
  1591. "DfspGetAllV3SpecialReferral() exit STATUS_INSUFFICIENT_RESOURCES\n",
  1592. 0);
  1593. status = STATUS_INSUFFICIENT_RESOURCES;
  1594. DFS_TRACE_HIGH(ERROR, DfspGetAllV3SpecialReferral_Error3, LOGSTATUS(status));
  1595. return status;
  1596. }
  1597. //
  1598. // Initialize it
  1599. //
  1600. for (j = 0; j < pSpcInfo->NameCount; j++) {
  1601. pRefList[j].pName = pSpcInfo->Name[j];
  1602. pRefList[j].pAddress = pSpcInfo->Name[j];
  1603. pRefList[j].Type = 0;
  1604. }
  1605. //
  1606. // Shuffle the list in case we don't have site info
  1607. //
  1608. SrvShuffle(pRefList, 0, pSpcInfo->NameCount - 1);
  1609. //
  1610. // Reorder by site
  1611. //
  1612. //
  1613. // Determine client's site based on the IP address srv gave us.
  1614. //
  1615. if (pSpcInfo->NameCount > 1 && pIpInfo != NULL) {
  1616. //
  1617. // Reorder by site
  1618. //
  1619. DfsIpOrdering(pIpInfo, pSpcInfo->NameCount, pRefList);
  1620. }
  1621. //
  1622. // Load the referrals
  1623. //
  1624. pv3[i].NumberOfExpandedNames = (USHORT) pSpcInfo->NameCount;
  1625. pv3[i].ExpandedNameOffset = (USHORT) (((PCHAR) pwName) - ((PCHAR) &pv3[i]));
  1626. for (j = 0; j < pSpcInfo->NameCount; j++) {
  1627. *pwName++ = UNICODE_PATH_SEP;
  1628. RtlCopyMemory(
  1629. pwName,
  1630. pRefList[j].pName.Buffer,
  1631. pRefList[j].pName.Length);
  1632. pwName[ pRefList[j].pName.Length/sizeof(WCHAR) ] = UNICODE_NULL;
  1633. pwName += pRefList[j].pName.Length/sizeof(WCHAR) + 1;
  1634. }
  1635. ExFreePool(pRefList);
  1636. // Double UNICODE_NULL at end
  1637. *pwName++ = UNICODE_NULL;
  1638. } else {
  1639. pv3[i].NumberOfExpandedNames = 0;
  1640. pv3[i].ExpandedNameOffset = 0;
  1641. }
  1642. i++;
  1643. }
  1644. DfsSpcInfoFindClose(pHashTable);
  1645. DebugTrace(-1, Dbg, "DfspGetAllV3SpecialReferral() -- exit\n", 0);
  1646. return STATUS_SUCCESS;
  1647. }
  1648. //+----------------------------------------------------------------------------
  1649. //
  1650. // Function: DfspGetV3FtDfsReferral, private
  1651. //
  1652. //-----------------------------------------------------------------------------
  1653. NTSTATUS
  1654. DfspGetV3FtDfsReferral(
  1655. IN PUNICODE_STRING DomainName,
  1656. IN PUNICODE_STRING ShareName,
  1657. IN PDFS_IP_INFO pIpInfo,
  1658. OUT PRESP_GET_DFS_REFERRAL Ref,
  1659. IN ULONG MaximumSize,
  1660. PULONG ReturnedSize)
  1661. {
  1662. NTSTATUS status;
  1663. PDFS_REFERRAL_V3 pv3;
  1664. PSPECIAL_HASH_TABLE pFtHashTable = DfsData.FtDfsHashTable;
  1665. PDFS_REFERRAL_LIST pRefList;
  1666. PDFS_SPECIAL_INFO pFtInfo = NULL;
  1667. LPWSTR dfsPath, alternatePath, ustrp;
  1668. LONG i, j;
  1669. ULONG k;
  1670. ULONG size;
  1671. UNICODE_STRING MachineName;
  1672. UNICODE_STRING TempName;
  1673. LARGE_INTEGER now;
  1674. PDFS_SPECIAL_INFO pSpcInfo = NULL;
  1675. PSPECIAL_HASH_TABLE pHashTable = DfsData.SpcHashTable;
  1676. BOOLEAN fSysvol = FALSE;
  1677. DFS_REFERRAL_LIST MustKeep;
  1678. BOOLEAN SpecialInfoCreated = FALSE;
  1679. BOOLEAN FoundMustKeep;
  1680. ULONG CumulativeSize;
  1681. ULONG CurrentSize;
  1682. ULONG TotalCount;
  1683. DebugTrace(+1, Dbg, "DfspGetV3FtDfsReferral()\n", 0);
  1684. if (DfspIsSpecialShare(ShareName) == TRUE) {
  1685. pSpcInfo = DfspLookupSpcEntry(DomainName);
  1686. if (pSpcInfo == NULL || pSpcInfo->NameCount == 0) {
  1687. status = STATUS_NO_SUCH_DEVICE;
  1688. goto ErrorOnSpecialShare;
  1689. }
  1690. size = sizeof(DFS_SPECIAL_INFO) + DomainName->Length;
  1691. if (pSpcInfo->NameCount > 1)
  1692. size += sizeof(UNICODE_STRING) * (pSpcInfo->NameCount - 1);
  1693. for (i = 0; i < pSpcInfo->NameCount; i++) {
  1694. size += sizeof(UNICODE_PATH_SEP) +
  1695. pSpcInfo->Name[i].Length +
  1696. sizeof(UNICODE_PATH_SEP) +
  1697. ShareName->Length;
  1698. }
  1699. pFtInfo = ExAllocatePoolWithTag(
  1700. PagedPool,
  1701. size,
  1702. ' sfD');
  1703. if (pFtInfo == NULL) {
  1704. status = STATUS_INSUFFICIENT_RESOURCES;
  1705. goto ErrorOnSpecialShare;
  1706. }
  1707. RtlZeroMemory(pFtInfo, size);
  1708. ustrp = (LPWSTR) &pFtInfo->Name[pSpcInfo->NameCount];
  1709. pFtInfo->SpecialName.Length = DomainName->Length;
  1710. pFtInfo->SpecialName.MaximumLength = DomainName->MaximumLength;
  1711. pFtInfo->SpecialName.Buffer = ustrp;
  1712. RtlCopyMemory(
  1713. ustrp,
  1714. DomainName->Buffer,
  1715. DomainName->Length);
  1716. ustrp += DomainName->Length / sizeof(WCHAR);
  1717. //
  1718. // NOTE:
  1719. // By setting UseCount to 1 and SPECIAL_INFO_DELETE_PENDING, the
  1720. // call to DfsReleaseSpcInfo() will free up this chunk of memory.
  1721. //
  1722. InitializeListHead(&pFtInfo->HashChain);
  1723. pFtInfo->NodeTypeCode = DFS_NTC_SPECIAL_INFO;
  1724. pFtInfo->NodeByteSize = (USHORT) size;
  1725. pFtInfo->UseCount = 1;
  1726. pFtInfo->Flags = SPECIAL_INFO_DELETE_PENDING;
  1727. pFtInfo->NameCount = pSpcInfo->NameCount;
  1728. SpecialInfoCreated = TRUE;
  1729. for (i = 0; i < pSpcInfo->NameCount; i++) {
  1730. pFtInfo->Name[i].Length = sizeof(UNICODE_PATH_SEP) +
  1731. pSpcInfo->Name[i].Length +
  1732. sizeof(UNICODE_PATH_SEP) +
  1733. ShareName->Length;
  1734. pFtInfo->Name[i].MaximumLength = pFtInfo->Name[i].Length;
  1735. pFtInfo->Name[i].Buffer = ustrp;
  1736. *ustrp++ = UNICODE_PATH_SEP;
  1737. RtlCopyMemory(
  1738. ustrp,
  1739. pSpcInfo->Name[i].Buffer,
  1740. pSpcInfo->Name[i].Length);
  1741. ustrp += pSpcInfo->Name[i].Length / sizeof(WCHAR);
  1742. *ustrp++ = UNICODE_PATH_SEP;
  1743. RtlCopyMemory(
  1744. ustrp,
  1745. ShareName->Buffer,
  1746. ShareName->Length);
  1747. ustrp += ShareName->Length / sizeof(WCHAR);
  1748. }
  1749. if (pSpcInfo != NULL) {
  1750. DfsReleaseSpcInfo(pHashTable, pSpcInfo);
  1751. pSpcInfo = NULL;
  1752. }
  1753. fSysvol = TRUE;
  1754. goto CreateReferral;
  1755. ErrorOnSpecialShare:
  1756. if (pSpcInfo != NULL) {
  1757. DfsReleaseSpcInfo(pHashTable, pSpcInfo);
  1758. pSpcInfo = NULL;
  1759. }
  1760. DebugTrace(-1, Dbg,
  1761. "DfspGetV3FtDfsReferral(Syvol or NetLogon) -- exit STATUS_NO_SUCH_DEVICE\n", 0);
  1762. status = STATUS_NO_SUCH_DEVICE;
  1763. DFS_TRACE_HIGH(ERROR, DfspGetV3FtDfsReferral_Error1,
  1764. LOGSTATUS(status)
  1765. LOGUSTR(*DomainName)
  1766. LOGUSTR(*ShareName));
  1767. return status;
  1768. }
  1769. //
  1770. // Check the FtDfs cache
  1771. //
  1772. pFtInfo = DfsLookupSpcInfo(
  1773. pFtHashTable,
  1774. ShareName);
  1775. //
  1776. // If the entry is old try to refresh it.
  1777. //
  1778. KeQuerySystemTime(&now);
  1779. if (pFtInfo != NULL && now.QuadPart > pFtInfo->ExpireTime.QuadPart) {
  1780. ExAcquireFastMutex( &pFtHashTable->HashListMutex );
  1781. pFtInfo->ExpireTime.QuadPart = now.QuadPart + UInt32x32To64(
  1782. 10 * 60,
  1783. 10 * 1000 * 1000);
  1784. ExReleaseFastMutex( &pFtHashTable->HashListMutex );
  1785. DfsReleaseSpcInfo(pFtHashTable, pFtInfo);
  1786. pFtInfo = NULL;
  1787. }
  1788. if (pFtInfo == NULL) {
  1789. //
  1790. // Try to get it into the cache
  1791. //
  1792. DfsLpcDomRequest(ShareName);
  1793. //
  1794. // And try again
  1795. //
  1796. pFtInfo = DfsLookupSpcInfo(
  1797. pFtHashTable,
  1798. ShareName);
  1799. if (pFtInfo == NULL) {
  1800. //
  1801. // Not in the cache, and we couldn't get it
  1802. //
  1803. DebugTrace(-1, Dbg, "DfspGetV3FtDfsReferral(1) -- exit STATUS_NO_SUCH_DEVICE\n", 0);
  1804. status = STATUS_NO_SUCH_DEVICE;
  1805. DFS_TRACE_HIGH(ERROR, DfspGetV3FtDfsReferral_Error2,
  1806. LOGSTATUS(status)
  1807. LOGUSTR(*DomainName)
  1808. LOGUSTR(*ShareName));
  1809. return status;
  1810. }
  1811. }
  1812. if (pFtInfo->NameCount == 0) {
  1813. DfsReleaseSpcInfo(pFtHashTable, pFtInfo);
  1814. DebugTrace(-1, Dbg, "DfspGetOneV3SpecialReferral(2) -- exit STATUS_NO_SUCH_DEVICE\n", 0);
  1815. status = STATUS_NO_SUCH_DEVICE;
  1816. DFS_TRACE_HIGH(ERROR, DfspGetV3FtDfsReferral_Error3,
  1817. LOGSTATUS(status)
  1818. LOGUSTR(*DomainName)
  1819. LOGUSTR(*ShareName));
  1820. return STATUS_NO_SUCH_DEVICE;
  1821. }
  1822. CreateReferral:
  1823. CumulativeSize = sizeof( RESP_GET_DFS_REFERRAL );
  1824. // Longname
  1825. CumulativeSize += sizeof(UNICODE_PATH_SEP) +
  1826. DomainName->Length +
  1827. sizeof(UNICODE_PATH_SEP) +
  1828. ShareName->Length +
  1829. sizeof(UNICODE_NULL);
  1830. // Shortname
  1831. CumulativeSize += sizeof(UNICODE_PATH_SEP) +
  1832. DomainName->Length +
  1833. sizeof(UNICODE_PATH_SEP) +
  1834. ShareName->Length +
  1835. sizeof(UNICODE_NULL);
  1836. if (CumulativeSize > MaximumSize) {
  1837. *((PULONG) Ref) = (CumulativeSize + sizeof(ULONG));
  1838. *ReturnedSize = sizeof(ULONG);
  1839. DfsReleaseSpcInfo(pFtHashTable, pFtInfo);
  1840. return STATUS_BUFFER_OVERFLOW;
  1841. }
  1842. //
  1843. // Alloc and init a DFS_REFERRAL_LIST
  1844. //
  1845. pRefList = ExAllocatePoolWithTag(
  1846. PagedPool,
  1847. sizeof(DFS_REFERRAL_LIST) * pFtInfo->NameCount,
  1848. ' sfD');
  1849. if (pRefList == NULL) {
  1850. DfsReleaseSpcInfo(pFtHashTable, pFtInfo);
  1851. DebugTrace(-1,
  1852. Dbg,
  1853. "DfspGetV3FtDfsReferral exit STATUS_INSUFFICIENT_RESOURCES\n",
  1854. 0);
  1855. status = STATUS_INSUFFICIENT_RESOURCES;
  1856. DFS_TRACE_HIGH(ERROR, DfspGetV3FtDfsReferral_Error4,
  1857. LOGSTATUS(status)
  1858. LOGUSTR(*DomainName)
  1859. LOGUSTR(*ShareName));
  1860. return status;
  1861. }
  1862. //
  1863. // Initialize it
  1864. //
  1865. for (i = 0; i < pFtInfo->NameCount; i++) {
  1866. //
  1867. // We need to extract the servername from the address
  1868. //
  1869. pRefList[i].pName = pFtInfo->Name[i];
  1870. pRefList[i].pName.Buffer++;
  1871. pRefList[i].pName.Length -= sizeof(WCHAR);
  1872. for (k = 0;
  1873. k < pRefList[i].pName.Length/sizeof(WCHAR)
  1874. &&
  1875. pRefList[i].pName.Buffer[k] != L'\\';
  1876. k++) {
  1877. /* NOTHING */;
  1878. }
  1879. if (k < pRefList[i].pName.Length/sizeof(WCHAR)) {
  1880. pRefList[i].pName.Length = (USHORT) (k * sizeof(WCHAR));
  1881. }
  1882. pRefList[i].pAddress = pFtInfo->Name[i];
  1883. pRefList[i].Type = 0;
  1884. }
  1885. //
  1886. // Shuffle the list in case we don't have site info
  1887. //
  1888. SrvShuffle(pRefList, (SpecialInfoCreated == TRUE) ? 1 : 0, pFtInfo->NameCount - 1);
  1889. TotalCount = 0;
  1890. if ((SpecialInfoCreated == TRUE) && (pFtInfo->NameCount > 0)) {
  1891. MustKeep = pRefList[0];
  1892. CurrentSize = sizeof(UNICODE_PATH_SEP);
  1893. CurrentSize += MustKeep.pAddress.Length;
  1894. CurrentSize += sizeof(UNICODE_NULL);
  1895. CumulativeSize += CurrentSize;
  1896. }
  1897. //
  1898. // Determine client's site based on the IP address srv gave us.
  1899. //
  1900. if (pIpInfo != NULL) {
  1901. //
  1902. // Reorder by site
  1903. //
  1904. DfsIpOrdering(pIpInfo, pFtInfo->NameCount, pRefList);
  1905. }
  1906. FoundMustKeep = FALSE;
  1907. for (i = 0; i < pFtInfo->NameCount; i++) {
  1908. if ((SpecialInfoCreated == TRUE) &&
  1909. (FoundMustKeep == FALSE) &&
  1910. (MustKeep.pAddress.Buffer == pRefList[i].pAddress.Buffer)) {
  1911. FoundMustKeep = TRUE;
  1912. if (CumulativeSize >= MaximumSize) {
  1913. break;
  1914. }
  1915. }
  1916. else {
  1917. CurrentSize = sizeof(DFS_REFERRAL_V3) +
  1918. pRefList[i].pAddress.Length +
  1919. sizeof(UNICODE_NULL);
  1920. if ((CumulativeSize + CurrentSize) >= MaximumSize) {
  1921. break;
  1922. }
  1923. CumulativeSize += CurrentSize;
  1924. }
  1925. }
  1926. if ((pFtInfo->NameCount > 0) && (SpecialInfoCreated == TRUE) && (FoundMustKeep == FALSE)) {
  1927. if (CumulativeSize < MaximumSize) {
  1928. TotalCount++;
  1929. pRefList[i] = MustKeep;
  1930. }
  1931. }
  1932. TotalCount += i;
  1933. if ((TotalCount == 0) && (pFtInfo->NameCount > 0)) {
  1934. *ReturnedSize = CumulativeSize + CurrentSize;
  1935. DfsReleaseSpcInfo(pFtHashTable, pFtInfo);
  1936. ExFreePool(pRefList);
  1937. return STATUS_BUFFER_OVERFLOW;
  1938. }
  1939. //
  1940. // Fill in the referral
  1941. //
  1942. Ref->NumberOfReferrals = (USHORT) TotalCount;
  1943. Ref->ReferralServers = 1; // Means the FtDFS roots can handle referrals (should be true)
  1944. Ref->StorageServers = 1; // Means the FtDFS roots contain data/storage (should be true)
  1945. pv3 = &Ref->Referrals[0].v3;
  1946. //
  1947. // Copy the FtDfs prefix into the response buffer, just past the end
  1948. // of all the V3 referrals
  1949. //
  1950. dfsPath = ustrp = (LPWSTR) &pv3[ TotalCount ];
  1951. *ustrp++ = UNICODE_PATH_SEP;
  1952. RtlCopyMemory(
  1953. ustrp,
  1954. DomainName->Buffer,
  1955. DomainName->Length);
  1956. ustrp += DomainName->Length / sizeof(WCHAR);
  1957. *ustrp++ = UNICODE_PATH_SEP;
  1958. RtlCopyMemory(
  1959. ustrp,
  1960. ShareName->Buffer,
  1961. ShareName->Length);
  1962. ustrp += ShareName->Length / sizeof(WCHAR);
  1963. *ustrp++ = UNICODE_NULL;
  1964. //
  1965. // Copy the 8.3 volume prefix into the response buffer after the
  1966. // dfsPath
  1967. //
  1968. alternatePath = ustrp;
  1969. *ustrp++ = UNICODE_PATH_SEP;
  1970. RtlCopyMemory(
  1971. ustrp,
  1972. DomainName->Buffer,
  1973. DomainName->Length);
  1974. ustrp += DomainName->Length / sizeof(WCHAR);
  1975. *ustrp++ = UNICODE_PATH_SEP;
  1976. RtlCopyMemory(
  1977. ustrp,
  1978. ShareName->Buffer,
  1979. ShareName->Length);
  1980. ustrp += ShareName->Length / sizeof(WCHAR);
  1981. *ustrp++ = UNICODE_NULL;
  1982. //
  1983. // Initialize pointer into buffer where the individual service addresses
  1984. // will go.
  1985. //
  1986. for (i = 0; i < Ref->NumberOfReferrals; i++) {
  1987. pv3->VersionNumber = 3;
  1988. pv3->Size = sizeof(DFS_REFERRAL_V3);
  1989. pv3->ServerType = (fSysvol == TRUE) ? 0 : 1;
  1990. pv3->StripPath = 0; // for now
  1991. pv3->NameListReferral = 0;
  1992. pv3->TimeToLive = pFtHashTable->SpcTimeout;
  1993. pv3->DfsPathOffset = (USHORT) (((PCHAR) dfsPath) - ((PCHAR) pv3));
  1994. pv3->DfsAlternatePathOffset =
  1995. (USHORT) (((PCHAR) alternatePath) - ((PCHAR) pv3));
  1996. pv3->NetworkAddressOffset =
  1997. (USHORT) (((PCHAR) ustrp) - ((PCHAR) pv3));
  1998. RtlZeroMemory(
  1999. &pv3->ServiceSiteGuid,
  2000. sizeof (GUID));
  2001. RtlCopyMemory(
  2002. ustrp,
  2003. pRefList[i].pAddress.Buffer,
  2004. pRefList[i].pAddress.Length);
  2005. ustrp += pRefList[i].pAddress.Length / sizeof(WCHAR);
  2006. *ustrp++ = UNICODE_NULL;
  2007. pv3++;
  2008. }
  2009. DfsReleaseSpcInfo(pFtHashTable, pFtInfo);
  2010. ExFreePool(pRefList);
  2011. *ReturnedSize = CumulativeSize;
  2012. return STATUS_SUCCESS;
  2013. }
  2014. //+----------------------------------------------------------------------------
  2015. //
  2016. // Function: DfsFsctrlIsShareInDfs
  2017. //
  2018. // Synopsis: Determines whether a share path is also in the Dfs.
  2019. //
  2020. // Arguments: [InputBuffer] -- Pointer to DFS_IS_SHARE_IN_DFS_ARG.
  2021. // [InputBufferLength] -- Length in bytes of InputBuffer.
  2022. //
  2023. // Returns: [STATUS_SUCCESS] -- Share path is in Dfs
  2024. //
  2025. // [STATUS_NO_SUCH_DEVICE] -- Share path is not in Dfs.
  2026. //
  2027. //-----------------------------------------------------------------------------
  2028. NTSTATUS
  2029. DfsFsctrlIsShareInDfs(
  2030. IN PVOID InputBuffer,
  2031. IN ULONG InputBufferLength)
  2032. {
  2033. PDFS_IS_SHARE_IN_DFS_ARG arg = (PDFS_IS_SHARE_IN_DFS_ARG) InputBuffer;
  2034. PDFS_PKT pkt;
  2035. PUNICODE_PREFIX_TABLE_ENTRY lvPrefix;
  2036. PDFS_LOCAL_VOL_ENTRY lvEntry;
  2037. UNICODE_STRING lvName, remPath;
  2038. NTSTATUS status = STATUS_SUCCESS;
  2039. //
  2040. // Verify the buffer is at least of size DFS_IS_SHARE_IN_DFS_ARG
  2041. // And that this is the system process.
  2042. //
  2043. if (InputBufferLength < sizeof(DFS_IS_SHARE_IN_DFS_ARG)
  2044. ||
  2045. PsGetCurrentProcess() != DfsData.OurProcess
  2046. ) {
  2047. status = STATUS_INVALID_PARAMETER;
  2048. DFS_TRACE_HIGH(ERROR, DfsFsctrlIsShareInDfs_Error1, LOGSTATUS(status));
  2049. return status;
  2050. }
  2051. lvName = arg->SharePath;
  2052. DebugTrace(+1, Dbg, "DfsFsctrlIsShareInDfs(%wZ)\n", &lvName);
  2053. //
  2054. // Lookup the localVol in the local volume prefix table.
  2055. //
  2056. pkt = _GetPkt();
  2057. PktAcquireShared( pkt, TRUE );
  2058. lvPrefix = DfsFindUnicodePrefix(
  2059. &pkt->LocalVolTable,
  2060. &lvName,
  2061. &remPath);
  2062. DebugTrace( 0, Dbg, " lvPrefix=0x%x\n", lvPrefix);
  2063. if (lvPrefix != NULL) {
  2064. lvEntry = CONTAINING_RECORD(
  2065. lvPrefix,
  2066. DFS_LOCAL_VOL_ENTRY,
  2067. PrefixTableEntry);
  2068. DebugTrace( 0, Dbg, " lvEntry=0x%x\n", lvEntry);
  2069. DebugTrace( 0, Dbg, " lvEntry->LocalPath=[%wZ]\n", &lvEntry->LocalPath);
  2070. if (lvEntry->LocalPath.Length == lvName.Length) {
  2071. if (RtlEqualUnicodeString(
  2072. &lvEntry->ShareName, &arg->ShareName, TRUE)) {
  2073. arg->ShareType = DFS_SHARE_TYPE_DFS_VOLUME;
  2074. if (lvEntry->PktEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC)
  2075. arg->ShareType |= DFS_SHARE_TYPE_ROOT;
  2076. status = STATUS_SUCCESS;
  2077. } else {
  2078. DebugTrace( 0, Dbg, " NO_SUCH_DEVICE(1)\n", 0);
  2079. status = STATUS_NO_SUCH_DEVICE;
  2080. }
  2081. } else {
  2082. DebugTrace( 0, Dbg, " NO_SUCH_DEVICE(2)\n", 0);
  2083. status = STATUS_NO_SUCH_DEVICE;
  2084. }
  2085. } else {
  2086. DebugTrace( 0, Dbg, " NO_SUCH_DEVICE(3)\n", 0);
  2087. status = STATUS_NO_SUCH_DEVICE;
  2088. }
  2089. PktRelease( pkt );
  2090. DebugTrace(-1, Dbg, "DfsFsctrlIsShareInDfs exit 0x%x\n", ULongToPtr( status ));
  2091. DFS_TRACE_ERROR_HIGH(status, ALL_ERROR, DfsFsctrlIsShareInDfs_Error2, LOGSTATUS(status));
  2092. return( status );
  2093. }
  2094. //+----------------------------------------------------------------------------
  2095. //
  2096. // Function: DfsFsctrlFindShare
  2097. //
  2098. // Synopsis: Determines whether a share path is an FtDFS root
  2099. //
  2100. // Arguments: [InputBuffer] -- Pointer to DFS_FIND_SHARE_ARG
  2101. // [InputBufferLength] -- Length in bytes of InputBuffer.
  2102. //
  2103. // Returns: [STATUS_PATH_NOT_COVERED] -- Share path is an FtDFS root
  2104. // [STATUS_BAD_NETWORK_NAME] -- Share path is NOT an FtDFS root
  2105. //
  2106. //-----------------------------------------------------------------------------
  2107. NTSTATUS
  2108. DfsFsctrlFindShare(
  2109. IN PVOID InputBuffer,
  2110. IN ULONG InputBufferLength)
  2111. {
  2112. PSPECIAL_HASH_TABLE pFtHashTable = DfsData.FtDfsHashTable;
  2113. PDFS_SPECIAL_INFO pFtInfo;
  2114. NTSTATUS status = STATUS_SUCCESS;
  2115. PDFS_FIND_SHARE_ARG arg = (PDFS_FIND_SHARE_ARG) InputBuffer;
  2116. DFS_TRACE_NORM(EVENT, DfsFsctrlFindShare_Start,
  2117. LOGSTATUS(status)
  2118. LOGUSTR(arg->ShareName));
  2119. DebugTrace(+1, Dbg, "DfsFsctrlFindShare(%ws)\n", arg->ShareName.Buffer);
  2120. //
  2121. // See if we have the FtDfs info cached
  2122. //
  2123. pFtInfo = DfsLookupSpcInfo(
  2124. pFtHashTable,
  2125. &arg->ShareName);
  2126. if (pFtInfo != NULL) {
  2127. if (pFtInfo->NameCount > 0) {
  2128. status = STATUS_PATH_NOT_COVERED;
  2129. } else {
  2130. status = STATUS_BAD_NETWORK_NAME;
  2131. }
  2132. DfsReleaseSpcInfo(
  2133. pFtHashTable,
  2134. pFtInfo);
  2135. DebugTrace(-1, Dbg, "DfsFsctrlFindShare() -- returning 0x%x\n", ULongToPtr( status ));
  2136. DFS_TRACE_ERROR_HIGH(status, ALL_ERROR, DfsFsctrlFindShare_Error1, LOGSTATUS(status));
  2137. //return status;
  2138. goto cleanup;
  2139. }
  2140. //
  2141. // Not in cache -- call up pipe to dfssvc.exe
  2142. //
  2143. status = DfsLpcDomRequest(&arg->ShareName);
  2144. //
  2145. // If success, return STATUS_PATH_NOT_COVERED
  2146. if (NT_SUCCESS(status)) {
  2147. status = STATUS_PATH_NOT_COVERED;
  2148. } else {
  2149. status = STATUS_BAD_NETWORK_NAME;
  2150. }
  2151. DebugTrace(-1, Dbg, "DfsFsctrlFindShare() -- returning 0x%x\n", ULongToPtr( status ));
  2152. DFS_TRACE_ERROR_HIGH(status, ALL_ERROR, DfsFsctrlFindShare_Error2, LOGSTATUS(status));
  2153. cleanup:
  2154. DFS_TRACE_NORM(EVENT, DfsFsctrlFindShare_End,
  2155. LOGSTATUS(status)
  2156. LOGUSTR(arg->ShareName));
  2157. return( status );
  2158. }
  2159. //+----------------------------------------------------------------------------
  2160. //
  2161. // Function: SrvShuffle
  2162. //
  2163. // Synopsis: Shuffles a cost equivalent group of (pointers to) services around
  2164. // for load balancing. Uses the classic card shuffling algorithm - for
  2165. // each card in the deck, exchange it with a random card in the
  2166. // deck.
  2167. //
  2168. //-----------------------------------------------------------------------------
  2169. VOID
  2170. SrvShuffle(
  2171. PDFS_REFERRAL_LIST pRefList,
  2172. LONG nStart,
  2173. LONG nEnd)
  2174. {
  2175. LONG i;
  2176. LARGE_INTEGER seed;
  2177. //
  2178. // We allow caller to have nEnd to be before nStart, so check for this
  2179. //
  2180. if (nStart >= nEnd)
  2181. return;
  2182. KeQuerySystemTime( &seed );
  2183. for (i = nStart; i <= nEnd; i++) {
  2184. DFS_REFERRAL_LIST pTempEntry;
  2185. ULONG j;
  2186. j = (RtlRandom( &seed.LowPart ) % (nEnd - nStart + 1)) + nStart;
  2187. pTempEntry = pRefList[i];
  2188. pRefList[i] = pRefList[j];
  2189. pRefList[j] = pTempEntry;
  2190. }
  2191. }
  2192. //+----------------------------------------------------------------------------
  2193. //
  2194. // Function: DfsIpOrdering
  2195. //
  2196. // Synopsis: Reorders a list of names based upon the passed-in client ip address.
  2197. //
  2198. //-----------------------------------------------------------------------------
  2199. ULONG
  2200. DfsIpOrdering(
  2201. IN PDFS_IP_INFO pIpInfo,
  2202. IN ULONG RefCount,
  2203. IN PDFS_REFERRAL_LIST pRefList)
  2204. {
  2205. PDFS_REFERRAL_LIST pOrdRefList;
  2206. PDFS_SITE_INFO pSiteInfo;
  2207. BOOLEAN ToFront;
  2208. LONG Front = RefCount;
  2209. LONG Back;
  2210. ULONG i, j;
  2211. DebugTrace(+1, Dbg, "DfsIpOrdering()\n", 0);
  2212. //
  2213. // Create an ordered list of addresses based on Sites
  2214. //
  2215. pOrdRefList = ExAllocatePoolWithTag(
  2216. PagedPool,
  2217. sizeof(DFS_REFERRAL_LIST) * RefCount,
  2218. ' sfD');
  2219. if (pOrdRefList != NULL) {
  2220. Front = 0;
  2221. Back = RefCount - 1;
  2222. for (i = 0; i < RefCount; i++) {
  2223. //
  2224. // Scan the list of alternates, placing each alternate either toward the
  2225. // front of the ordered list (if site matches) or toward the rear of the
  2226. // ordered list (if sites don't match).
  2227. //
  2228. ToFront = FALSE;
  2229. pSiteInfo = DfsLookupSiteInfo(&pRefList[i].pName);
  2230. if (pSiteInfo != NULL) {
  2231. for (j = 0; ToFront == FALSE && j < pSiteInfo->SiteCount; j++) {
  2232. if (RtlCompareUnicodeString(
  2233. &pIpInfo->SiteName,
  2234. &pSiteInfo->SiteName[j],
  2235. TRUE) == 0) {
  2236. ToFront = TRUE;
  2237. }
  2238. }
  2239. DfsReleaseSiteInfo(pSiteInfo);
  2240. }
  2241. if (ToFront == TRUE) {
  2242. pOrdRefList[Front++] = pRefList[i];
  2243. } else {
  2244. pOrdRefList[Back--] = pRefList[i];
  2245. }
  2246. }
  2247. //
  2248. // Replace the unordered list with the ordered one
  2249. //
  2250. for (i = 0; i < RefCount; i++) {
  2251. pRefList[i] = pOrdRefList[i];
  2252. }
  2253. ExFreePool(pOrdRefList);
  2254. }
  2255. DebugTrace(-1, Dbg, "DfsIpOrdering()--exit\n", 0);
  2256. return Front;
  2257. }
  2258. //+----------------------------------------------------------------------------
  2259. //
  2260. // Function: DfspLookupSpcEntry
  2261. //
  2262. // Synopsis: Returns a special list info entry, expanded if necessary
  2263. //
  2264. //-----------------------------------------------------------------------------
  2265. PDFS_SPECIAL_INFO
  2266. DfspLookupSpcEntry(
  2267. IN PUNICODE_STRING SpecialName)
  2268. {
  2269. PSPECIAL_HASH_TABLE pHashTable = DfsData.SpcHashTable;
  2270. PDFS_SPECIAL_INFO pSpcInfo = NULL;
  2271. LARGE_INTEGER now;
  2272. ULONG TypeFlags;
  2273. DebugTrace(+1, Dbg, "DfspLookupSpcEntry(%wZ)\n", SpecialName);
  2274. //
  2275. // Check the SpcName cache
  2276. //
  2277. pSpcInfo = DfsLookupSpcInfo(
  2278. pHashTable,
  2279. SpecialName);
  2280. if (pSpcInfo != NULL) {
  2281. //
  2282. // If the entry is old or unexpanded, try to expand it
  2283. //
  2284. KeQuerySystemTime(&now);
  2285. if ((now.QuadPart > pSpcInfo->ExpireTime.QuadPart ||
  2286. pSpcInfo->NameCount == -1)
  2287. ) {
  2288. ExAcquireFastMutex( &pHashTable->HashListMutex );
  2289. if (now.QuadPart > pSpcInfo->ExpireTime.QuadPart) {
  2290. pSpcInfo->ExpireTime.QuadPart = now.QuadPart + UInt32x32To64(
  2291. 60 * 60,
  2292. 10 * 1000 * 1000);
  2293. TypeFlags = pSpcInfo->TypeFlags;
  2294. ExReleaseFastMutex( &pHashTable->HashListMutex );
  2295. DfsReleaseSpcInfo(pHashTable, pSpcInfo);
  2296. //
  2297. // Try to refresh the cache
  2298. //
  2299. if (pSpcInfo->Flags & SPECIAL_INFO_IS_LONG_NAME) {
  2300. pSpcInfo->Flags |= SPECIAL_INFO_NEEDS_REFRESH;
  2301. }
  2302. DfsLpcSpcRequest(SpecialName, TypeFlags);
  2303. //
  2304. // And try again
  2305. //
  2306. pSpcInfo = DfsLookupSpcInfo(
  2307. pHashTable,
  2308. SpecialName);
  2309. } else {
  2310. ExReleaseFastMutex( &pHashTable->HashListMutex );
  2311. }
  2312. }
  2313. if (pSpcInfo != NULL) {
  2314. if (pSpcInfo->NameCount == -1) {
  2315. DfsReleaseSpcInfo(pHashTable, pSpcInfo);
  2316. pSpcInfo = NULL;
  2317. }
  2318. }
  2319. }
  2320. DebugTrace(-1, Dbg, "DfspLookupSpcEntry returning 0x%x\n", pSpcInfo);
  2321. return pSpcInfo;
  2322. }
  2323. //+----------------------------------------------------------------------------
  2324. //
  2325. // Function: DfspIsSpecialShare, local
  2326. //
  2327. // Synopsis: Sees if a share name is a special share.
  2328. //
  2329. // Arguments: [ShareName] -- Name of share to test.
  2330. //
  2331. // Returns: TRUE if special, FALSE otherwise.
  2332. //
  2333. //-----------------------------------------------------------------------------
  2334. BOOLEAN
  2335. DfspIsSpecialShare(
  2336. PUNICODE_STRING ShareName)
  2337. {
  2338. ULONG i;
  2339. BOOLEAN fSpecial = FALSE;
  2340. for (i = 0;
  2341. (i < (sizeof(SpecialShares) / sizeof(SpecialShares[0]))) &&
  2342. !fSpecial;
  2343. i++) {
  2344. if (SpecialShares[i].Length == ShareName->Length) {
  2345. if (RtlCompareUnicodeString(&SpecialShares[i],ShareName,TRUE) == 0) {
  2346. fSpecial = TRUE;
  2347. }
  2348. }
  2349. }
  2350. return( fSpecial );
  2351. }