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.

432 lines
12 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <windows.h>
  5. #include <windef.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <stddef.h>
  9. #include "dfsgeneric.hxx"
  10. #include "dfsinit.hxx"
  11. #include "dsgetdc.h"
  12. #include "lm.h"
  13. #include <dsrole.h>
  14. #include <DfsReferralData.h>
  15. #include <DfsReferral.hxx>
  16. #include <dfsheader.h>
  17. #include <Dfsumr.h>
  18. #include <winsock2.h>
  19. #include <DfsSiteCache.hxx>
  20. #include <DfsSiteCostCache.hxx>
  21. #include <DfsSiteNameSupport.hxx>
  22. #include <DfsSite.hxx>
  23. //
  24. // logging includes.
  25. //
  26. #include "DfsSite.tmh"
  27. #define _Dfs_LocalAddress 0x0100007f //localaddress (127.0.0.1)
  28. //
  29. // Given the sitename initialize this site.
  30. // We'll also calculate the corresponding hashvalue
  31. // for future use. The SiteCostCache for this site
  32. // will be allocated also. It'll get populated as we get
  33. // referrals.
  34. //
  35. DFSSTATUS
  36. DfsSite::Initialize(
  37. IN PUNICODE_STRING pSiteName)
  38. {
  39. DFSSTATUS Status = ERROR_SUCCESS;
  40. //
  41. // Copy the sitename. It's ok if this is NULL.
  42. //
  43. Status = DfsCreateUnicodeString(&_SiteName, pSiteName);
  44. if (Status != ERROR_SUCCESS)
  45. {
  46. return ERROR_NOT_ENOUGH_MEMORY;
  47. }
  48. // Pre-calculate that wonderful hash value.
  49. CalcHash();
  50. Status = DfsSiteCostSupport::DfsCreateSiteCostSupport( &_pSiteCostSupport );
  51. return Status;
  52. }
  53. //
  54. //
  55. //
  56. VOID
  57. DfsSite::GetDefaultSiteCost(
  58. DfsSite *DestinationSite,
  59. PULONG pCost)
  60. {
  61. //
  62. // If we are dealing with an empty sitename at either end,
  63. // we err on the safe side.
  64. //
  65. *pCost = DFS_MAX_COST;
  66. if ((IsEmptyString( DestinationSite->SiteNameString() ) == FALSE) &&
  67. (IsEmptyString( _SiteName.Buffer ) == FALSE))
  68. {
  69. // If the sitenames are the same the cost is zero by definition.
  70. if (DfsCompareSiteNames( &_SiteName, DestinationSite->SiteName() ) == 0)
  71. {
  72. *pCost = DFS_MIN_COST;
  73. }
  74. }
  75. return;
  76. }
  77. //
  78. // Given a target site, return its cost.
  79. // We simply have to get it from the Cache.
  80. // We return ERROR_NOT_FOUND if it's not there.
  81. //
  82. DFSSTATUS
  83. DfsSite::GetRealSiteCost(
  84. DfsSite *DestinationSite,
  85. PULONG pCost)
  86. {
  87. DFSSTATUS Status = ERROR_SUCCESS;
  88. ASSERT(DestinationSite);
  89. DfsSiteCostCache *pCache = NULL;
  90. ASSERT(_pSiteCostSupport != NULL);
  91. if ((IsEmptyString( DestinationSite->SiteNameString() )) ||
  92. (IsEmptyString( _SiteName.Buffer )))
  93. {
  94. *pCost = DFS_MAX_COST;
  95. return Status;
  96. }
  97. Status = _pSiteCostSupport->Acquire( &pCache );
  98. if (Status == ERROR_SUCCESS)
  99. {
  100. //
  101. // Get the value from the cache if it's there.
  102. // Else, it'll return NOT_FOUND.
  103. //
  104. Status = pCache->GetCost( DestinationSite, pCost );
  105. _pSiteCostSupport->Release();
  106. }
  107. DFS_TRACE_LOW( REFERRAL, "GetCost Status 0x%x: From %ws to %ws, Cost = 0x%x\n",
  108. Status, SiteNameString(), DestinationSite->SiteNameString(), *pCost );
  109. return Status;
  110. }
  111. //
  112. // Given the IpAddress, return a corresponding
  113. // DfsSite. This is meant to always succeed.
  114. //
  115. VOID
  116. DfsIpToDfsSite(
  117. IN char * IpData,
  118. IN ULONG IpLength,
  119. IN USHORT IpFamily,
  120. OUT DfsSite **ppSite)
  121. {
  122. DFSSTATUS Status = ERROR_SUCCESS;
  123. LPWSTR *SiteNamesArray = NULL;
  124. DWORD IpAddress = 0;
  125. unsigned char *IpAddr = (unsigned char *)IpData;
  126. PVOID pBufferToFree = NULL;
  127. LPWSTR FoundSiteName = NULL;
  128. DfsSite *pFoundSite = NULL;
  129. CopyMemory(&IpAddress, IpAddr, sizeof(IpAddress));
  130. //
  131. // If this is local then we have it easy.
  132. //
  133. if ((IpAddress == _Dfs_LocalAddress) &&
  134. (IpLength == 4))
  135. {
  136. Status = DsGetSiteName( NULL, &FoundSiteName );
  137. if (Status == ERROR_SUCCESS)
  138. {
  139. pBufferToFree = (PVOID)FoundSiteName;
  140. DFS_TRACE_LOW(REFERRAL, "IpToDfsSite: LOCAL IP maps to SiteName %ws\n",
  141. FoundSiteName);
  142. }
  143. DFS_TRACE_ERROR_HIGH(Status, REFERRAL, "DsGetSiteName fails with Status 0x%x for LOCAL IP\n",
  144. Status);
  145. }
  146. else
  147. {
  148. //
  149. // Send in the IP Address to get the site name.
  150. //
  151. Status = DfsGetSiteNameFromIpAddress( IpData,
  152. IpLength,
  153. IpFamily,
  154. &SiteNamesArray );
  155. if ((Status == ERROR_SUCCESS) &&
  156. (SiteNamesArray != NULL))
  157. {
  158. //
  159. // We found the sitename. We only look at the first entry
  160. // returned. We'll also create the hash entry for future use.
  161. //
  162. if (SiteNamesArray[0] != NULL)
  163. {
  164. FoundSiteName = SiteNamesArray[0];
  165. }
  166. pBufferToFree = (PVOID)SiteNamesArray;
  167. }
  168. DFS_TRACE_ERROR_HIGH(Status, REFERRAL, "DsGetSiteNameFromIpAddress fails with Status 0x%x for IP\n",
  169. Status);
  170. }
  171. if (FoundSiteName != NULL)
  172. {
  173. //
  174. // Get the DfsSite corresponding to this site name.
  175. // If for any reason, including NOT_ENOUGH_MEMORY, this fails,
  176. // we simply use our default dfssite (see below).
  177. //
  178. (VOID) DfsGetSiteBySiteName( FoundSiteName, &pFoundSite );
  179. }
  180. //
  181. // Default DfsSite has a NULL site name, and knows of no site-cost to anybody.
  182. // It is pre-created at startup time, so it's guaranteed to exist.
  183. //
  184. if (pFoundSite == NULL)
  185. {
  186. pFoundSite = DfsGetDefaultSite();
  187. DFS_TRACE_LOW(REFERRAL, "IpToDfsSite: Using default Empty DfsSite for IP %d:%d:%d:%d\n",
  188. IpAddr[0],
  189. IpAddr[1],
  190. IpAddr[2],
  191. IpAddr[3]);
  192. }
  193. *ppSite = pFoundSite;
  194. //
  195. // We've made a copy, ok to free this array now.
  196. //
  197. if (pBufferToFree != NULL)
  198. {
  199. NetApiBufferFree( pBufferToFree );
  200. }
  201. }
  202. //
  203. // Given a sitename, return a referenced DfsSite.
  204. //
  205. DFSSTATUS
  206. DfsGetSiteBySiteName(
  207. LPWSTR SiteNameString,
  208. DfsSite **ppSite)
  209. {
  210. DFSSTATUS Status = ERROR_SUCCESS;
  211. DfsSite *pDfsSite = NULL;
  212. PDFS_SITE_NAME_DATA pSiteNameData = NULL;
  213. UNICODE_STRING SiteName;
  214. do {
  215. Status = DfsRtlInitUnicodeStringEx( &SiteName, SiteNameString );
  216. if (Status != ERROR_SUCCESS)
  217. {
  218. break;
  219. }
  220. //
  221. // Empty site names get the default site.
  222. //
  223. if (IsEmptyString( SiteNameString ))
  224. {
  225. *ppSite = DfsGetDefaultSite();
  226. DFS_TRACE_LOW(REFERRAL, "SiteBySiteName:Using default Empty DfsSite for Empty sitename\n");
  227. break;
  228. }
  229. //
  230. // Look it up to see if we know about this site already.
  231. //
  232. pSiteNameData = (PDFS_SITE_NAME_DATA)DfsServerGlobalData.pSiteNameSupport->LookupIpInHash(
  233. &SiteName );
  234. if (pSiteNameData != NULL)
  235. {
  236. ASSERT( pSiteNameData->pDfsSite != NULL );
  237. ASSERT( Status == ERROR_SUCCESS );
  238. //
  239. // take a new reference on this site we found before returning.
  240. //
  241. pSiteNameData->pDfsSite->AcquireReference();
  242. *ppSite = pSiteNameData->pDfsSite;
  243. //
  244. // Release the reference we acquired during lookup.
  245. // We have a reference to the DfsSite inside it anyway.
  246. //
  247. DfsServerGlobalData.pSiteNameSupport->ReleaseSiteNameData( pSiteNameData );
  248. DFS_TRACE_LOW(REFERRAL, "SiteBySiteName: Cachehit for sitename %ws -> DfsSite %p\n",
  249. SiteNameString, *ppSite);
  250. break;
  251. }
  252. //
  253. // We have to create a new DfsSite.
  254. //
  255. pDfsSite = new DfsSite;
  256. if (pDfsSite == NULL)
  257. {
  258. Status = ERROR_NOT_ENOUGH_MEMORY;
  259. DFS_TRACE_ERROR_LOW(Status, REFERRAL, "DfsSite->constructor failed with 0x%x for sitename %ws\n",
  260. Status, SiteNameString);
  261. break;
  262. }
  263. //
  264. // Initialize the site name as well as its site-cost cache.
  265. // This call will make a copy of the sitename we send.
  266. //
  267. Status = pDfsSite->Initialize( &SiteName );
  268. if (Status != ERROR_SUCCESS)
  269. {
  270. DFS_TRACE_ERROR_HIGH(Status, REFERRAL, "DfsSite->Initialize failed with 0x%x for sitename %ws\n",
  271. Status, SiteNameString);
  272. break;
  273. }
  274. //
  275. // Put this in the SiteName->DfsSite cache.
  276. // This StoreSiteInCache method will take a reference on the
  277. // DfsSite. We ignore the return status; we don't need
  278. // to fail this call just because the hash insertion failed.
  279. //
  280. (VOID) DfsServerGlobalData.pSiteNameSupport->StoreSiteInCache( pDfsSite );
  281. //
  282. // We've already taken a reference on this DfsSite
  283. // when it was created. So just return the pointer.
  284. // The caller needs to make sure that it releases this
  285. // reference when its done.
  286. //
  287. *ppSite = pDfsSite;
  288. DFS_TRACE_LOW(REFERRAL, "SiteBySiteName ->StoreInCache: Created new DfsSite %p for site %ws\n",
  289. *ppSite, SiteNameString );
  290. } while (FALSE);
  291. // Error path.
  292. if (Status != ERROR_SUCCESS)
  293. {
  294. //
  295. // We acquired this reference when we instantiated this.
  296. // This will delete it if we actually created it.
  297. //
  298. if (pDfsSite != NULL)
  299. {
  300. pDfsSite->ReleaseReference();
  301. }
  302. *ppSite = NULL;
  303. }
  304. return Status;
  305. }
  306. //
  307. // The following are callbacks for the SiteCost hashtable.
  308. //
  309. // The hash value was pre-calculated at the
  310. // time we initialized the site name.
  311. ULONG
  312. DfsHashDfsSite(
  313. IN PVOID pSite)
  314. {
  315. DfsSite *Site = (DfsSite *)pSite;
  316. ASSERT(Site != NULL);
  317. return Site->Hash();
  318. }
  319. // Compare two sites to see if their names match.
  320. int
  321. DfsCompareDfsSites(
  322. void* pvKey1,
  323. void* pvKey2)
  324. {
  325. PUNICODE_STRING Site1 = ((DfsSite *) pvKey1)->SiteName();
  326. PUNICODE_STRING Site2 = ((DfsSite *) pvKey2)->SiteName();
  327. if (Site1->Length == Site2->Length)
  328. {
  329. return RtlCompareUnicodeString( Site1, Site2, FALSE );
  330. } else {
  331. return (signed)Site1->Length - (signed)Site2->Length;
  332. }
  333. }
  334. // Compare two sites to see if their names match.
  335. int
  336. DfsCompareSiteNames(
  337. void* pvKey1,
  338. void* pvKey2)
  339. {
  340. PUNICODE_STRING Site1 = (PUNICODE_STRING) pvKey1;
  341. PUNICODE_STRING Site2 = (PUNICODE_STRING) pvKey2;
  342. if (Site1->Length == Site2->Length)
  343. {
  344. return RtlCompareUnicodeString( Site1, Site2, FALSE );
  345. } else {
  346. return (signed)Site1->Length - (signed)Site2->Length;
  347. }
  348. }
  349. // Allocate the cache data entry
  350. PVOID
  351. DfsAllocateHashData(ULONG Size )
  352. {
  353. PVOID RetValue = NULL;
  354. if (Size)
  355. {
  356. RetValue = (PVOID) new BYTE[Size];
  357. if (RetValue != NULL)
  358. {
  359. RtlZeroMemory( RetValue, Size );
  360. }
  361. }
  362. return RetValue;
  363. }
  364. VOID
  365. DfsDeallocateHashData(PVOID pPointer )
  366. {
  367. PDFS_SITE_COST_DATA pSiteStructure = (PDFS_SITE_COST_DATA)pPointer;
  368. if (pSiteStructure)
  369. {
  370. delete [] (PBYTE)pSiteStructure;
  371. }
  372. }