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.

439 lines
13 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsTrustedDomain.cxx
  6. //
  7. // Contents: implements the trusted domain
  8. //
  9. // Classes: DfsTrustedDomain
  10. //
  11. // History: Apr. 8 2000, Author: udayh
  12. //
  13. //-----------------------------------------------------------------------------
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <windowsx.h>
  19. #include <ntsam.h>
  20. #include <dsgetdc.h>
  21. #include <lmcons.h>
  22. #include <lmapibuf.h>
  23. #include <lmaccess.h>
  24. #include <string.h>
  25. #include <tchar.h>
  26. #include <stdarg.h>
  27. #include <process.h>
  28. #include <ole2.h>
  29. #include <ntdsapi.h>
  30. #include "DfsReferralData.hxx"
  31. #include "DfsTrustedDomain.hxx"
  32. #include "DfsReplica.hxx"
  33. //
  34. // logging specific includes
  35. //
  36. #include "DfsTrustedDomain.tmh"
  37. //+-------------------------------------------------------------------------
  38. //
  39. // Function: GetDcReferralData - get the referral data
  40. //
  41. // Arguments: ppReferralData - the referral data for this instance
  42. // pCacheHit - did we find it already loaded?
  43. //
  44. // Returns: Status
  45. // ERROR_SUCCESS if we could get the referral data
  46. // error status otherwise.
  47. //
  48. //
  49. // Description: This routine returns a reference DfsReferralDAta
  50. // If one does not already exist in this class instance,
  51. // we create a new one. If someone is in the process
  52. // of loading the referral, we wait on the event in
  53. // the referral data which gets signalled when the thread
  54. // responsible for loading is done with the load.
  55. //
  56. //--------------------------------------------------------------------------
  57. DFSSTATUS
  58. DfsTrustedDomain::GetDcReferralData(
  59. OUT DfsReferralData **ppReferralData,
  60. OUT BOOLEAN *pCacheHit )
  61. {
  62. DfsReferralData *pRefData = NULL;
  63. DFSSTATUS Status = STATUS_SUCCESS;
  64. if (_DomainName.Length == 0)
  65. {
  66. return ERROR_INVALID_PARAMETER;
  67. }
  68. *pCacheHit = FALSE;
  69. Status = AcquireLock();
  70. if ( Status != STATUS_SUCCESS )
  71. {
  72. return Status;
  73. }
  74. // First see if we may need to do a reload.
  75. if (_LoadState == DfsTrustedDomainDcLoadFailed &&
  76. IsTimeToRetry())
  77. {
  78. ASSERT(_pDcReferralData == NULL);
  79. _LoadState = DfsTrustedDomainDcNotLoaded;
  80. }
  81. //
  82. // WE take difference action depending on the load state.
  83. //
  84. switch ( _LoadState )
  85. {
  86. case DfsTrustedDomainDcLoaded:
  87. DFS_TRACE_LOW(REFERRAL_SERVER, " Get Referral Data: Cache hit\n");
  88. //
  89. // we are dealing with a loaded instance. Just acquire a reference
  90. // and return the loaded referral data.
  91. //
  92. ASSERT (_pDcReferralData != NULL);
  93. pRefData = _pDcReferralData;
  94. pRefData->AcquireReference();
  95. ReleaseLock();
  96. *pCacheHit = TRUE;
  97. *ppReferralData = pRefData;
  98. break;
  99. case DfsTrustedDomainDcNotLoaded:
  100. //
  101. // The dc info is not loaded. Make sure that the referral data is
  102. // indeed empty. Create a new instance of the referral data
  103. // and set the state to load in progress.
  104. ASSERT(_pDcReferralData == NULL);
  105. DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: not loaded\n");
  106. _pDcReferralData = new DfsReferralData( &Status );
  107. if ( _pDcReferralData != NULL )
  108. {
  109. if(Status == ERROR_SUCCESS)
  110. {
  111. _LoadState = DfsTrustedDomainDcLoadInProgress;
  112. //
  113. // Acquire a reference on the new referral data, since we
  114. // have to return a referenced referral data to the caller.
  115. //
  116. pRefData = _pDcReferralData;
  117. pRefData->AcquireReference();
  118. }
  119. else
  120. {
  121. _pDcReferralData->ReleaseReference();
  122. _pDcReferralData = NULL;
  123. }
  124. } else
  125. {
  126. Status = ERROR_NOT_ENOUGH_MEMORY;
  127. }
  128. //
  129. // We no longer need the lock. We have allocate the referral
  130. // data and marked the state accordingly. No other thread can
  131. // interfere with our load now.
  132. //
  133. ReleaseLock();
  134. //
  135. // Now we load the referral data, and save the status of the
  136. // load in both our load status as well as the load status
  137. // in the referral data.
  138. // If the load was successful, we add this to the loaded list
  139. // of referral data that can be scavenged later. We set the load
  140. // state to loaded, and signal the event so that all waiting
  141. // threads can now be woken up.
  142. //
  143. if ( Status == ERROR_SUCCESS )
  144. {
  145. _pDcReferralData->DoSiteCosting = (BOOLEAN)DfsCheckSiteCostingEnabled();
  146. Status = LoadDcReferralData( _pDcReferralData );
  147. _LoadStatus = Status;
  148. _RetryFailedLoadTimeout = 0;
  149. _pDcReferralData->LoadStatus = Status;
  150. if ( Status == ERROR_SUCCESS )
  151. {
  152. _LoadState = DfsTrustedDomainDcLoaded;
  153. *ppReferralData = pRefData;
  154. pRefData->Signal();
  155. } else
  156. {
  157. _LoadState = DfsTrustedDomainDcLoadFailed;
  158. _RetryFailedLoadTimeout = GetTickCount();
  159. pRefData->Signal();
  160. (VOID)RemoveDcReferralData( pRefData, NULL );
  161. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER,
  162. "DomainDC load failed for %wZ, LoadStatus %x, Status %x\n",
  163. GetDomainName(),
  164. _LoadStatus,
  165. Status );
  166. }
  167. }
  168. break;
  169. case DfsTrustedDomainDcLoadInProgress:
  170. //
  171. // The load is in progress. We acquire a reference on the
  172. // referral data being loaded and wait for the event in the
  173. // referral data to be signalled. The return status of the wait
  174. // indicates if we can return the referral data or we fail
  175. // this request with an error.
  176. //
  177. DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: load in progress\n");
  178. ASSERT(_pDcReferralData != NULL);
  179. pRefData = _pDcReferralData;
  180. pRefData->AcquireReference();
  181. ReleaseLock();
  182. DFS_TRACE_NORM(REFERRAL_SERVER, "Thread: Waiting for referral load\n");
  183. Status = pRefData->Wait();
  184. if ( Status == ERROR_SUCCESS )
  185. {
  186. *ppReferralData = pRefData;
  187. } else
  188. {
  189. pRefData->ReleaseReference();
  190. }
  191. DFS_TRACE_NORM(REFERRAL_SERVER, " Get Referral Data: load in progress done\n");
  192. break;
  193. case DfsTrustedDomainDcLoadFailed:
  194. //
  195. // The Load failed. REturn error. We need to setup a time
  196. // after which we need to reattempt the load.
  197. //
  198. Status = _LoadStatus;
  199. ReleaseLock();
  200. *ppReferralData = NULL;
  201. break;
  202. default:
  203. //
  204. // We should never get here. Its an invalid state.
  205. //
  206. ASSERT(TRUE);
  207. Status = ERROR_INVALID_STATE;
  208. ReleaseLock();
  209. break;
  210. }
  211. ASSERT((Status != ERROR_SUCCESS) || (*ppReferralData != NULL));
  212. return Status;
  213. }
  214. DFSSTATUS
  215. DfsTrustedDomain::RemoveDcReferralData(
  216. DfsReferralData *pRemoveReferralData,
  217. PBOOLEAN pRemoved )
  218. {
  219. DFSSTATUS Status = ERROR_SUCCESS;
  220. DfsReferralData *pRefData = NULL;
  221. //
  222. // Get the exclusive lock on this instance
  223. //
  224. if (pRemoved != NULL)
  225. {
  226. *pRemoved = FALSE;
  227. }
  228. AcquireLock();
  229. //
  230. // make sure _LoadState indicates that it is loaded.
  231. // Set the referralData to null, and state to NotLoaded.
  232. //
  233. if (_LoadState == DfsTrustedDomainDcLoaded || _LoadState == DfsTrustedDomainDcLoadFailed)
  234. {
  235. pRefData = _pDcReferralData;
  236. if ( (pRemoveReferralData == NULL) ||
  237. (pRemoveReferralData == pRefData) )
  238. {
  239. _pDcReferralData = NULL;
  240. _LoadState = (_LoadState == DfsTrustedDomainDcLoaded) ?
  241. DfsTrustedDomainDcNotLoaded : DfsTrustedDomainDcLoadFailed;
  242. }
  243. else {
  244. pRefData = NULL;
  245. }
  246. }
  247. ReleaseLock();
  248. //
  249. // Release reference on the referral data. This is the reference
  250. // we had taken when we had cached the referral data here.
  251. //
  252. if (pRefData != NULL)
  253. {
  254. pRefData->ReleaseReference();
  255. if (pRemoved != NULL)
  256. {
  257. *pRemoved = TRUE;
  258. }
  259. }
  260. return Status;
  261. }
  262. DFSSTATUS
  263. DfsTrustedDomain::LoadDcReferralData(
  264. IN DfsReferralData *pReferralData )
  265. {
  266. DFSSTATUS Status;
  267. PDS_DOMAIN_CONTROLLER_INFO_1 pDsDomainControllerInfo1 = NULL;
  268. HANDLE HandleToDs = NULL;
  269. ULONG NameCount = 0, Index;
  270. ULONG DsDcCount = 0;
  271. ULONG UseIndex = 0;
  272. BOOLEAN CacheHit = FALSE;
  273. LPWSTR DomainController = NULL;
  274. //
  275. // we have a problem that DsBind fails when going across forests
  276. // for netbios domains as local system.
  277. // So we bind to the DNS domain name only for cross forest domains,
  278. // this information is stored by UseBindDomain boolean.
  279. //
  280. Status = DsBind(DomainController,
  281. _UseBindDomain ? _BindDomainName.Buffer : _DomainName.Buffer,
  282. &HandleToDs);
  283. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsTrustedDomain DsBind Status %d\n",
  284. Status);
  285. if (Status == ERROR_SUCCESS)
  286. {
  287. Status = DsGetDomainControllerInfo( HandleToDs,
  288. _DomainName.Buffer,
  289. 1,
  290. &NameCount,
  291. (PVOID *)(&pDsDomainControllerInfo1));
  292. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsTrustedDomain DsGetDomainControllerInfo Status %d\n",
  293. Status);
  294. DsUnBind( &HandleToDs);
  295. }
  296. if (Status == ERROR_SUCCESS)
  297. {
  298. for (Index = 0; Index < NameCount; Index++)
  299. {
  300. if (pDsDomainControllerInfo1[Index].fDsEnabled == TRUE)
  301. {
  302. DsDcCount++;
  303. }
  304. }
  305. if (DsDcCount > 0)
  306. {
  307. pReferralData->pReplicas = new DfsReplica[ DsDcCount ];
  308. if (pReferralData->pReplicas == NULL)
  309. {
  310. Status = ERROR_NOT_ENOUGH_MEMORY;
  311. }
  312. else
  313. {
  314. pReferralData->ReplicaCount = DsDcCount;
  315. }
  316. }
  317. for (Index = 0; ((Index < NameCount) && (Status == ERROR_SUCCESS)); Index++)
  318. {
  319. LPWSTR UseName;
  320. CacheHit = FALSE;
  321. if (pDsDomainControllerInfo1[Index].fDsEnabled != TRUE)
  322. {
  323. continue;
  324. }
  325. if (_Netbios == TRUE)
  326. {
  327. UseName = pDsDomainControllerInfo1[Index].NetbiosName;
  328. }
  329. else
  330. {
  331. UseName = pDsDomainControllerInfo1[Index].DnsHostName;
  332. if (UseName == NULL)
  333. {
  334. UseName = pDsDomainControllerInfo1[Index].NetbiosName;
  335. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsDomainInformation DNS Name is NULL. Using Netbios =%ws Status %d\n",
  336. UseName, Status);
  337. }
  338. }
  339. if (UseName != NULL)
  340. {
  341. UNICODE_STRING TargetName;
  342. Status = DfsRtlInitUnicodeStringEx(&TargetName, UseName);
  343. if(Status == ERROR_SUCCESS)
  344. {
  345. Status = (&pReferralData->pReplicas[ UseIndex ])->SetTargetServer( &TargetName, &CacheHit );
  346. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "DfsDomainInformation SetTargetServer=%wZ Status %d\n",
  347. &TargetName, Status);
  348. }
  349. UseIndex++;
  350. }
  351. }
  352. DsFreeDomainControllerInfo( 1,
  353. NameCount,
  354. pDsDomainControllerInfo1);
  355. }
  356. return Status;
  357. }