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.

1131 lines
31 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsDownLevel.cxx
  6. //
  7. // Contents: Contains APIs to communicate old DFS Servers
  8. //
  9. // Classes: none.
  10. //
  11. // History: Jan. 24 2001, Author: Rohanp
  12. //
  13. //-----------------------------------------------------------------------------
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <windef.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <stddef.h>
  22. #include <lm.h>
  23. #include <winsock2.h>
  24. #include <smbtypes.h>
  25. #pragma warning(disable: 4200) //nonstandard extension used: zero-sized array in struct/union (line 1085
  26. #include <smbtrans.h>
  27. #pragma warning(default: 4200)
  28. #include <dsgetdc.h>
  29. #include <dsrole.h>
  30. #include <DfsReferralData.h>
  31. #include <DfsReferral.hxx>
  32. #include <dfsheader.h>
  33. #include <Dfsumr.h>
  34. #include <dfsfilterapi.hxx>
  35. #define PATH_DELIMITER L'\\'
  36. //+-------------------------------------------------------------------------
  37. //
  38. // Function: DfspGetV1ReferralSize
  39. //
  40. // Arguments: List of referrals
  41. //
  42. // Returns: size of referrals
  43. //
  44. //
  45. // Description: calculates size needed to fit V1 referrals
  46. //
  47. //--------------------------------------------------------------------------
  48. ULONG
  49. DfspGetV1ReferralSize(
  50. IN PREFERRAL_HEADER pRefHeader)
  51. {
  52. ULONG i = 0;
  53. ULONG size = 0;
  54. PREPLICA_INFORMATION pRep = NULL;
  55. size = sizeof( RESP_GET_DFS_REFERRAL );
  56. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  57. for (i = 0; i < pRefHeader->ReplicaCount; i++)
  58. {
  59. size += sizeof(DFS_REFERRAL_V1) +
  60. pRep->ReplicaNameLength +
  61. sizeof(UNICODE_NULL);
  62. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  63. }
  64. return( size );
  65. }
  66. //+-------------------------------------------------------------------------
  67. //
  68. // Function: DfspGetV2ReferralSize
  69. //
  70. // Arguments: List of referrals
  71. //
  72. // Returns: size of referrals
  73. //
  74. //
  75. // Description: calculates size needed to fit V2 referrals
  76. //
  77. //--------------------------------------------------------------------------
  78. ULONG
  79. DfspGetV2ReferralSize(
  80. IN PREFERRAL_HEADER pRefHeader)
  81. {
  82. ULONG i = 0;
  83. ULONG size = 0;
  84. PREPLICA_INFORMATION pRep = NULL;
  85. UNICODE_STRING PrefixTail;
  86. size = sizeof( RESP_GET_DFS_REFERRAL );
  87. PrefixTail.Length = 0;
  88. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  89. for (i = 0; i < pRefHeader->ReplicaCount; i++)
  90. {
  91. size += sizeof(DFS_REFERRAL_V2) +
  92. pRep->ReplicaNameLength +
  93. sizeof(UNICODE_NULL);
  94. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  95. }
  96. size += sizeof(UNICODE_PATH_SEP) +
  97. pRefHeader->LinkNameLength +
  98. sizeof(UNICODE_NULL);
  99. size += sizeof(UNICODE_PATH_SEP) +
  100. pRefHeader->LinkNameLength +
  101. sizeof(UNICODE_NULL);
  102. return( size );
  103. }
  104. //+-------------------------------------------------------------------------
  105. //
  106. // Function: DfspGetV3ReferralSize
  107. //
  108. // Arguments: List of referrals
  109. //
  110. // Returns: size of referrals
  111. //
  112. //
  113. // Description: calculates size needed to fit V3 referrals
  114. //
  115. //--------------------------------------------------------------------------
  116. ULONG
  117. DfspGetV3ReferralSize(
  118. IN PREFERRAL_HEADER pRefHeader)
  119. {
  120. ULONG i = 0;
  121. ULONG size = 0;
  122. PREPLICA_INFORMATION pRep = NULL;
  123. UNICODE_STRING PrefixTail;
  124. size = sizeof( RESP_GET_DFS_REFERRAL );
  125. PrefixTail.Length = 0;
  126. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  127. for (i = 0; i < pRefHeader->ReplicaCount; i++)
  128. {
  129. size += sizeof(DFS_REFERRAL_V3) +
  130. pRep->ReplicaNameLength +
  131. sizeof(UNICODE_NULL);
  132. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  133. }
  134. size += sizeof(UNICODE_PATH_SEP) +
  135. pRefHeader->LinkNameLength +
  136. sizeof(UNICODE_NULL);
  137. size += sizeof(UNICODE_PATH_SEP) +
  138. pRefHeader->LinkNameLength +
  139. sizeof(UNICODE_NULL);
  140. return( size );
  141. }
  142. //+-------------------------------------------------------------------------
  143. //
  144. // Function: DfspGetV1Referral
  145. //
  146. // Arguments: List of referrals
  147. //
  148. // Returns:
  149. //
  150. //
  151. // Description: Copies the V1 referrals to output buffer
  152. //
  153. //--------------------------------------------------------------------------
  154. VOID
  155. DfspGetV1Referral(
  156. IN PREFERRAL_HEADER pRefHeader,
  157. OUT PRESP_GET_DFS_REFERRAL Ref)
  158. {
  159. PDFS_REFERRAL_V1 pv1 = NULL;
  160. PREPLICA_INFORMATION pRep = NULL;
  161. ULONG i = 0;
  162. Ref->NumberOfReferrals = (USHORT) pRefHeader->ReplicaCount;
  163. Ref->ReferralServers = 1;
  164. Ref->StorageServers = 1;
  165. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  166. pv1 = &Ref->Referrals[0].v1;
  167. for (i = 0; i < pRefHeader->ReplicaCount; i++)
  168. {
  169. pv1->VersionNumber = 1;
  170. pv1->Size = (USHORT)( sizeof(DFS_REFERRAL_V1) +
  171. pRep->ReplicaNameLength +
  172. sizeof(UNICODE_NULL));
  173. if (((pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL) == 0) &&
  174. ((pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_OUT_OF_DOMAIN) == 0))
  175. {
  176. pv1->ServerType = 0;
  177. }
  178. else
  179. {
  180. pv1->ServerType = 1;
  181. }
  182. RtlCopyMemory(
  183. pv1->ShareName,
  184. pRep->ReplicaName,
  185. pRep->ReplicaNameLength);
  186. pv1->ShareName[ pRep->ReplicaNameLength / sizeof(WCHAR) ] =
  187. UNICODE_NULL;
  188. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  189. pv1 = (PDFS_REFERRAL_V1) ( ((PCHAR) pv1) + pv1->Size );
  190. }
  191. }
  192. //+-------------------------------------------------------------------------
  193. //
  194. // Function: DfspGetV2Referral
  195. //
  196. // Arguments: List of referrals
  197. //
  198. // Returns:
  199. //
  200. //
  201. // Description: Copies the V2 referrals to output buffer
  202. //
  203. //--------------------------------------------------------------------------
  204. NTSTATUS
  205. DfspGetV2Referral(
  206. IN PREFERRAL_HEADER pRefHeader,
  207. IN ULONG BufferSize,
  208. OUT PRESP_GET_DFS_REFERRAL pRef,
  209. OUT PULONG ReferralSize)
  210. {
  211. DFSSTATUS Status = ERROR_SUCCESS;
  212. PDFS_REFERRAL_V2 pv2 = NULL;
  213. PREPLICA_INFORMATION pRep = NULL;
  214. ULONG i = 0;
  215. ULONG CumulativeSize = 0;
  216. ULONG CurrentSize = 0;
  217. LPWSTR pDfsPath = NULL;
  218. LPWSTR pAlternatePath = NULL;
  219. LPWSTR pNextAddress = NULL;
  220. LPWSTR LinkName;
  221. ULONG LinkNameLength;
  222. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  223. // Calculate the size of the referral, and make sure our size does not
  224. // exceed the passed in buffer len.
  225. CumulativeSize =
  226. sizeof (RESP_GET_DFS_REFERRAL) +
  227. pRefHeader->LinkNameLength +
  228. sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL) +
  229. pRefHeader->LinkNameLength +
  230. sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL);
  231. if (BufferSize < CumulativeSize)
  232. {
  233. Status = ERROR_MORE_DATA;
  234. return Status;
  235. }
  236. if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_OUT_OF_DOMAIN)
  237. {
  238. pRef->ReferralServers = 1;
  239. pRef->StorageServers = 0;
  240. }
  241. else if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL)
  242. {
  243. pRef->ReferralServers = 1;
  244. pRef->StorageServers = 1;
  245. }
  246. else
  247. {
  248. pRef->ReferralServers = 0;
  249. pRef->StorageServers = 1;
  250. }
  251. pRef->NumberOfReferrals = (USHORT) pRefHeader->ReplicaCount;
  252. pv2 = &pRef->Referrals[0].v2;
  253. //see how many referrals we can actually fit into the buffer
  254. for (i = 0; i < pRef->NumberOfReferrals; i++)
  255. {
  256. CurrentSize = sizeof(DFS_REFERRAL_V3) +
  257. pRep->ReplicaNameLength + sizeof(UNICODE_NULL);
  258. if ((CumulativeSize + CurrentSize) >= BufferSize)
  259. break;
  260. CumulativeSize += CurrentSize;
  261. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  262. }
  263. // Adjust the number of referrals accordingly.
  264. pRef->NumberOfReferrals = (USHORT)i;
  265. //
  266. // we have more than one service, but cannot fit any into the buffer
  267. // return buffer overflow.
  268. //
  269. if ((pRefHeader->ReplicaCount > 0) && (pRef->NumberOfReferrals == 0))
  270. {
  271. return ERROR_MORE_DATA;
  272. }
  273. //
  274. // Copy the volume prefix into the response buffer, just past the end
  275. // of all the V3 referrals
  276. //
  277. pNextAddress = pDfsPath = (LPWSTR) &pv2[ pRef->NumberOfReferrals ];
  278. LinkName = pRefHeader->LinkName;
  279. LinkNameLength = pRefHeader->LinkNameLength;
  280. while ((LinkNameLength > (sizeof(WCHAR) + sizeof(WCHAR))) &&
  281. (LinkName[0] == UNICODE_PATH_SEP) &&
  282. (LinkName[1] == UNICODE_PATH_SEP))
  283. {
  284. LinkName++;
  285. LinkNameLength -= sizeof(WCHAR);
  286. }
  287. pRef->PathConsumed = (USHORT)LinkNameLength;
  288. RtlCopyMemory(
  289. pNextAddress,
  290. LinkName,
  291. LinkNameLength);
  292. pNextAddress += LinkNameLength/sizeof(WCHAR);
  293. *pNextAddress++ = UNICODE_NULL;
  294. //
  295. // Copy the 8.3 volume prefix into the response buffer after the
  296. // dfsPath
  297. //
  298. pAlternatePath = pNextAddress;
  299. RtlCopyMemory(
  300. pNextAddress,
  301. LinkName,
  302. LinkNameLength);
  303. pNextAddress += LinkNameLength/sizeof(WCHAR);
  304. *pNextAddress++ = UNICODE_NULL;
  305. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  306. for (i = 0; i < pRef->NumberOfReferrals; i++)
  307. {
  308. pv2->VersionNumber = 2;
  309. pv2->Size = sizeof(DFS_REFERRAL_V2);
  310. //
  311. // Clients who use V2 Referrals (< NT4SP5 for example) expect ServerType of 0
  312. // for SMB link targets. Root referrals and targets pointing at other
  313. // DFS namespaces need to send ServerType of 1.
  314. //
  315. if (((pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL) == 0) &&
  316. ((pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_OUT_OF_DOMAIN) == 0))
  317. {
  318. pv2->ServerType = 0;
  319. }
  320. else
  321. {
  322. pv2->ServerType = 1;
  323. }
  324. pv2->Proximity = 0;
  325. pv2->TimeToLive = pRefHeader->Timeout;
  326. pv2->DfsPathOffset = (USHORT) (((PCHAR) pDfsPath) - ((PCHAR) pv2));
  327. pv2->DfsAlternatePathOffset =
  328. (USHORT) (((PCHAR) pAlternatePath) - ((PCHAR) pv2));
  329. pv2->NetworkAddressOffset =
  330. (USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv2));
  331. RtlCopyMemory(
  332. pNextAddress,
  333. pRep->ReplicaName,
  334. pRep->ReplicaNameLength);
  335. pNextAddress[ pRep->ReplicaNameLength/sizeof(WCHAR) ] = UNICODE_NULL;
  336. pNextAddress += pRep->ReplicaNameLength/sizeof(WCHAR) + 1;
  337. pv2++;
  338. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  339. }
  340. *ReferralSize = (ULONG)((PUCHAR)pNextAddress - (PUCHAR)pRef);
  341. return Status;
  342. }
  343. //+-------------------------------------------------------------------------
  344. //
  345. // Function: DfspGetV3DomainReferral
  346. //
  347. // Arguments: dfsdev: fill this in.
  348. //
  349. // Returns:
  350. //
  351. //
  352. // Description: Copies the V3 referrals to output buffer
  353. //
  354. //--------------------------------------------------------------------------
  355. DFSSTATUS
  356. DfsGetV3DomainReferral(
  357. IN PREFERRAL_HEADER pRefHeader,
  358. IN ULONG BufferSize,
  359. OUT PRESP_GET_DFS_REFERRAL pRef,
  360. OUT PULONG ReferralSize)
  361. {
  362. DFSSTATUS Status = ERROR_SUCCESS;
  363. PDFS_REFERRAL_V3 pv3 = NULL;
  364. PREPLICA_INFORMATION pRep = NULL;
  365. ULONG i = 0;
  366. ULONG CumulativeSize = 0;
  367. ULONG CurrentSize = 0;
  368. LPWSTR pDfsPath = NULL;
  369. LPWSTR pAlternatePath = NULL;
  370. LPWSTR pNextAddress = NULL;
  371. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  372. // Calculate the size of the referral, and make sure our size does not
  373. // exceed the passed in buffer len.
  374. CumulativeSize = sizeof (RESP_GET_DFS_REFERRAL);
  375. if (BufferSize < CumulativeSize)
  376. {
  377. Status = ERROR_MORE_DATA;
  378. return Status;
  379. }
  380. //
  381. // For compatibility, set all referrals to be storage servers.
  382. // and only the root referral as the referral servers.
  383. // This appears to keep the client happy for all cases
  384. // dfsdev: investigate if this is fine.
  385. //
  386. pRef->StorageServers = 0;
  387. pRef->ReferralServers = 0;
  388. pRef->NumberOfReferrals = (USHORT) pRefHeader->ReplicaCount;
  389. pRef->PathConsumed = 0;
  390. pv3 = &pRef->Referrals[0].v3;
  391. //
  392. // double unicode_null at end.
  393. //
  394. CumulativeSize += sizeof(UNICODE_NULL);
  395. //see how many referrals we can actually fit into the buffer
  396. for (i = 0; i < pRef->NumberOfReferrals; i++)
  397. {
  398. CurrentSize = sizeof(DFS_REFERRAL_V3) + sizeof(UNICODE_PATH_SEP) +
  399. pRep->ReplicaNameLength + sizeof(UNICODE_NULL);
  400. if ((CumulativeSize + CurrentSize) >= BufferSize)
  401. {
  402. Status = ERROR_MORE_DATA;
  403. break;
  404. }
  405. CumulativeSize += CurrentSize;
  406. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  407. }
  408. if (Status == ERROR_MORE_DATA)
  409. {
  410. #define EVENT_POSTED 1
  411. #define EVENT_NOT_POSTED 0
  412. static LONG DomainOverflowMaxEventPosted = 0;
  413. static LONG DomainOverflowMinEventPosted = 0;
  414. LONG PostedState;
  415. PostedState = InterlockedCompareExchange(&DomainOverflowMinEventPosted,
  416. EVENT_POSTED, EVENT_NOT_POSTED);
  417. if (PostedState == EVENT_NOT_POSTED)
  418. {
  419. DfsLogDfsEvent(DFS_INFO_DOMAIN_REFERRAL_MIN_OVERFLOW,
  420. 0, NULL, 0);
  421. }
  422. if (BufferSize < MAX_REFERRAL_SIZE)
  423. {
  424. return Status;
  425. }
  426. else
  427. {
  428. Status = ERROR_SUCCESS;
  429. PostedState = InterlockedCompareExchange(&DomainOverflowMaxEventPosted,
  430. EVENT_POSTED, EVENT_NOT_POSTED);
  431. if (PostedState == EVENT_NOT_POSTED)
  432. {
  433. //post event;
  434. DfsLogDfsEvent(DFS_WARN_DOMAIN_REFERRAL_OVERFLOW,
  435. 0, NULL, 0);
  436. }
  437. }
  438. }
  439. // Adjust the number of referrals accordingly.
  440. pRef->NumberOfReferrals = (USHORT)i;
  441. //
  442. // we have more than one service, but cannot fit any into the buffer
  443. // return buffer overflow.
  444. //
  445. if ((pRefHeader->ReplicaCount > 0) && (pRef->NumberOfReferrals == 0))
  446. {
  447. return ERROR_MORE_DATA;
  448. }
  449. //
  450. // Copy the volume prefix into the response buffer, just past the end
  451. // of all the V3 referrals
  452. //
  453. pNextAddress = pDfsPath = (LPWSTR) &pv3[ pRef->NumberOfReferrals ];
  454. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  455. for (i = 0; i < pRef->NumberOfReferrals; i++)
  456. {
  457. pv3->VersionNumber = 3;
  458. pv3->Size = sizeof(DFS_REFERRAL_V3);
  459. pv3->ServerType = 0;
  460. pv3->StripPath = 0; // for now
  461. pv3->NameListReferral = 1;
  462. pv3->TimeToLive = 600;
  463. pv3->SpecialNameOffset =
  464. (USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv3));
  465. pv3->NumberOfExpandedNames = 0;
  466. pv3->ExpandedNameOffset = 0;
  467. //
  468. // dfsdev investigate.
  469. //
  470. *pNextAddress++ = UNICODE_PATH_SEP;
  471. RtlMoveMemory(
  472. pNextAddress,
  473. pRep->ReplicaName,
  474. pRep->ReplicaNameLength);
  475. pNextAddress[ pRep->ReplicaNameLength / sizeof(WCHAR)] = UNICODE_NULL;
  476. pNextAddress += pRep->ReplicaNameLength / sizeof(WCHAR) + 1;
  477. pv3++;
  478. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  479. }
  480. *ReferralSize = (ULONG)((PUCHAR)pNextAddress - (PUCHAR)pRef);
  481. return Status;
  482. }
  483. //+-------------------------------------------------------------------------
  484. //
  485. // Function: DfspGetV3Referral
  486. //
  487. // Arguments: List of referrals
  488. //
  489. // Returns:
  490. //
  491. //
  492. // Description: Copies the V3 referrals to output buffer
  493. //
  494. //--------------------------------------------------------------------------
  495. DFSSTATUS
  496. DfsGetV3DCReferral(
  497. IN PREFERRAL_HEADER pRefHeader,
  498. IN ULONG BufferSize,
  499. OUT PRESP_GET_DFS_REFERRAL pRef,
  500. OUT PULONG ReferralSize)
  501. {
  502. DFSSTATUS Status = ERROR_SUCCESS;
  503. PDFS_REFERRAL_V3 pv3 = NULL;
  504. PREPLICA_INFORMATION pRep = NULL;
  505. ULONG i = 0;
  506. ULONG CumulativeSize = 0;
  507. ULONG CurrentSize = 0;
  508. LPWSTR pDfsPath = NULL;
  509. LPWSTR pAlternatePath = NULL;
  510. LPWSTR pNextAddress = NULL;
  511. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  512. // Calculate the size of the referral, and make sure our size does not
  513. // exceed the passed in buffer len.
  514. CumulativeSize = sizeof (RESP_GET_DFS_REFERRAL) +
  515. pRefHeader->LinkNameLength + sizeof(UNICODE_NULL);
  516. if (BufferSize < CumulativeSize)
  517. {
  518. Status = ERROR_MORE_DATA;
  519. return Status;
  520. }
  521. //
  522. // For compatibility, set all referrals to be storage servers.
  523. // and only the root referral as the referral servers.
  524. // This appears to keep the client happy for all cases
  525. // dfsdev: investigate if this is fine.
  526. //
  527. pRef->StorageServers = 0;
  528. pRef->ReferralServers = 0;
  529. pRef->NumberOfReferrals = 1;
  530. pRef->PathConsumed = 0;
  531. pv3 = &pRef->Referrals[0].v3;
  532. //
  533. // double unicode_null at end.
  534. //
  535. CumulativeSize += sizeof(UNICODE_NULL);
  536. //see how many referrals we can actually fit into the buffer
  537. for (i = 0; i < pRefHeader->ReplicaCount; i++)
  538. {
  539. CurrentSize = sizeof(UNICODE_PATH_SEP) +
  540. pRep->ReplicaNameLength +
  541. sizeof(UNICODE_NULL);
  542. if ((CumulativeSize + CurrentSize) >= BufferSize)
  543. break;
  544. CumulativeSize += CurrentSize;
  545. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  546. }
  547. // Adjust the number of referrals accordingly.
  548. pv3->NumberOfExpandedNames = (USHORT)i;
  549. //
  550. // we have more than one service, but cannot fit any into the buffer
  551. // return buffer overflow.
  552. //
  553. if ((pRefHeader->ReplicaCount > 0) && (pv3->NumberOfExpandedNames == 0))
  554. {
  555. return ERROR_MORE_DATA;
  556. }
  557. //
  558. // Copy the volume prefix into the response buffer, just past the end
  559. // of all the V3 referrals
  560. //
  561. pNextAddress = pDfsPath = (LPWSTR) &pv3[ pRef->NumberOfReferrals ];
  562. pv3->SpecialNameOffset =
  563. (USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv3));
  564. *pNextAddress++ = UNICODE_PATH_SEP;
  565. RtlMoveMemory(
  566. pNextAddress,
  567. pRefHeader->LinkName,
  568. pRefHeader->LinkNameLength);
  569. pNextAddress += pRefHeader->LinkNameLength/sizeof(WCHAR);
  570. *pNextAddress++ = UNICODE_NULL;
  571. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  572. pv3->VersionNumber = 3;
  573. pv3->Size = sizeof(DFS_REFERRAL_V3);
  574. pv3->ServerType = 0;
  575. pv3->StripPath = 0; // for now
  576. pv3->NameListReferral = 1;
  577. pv3->TimeToLive = 600;
  578. pv3->ExpandedNameOffset =
  579. (USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv3));
  580. for (i = 0; i < pv3->NumberOfExpandedNames; i++) {
  581. //
  582. // dfsdev: this is very confusing..
  583. // investigate. Each of the referrals we call keep
  584. // adding a unicode path sep.
  585. //
  586. #if 0
  587. *pNextAddress++ = UNICODE_PATH_SEP;
  588. #endif
  589. RtlCopyMemory(
  590. pNextAddress,
  591. pRep->ReplicaName,
  592. pRep->ReplicaNameLength );
  593. pNextAddress[ pRep->ReplicaNameLength / sizeof(WCHAR)] = UNICODE_NULL;
  594. pNextAddress += pRep->ReplicaNameLength / sizeof(WCHAR) + 1;
  595. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  596. }
  597. *ReferralSize = (ULONG)((PUCHAR)pNextAddress - (PUCHAR)pRef);
  598. return Status;
  599. }
  600. DFSSTATUS
  601. DfsGetV3NormalReferral(
  602. IN PREFERRAL_HEADER pRefHeader,
  603. IN ULONG BufferSize,
  604. OUT PRESP_GET_DFS_REFERRAL pRef,
  605. OUT PULONG ReferralSize)
  606. {
  607. DFSSTATUS Status = ERROR_SUCCESS;
  608. PDFS_REFERRAL_V3 pv3 = NULL;
  609. PREPLICA_INFORMATION pRep = NULL;
  610. ULONG i = 0;
  611. ULONG CumulativeSize = 0;
  612. ULONG CurrentSize = 0;
  613. LPWSTR pDfsPath = NULL;
  614. LPWSTR pAlternatePath = NULL;
  615. LPWSTR pNextAddress = NULL;
  616. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  617. // Calculate the size of the referral, and make sure our size does not
  618. // exceed the passed in buffer len.
  619. CumulativeSize =
  620. sizeof (RESP_GET_DFS_REFERRAL) +
  621. pRefHeader->LinkNameLength +
  622. sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL) +
  623. pRefHeader->LinkNameLength +
  624. sizeof(UNICODE_PATH_SEP) + sizeof(UNICODE_NULL);
  625. if (BufferSize < CumulativeSize)
  626. {
  627. Status = ERROR_MORE_DATA;
  628. return Status;
  629. }
  630. //
  631. // For compatibility, set all referrals to be storage servers.
  632. // and only the root referral as the referral servers.
  633. // This appears to keep the client happy for all cases
  634. // dfsdev: investigate if this is fine.
  635. //
  636. if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_OUT_OF_DOMAIN)
  637. {
  638. pRef->ReferralServers = 1;
  639. pRef->StorageServers = 0;
  640. }
  641. else if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL)
  642. {
  643. pRef->ReferralServers = 1;
  644. pRef->StorageServers = 1;
  645. }
  646. else
  647. {
  648. pRef->ReferralServers = 0;
  649. pRef->StorageServers = 1;
  650. }
  651. pRef->NumberOfReferrals = (USHORT) pRefHeader->ReplicaCount;
  652. pv3 = &pRef->Referrals[0].v3;
  653. //see how many referrals we can actually fit into the buffer
  654. for (i = 0; i < pRef->NumberOfReferrals; i++)
  655. {
  656. CurrentSize = sizeof(DFS_REFERRAL_V3) +
  657. pRep->ReplicaNameLength + sizeof(UNICODE_NULL);
  658. if ((CumulativeSize + CurrentSize) >= BufferSize)
  659. break;
  660. CumulativeSize += CurrentSize;
  661. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  662. }
  663. // Adjust the number of referrals accordingly.
  664. pRef->NumberOfReferrals = (USHORT)i;
  665. //
  666. // we have more than one service, but cannot fit any into the buffer
  667. // return buffer overflow.
  668. //
  669. if ((pRefHeader->ReplicaCount > 0) && (pRef->NumberOfReferrals == 0))
  670. {
  671. return ERROR_MORE_DATA;
  672. }
  673. //
  674. // Copy the volume prefix into the response buffer, just past the end
  675. // of all the V3 referrals
  676. //
  677. pNextAddress = pDfsPath = (LPWSTR) &pv3[ pRef->NumberOfReferrals ];
  678. RtlMoveMemory(
  679. pNextAddress,
  680. pRefHeader->LinkName,
  681. pRefHeader->LinkNameLength);
  682. pNextAddress += pRefHeader->LinkNameLength/sizeof(WCHAR);
  683. *pNextAddress++ = UNICODE_NULL;
  684. //
  685. // Copy the 8.3 volume prefix into the response buffer after the
  686. // dfsPath
  687. //
  688. pAlternatePath = pNextAddress;
  689. RtlMoveMemory(
  690. pNextAddress,
  691. pRefHeader->LinkName,
  692. pRefHeader->LinkNameLength);
  693. pNextAddress += pRefHeader->LinkNameLength/sizeof(WCHAR);
  694. *pNextAddress++ = UNICODE_NULL;
  695. pRep = (PREPLICA_INFORMATION) ((PBYTE)pRefHeader + pRefHeader->OffsetToReplicas);
  696. for (i = 0; i < pRef->NumberOfReferrals; i++)
  697. {
  698. pv3->VersionNumber = 3;
  699. pv3->Size = sizeof(DFS_REFERRAL_V3);
  700. //
  701. // The server type is important for the client. Set to 1 for
  702. // root referral, and 0 otherwise. It appears to keep the client
  703. // happy.
  704. // dfsdev: investigate further.
  705. //
  706. if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_ROOT_REFERRAL)
  707. {
  708. pv3->ServerType = 1;
  709. }
  710. else {
  711. pv3->ServerType = 0;
  712. }
  713. pv3->StripPath = 0; // for now
  714. pv3->NameListReferral = 0;
  715. pv3->TimeToLive = pRefHeader->Timeout;
  716. pv3->DfsPathOffset = (USHORT) (((PCHAR) pDfsPath) - ((PCHAR) pv3));
  717. pv3->DfsAlternatePathOffset =
  718. (USHORT) (((PCHAR) pAlternatePath) - ((PCHAR) pv3));
  719. pv3->NetworkAddressOffset =
  720. (USHORT) (((PCHAR) pNextAddress) - ((PCHAR) pv3));
  721. RtlZeroMemory(
  722. &pv3->ServiceSiteGuid,
  723. sizeof (GUID));
  724. RtlMoveMemory(
  725. pNextAddress,
  726. pRep->ReplicaName,
  727. pRep->ReplicaNameLength);
  728. pNextAddress[ pRep->ReplicaNameLength / sizeof(WCHAR)] = UNICODE_NULL;
  729. pNextAddress += pRep->ReplicaNameLength / sizeof(WCHAR) + 1;
  730. pv3++;
  731. pRep = (PREPLICA_INFORMATION) ( ((PCHAR) pRefHeader) + pRep->NextEntryOffset );
  732. }
  733. *ReferralSize = (ULONG)((PUCHAR)pNextAddress - (PUCHAR)pRef);
  734. return Status;
  735. }
  736. //+-------------------------------------------------------------------------
  737. //
  738. // Function: DfspGetV3Referral
  739. //
  740. // Arguments: List of referrals
  741. //
  742. // Returns:
  743. //
  744. //
  745. // Description: Copies the V3 referrals to output buffer
  746. //
  747. //--------------------------------------------------------------------------
  748. NTSTATUS
  749. DfspGetV3Referral(
  750. IN PREFERRAL_HEADER pRefHeader,
  751. IN ULONG BufferSize,
  752. OUT PRESP_GET_DFS_REFERRAL pRef,
  753. OUT PULONG ReferralSize)
  754. {
  755. DFSSTATUS Status = ERROR_SUCCESS;
  756. //
  757. //The client could be asking for either the trusted domains referral
  758. // or for the list of DC for a domain or for a normal dfs referral
  759. // to a path.
  760. //
  761. if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_DOMAIN_REFERRAL)
  762. {
  763. Status = DfsGetV3DomainReferral( pRefHeader,
  764. BufferSize,
  765. pRef,
  766. ReferralSize );
  767. }
  768. else if (pRefHeader->ReferralFlags & DFS_REFERRAL_DATA_DOMAIN_DC_REFERRAL)
  769. {
  770. Status = DfsGetV3DCReferral( pRefHeader,
  771. BufferSize,
  772. pRef,
  773. ReferralSize );
  774. }
  775. else
  776. {
  777. Status = DfsGetV3NormalReferral( pRefHeader,
  778. BufferSize,
  779. pRef,
  780. ReferralSize );
  781. }
  782. return Status;
  783. }
  784. //+-------------------------------------------------------------------------
  785. //
  786. // Function: ProcessOldDfsServerRequest
  787. //
  788. // Arguments:
  789. //
  790. // Returns: Status
  791. // ERROR_SUCCESS on success
  792. // ERROR status code otherwise
  793. //
  794. //
  795. // Description: Converts new data to what the old DFS server expects
  796. //
  797. //--------------------------------------------------------------------------
  798. DFSSTATUS ProcessOldDfsServerRequest(HANDLE hDriverHandle,
  799. PUMRX_USERMODE_WORKITEM ProtocolBuffer,
  800. PUMR_GETDFSREPLICAS_REQ pGetReplicaRequest,
  801. REFERRAL_HEADER *pReferral,
  802. ULONG *ReturnedDataSize)
  803. {
  804. DFSSTATUS Status = ERROR_SUCCESS;
  805. ULONG Size = 0;
  806. ULONG SendSize = 0;
  807. ULONG MaxLevel = 0;
  808. DWORD BytesReturned = 0;
  809. PRESP_GET_DFS_REFERRAL pRef = NULL;
  810. PBYTE pSendBuffer = NULL;
  811. PUMRX_USERMODE_WORKITEM pSendWorkItem = NULL;
  812. //get the level
  813. MaxLevel = pGetReplicaRequest->RepInfo.MaxReferralLevel;
  814. //check if MaxLevel is legal
  815. switch (MaxLevel)
  816. {
  817. case 1:
  818. Size = DfspGetV1ReferralSize(pReferral);
  819. break;
  820. case 2:
  821. Size = DfspGetV2ReferralSize(pReferral);
  822. break;
  823. case 3:
  824. Size = DfspGetV3ReferralSize(pReferral);
  825. break;
  826. default:
  827. ASSERT(FALSE && "Invalid MaxLevel");
  828. Status = ERROR_INVALID_PARAMETER;
  829. break;
  830. }
  831. if(Status != ERROR_SUCCESS)
  832. {
  833. return Status;
  834. }
  835. SendSize = UMR_ALIGN(pGetReplicaRequest->RepInfo.ClientBufferSize) + sizeof(UMRX_USERMODE_WORKITEM);
  836. pSendWorkItem = (PUMRX_USERMODE_WORKITEM) HeapAlloc(GetProcessHeap(), 0, SendSize);
  837. if(pSendWorkItem == NULL)
  838. {
  839. return ERROR_NOT_ENOUGH_MEMORY;
  840. }
  841. //get a pointer to the response buffer
  842. pSendBuffer = pSendWorkItem->WorkResponse.GetDfsReplicasResponse.Buffer;
  843. pRef = (PRESP_GET_DFS_REFERRAL) pSendBuffer;
  844. pRef->PathConsumed = (USHORT) pReferral->LinkNameLength;
  845. //
  846. // For level 1 referral, we fail if buffer is not big enough to
  847. // fit entire referral. For level 2 and 3, we try to fit as many
  848. // entries as possible into the refferal.
  849. if(MaxLevel == 1)
  850. {
  851. if(Size < pGetReplicaRequest->RepInfo.ClientBufferSize)
  852. {
  853. DfspGetV1Referral(pReferral, pRef);
  854. }
  855. else
  856. {
  857. Status = ERROR_MORE_DATA;
  858. }
  859. }
  860. else if(MaxLevel == 2)
  861. {
  862. Status = DfspGetV2Referral(pReferral, pGetReplicaRequest->RepInfo.ClientBufferSize, pRef,&Size);
  863. }
  864. else
  865. {
  866. Status = DfspGetV3Referral(pReferral, pGetReplicaRequest->RepInfo.ClientBufferSize, pRef ,&Size);
  867. }
  868. if(Status == ERROR_SUCCESS)
  869. {
  870. //copy the original header
  871. pSendWorkItem->Header = ProtocolBuffer->Header;
  872. pSendWorkItem->Header.IoStatus.Status = Status;
  873. pSendWorkItem->Header.IoStatus.Information = 0;
  874. //return without waiting for a response
  875. pSendWorkItem->Header.ulFlags = UMR_WORKITEM_HEADER_FLAG_RETURN_IMMEDIATE;
  876. //set the size of the data being returned
  877. pSendWorkItem->WorkResponse.GetDfsReplicasResponse.Length = Size;
  878. //finally send the data
  879. Status = DfsUserModeProcessPacket(hDriverHandle,
  880. (PBYTE) pSendWorkItem,
  881. SendSize,
  882. NULL,
  883. 0,
  884. &BytesReturned);
  885. }
  886. if(pSendWorkItem != NULL)
  887. {
  888. HeapFree (GetProcessHeap(), 0, (PVOID) pSendWorkItem);
  889. }
  890. *ReturnedDataSize = Size;
  891. return Status;
  892. }