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.

1098 lines
29 KiB

  1. /*++
  2. Copyright (c) 1991-1996 Microsoft Corporation
  3. Module Name:
  4. dfsstub.c
  5. Abstract:
  6. These are the server service API RPC client stubs for DFS operations
  7. Environment:
  8. User Mode - Win32
  9. --*/
  10. //
  11. // INCLUDES
  12. //
  13. #include <nt.h> // DbgPrint prototype
  14. #include <ntrtl.h> // DbgPrint
  15. #include <rpc.h> // DataTypes and runtime APIs
  16. #include <srvsvc.h> // generated by the MIDL complier
  17. #include <lmcons.h> // NET_API_STATUS
  18. #include <debuglib.h> // (needed by netrpc.h)
  19. #include <lmsvc.h> // (needed by netrpc.h)
  20. #include <netdebug.h> // (needed by netrpc.h)
  21. #include <lmerr.h> // NetError codes
  22. #include <netrpc.h> // NET_REMOTE_ macros.
  23. #include <nturtl.h>
  24. #include <winbase.h>
  25. #include <dfspriv.h>
  26. #include <Winsock2.h>
  27. #include <Dsgetdc.h>
  28. #include <malloc.h>
  29. #include <stdio.h>
  30. #include <Lm.h>
  31. NET_API_STATUS NET_API_FUNCTION
  32. I_NetDfsGetVersion(
  33. IN LPWSTR servername,
  34. OUT LPDWORD Version)
  35. {
  36. NET_API_STATUS apiStatus;
  37. NET_REMOTE_TRY_RPC
  38. apiStatus = NetrDfsGetVersion( servername, Version );
  39. NET_REMOTE_RPC_FAILED(
  40. "I_NetDfsGetVersion",
  41. servername,
  42. apiStatus,
  43. NET_REMOTE_FLAG_NORMAL,
  44. SERVICE_SERVER)
  45. apiStatus = ERROR_NOT_SUPPORTED;
  46. NET_REMOTE_END
  47. return(apiStatus);
  48. }
  49. NET_API_STATUS NET_API_FUNCTION
  50. I_NetDfsCreateLocalPartition (
  51. IN LPWSTR servername,
  52. IN LPWSTR ShareName,
  53. IN LPGUID EntryUid,
  54. IN LPWSTR EntryPrefix,
  55. IN LPWSTR ShortName,
  56. IN LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo,
  57. IN BOOL Force
  58. )
  59. {
  60. NET_API_STATUS apiStatus;
  61. NET_REMOTE_TRY_RPC
  62. apiStatus = NetrDfsCreateLocalPartition (
  63. servername,
  64. ShareName,
  65. EntryUid,
  66. EntryPrefix,
  67. ShortName,
  68. RelationInfo,
  69. Force
  70. );
  71. NET_REMOTE_RPC_FAILED(
  72. "NetDfsCreateLocalPartition",
  73. servername,
  74. apiStatus,
  75. NET_REMOTE_FLAG_NORMAL,
  76. SERVICE_SERVER)
  77. apiStatus = ERROR_NOT_SUPPORTED;
  78. NET_REMOTE_END
  79. return(apiStatus);
  80. }
  81. NET_API_STATUS NET_API_FUNCTION
  82. I_NetDfsDeleteLocalPartition (
  83. IN LPWSTR servername OPTIONAL,
  84. IN LPGUID Uid,
  85. IN LPWSTR Prefix
  86. )
  87. {
  88. NET_API_STATUS apiStatus;
  89. NET_REMOTE_TRY_RPC
  90. apiStatus = NetrDfsDeleteLocalPartition (
  91. servername,
  92. Uid,
  93. Prefix
  94. );
  95. NET_REMOTE_RPC_FAILED(
  96. "NetDfsDeleteLocalPartition",
  97. servername,
  98. apiStatus,
  99. NET_REMOTE_FLAG_NORMAL,
  100. SERVICE_SERVER)
  101. apiStatus = ERROR_NOT_SUPPORTED;
  102. NET_REMOTE_END;
  103. return apiStatus;
  104. }
  105. NET_API_STATUS NET_API_FUNCTION
  106. I_NetDfsSetLocalVolumeState (
  107. IN LPWSTR servername OPTIONAL,
  108. IN LPGUID Uid,
  109. IN LPWSTR Prefix,
  110. IN ULONG State
  111. )
  112. {
  113. NET_API_STATUS apiStatus;
  114. NET_REMOTE_TRY_RPC
  115. apiStatus = NetrDfsSetLocalVolumeState (
  116. servername,
  117. Uid,
  118. Prefix,
  119. State
  120. );
  121. NET_REMOTE_RPC_FAILED(
  122. "NetDfsSetLocalVolumeState",
  123. servername,
  124. apiStatus,
  125. NET_REMOTE_FLAG_NORMAL,
  126. SERVICE_SERVER)
  127. apiStatus = ERROR_NOT_SUPPORTED;
  128. NET_REMOTE_END;
  129. return apiStatus;
  130. }
  131. NET_API_STATUS NET_API_FUNCTION
  132. I_NetDfsSetServerInfo (
  133. IN LPWSTR servername OPTIONAL,
  134. IN LPGUID Uid,
  135. IN LPWSTR Prefix
  136. )
  137. {
  138. NET_API_STATUS apiStatus;
  139. NET_REMOTE_TRY_RPC
  140. apiStatus = NetrDfsSetServerInfo (
  141. servername,
  142. Uid,
  143. Prefix
  144. );
  145. NET_REMOTE_RPC_FAILED(
  146. "NetDfsSetServerInfo",
  147. servername,
  148. apiStatus,
  149. NET_REMOTE_FLAG_NORMAL,
  150. SERVICE_SERVER)
  151. apiStatus = ERROR_NOT_SUPPORTED;
  152. NET_REMOTE_END;
  153. return apiStatus;
  154. }
  155. NET_API_STATUS NET_API_FUNCTION
  156. I_NetDfsCreateExitPoint (
  157. IN LPWSTR servername OPTIONAL,
  158. IN LPGUID Uid,
  159. IN LPWSTR Prefix,
  160. IN ULONG Type,
  161. IN ULONG ShortPrefixSize,
  162. OUT LPWSTR ShortPrefix
  163. )
  164. {
  165. NET_API_STATUS apiStatus;
  166. NET_REMOTE_TRY_RPC
  167. apiStatus = NetrDfsCreateExitPoint (
  168. servername,
  169. Uid,
  170. Prefix,
  171. Type,
  172. ShortPrefixSize,
  173. ShortPrefix
  174. );
  175. NET_REMOTE_RPC_FAILED(
  176. "NetDfsCreateExitPoint",
  177. servername,
  178. apiStatus,
  179. NET_REMOTE_FLAG_NORMAL,
  180. SERVICE_SERVER)
  181. apiStatus = ERROR_NOT_SUPPORTED;
  182. NET_REMOTE_END;
  183. return apiStatus;
  184. }
  185. NET_API_STATUS NET_API_FUNCTION
  186. I_NetDfsDeleteExitPoint (
  187. IN LPWSTR servername OPTIONAL,
  188. IN LPGUID Uid,
  189. IN LPWSTR Prefix,
  190. IN ULONG Type
  191. )
  192. {
  193. NET_API_STATUS apiStatus;
  194. NET_REMOTE_TRY_RPC
  195. apiStatus = NetrDfsDeleteExitPoint (
  196. servername,
  197. Uid,
  198. Prefix,
  199. Type
  200. );
  201. NET_REMOTE_RPC_FAILED(
  202. "NetDfsDeleteExitPoint",
  203. servername,
  204. apiStatus,
  205. NET_REMOTE_FLAG_NORMAL,
  206. SERVICE_SERVER)
  207. apiStatus = ERROR_NOT_SUPPORTED;
  208. NET_REMOTE_END;
  209. return apiStatus;
  210. }
  211. NET_API_STATUS NET_API_FUNCTION
  212. I_NetDfsModifyPrefix (
  213. IN LPWSTR servername OPTIONAL,
  214. IN LPGUID Uid,
  215. IN LPWSTR Prefix
  216. )
  217. {
  218. NET_API_STATUS apiStatus;
  219. NET_REMOTE_TRY_RPC
  220. apiStatus = NetrDfsModifyPrefix (
  221. servername,
  222. Uid,
  223. Prefix
  224. );
  225. NET_REMOTE_RPC_FAILED(
  226. "NetDfsModifyPrefix",
  227. servername,
  228. apiStatus,
  229. NET_REMOTE_FLAG_NORMAL,
  230. SERVICE_SERVER)
  231. apiStatus = ERROR_NOT_SUPPORTED;
  232. NET_REMOTE_END;
  233. return apiStatus;
  234. }
  235. NET_API_STATUS NET_API_FUNCTION
  236. I_NetDfsFixLocalVolume (
  237. IN LPWSTR servername OPTIONAL,
  238. IN LPWSTR VolumeName,
  239. IN ULONG EntryType,
  240. IN ULONG ServiceType,
  241. IN LPWSTR StgId,
  242. IN LPGUID EntryUid, // unique id for this partition
  243. IN LPWSTR EntryPrefix, // path prefix for this partition
  244. IN LPNET_DFS_ENTRY_ID_CONTAINER RelationInfo,
  245. IN ULONG CreateDisposition
  246. )
  247. {
  248. NET_API_STATUS apiStatus;
  249. NET_REMOTE_TRY_RPC
  250. apiStatus = NetrDfsFixLocalVolume (
  251. servername,
  252. VolumeName,
  253. EntryType,
  254. ServiceType,
  255. StgId,
  256. EntryUid,
  257. EntryPrefix,
  258. RelationInfo,
  259. CreateDisposition
  260. );
  261. NET_REMOTE_RPC_FAILED(
  262. "NetDfsFixLocalVolume",
  263. servername,
  264. apiStatus,
  265. NET_REMOTE_FLAG_NORMAL,
  266. SERVICE_SERVER)
  267. apiStatus = ERROR_NOT_SUPPORTED;
  268. NET_REMOTE_END;
  269. return apiStatus;
  270. }
  271. NET_API_STATUS NET_API_FUNCTION
  272. I_NetDfsManagerReportSiteInfo (
  273. IN LPWSTR ServerName,
  274. OUT LPDFS_SITELIST_INFO *ppSiteInfo
  275. )
  276. {
  277. struct sockaddr_in Destination;
  278. struct hostent * pHostEnt;
  279. SOCKET_ADDRESS SocketAddress;
  280. NET_API_STATUS apiStatus;
  281. LPWSTR *SiteName = NULL;
  282. char* ServerNameA = NULL;
  283. NET_REMOTE_TRY_RPC
  284. apiStatus = NetrDfsManagerReportSiteInfo (
  285. ServerName,
  286. ppSiteInfo
  287. );
  288. NET_REMOTE_RPC_FAILED(
  289. "NetDfsMangerReportSiteInfo",
  290. ServerName,
  291. apiStatus,
  292. NET_REMOTE_FLAG_NORMAL,
  293. SERVICE_SERVER)
  294. NET_REMOTE_END;
  295. if(apiStatus != ERROR_SUCCESS) {
  296. WORD wVersionRequested;
  297. WSADATA wsaData;
  298. DWORD dwErr = ERROR_SUCCESS;
  299. int err;
  300. PDOMAIN_CONTROLLER_INFO pDCInfo;
  301. wVersionRequested = MAKEWORD( 2, 2 );
  302. err = WSAStartup( wVersionRequested, &wsaData );
  303. if ( err != 0 ) {
  304. /* We could not find a usable */
  305. /* WinSock DLL. */
  306. return apiStatus;
  307. }
  308. // we couldn't get the site name
  309. ServerNameA = malloc(wcslen(ServerName) + 1);
  310. if(ServerNameA == NULL) {
  311. apiStatus = ERROR_NOT_ENOUGH_MEMORY;
  312. } else {
  313. // need to convert from WCHAR* to char*
  314. sprintf(ServerNameA, "%ws", ServerName);
  315. if ((pHostEnt = gethostbyname(ServerNameA)) != NULL) {
  316. memcpy(&(Destination.sin_addr), pHostEnt->h_addr, pHostEnt->h_length);
  317. Destination.sin_family = pHostEnt->h_addrtype;
  318. if(pHostEnt->h_addrtype != AF_INET) {
  319. apiStatus = ERROR_NOT_SUPPORTED;
  320. } else {
  321. SocketAddress.lpSockaddr = (struct sockaddr *)&Destination;
  322. SocketAddress.iSockaddrLength = sizeof(Destination);
  323. Destination.sin_port = 0;
  324. dwErr = DsGetDcName(
  325. NULL, // Computer to remote to
  326. NULL, // Domain - use local domain
  327. NULL, // Domain Guid
  328. NULL, // Site Guid
  329. 0, // Flags
  330. &pDCInfo);
  331. if(dwErr == ERROR_SUCCESS) {
  332. apiStatus = DsAddressToSiteNames(pDCInfo->DomainControllerAddress,
  333. 1,
  334. &SocketAddress,
  335. &SiteName
  336. );
  337. NetApiBufferFree( pDCInfo );
  338. } else {
  339. apiStatus = ERROR_NOT_SUPPORTED;
  340. }
  341. if(apiStatus == NO_ERROR) {
  342. if((SiteName == NULL) || (*SiteName == NULL)) {
  343. // If DsAddressToSiteNames can't map to a site name,
  344. // it returns success but sets the buffer to NULL.
  345. apiStatus = ERROR_NO_SITENAME;
  346. } else {
  347. // we got the site name
  348. apiStatus = NetApiBufferAllocate(
  349. sizeof(DFS_SITELIST_INFO) + ((wcslen(*SiteName) + 1) * sizeof(WCHAR)),
  350. ppSiteInfo
  351. );
  352. if(apiStatus == ERROR_SUCCESS) {
  353. (*ppSiteInfo)->cSites = 1;
  354. (*ppSiteInfo)->Site[0].SiteName = (LPWSTR)((ULONG_PTR)(*ppSiteInfo) + sizeof(DFS_SITELIST_INFO));
  355. wcscpy((*ppSiteInfo)->Site[0].SiteName, *SiteName);
  356. }
  357. }
  358. }
  359. }
  360. } else {
  361. apiStatus = WSAGetLastError();
  362. apiStatus = ERROR_NOT_SUPPORTED;
  363. }
  364. free(ServerNameA);
  365. }
  366. WSACleanup();
  367. }
  368. return apiStatus;
  369. }
  370. #include <dsgetdc.h>
  371. #include <winldap.h>
  372. #include <lmapibuf.h>
  373. //
  374. // This is the container which holds the DFS configuration data
  375. //
  376. static const WCHAR DfsConfigContainer[] = L"CN=Dfs-Configuration,CN=System";
  377. typedef struct
  378. {
  379. int cPieces;
  380. PCHAR rpPieces[1];
  381. } DNS_NAME, *PDNS_NAME;
  382. static
  383. DWORD
  384. BreakDnsName(
  385. IN CHAR *pName,
  386. OUT PDNS_NAME *ppDnsName
  387. )
  388. /*++
  389. Routine Description:
  390. Breaks a DNS name in dotted string format (eg: dbsd.microsoft.com) into
  391. its constituent parts.
  392. Arguments:
  393. pName - pointer to string representing dotted DNS name to break.
  394. ppDnsName - pointer to pointer to DNS_NAME struct which should be
  395. deallocated by NetApiBufferFree().
  396. --*/
  397. {
  398. int cPieces;
  399. CHAR *p;
  400. DWORD cBytes;
  401. CHAR *buffer;
  402. int i;
  403. LPSTR seps = ".";
  404. if ( (NULL == pName) || ('\0' == *pName) || ('.' == *pName) )
  405. {
  406. return(ERROR_INVALID_PARAMETER);
  407. }
  408. // Count number of pieces so we can figure out how much to allocate.
  409. cPieces = 1;
  410. p = pName;
  411. for ( p = pName; '\0' != *p; p++ )
  412. {
  413. if ( '.' == *p )
  414. {
  415. cPieces++;
  416. }
  417. }
  418. // Calculate bytes to allocate. Allocate memory which will hold (in order)
  419. // the DNS_NAME struct, the DNS_NAME.rpPieces pointer array, and finally
  420. // a scratch buffer where we can strtok the input name.
  421. cBytes = sizeof(DNS_NAME);
  422. cBytes += cPieces * sizeof(PCHAR);
  423. cBytes += strlen(pName) + 1;
  424. NetApiBufferAllocate( cBytes, (PVOID *)ppDnsName );
  425. if ( *ppDnsName == NULL )
  426. {
  427. return(ERROR_NOT_ENOUGH_MEMORY);
  428. }
  429. // Fill in the buffer and call strtok as often as required to chop it
  430. // into pieces filling the DNS_NAME as we go.
  431. buffer = (CHAR *) &((*ppDnsName)->rpPieces[cPieces]);
  432. strcpy(buffer, pName);
  433. (*ppDnsName)->cPieces = cPieces;
  434. (*ppDnsName)->rpPieces[0] = strtok(buffer, seps);
  435. for ( i = 1; i < cPieces; i++ )
  436. {
  437. (*ppDnsName)->rpPieces[i] = strtok(NULL, seps);
  438. }
  439. return(NO_ERROR);
  440. }
  441. static
  442. DWORD
  443. FindContext(
  444. IN CHAR *pName,
  445. IN int cDnValues,
  446. IN CHAR **rpDnValues,
  447. OUT int *pMatchingValueIndex
  448. )
  449. /*++
  450. Routine Description:
  451. Determines the best match of a DNS name (eg: dbsd.microsoft.com)
  452. to a set of RFC 1779 DNs (eg: ou=dbsd, ou=microsoft, c=us). We assume
  453. that the array of DNs represent NT5 DS naming contexts (i.e. domains)
  454. which is true with the exception of the Configuration naming context.
  455. For example, let's say a DC hosted three naming contexts:
  456. 1 - ou=dbsd, ou=microsoft, c=us
  457. 2 - ou=nt, ou=dbsd, ou=microsoft, c=us
  458. 3 - ou=configuration, ou=microsoft, c=us
  459. Then dbsd.microsoft.com would match the 1st DN in the list. This is not
  460. foolproof in the case of a deviant namespace which has a domain structure
  461. like:
  462. ou=dbsd, ou=microsoft, ou=com, ou=dbsd, ou=microsoft, c=us
  463. But anyone with a namespace like that is going to have other problems
  464. anyway.
  465. Arguments:
  466. pName - pointer to DNS name to match.
  467. cDnValues - count of values in rpDnValues.
  468. rpDnValues - array of pointers to DNs to match against.
  469. pMatchingValueIndex - pointer to int which will identify the best
  470. matching DN in rpDnValues on successful return.
  471. Return Value:
  472. NO_ERROR - success
  473. ERROR_NOT_ENOUGH_MEMORY - allocation error
  474. ERROR_INVALID_PARAMETER - invalid parameter
  475. ERROR_INVALID_DOMAINNAME - bad DNS or DN domain name
  476. --*/
  477. {
  478. DWORD dwErr;
  479. int i, j;
  480. CHAR **rpDn = NULL;
  481. int currentMatchLength;
  482. int bestMatchLength;
  483. int bestMatchIndex;
  484. PDNS_NAME pDomainDnsName = NULL;
  485. dwErr = BreakDnsName(pName, &pDomainDnsName);
  486. if ( NO_ERROR != dwErr )
  487. {
  488. return(dwErr);
  489. }
  490. // Iterate over the DN values and see which one has the longest match.
  491. bestMatchIndex = 0;
  492. bestMatchLength = -1;
  493. for ( i = 0; i < cDnValues; i++ )
  494. {
  495. rpDn = ldap_explode_dn(rpDnValues[i], 1); // 1 ==> notypes
  496. if ( NULL == rpDn )
  497. {
  498. dwErr = ERROR_INVALID_DOMAINNAME;
  499. goto Cleanup;
  500. }
  501. currentMatchLength = 0;
  502. // Try to match each piece of the domain name to each piece of the
  503. // DN. Fortunately, RFC 1779 DNs are ordered least to most significant
  504. // just as DNS domain names are. rpDn[] is "terminated" with a NULL.
  505. for ( j = 0; (j < pDomainDnsName->cPieces) && (NULL != rpDn[j]); j++ )
  506. {
  507. if ( 0 == _stricmp(pDomainDnsName->rpPieces[j], rpDn[j]) )
  508. {
  509. currentMatchLength++;
  510. }
  511. }
  512. if ( (0 != currentMatchLength) &&
  513. (currentMatchLength > bestMatchLength) )
  514. {
  515. bestMatchLength = currentMatchLength;
  516. bestMatchIndex = i;
  517. }
  518. ldap_value_free(rpDn);
  519. }
  520. *pMatchingValueIndex = bestMatchIndex;
  521. dwErr = NO_ERROR;
  522. Cleanup:
  523. if ( pDomainDnsName != NULL ) {
  524. NetApiBufferFree( pDomainDnsName );
  525. }
  526. return(dwErr);
  527. }
  528. /*
  529. * This API returns a vector of \\server\share combinations which form the
  530. * root of a Fault Tolerant DFS. This null-terminated vector should be
  531. * freed by the caller with NetApiBufferFree().
  532. *
  533. * If pLDAP is supplied, we asssume that this is the handle to the DS server
  534. * holding the configuration data. Else, we use wszDomainName to locate the
  535. * proper DS server.
  536. *
  537. * wszDfsName is the name of the fault tolerant DFS for which individual servers
  538. * are to be discovered.
  539. *
  540. */
  541. NET_API_STATUS NET_API_FUNCTION
  542. I_NetDfsGetFtServers(
  543. IN PVOID LdapInputArg OPTIONAL,
  544. IN LPWSTR wszDomainName OPTIONAL,
  545. IN LPWSTR wszDfsName OPTIONAL,
  546. OUT LPWSTR **List
  547. )
  548. {
  549. PLDAP pLDAP = (PLDAP)LdapInputArg;
  550. BOOLEAN bUnbindNeeded = FALSE;
  551. DWORD dwErr;
  552. NTSTATUS status;
  553. PWCHAR attrs[2];
  554. LDAPMessage *pMsg = NULL;
  555. LDAPMessage *pEntry = NULL;
  556. WCHAR *pAttr = NULL;
  557. WCHAR **rpValues = NULL;
  558. WCHAR **allValues = NULL;
  559. WCHAR ***rpValuesToFree = NULL;
  560. INT cValues = 0;
  561. INT i;
  562. WCHAR *dfsDn = NULL;
  563. DWORD len;
  564. USHORT cChar;
  565. PWCHAR *resultVector;
  566. ULONG cBytes;
  567. if (List == NULL) {
  568. return ERROR_INVALID_PARAMETER;
  569. }
  570. *List = NULL;
  571. if (!ARGUMENT_PRESENT(pLDAP)) {
  572. DOMAIN_CONTROLLER_INFO *pInfo = NULL;
  573. ULONG dsAdditionalFlags = 0;
  574. ULONG retry;
  575. for (retry = 0; pLDAP == NULL && retry < 2; retry++) {
  576. //
  577. // Find a DC for the given domain.
  578. //
  579. dwErr = DsGetDcName(
  580. NULL, // computer name
  581. wszDomainName, // DNS domain name
  582. NULL, // domain guid
  583. NULL, // site guid
  584. DS_DIRECTORY_SERVICE_REQUIRED |
  585. DS_IP_REQUIRED |
  586. dsAdditionalFlags,
  587. &pInfo);
  588. if (dwErr != NO_ERROR) {
  589. return dwErr;
  590. }
  591. //
  592. // DomainControllerAddress is prefixed with "\\" so
  593. // aditionally ensure there's some useful data there.
  594. //
  595. if (DS_INET_ADDRESS != pInfo->DomainControllerAddressType ||
  596. (cChar = (USHORT)wcslen(pInfo->DomainControllerAddress)) < 3) {
  597. NetApiBufferFree(pInfo);
  598. return ERROR_NO_SUCH_DOMAIN;
  599. }
  600. //
  601. // Try to connect to the DS server on the DC
  602. //
  603. pLDAP = ldap_openW(&pInfo->DomainControllerAddress[2], 0);
  604. if (pLDAP == NULL) {
  605. //
  606. // Couldn't connect. Let's force rediscovery and see if we
  607. // can connect to a DC which is working!
  608. //
  609. NetApiBufferFree(pInfo);
  610. dsAdditionalFlags |= DS_FORCE_REDISCOVERY;
  611. } else {
  612. dwErr = ldap_bind_s(pLDAP, NULL, NULL, LDAP_AUTH_SSPI);
  613. }
  614. NetApiBufferFree(pInfo);
  615. }
  616. if (pLDAP == NULL || dwErr != LDAP_SUCCESS) {
  617. return ERROR_PATH_NOT_FOUND;
  618. }
  619. bUnbindNeeded = TRUE;
  620. }
  621. //
  622. // Read the namingContexts operational attribute.
  623. //
  624. pLDAP->ld_sizelimit = 0; // no search limit
  625. pLDAP->ld_timelimit = 0; // no time limit
  626. pLDAP->ld_deref = LDAP_DEREF_NEVER;
  627. attrs[0] = L"defaultnamingContext";
  628. attrs[1] = NULL;
  629. if ((dwErr = ldap_search_sW(
  630. pLDAP,
  631. L"", // search base
  632. LDAP_SCOPE_BASE,
  633. L"(objectClass=*)", // filter
  634. attrs,
  635. 0, // attrs and values
  636. &pMsg)) != LDAP_SUCCESS) {
  637. goto Cleanup;
  638. }
  639. //
  640. // Make sure we got back something reasonable
  641. //
  642. if (ldap_count_entries(pLDAP, pMsg) != 1 ||
  643. (pEntry = ldap_first_entry(pLDAP, pMsg)) == NULL ||
  644. (rpValues = ldap_get_valuesW(pLDAP, pEntry, attrs[0])) == NULL ||
  645. (cValues = ldap_count_valuesW(rpValues)) == 0
  646. ) {
  647. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  648. goto Cleanup;
  649. }
  650. if (ARGUMENT_PRESENT(wszDfsName)) {
  651. //
  652. // Looks good. Allocate enough memory to hold the DN of the
  653. // DFS configuration data for the fault tolerant DFS in question
  654. //
  655. len = (DWORD)(3 * sizeof(WCHAR) +
  656. (wcslen(wszDfsName) + 1) * sizeof(WCHAR) +
  657. (wcslen(DfsConfigContainer) + 1) * sizeof(WCHAR) +
  658. (wcslen(rpValues[0]) + 1) * sizeof(WCHAR));
  659. dwErr = NetApiBufferAllocate(len, (PVOID *)&dfsDn);
  660. if (dfsDn == NULL) {
  661. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  662. goto Cleanup;
  663. }
  664. //
  665. // Construct the DN
  666. //
  667. RtlZeroMemory(dfsDn, len);
  668. wcscpy(dfsDn, L"CN=");
  669. wcscat(dfsDn, wszDfsName);
  670. wcscat(dfsDn, L",");
  671. wcscat(dfsDn, DfsConfigContainer);
  672. wcscat(dfsDn, L",");
  673. wcscat(dfsDn, rpValues[0]);
  674. //
  675. // Now see if we can get at the 'remoteServerName' property of this object.
  676. // This property holds the names of the servers hosting this DFS
  677. //
  678. pLDAP->ld_sizelimit = 0;
  679. pLDAP->ld_timelimit= 0;
  680. pLDAP->ld_deref = LDAP_DEREF_NEVER;
  681. ldap_msgfree(pMsg);
  682. pMsg = NULL;
  683. ldap_value_freeW(rpValues);
  684. rpValues = NULL;
  685. attrs[0] = L"remoteServerName";
  686. attrs[1] = NULL;
  687. dwErr = ldap_search_sW(
  688. pLDAP,
  689. dfsDn,
  690. LDAP_SCOPE_BASE,
  691. L"(objectClass=*)",
  692. attrs,
  693. 0,
  694. &pMsg);
  695. //
  696. // Make sure the result is reasonable
  697. //
  698. if (ldap_count_entries(pLDAP, pMsg) == 0 ||
  699. (pEntry = ldap_first_entry(pLDAP, pMsg)) == NULL ||
  700. (rpValues = ldap_get_valuesW(pLDAP, pEntry, attrs[0])) == NULL ||
  701. rpValues[0][0] == L'\0'
  702. ) {
  703. dwErr = ERROR_PATH_NOT_FOUND;
  704. goto Cleanup;
  705. }
  706. //
  707. // The result is reasonable, just point allValues to rpValues
  708. //
  709. allValues = rpValues;
  710. } else {
  711. //
  712. // The caller is trying to retrieve the names of all the FT DFSs in the domain
  713. //
  714. // Allocate enough memory to hold the DN of the
  715. // DFS configuration container
  716. //
  717. len = (wcslen(DfsConfigContainer) + 1) * sizeof(WCHAR) +
  718. (wcslen(rpValues[0]) + 1) * sizeof(WCHAR);
  719. dwErr = NetApiBufferAllocate(len, (PVOID *)&dfsDn);
  720. if (dfsDn == NULL) {
  721. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  722. goto Cleanup;
  723. }
  724. //
  725. // Construct the DN
  726. //
  727. RtlZeroMemory(dfsDn, len);
  728. wcscpy(dfsDn, DfsConfigContainer);
  729. wcscat(dfsDn, L",");
  730. wcscat(dfsDn, rpValues[0]);
  731. //
  732. // Now see if we can enumerate the objects below this one. The names
  733. // of these objects will be the different FT dfs's available
  734. //
  735. pLDAP->ld_sizelimit = 0;
  736. pLDAP->ld_timelimit= 0;
  737. pLDAP->ld_deref = LDAP_DEREF_NEVER;
  738. ldap_msgfree(pMsg);
  739. pMsg = NULL;
  740. ldap_value_freeW(rpValues);
  741. rpValues = NULL;
  742. attrs[0] = L"CN";
  743. attrs[1] = NULL;
  744. dwErr = ldap_search_sW(
  745. pLDAP,
  746. dfsDn,
  747. LDAP_SCOPE_ONELEVEL,
  748. L"(objectClass=fTDfs)",
  749. attrs,
  750. 0,
  751. &pMsg);
  752. //
  753. // Make sure the result is reasonable
  754. //
  755. if (
  756. ((cValues = ldap_count_entries(pLDAP, pMsg)) == 0) ||
  757. (pEntry = ldap_first_entry(pLDAP, pMsg)) == NULL
  758. ) {
  759. dwErr = ERROR_PATH_NOT_FOUND;
  760. goto Cleanup;
  761. }
  762. //
  763. // The search for all FTDfs's returns multiple entries, each with
  764. // one value for the object's CN. Coalesce these into a single array.
  765. //
  766. dwErr = NetApiBufferAllocate(2 * (cValues + 1) * sizeof(PWSTR), (PVOID *)&allValues);
  767. if (dwErr != ERROR_SUCCESS) {
  768. goto Cleanup;
  769. }
  770. rpValuesToFree = (WCHAR ***) &allValues[cValues + 1];
  771. for (i = 0; (i < cValues) && (dwErr == ERROR_SUCCESS); i++) {
  772. rpValues = ldap_get_valuesW(pLDAP, pEntry, attrs[0]);
  773. rpValuesToFree[i] = rpValues;
  774. //
  775. // Sanity check
  776. //
  777. if (ldap_count_valuesW(rpValues) == 0 || rpValues[0][0] == L'\0') {
  778. dwErr = ERROR_PATH_NOT_FOUND;
  779. } else {
  780. allValues[i] = rpValues[0];
  781. pEntry = ldap_next_entry(pLDAP, pEntry);
  782. }
  783. }
  784. if (dwErr == ERROR_SUCCESS) {
  785. allValues[i] = NULL;
  786. rpValuesToFree[i] = NULL;
  787. } else {
  788. goto Cleanup;
  789. }
  790. }
  791. if (dwErr != LDAP_SUCCESS) {
  792. dwErr = ERROR_PATH_NOT_FOUND;
  793. goto Cleanup;
  794. }
  795. //
  796. // Now we need to allocate the memory to hold this vector and return the results.
  797. //
  798. // First see how much space we need
  799. //
  800. for (len = cValues = 0; allValues[cValues]; cValues++) {
  801. len += sizeof(LPWSTR) + (wcslen(allValues[cValues]) + 1) * sizeof(WCHAR);
  802. }
  803. len += sizeof(LPWSTR); // for the final NULL pointer
  804. dwErr = NetApiBufferAllocate(len, (PVOID *)&resultVector);
  805. if (dwErr == NO_ERROR) {
  806. LPWSTR pstr = (LPWSTR)((PCHAR)resultVector + (cValues + 1) * sizeof(LPWSTR));
  807. ULONG slen;
  808. RtlZeroMemory(resultVector, len);
  809. len -= (cValues+1) * sizeof(LPWSTR);
  810. for (cValues = 0; allValues[cValues] && len >= sizeof(WCHAR); cValues++) {
  811. resultVector[cValues] = pstr;
  812. wcscpy(pstr, allValues[cValues]);
  813. slen = wcslen(allValues[cValues]);
  814. pstr += slen + 1;
  815. len -= (slen + 1) * sizeof(WCHAR);
  816. }
  817. }
  818. if (dwErr == NO_ERROR) {
  819. *List = resultVector;
  820. }
  821. Cleanup:
  822. if (ARGUMENT_PRESENT(wszDfsName)) {
  823. if (rpValues != NULL) {
  824. ldap_value_freeW(rpValues);
  825. }
  826. } else {
  827. if (rpValuesToFree != NULL) {
  828. for (i = 0; rpValuesToFree[i] != NULL; i++) {
  829. ldap_value_freeW(rpValuesToFree[i]);
  830. }
  831. }
  832. if (allValues != NULL) {
  833. NetApiBufferFree(allValues);
  834. }
  835. }
  836. if (pMsg != NULL) {
  837. ldap_msgfree(pMsg);
  838. }
  839. if (dfsDn != NULL) {
  840. NetApiBufferFree(dfsDn);
  841. }
  842. if (pLDAP != NULL && bUnbindNeeded == TRUE) {
  843. ldap_unbind(pLDAP);
  844. }
  845. return dwErr;
  846. }