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.

870 lines
22 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ds.c
  5. Abstract:
  6. This file contains all the routines used in interfacing with the DS. We go
  7. to the DS go make sure we are not a Rogue server, and also to retrieve all
  8. configuration information.
  9. Author:
  10. Shirish Koti (koti) 26-May-1997
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. --*/
  15. //
  16. // System Includes
  17. //
  18. #define INC_OLE2
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include "activeds.h"
  23. #include "adsi.h"
  24. #if DBG
  25. #define DBGPRINT printf
  26. #else
  27. #define DBGPRINT
  28. #endif
  29. #include <netlib.h>
  30. #include <lmapibuf.h>
  31. #include <dsgetdc.h>
  32. #include <dnsapi.h>
  33. #include "adsi.h"
  34. #include <dsauth.h>
  35. #include <dhcpapi.h>
  36. #include <dhcpds.h>
  37. DWORD
  38. ValidateService(
  39. LPWSTR lpwDomain, // domain name
  40. LPWSTR lpwUserName, // usually NULL
  41. LPWSTR lpwPassword, // usually NULL
  42. DWORD dwAuthFlags, // ??
  43. LPWSTR lpwObjectPath, // where our things are stored (e.g. DHCP)
  44. LPWSTR lpwSrchFilter, // objects we're looking for (objectClass==DHCP)
  45. LPWSTR *ppwAttrName, // name of the attribute we're looking for
  46. LPWSTR lpwAttrVal // value of the attribute we're looking for
  47. );
  48. LPWSTR lpwGlbNamingContextString = DHCPDS_NAMING_CONTEXT;
  49. DWORD
  50. DhcpDSGetDomainAndRoot(
  51. LPWSTR * ppwDomainName,
  52. LPWSTR * ppwRootName,
  53. BOOLEAN * fIsStandAlone
  54. )
  55. /*++
  56. Routine Description:
  57. This function gets the DS Domain and the root of the enterprise that this
  58. machine is a member of.
  59. NOTE: Memory is allocated to hold strings pointed to by *ppwDomainName and
  60. *ppwRootName, and the caller must free that memory.
  61. One of ppwDomainName or ppwRootName can be NULL, to indicate the caller
  62. doesn't want that info. (e.g. only root is needed, not domain)
  63. Arguments:
  64. ppwDomainName - pointer to a string that will hold domain name
  65. ppwRootName - pointer to a string that will hold the root of enterprise
  66. fIsStandAlone - pointer to a boolean: TRUE if this server is Standalone
  67. Return Value:
  68. Result of the operation
  69. --*/
  70. {
  71. DWORD dwError;
  72. LPTSTR NetbiosDomNamePtr=NULL;
  73. LPTSTR pDomain=NULL;
  74. LPWSTR lpwRetDomainName=NULL;
  75. LPWSTR lpwRetRootName=NULL;
  76. BOOLEAN IsWorkgroup=TRUE;
  77. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  78. // initialize, in case we bail out
  79. if (ppwDomainName)
  80. {
  81. *ppwDomainName = NULL;
  82. }
  83. if (ppwRootName)
  84. {
  85. *ppwRootName = NULL;
  86. }
  87. *fIsStandAlone = FALSE;
  88. //
  89. // first, find out which domain we are a member of.
  90. //
  91. dwError = NetpGetDomainNameExEx(
  92. &NetbiosDomNamePtr,
  93. &pDomain,
  94. &IsWorkgroup);
  95. //
  96. // if NetpGetDomainNameExEx failed, we shouldn't proceed
  97. //
  98. if (dwError != NO_ERROR)
  99. {
  100. DBGPRINT("DhcpGetDSDomain: NetpGetDomainNameExEx failed (%ld)\n",dwError);
  101. return(dwError);
  102. }
  103. // we don't care about this domain name: free the buffer
  104. if (NetbiosDomNamePtr)
  105. {
  106. NetApiBufferFree(NetbiosDomNamePtr);
  107. }
  108. // if this is a standalone server, we're done here
  109. if (IsWorkgroup)
  110. {
  111. DBGPRINT("DhcpGetDSDomain: server is part of a workgroup\n");
  112. *fIsStandAlone = TRUE;
  113. if (pDomain)
  114. {
  115. NetApiBufferFree(pDomain);
  116. }
  117. return(NO_ERROR);
  118. }
  119. // if pDomain is NULL, it means that the DNS domain isn't configured.
  120. // For the purpose of rogue-detection, we will assume it to be a workgroup
  121. // though in the strictest sense that's not true.
  122. if (pDomain == NULL)
  123. {
  124. DBGPRINT("DhcpGetDSDomain: pDomain is NULL: assuming part of workgroup\n");
  125. *fIsStandAlone = TRUE;
  126. return(NO_ERROR);
  127. }
  128. //
  129. // if the caller wants DomainName, allocate space, and copy it in
  130. //
  131. if (ppwDomainName)
  132. {
  133. lpwRetDomainName = (LPWSTR)LocalAlloc(
  134. LPTR,
  135. (wcslen(pDomain)+1)*sizeof(WCHAR) );
  136. if (lpwRetDomainName == NULL)
  137. {
  138. DBGPRINT("DhcpGetDSDomain: malloc 1 failed (%ld)\n",
  139. (wcslen(pDomain)+1)*sizeof(WCHAR));
  140. dwError = ERROR_NOT_ENOUGH_MEMORY;
  141. goto DhcpGetDSDomain_ErrExit;
  142. }
  143. // copy the name in
  144. wcscpy(lpwRetDomainName, pDomain);
  145. *ppwDomainName = lpwRetDomainName;
  146. }
  147. //
  148. // See if the caller wants DS Root as well
  149. // get the info about this domain controller (the only thing we want
  150. // from all the good info in pDCInfo is the DS root name (DnsForestName field)
  151. //
  152. if (ppwRootName)
  153. {
  154. dwError = DsGetDcName(
  155. NULL, // server name
  156. pDomain, // domain name
  157. NULL, // domain guid
  158. NULL, // site name
  159. DS_IS_DNS_NAME,
  160. &pDCInfo);
  161. if (dwError != NO_ERROR)
  162. {
  163. DBGPRINT("DhcpGetDSDomain: DsGetDcName failed %ld\n",dwError);
  164. goto DhcpGetDSDomain_ErrExit;
  165. }
  166. //
  167. // RootName: allocate space, and copy the root name in
  168. //
  169. lpwRetRootName = (LPWSTR)LocalAlloc(
  170. LPTR,
  171. (wcslen(pDCInfo->DnsForestName)+1)*sizeof(WCHAR) );
  172. if (lpwRetRootName == NULL)
  173. {
  174. DBGPRINT("DhcpGetDSDomain: malloc 2 failed (%ld)\n",
  175. (wcslen(pDCInfo->DnsForestName)+1)*sizeof(WCHAR));
  176. dwError = ERROR_NOT_ENOUGH_MEMORY;
  177. goto DhcpGetDSDomain_ErrExit;
  178. }
  179. // copy the name in
  180. wcscpy(lpwRetRootName, pDCInfo->DnsForestName);
  181. *ppwRootName = lpwRetRootName;
  182. NetApiBufferFree(pDCInfo);
  183. }
  184. NetApiBufferFree(pDomain);
  185. return(NO_ERROR);
  186. DhcpGetDSDomain_ErrExit:
  187. DBGPRINT("DhcpGetDSDomain: executing error path, dwError = %ld\n",dwError);
  188. //
  189. // free the things that were given to us (or we took!)
  190. //
  191. if (pDomain)
  192. {
  193. NetApiBufferFree(pDomain);
  194. }
  195. if (pDCInfo)
  196. {
  197. NetApiBufferFree(pDCInfo);
  198. }
  199. if (lpwRetDomainName)
  200. {
  201. LocalFree(lpwRetDomainName);
  202. }
  203. if (lpwRetRootName)
  204. {
  205. LocalFree(lpwRetRootName);
  206. }
  207. if (ppwDomainName)
  208. {
  209. *ppwDomainName = NULL;
  210. }
  211. if (ppwRootName)
  212. {
  213. *ppwRootName = NULL;
  214. }
  215. return(dwError);
  216. }
  217. //BeginExport(function)
  218. //DOC DhcpDSValidateServer validates the server in the DS by looking for the server
  219. //DOC object and checking to see if the given IpAddress is present in the DS.
  220. //DOC This calls the other helper routine in DhcpDs.dll to do the real work.
  221. //DOC Returns one of
  222. //DOC DHCPDSERR_DS_OPERATION_FAILED
  223. //DOC DHCPDSERR_ENTRY_NOT_FOUND
  224. //DOC DHCPDSERR_ENTRY_FOUND
  225. //DOC DHCPDSERR_SERVER_IS_STANDALONE
  226. DWORD
  227. DhcpDSValidateServer( // validate in DS
  228. IN LPWSTR lpwDomain, // OPTIONAL NULL ==> Default domain
  229. IN DWORD *lpIpAddress, // one of the IpAddresses that must exist in DS
  230. IN ULONG dwIpAddressCount, // # of ip addresses supplied..
  231. IN LPWSTR lpwUserName, // OPTIONAL NULL ==> m/c account
  232. IN LPWSTR lpwPassword, // OPTIONAL password to use
  233. IN DWORD dwAuthFlags // MUST BE ZERO?
  234. ) //EndExport(function)
  235. {
  236. DWORD Error;
  237. BOOL Found;
  238. BOOL IsStandAlone;
  239. IsStandAlone = FALSE;
  240. Found = FALSE;
  241. Error = DhcpDsValidateService // check to validate for dhcp
  242. (
  243. lpwDomain,
  244. lpIpAddress,
  245. dwIpAddressCount,
  246. lpwUserName,
  247. lpwPassword,
  248. dwAuthFlags,
  249. &Found,
  250. &IsStandAlone
  251. );
  252. if( ERROR_SUCCESS != Error )
  253. return DHCPDSERR_DS_OPERATION_FAILED;
  254. if( IsStandAlone ) return DHCPDSERR_SERVER_IS_STANDALONE;
  255. return Found? DHCPDSERR_ENTRY_FOUND : DHCPDSERR_ENTRY_NOT_FOUND;
  256. }
  257. DWORD
  258. DhcpDSMapDomainToCNPath(
  259. LPWSTR lpwDomain,
  260. LPWSTR lpwUserName,
  261. LPWSTR lpwPassword,
  262. DWORD dwAuthFlags,
  263. LPWSTR *ppwCNPath
  264. )
  265. /*++
  266. Routine Description:
  267. This function retrieves the full path to the Configuration Container, given
  268. the name of the domain. If the domain name is not specified, server's domain
  269. name is assumed.
  270. NOTE: memory is allocated for ppwCNPath on successful return. Caller must
  271. free this memory.
  272. Arguments:
  273. lpwDomain - domain name in which to validate the service. Can be NULL to
  274. indicate the server's domain
  275. lpwUserName - account name to use during DS lookup. Usually, NULL (default)
  276. lpwPassword - password for the above user
  277. dwAuthFlags - flags to use
  278. ppwCNPath - pointer to string containing the path, on return.
  279. Return Value:
  280. Result of the operation
  281. --*/
  282. {
  283. HRESULT hr=S_OK;
  284. LPWSTR pCanonName;
  285. LPWSTR lpwLocalDomain=NULL;
  286. LPWSTR lpwDomainToContact=NULL;
  287. LPWSTR lpwDCName;
  288. HANDLE handle = NULL;
  289. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  290. DWORD dwCanonNameLen;
  291. PADS_ATTR_INFO pAttributeEntries=NULL;
  292. DWORD dwNumAttributesReturned=0;
  293. BOOLEAN fIsStandAlone;
  294. BOOLEAN fCNStringFound;
  295. DWORD dwRetCode;
  296. DWORD index;
  297. *ppwCNPath = NULL;
  298. lpwDomainToContact = lpwDomain;
  299. //
  300. // if domain name is not supplied, find local domain first
  301. //
  302. if (!lpwDomain)
  303. {
  304. dwRetCode = DhcpDSGetDomainAndRoot(
  305. &lpwLocalDomain,
  306. NULL,
  307. &fIsStandAlone);
  308. if (dwRetCode != NO_ERROR)
  309. {
  310. DBGPRINT("DhcpDSMap..CNPath: GetLocalDom.. failed (0x%x)\n",dwRetCode);
  311. return(dwRetCode);
  312. }
  313. //
  314. // are we a standalone server? if so, return error since there is no
  315. // local domain (and the caller didn't specify a domain)
  316. //
  317. if (fIsStandAlone)
  318. {
  319. DBGPRINT("DhcpDSMap..CNPath: standalone has no domain!\n");
  320. return(DHCPDSERR_SERVER_IS_STANDALONE);
  321. }
  322. lpwDomainToContact = lpwLocalDomain;
  323. }
  324. //
  325. // first, find a DC for this domain
  326. //
  327. dwRetCode = DsGetDcName(
  328. NULL, // server name
  329. lpwDomainToContact, // domain name
  330. NULL, // domain guid
  331. NULL, // site name
  332. DS_IS_DNS_NAME, // what flag(s) to use?
  333. &pDCInfo);
  334. // if we first obtained local domain, free it here
  335. if (lpwLocalDomain != NULL)
  336. {
  337. LocalFree((PCHAR)lpwLocalDomain);
  338. }
  339. if (dwRetCode != NO_ERROR)
  340. {
  341. DBGPRINT("MapDomainToCNPath: DsGetDcName failed %ld\n",dwRetCode);
  342. return(dwRetCode);
  343. }
  344. lpwDCName = pDCInfo->DomainControllerName;
  345. // skip the two leading '\'
  346. lpwDCName += 2;
  347. // also, skip the trailing '.'
  348. lpwDCName[wcslen(lpwDCName)-1] = 0;
  349. dwCanonNameLen = sizeof(DHCPDS_ROOTDSE_PRE) +
  350. (wcslen(lpwDCName)+1)*sizeof(WCHAR) +
  351. sizeof(DHCPDS_ROOTDSE_POST) +
  352. sizeof(WCHAR);
  353. pCanonName = (LPWSTR)LocalAlloc(LPTR, dwCanonNameLen);
  354. if (pCanonName == NULL)
  355. {
  356. DBGPRINT("DhcpDSMapDomainToCNPath: malloc 1 failed (%ld)\n",dwCanonNameLen);
  357. NetApiBufferFree(pDCInfo);
  358. return(ERROR_NOT_ENOUGH_MEMORY);
  359. }
  360. // copy the LDAP:// string
  361. wcscpy(pCanonName, DHCPDS_ROOTDSE_PRE);
  362. // append the server name
  363. wcscat(pCanonName, lpwDCName);
  364. // then append the RootDSE part
  365. wcscat(pCanonName, DHCPDS_ROOTDSE_POST);
  366. // don't need this nomore: free it now
  367. NetApiBufferFree(pDCInfo);
  368. // now, open the RootDSE "object"
  369. hr = ADSIOpenDSObject(
  370. pCanonName,
  371. lpwUserName,
  372. lpwPassword,
  373. dwAuthFlags,
  374. &handle
  375. );
  376. // free this first: don't need this nomore
  377. LocalFree((PCHAR)pCanonName);
  378. if (FAILED(hr))
  379. {
  380. DBGPRINT("ADSIOpenDSObject (RootDSE) failed with 0x%x\n",hr);
  381. return(DHCPDSERR_DS_OPERATION_FAILED);
  382. }
  383. // now, get all the attributes on this object
  384. hr = ADSIGetObjectAttributes(
  385. handle,
  386. &lpwGlbNamingContextString,
  387. 1,
  388. &pAttributeEntries,
  389. &dwNumAttributesReturned);
  390. if (FAILED(hr))
  391. {
  392. DBGPRINT("ADSIGetObjectAttributes (RootDSE) failed with 0x%x\n",hr);
  393. dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
  394. goto DhcpDSMapDomainToCNPath_Exit;
  395. }
  396. fCNStringFound = FALSE;
  397. //
  398. // now, of all the values returned, find the one that we are
  399. // interested in (the one starts with CN=Configuration,)
  400. //
  401. for (index=0; index<pAttributeEntries->dwNumValues; index++)
  402. {
  403. if (pAttributeEntries->pADsValues[index].dwType != ADSTYPE_CASE_IGNORE_STRING)
  404. {
  405. continue;
  406. }
  407. if (wcsncmp(pAttributeEntries->pADsValues[index].CaseIgnoreString,
  408. DHCPDS_CN_STRING,
  409. wcslen(DHCPDS_CN_STRING)) == 0)
  410. {
  411. fCNStringFound = TRUE;
  412. break;
  413. }
  414. }
  415. if (!fCNStringFound)
  416. {
  417. DBGPRINT("MapDomainToCNPath: %d values returned, but not ours\n",
  418. pAttributeEntries->dwNumValues);
  419. dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
  420. goto DhcpDSMapDomainToCNPath_Exit;
  421. }
  422. dwCanonNameLen = (wcslen(pAttributeEntries->pADsValues[index].CaseIgnoreString) +
  423. 1) * sizeof(WCHAR);
  424. (*ppwCNPath) = (LPWSTR)LocalAlloc(LPTR, dwCanonNameLen);
  425. if ((*ppwCNPath) == NULL)
  426. {
  427. DBGPRINT("MapDomainToCNPath: malloc 2 failed (%ld)\n",dwCanonNameLen);
  428. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  429. goto DhcpDSMapDomainToCNPath_Exit;
  430. }
  431. // now, copy the-path-to-Configuration string
  432. wcscpy((*ppwCNPath),pAttributeEntries->pADsValues[index].CaseIgnoreString);
  433. dwRetCode = 0;
  434. DhcpDSMapDomainToCNPath_Exit:
  435. // free pAttributeEntries
  436. if (pAttributeEntries)
  437. {
  438. FreeADsMem(pAttributeEntries);
  439. }
  440. ADSICloseDSObject( handle );
  441. return(dwRetCode);
  442. }
  443. DWORD
  444. ValidateService(
  445. LPWSTR lpwDomain,
  446. LPWSTR lpwUserName,
  447. LPWSTR lpwPassword,
  448. DWORD dwAuthFlags,
  449. LPWSTR lpwObjectPath,
  450. LPWSTR lpwSrchFilter,
  451. LPWSTR *ppwAttrName,
  452. LPWSTR lpwAttrVal
  453. )
  454. /*++
  455. Routine Description:
  456. This function determines if the given attribute (ipaddress in case of
  457. DHCP) is present in the list of authorized entities (DHCP Servers) on the DS
  458. enterprise.
  459. Arguments:
  460. lpwDomain - domain name in which to validate the service. Can be NULL to
  461. indicate the server's domain
  462. lpwUserName - account name to use during DS lookup. Usually, NULL (default)
  463. lpwPassword - password for the above user
  464. dwAuthFlags - flags to use
  465. lpwObjectPath - path to where the "entities" are stored
  466. lpwSrchFilter - the filter to use to get our "entities" (e.g.(objectClass==DHCPClass)
  467. ppwAttrName - name of the attribute we're looking for (e.g. IpAddress)
  468. lpwAttrVal - value of the attribute (e.g. the server's ipaddress to validate)
  469. Return Value:
  470. Result of the operation
  471. --*/
  472. {
  473. HRESULT hr=S_OK;
  474. HANDLE handle = NULL;
  475. ADS_SEARCH_HANDLE hSearchHandle=NULL;
  476. ADS_SEARCH_COLUMN Column;
  477. DWORD dwRetCode;
  478. DWORD i;
  479. LPWSTR lpwCNPath=NULL;
  480. LPWSTR lpwFullDSPath=NULL;
  481. DWORD dwLen;
  482. BOOLEAN fObjectFound=FALSE;
  483. dwRetCode = DHCPDSERR_ENTRY_NOT_FOUND;
  484. //
  485. // first, we need to get the full ads path to our container within the
  486. // configuration container, from the domain name
  487. //
  488. dwRetCode = DhcpDSMapDomainToCNPath(
  489. lpwDomain,
  490. lpwUserName,
  491. lpwPassword,
  492. dwAuthFlags,
  493. &lpwCNPath);
  494. if (dwRetCode != 0)
  495. {
  496. DBGPRINT("ValidateService: MapDomainToCNPath failed with 0x%x\n",dwRetCode);
  497. goto ValidateService_Exit;
  498. }
  499. dwLen = (wcslen(lpwObjectPath)+1)*sizeof(WCHAR) +
  500. (wcslen(lpwCNPath)+1)*sizeof(WCHAR);
  501. lpwFullDSPath = (LPWSTR)LocalAlloc(LPTR, dwLen);
  502. if (lpwFullDSPath == NULL)
  503. {
  504. DBGPRINT("ValidateService: malloc failed (%ld)\n",dwLen);
  505. dwRetCode = ERROR_NOT_ENOUGH_MEMORY;
  506. goto ValidateService_Exit;
  507. }
  508. // copy the lpwObjectPath (e.g. LDAP://CN=DHCP) string
  509. wcscpy(lpwFullDSPath, lpwObjectPath);
  510. // now, concatenate the path to the configuration container
  511. wcscat(lpwFullDSPath, lpwCNPath);
  512. hr = ADSIOpenDSObject(
  513. lpwFullDSPath,
  514. lpwUserName,
  515. lpwPassword,
  516. dwAuthFlags,
  517. &handle
  518. );
  519. if (FAILED(hr))
  520. {
  521. DBGPRINT("ValidateService: ADSIOpenDSObject failed with 0x%x\n",hr);
  522. dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
  523. goto ValidateService_Exit;
  524. }
  525. hr = ADSIExecuteSearch(
  526. handle,
  527. lpwSrchFilter,
  528. ppwAttrName,
  529. -1, // ok to always pass this?
  530. &hSearchHandle
  531. );
  532. if (FAILED(hr))
  533. {
  534. DBGPRINT("ADSIExecuteSearch failed with 0x%x\n",hr);
  535. dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
  536. goto ValidateService_Exit;
  537. }
  538. hr = ADSIGetNextRow(
  539. handle,
  540. hSearchHandle
  541. );
  542. if (FAILED(hr))
  543. {
  544. DBGPRINT("ADSIGetNextRow failed with 0x%x\n",hr);
  545. dwRetCode = DHCPDSERR_DS_OPERATION_FAILED;
  546. goto ValidateService_Exit;
  547. }
  548. while (hr != S_ADS_NOMORE_ROWS && !fObjectFound)
  549. {
  550. //
  551. // get the values for the attribute requested (e.g. ipaddress)
  552. //
  553. hr = ADSIGetColumn(
  554. handle,
  555. hSearchHandle,
  556. ppwAttrName[0], // for now, only first one is needed
  557. &Column
  558. );
  559. if (SUCCEEDED(hr))
  560. {
  561. //
  562. // if the attribute is multivalued, compare all the values to see
  563. // if we find the one we want
  564. //
  565. for (i=0; i < Column.dwNumValues; i++)
  566. {
  567. if (_wcsnicmp(
  568. Column.pADsValues[i].CaseIgnoreString,
  569. lpwAttrVal,
  570. wcslen(lpwAttrVal)) == 0)
  571. {
  572. fObjectFound = TRUE;
  573. break;
  574. }
  575. }
  576. // free the column
  577. ADSIFreeColumn(
  578. handle,
  579. &Column);
  580. }
  581. //
  582. // it's strange if this attribute is not defined for this object since
  583. // it's one of our objects. But, nevertheless, just skip it
  584. //
  585. else
  586. {
  587. DBGPRINT("ADSIGetColumn failed with hr = 0x%x\n",hr);
  588. }
  589. // move to the next object
  590. hr = ADSIGetNextRow(
  591. handle,
  592. hSearchHandle
  593. );
  594. }
  595. dwRetCode = (fObjectFound)? DHCPDSERR_ENTRY_FOUND : DHCPDSERR_ENTRY_NOT_FOUND;
  596. ValidateService_Exit:
  597. if (hSearchHandle)
  598. {
  599. ADSICloseSearchHandle(
  600. handle,
  601. hSearchHandle);
  602. }
  603. if (handle)
  604. {
  605. ADSICloseDSObject( handle );
  606. }
  607. if (lpwCNPath)
  608. {
  609. LocalFree((PCHAR)lpwCNPath);
  610. }
  611. if (lpwFullDSPath)
  612. {
  613. LocalFree((PCHAR)lpwFullDSPath);
  614. }
  615. return(dwRetCode) ;
  616. }
  617. DWORD
  618. DhcpDSSameEnterprise(
  619. LPWSTR lpwDomainName,
  620. LPWSTR lpwRootName,
  621. BOOLEAN *fIsSameEnterprise
  622. )
  623. /*++
  624. Routine Description:
  625. This function checks if the given domain is part of the given DS Tree (in other
  626. words, we want to find out if this domain belongs to another enterprise)
  627. Arguments:
  628. lpwDomainName - name of the domain in question
  629. lpwRootName - root of the DS Tree to test against
  630. fIsSameEnterprise - on return, TRUE or FALSE
  631. Return Value:
  632. result of the operation
  633. --*/
  634. {
  635. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  636. DWORD dwRetCode;
  637. //
  638. // until we can definitely verify that the root of the given domain is
  639. // the same as the one that is supplied, we return FALSE.
  640. //
  641. (*fIsSameEnterprise) = FALSE;
  642. if (!lpwRootName)
  643. {
  644. DBGPRINT("DhcpDSSameEnterprise: C'mon, don't pass me a NULL!\n");
  645. return(0);
  646. }
  647. dwRetCode = DsGetDcName(
  648. NULL, // server name
  649. lpwDomainName, // domain name
  650. NULL, // domain guid
  651. NULL, // site name
  652. DS_IS_DNS_NAME, // what flag(s) to use?
  653. &pDCInfo);
  654. if (dwRetCode != NO_ERROR)
  655. {
  656. DBGPRINT("DhcpDSSameEnterprise: DsGetDcName failed (%ld)\n",dwRetCode);
  657. return(dwRetCode);
  658. }
  659. // moment of truth: are the two roots the same?
  660. (*fIsSameEnterprise) = (DnsCompareName(lpwRootName, pDCInfo->DnsForestName) != 0);
  661. NetApiBufferFree(pDCInfo);
  662. return(0);
  663. }