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.

5955 lines
150 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1995, Microsoft Corporation
  4. //
  5. // File: dfsstub.c
  6. //
  7. // Contents: Stub file for the NetDfsXXX APIs. The stubs turn around and
  8. // call the NetrDfsXXX APIs on the appropriate server, or (in the
  9. // case of NetDfs[G/S]etClientXXX, go directly to the driver on the
  10. // local machine.
  11. //
  12. // Classes:
  13. //
  14. // Functions: NetDfsXXX
  15. //
  16. // History: 01-10-96 Milans created
  17. //
  18. //-----------------------------------------------------------------------------
  19. #include <nt.h>
  20. #include <ntrtl.h>
  21. #include <nturtl.h>
  22. #include <windows.h>
  23. #include <stdlib.h>
  24. #include <lm.h>
  25. #include <lmdfs.h>
  26. #include <dfsp.h>
  27. #include <netdfs.h>
  28. #include <dfsfsctl.h>
  29. #include <dsrole.h>
  30. #include <ntdsapi.h>
  31. #include <dsgetdc.h>
  32. #include <winldap.h>
  33. #include <aclapi.h>
  34. #include "dfsacl.h"
  35. #define MAX_DFS_LDAP_RETRY 20
  36. #define IS_UNC_PATH(wsz, cw) \
  37. ((cw) > 2 && (wsz)[0] == L'\\' && (wsz)[1] == L'\\')
  38. #define IS_VALID_PREFIX(wsz, cw) \
  39. ((cw) > 1 && (wsz)[0] == L'\\' && (wsz)[1] != L'\\')
  40. #define IS_VALID_DFS_PATH(wsz, cw) \
  41. ((cw) > 0 && (wsz)[0] != L'\\')
  42. #define IS_VALID_STRING(wsz) \
  43. ((wsz) != NULL && (wsz)[0] != UNICODE_NULL)
  44. #define POINTER_TO_OFFSET(field, buffer) \
  45. ( ((PCHAR)field) -= ((ULONG_PTR)buffer) )
  46. #define OFFSET_TO_POINTER(field, buffer) \
  47. ( ((PCHAR)field) += ((ULONG_PTR)buffer) )
  48. NET_API_STATUS
  49. DfspGetDfsNameFromEntryPath(
  50. LPWSTR wszEntryPath,
  51. DWORD cwEntryPath,
  52. LPWSTR *ppwszDfsName);
  53. NET_API_STATUS
  54. DfspGetMachineNameFromEntryPath(
  55. LPWSTR wszEntryPath,
  56. DWORD cwEntryPath,
  57. LPWSTR *ppwszMachineName);
  58. NET_API_STATUS
  59. DfspBindRpc(
  60. IN LPWSTR DfsName,
  61. OUT RPC_BINDING_HANDLE *BindingHandle);
  62. NET_API_STATUS
  63. DfspBindToServer(
  64. IN LPWSTR DfsName,
  65. OUT RPC_BINDING_HANDLE *BindingHandle);
  66. VOID
  67. DfspFreeBinding(
  68. RPC_BINDING_HANDLE BindingHandle);
  69. NET_API_STATUS
  70. DfspVerifyBinding();
  71. VOID
  72. DfspFlushPkt(
  73. LPWSTR DfsEntryPath);
  74. NTSTATUS
  75. DfspIsThisADfsPath(
  76. LPWSTR pwszPathName);
  77. DWORD
  78. DfspDfsPathToRootMachine(
  79. LPWSTR pwszDfsName,
  80. LPWSTR *ppwszMachineName);
  81. DWORD
  82. DfspCreateFtDfs(
  83. LPWSTR ServerName,
  84. LPWSTR DcName,
  85. BOOLEAN IsPdc,
  86. LPWSTR RootShare,
  87. LPWSTR FtDfsName,
  88. LPWSTR Comment,
  89. DWORD Flags);
  90. DWORD
  91. DfspTearDownFtDfs(
  92. IN LPWSTR wszServerName,
  93. IN LPWSTR wszDsAddress,
  94. IN LPWSTR wszRootShare,
  95. IN LPWSTR wszFtDfsName,
  96. IN DWORD dwFlags);
  97. VOID
  98. DfspFlushFtTable(
  99. LPWSTR wszDcName,
  100. LPWSTR wszFtDfsName);
  101. NTSTATUS
  102. DfspSetDomainToDc(
  103. LPWSTR DomainName,
  104. LPWSTR DcName);
  105. DWORD
  106. I_NetDfsIsThisADomainName(
  107. LPWSTR wszDomain);
  108. DWORD
  109. DfspIsThisADomainName(
  110. LPWSTR wszName,
  111. PWCHAR *List);
  112. VOID
  113. DfspNotifyFtRoot(
  114. LPWSTR wszServerShare,
  115. LPWSTR wszDcName);
  116. DWORD
  117. NetpDfsAdd2(
  118. LPWSTR RootName,
  119. LPWSTR EntryPath,
  120. LPWSTR ServerName,
  121. LPWSTR ShareName,
  122. LPWSTR Comment,
  123. DWORD Flags);
  124. DWORD
  125. DfspAdd2(
  126. LPWSTR RootName,
  127. LPWSTR EntryPath,
  128. LPWSTR DcName,
  129. LPWSTR ServerName,
  130. LPWSTR ShareName,
  131. LPWSTR Comment,
  132. DWORD Flags);
  133. DWORD
  134. NetpDfsSetInfo2(
  135. LPWSTR RootName,
  136. LPWSTR EntryPath,
  137. LPWSTR ServerName,
  138. LPWSTR ShareName,
  139. DWORD Level,
  140. LPDFS_INFO_STRUCT pDfsInfo);
  141. DWORD
  142. DfspSetInfo2(
  143. LPWSTR RootName,
  144. LPWSTR EntryPath,
  145. LPWSTR DcName,
  146. LPWSTR ServerName,
  147. LPWSTR ShareName,
  148. DWORD Level,
  149. LPDFS_INFO_STRUCT pDfsInfo);
  150. DWORD
  151. NetpDfsRemove2(
  152. LPWSTR RootName,
  153. LPWSTR EntryPath,
  154. LPWSTR ServerName,
  155. LPWSTR ShareName);
  156. DWORD
  157. DfspRemove2(
  158. LPWSTR RootName,
  159. LPWSTR EntryPath,
  160. LPWSTR DcName,
  161. LPWSTR ServerName,
  162. LPWSTR ShareName);
  163. DWORD
  164. DfspLdapOpen(
  165. LPWSTR wszDcName,
  166. LDAP **ppldap,
  167. LPWSTR *pwszDfsConfigDN);
  168. INT
  169. _cdecl
  170. DfspCompareDsDomainControllerInfo1(
  171. const void *p1,
  172. const void *p2);
  173. BOOLEAN
  174. DfspIsInvalidName(
  175. LPWSTR ShareName);
  176. static LPWSTR InvalidNames[] = {
  177. L"SYSVOL",
  178. L"PIPE",
  179. L"IPC$",
  180. L"ADMIN$",
  181. L"MAILSLOT",
  182. L"NETLOGON",
  183. NULL};
  184. //
  185. // The APIs are all single-threaded - only 1 can be outstanding at a time in
  186. // any one process. The following critical section is used to gate the calls.
  187. // The critical section is initialized at DLL Load time.
  188. //
  189. CRITICAL_SECTION NetDfsApiCriticalSection;
  190. #define ENTER_NETDFS_API EnterCriticalSection( &NetDfsApiCriticalSection );
  191. #define LEAVE_NETDFS_API LeaveCriticalSection( &NetDfsApiCriticalSection );
  192. //
  193. // The name of the Dfs configuration container
  194. //
  195. static WCHAR DfsConfigContainer[] = L"CN=Dfs-Configuration,CN=System";
  196. #if DBG
  197. ULONG DfsDebug = 0;
  198. #endif
  199. VOID
  200. NetDfsApiInitialize(void)
  201. {
  202. #if DBG
  203. DWORD dwErr;
  204. DWORD dwType;
  205. DWORD cbData;
  206. HKEY hkey;
  207. dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\Dfs", &hkey );
  208. if (dwErr == ERROR_SUCCESS) {
  209. cbData = sizeof(DfsDebug);
  210. dwErr = RegQueryValueEx(
  211. hkey,
  212. L"NetApiDfsDebug",
  213. NULL,
  214. &dwType,
  215. (PBYTE) &DfsDebug,
  216. &cbData);
  217. if (!(dwErr == ERROR_SUCCESS && dwType == REG_DWORD)) {
  218. DfsDebug = 0;
  219. }
  220. RegCloseKey(hkey);
  221. }
  222. #endif
  223. }
  224. //+----------------------------------------------------------------------------
  225. //
  226. // Function: NetDfsAdd
  227. //
  228. // Synopsis: Creates a new volume, adds a replica to an existing volume,
  229. // or creates a link to another Dfs.
  230. //
  231. // Arguments: [DfsEntryPath] -- Name of volume/link to create/add replica
  232. // to.
  233. // [ServerName] -- Name of server hosting the storage, or for
  234. // link, name of Dfs root.
  235. // [ShareName] -- Name of share hosting the storage.
  236. // [Flags] -- Describes what is being added.
  237. //
  238. // Returns: [NERR_Success] -- Successfully completed operation.
  239. //
  240. // [ERROR_INVALID_PARAMETER] -- DfsEntryPath and/or ServerName
  241. // and/or ShareName and/or Flags are incorrect.
  242. //
  243. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  244. //
  245. // [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
  246. //
  247. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  248. //
  249. // [NERR_DfsNoSuchVolume] -- DfsEntryPath does not correspond to a
  250. // existing Dfs volume.
  251. //
  252. // [NERR_DfsVolumeAlreadyExists] -- DFS_ADD_VOLUME was specified
  253. // and a volume with DfsEntryPath already exists.
  254. //
  255. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  256. // encountered at the server.
  257. //
  258. //-----------------------------------------------------------------------------
  259. NET_API_STATUS
  260. NetDfsAdd(
  261. IN LPWSTR DfsEntryPath,
  262. IN LPWSTR ServerName,
  263. IN LPWSTR ShareName,
  264. IN LPWSTR Comment,
  265. IN DWORD Flags)
  266. {
  267. NET_API_STATUS dwErr;
  268. DWORD cwDfsEntryPath;
  269. LPWSTR pwszDfsName = NULL;
  270. #if DBG
  271. if (DfsDebug)
  272. DbgPrint("NetDfsAdd(%ws,%ws,%ws,%ws,%d)\n",
  273. DfsEntryPath,
  274. ServerName,
  275. ShareName,
  276. Comment,
  277. Flags);
  278. #endif
  279. //
  280. // Validate the string arguments so RPC won't complain...
  281. //
  282. if (!IS_VALID_STRING(DfsEntryPath) ||
  283. !IS_VALID_STRING(ServerName) ||
  284. !IS_VALID_STRING(ShareName)) {
  285. return( ERROR_INVALID_PARAMETER );
  286. }
  287. cwDfsEntryPath = wcslen(DfsEntryPath);
  288. if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) &&
  289. !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) &&
  290. !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) {
  291. return( ERROR_INVALID_PARAMETER );
  292. }
  293. dwErr = DfspGetMachineNameFromEntryPath(
  294. DfsEntryPath,
  295. cwDfsEntryPath,
  296. &pwszDfsName);
  297. ENTER_NETDFS_API
  298. if (dwErr == NERR_Success) {
  299. //
  300. // By now, we should have a valid pwszDfsName. Lets try to bind to it,
  301. // and call the server.
  302. //
  303. dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
  304. if (dwErr == NERR_Success) {
  305. RpcTryExcept {
  306. dwErr = NetrDfsAdd(
  307. DfsEntryPath,
  308. ServerName,
  309. ShareName,
  310. Comment,
  311. Flags);
  312. } RpcExcept(1) {
  313. dwErr = RpcExceptionCode();
  314. } RpcEndExcept;
  315. DfspFreeBinding( netdfs_bhandle );
  316. }
  317. }
  318. LEAVE_NETDFS_API
  319. //
  320. // If we failed with ERROR_NOT_SUPPORTED, this is an NT5+ server,
  321. // so we use the NetrDfsAdd2() call instead.
  322. //
  323. if (dwErr == ERROR_NOT_SUPPORTED) {
  324. dwErr = NetpDfsAdd2(
  325. pwszDfsName,
  326. DfsEntryPath,
  327. ServerName,
  328. ShareName,
  329. Comment,
  330. Flags);
  331. }
  332. if (pwszDfsName != NULL)
  333. free(pwszDfsName);
  334. #if DBG
  335. if (DfsDebug)
  336. DbgPrint("NetDfsAdd returning %d\n", dwErr);
  337. #endif
  338. return( dwErr );
  339. }
  340. DWORD
  341. NetpDfsAdd2(
  342. LPWSTR RootName,
  343. LPWSTR DfsEntryPath,
  344. LPWSTR ServerName,
  345. LPWSTR ShareName,
  346. LPWSTR Comment,
  347. DWORD Flags)
  348. {
  349. NET_API_STATUS dwErr;
  350. ULONG i;
  351. ULONG NameCount;
  352. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
  353. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  354. #if DBG
  355. if (DfsDebug)
  356. DbgPrint("NetpDfsAdd2(%ws,%ws,%ws,%ws,%ws,%d)\n",
  357. RootName,
  358. DfsEntryPath,
  359. ServerName,
  360. ShareName,
  361. Comment,
  362. Flags);
  363. #endif
  364. //
  365. // Contact the server and ask for its domain name
  366. //
  367. dwErr = DsRoleGetPrimaryDomainInformation(
  368. RootName,
  369. DsRolePrimaryDomainInfoBasic,
  370. (PBYTE *)&pPrimaryDomainInfo);
  371. if (dwErr != ERROR_SUCCESS) {
  372. #if DBG
  373. if (DfsDebug)
  374. DbgPrint("DsRoleGetPrimaryDomainInformation returned %d\n", dwErr);
  375. #endif
  376. goto Cleanup;
  377. }
  378. if (pPrimaryDomainInfo->DomainNameDns == NULL) {
  379. #if DBG
  380. if (DfsDebug)
  381. DbgPrint(" DomainNameDns is NULL\n", NULL);
  382. #endif
  383. dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO;
  384. goto Cleanup;
  385. }
  386. //
  387. // Get the PDC in that domain
  388. //
  389. dwErr = DsGetDcName(
  390. NULL,
  391. pPrimaryDomainInfo->DomainNameDns,
  392. NULL,
  393. NULL,
  394. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY,
  395. &pDomainControllerInfo);
  396. if (dwErr != ERROR_SUCCESS) {
  397. #if DBG
  398. if (DfsDebug)
  399. DbgPrint(" NetpDfsAdd2:DsGetDcName(%ws) returned %d\n",
  400. pPrimaryDomainInfo->DomainNameDns,
  401. dwErr);
  402. #endif
  403. goto Cleanup;
  404. }
  405. ENTER_NETDFS_API
  406. //
  407. // Call the server
  408. //
  409. dwErr = DfspAdd2(
  410. RootName,
  411. DfsEntryPath,
  412. &pDomainControllerInfo->DomainControllerName[2],
  413. ServerName,
  414. ShareName,
  415. Comment,
  416. Flags);
  417. LEAVE_NETDFS_API
  418. Cleanup:
  419. if (pPrimaryDomainInfo != NULL)
  420. DsRoleFreeMemory(pPrimaryDomainInfo);
  421. if (pDomainControllerInfo != NULL)
  422. NetApiBufferFree(pDomainControllerInfo);
  423. #if DBG
  424. if (DfsDebug)
  425. DbgPrint("NetpDfsAdd2 returning %d\n", dwErr);
  426. #endif
  427. return( dwErr );
  428. }
  429. DWORD
  430. DfspAdd2(
  431. LPWSTR RootName,
  432. LPWSTR EntryPath,
  433. LPWSTR DcName,
  434. LPWSTR ServerName,
  435. LPWSTR ShareName,
  436. LPWSTR Comment,
  437. DWORD Flags)
  438. {
  439. DWORD dwErr;
  440. PDFSM_ROOT_LIST RootList = NULL;
  441. #if DBG
  442. if (DfsDebug)
  443. DbgPrint("DfspAdd2(%ws,%ws,%ws,%ws,%ws,%ws,%d)\n",
  444. RootName,
  445. EntryPath,
  446. DcName,
  447. ServerName,
  448. ShareName,
  449. Comment,
  450. Flags);
  451. #endif
  452. dwErr = DfspBindRpc( RootName, &netdfs_bhandle );
  453. if (dwErr == NERR_Success) {
  454. RpcTryExcept {
  455. dwErr = NetrDfsAdd2(
  456. EntryPath,
  457. DcName,
  458. ServerName,
  459. ShareName,
  460. Comment,
  461. Flags,
  462. &RootList);
  463. } RpcExcept(1) {
  464. dwErr = RpcExceptionCode();
  465. } RpcEndExcept;
  466. DfspFreeBinding( netdfs_bhandle );
  467. }
  468. #if DBG
  469. if (DfsDebug) {
  470. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  471. ULONG n;
  472. DbgPrint("cEntries=%d\n", RootList->cEntries);
  473. for (n = 0; n < RootList->cEntries; n++)
  474. DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare);
  475. }
  476. }
  477. #endif
  478. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  479. ULONG n;
  480. for (n = 0; n < RootList->cEntries; n++) {
  481. DfspNotifyFtRoot(
  482. RootList->Entry[n].ServerShare,
  483. DcName);
  484. }
  485. NetApiBufferFree(RootList);
  486. }
  487. #if DBG
  488. if (DfsDebug)
  489. DbgPrint("DfspAdd2 returning %d\n", dwErr);
  490. #endif
  491. return dwErr;
  492. }
  493. //+----------------------------------------------------------------------------
  494. //
  495. // Function: NetDfsAddFtRoot
  496. //
  497. // Synopsis: Creates a new FtDfs, adds a new server to an existing FtDfs.
  498. //
  499. // Arguments: [ServerName] -- Name of server to make a root, or to join to an existing FtDfs.
  500. // [RootShare] -- Name of share hosting the storage.
  501. // [FtDfsName] -- Name of FtDfs to join or create.
  502. // [Comment] -- Optional comment
  503. // [Flags] -- Flags to operation
  504. //
  505. // Returns: [NERR_Success] -- Successfully completed operation.
  506. //
  507. // [ERROR_INVALID_PARAMETER] -- ServerName and/or RootShare are incorrect.
  508. //
  509. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  510. //
  511. // [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
  512. //
  513. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  514. //
  515. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  516. // encountered at the server.
  517. //
  518. //-----------------------------------------------------------------------------
  519. NET_API_STATUS
  520. NetDfsAddFtRoot(
  521. IN LPWSTR ServerName,
  522. IN LPWSTR RootShare,
  523. IN LPWSTR FtDfsName,
  524. IN LPWSTR Comment,
  525. IN DWORD Flags)
  526. {
  527. NET_API_STATUS dwErr;
  528. BOOLEAN IsRoot = FALSE;
  529. ULONG Timeout = 0;
  530. ULONG i;
  531. ULONG NameCount;
  532. LPWSTR DcName = NULL;
  533. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
  534. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  535. PDFSM_ROOT_LIST RootList = NULL;
  536. #if DBG
  537. if (DfsDebug)
  538. DbgPrint("NetDfsAddFtRoot(%ws,%ws,%ws,%ws,%d)\n",
  539. ServerName,
  540. RootShare,
  541. FtDfsName,
  542. Comment,
  543. Flags);
  544. #endif
  545. //
  546. // Validate the string arguments so RPC won't complain...
  547. //
  548. if (!IS_VALID_STRING(ServerName) ||
  549. !IS_VALID_STRING(RootShare) ||
  550. !IS_VALID_STRING(FtDfsName)) {
  551. return( ERROR_INVALID_PARAMETER );
  552. }
  553. if (FtDfsName[0] == L' ' || DfspIsInvalidName(FtDfsName) == TRUE) {
  554. return( ERROR_INVALID_PARAMETER );
  555. }
  556. while (*ServerName == L'\\') {
  557. ServerName++;
  558. }
  559. if (wcschr(ServerName, L'\\') != NULL)
  560. {
  561. return (ERROR_INVALID_NAME);
  562. }
  563. //
  564. // WE let the server add the root for us. If this fails,
  565. // with invalid parameter, we then get the dc name
  566. // and get the root list for NT5 DFS servers.
  567. //
  568. ENTER_NETDFS_API
  569. dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
  570. if (dwErr == NERR_Success) {
  571. RpcTryExcept {
  572. dwErr = NetrDfsAddFtRoot(
  573. ServerName,
  574. L"",
  575. RootShare,
  576. FtDfsName,
  577. (Comment != NULL) ? Comment : L"",
  578. L"",
  579. 0,
  580. Flags,
  581. &RootList );
  582. #if DBG
  583. if (DfsDebug)
  584. DbgPrint("NetrDfsAddFtRoot returned %d\n", dwErr);
  585. #endif
  586. } RpcExcept(1) {
  587. dwErr = RpcExceptionCode();
  588. } RpcEndExcept;
  589. DfspFreeBinding( netdfs_bhandle );
  590. }
  591. LEAVE_NETDFS_API
  592. if (dwErr != ERROR_INVALID_PARAMETER)
  593. {
  594. goto Cleanup;
  595. }
  596. //
  597. // Contact the server and ask for the DC to work with
  598. //
  599. dwErr = NetDfsGetDcAddress(
  600. ServerName,
  601. &DcName,
  602. &IsRoot,
  603. &Timeout);
  604. if (dwErr != ERROR_SUCCESS) {
  605. #if DBG
  606. if (DfsDebug)
  607. DbgPrint("NetDfsGetDcAddress returned %d\n", dwErr);
  608. #endif
  609. goto Cleanup;
  610. }
  611. if (IsRoot == TRUE) {
  612. #if DBG
  613. if (DfsDebug)
  614. DbgPrint("Root already exists!\n");
  615. #endif
  616. dwErr = ERROR_ALREADY_EXISTS;
  617. goto Cleanup;
  618. }
  619. //
  620. // Now get its domain name
  621. //
  622. dwErr = DsRoleGetPrimaryDomainInformation(
  623. ServerName,
  624. DsRolePrimaryDomainInfoBasic,
  625. (PBYTE *)&pPrimaryDomainInfo);
  626. if (dwErr != ERROR_SUCCESS) {
  627. #if DBG
  628. if (DfsDebug)
  629. DbgPrint("DsRoleGetPrimaryDomainInformation returned %d\n", dwErr);
  630. #endif
  631. goto Cleanup;
  632. }
  633. if (pPrimaryDomainInfo->DomainNameDns == NULL) {
  634. #if DBG
  635. if (DfsDebug)
  636. DbgPrint(" DsRoleGetPrimaryDomainInformation returned NULL domain name\n");
  637. #endif
  638. dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO;
  639. goto Cleanup;
  640. }
  641. //
  642. // Get the PDC in that domain
  643. //
  644. dwErr = DsGetDcName(
  645. NULL,
  646. pPrimaryDomainInfo->DomainNameDns,
  647. NULL,
  648. NULL,
  649. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY,
  650. &pDomainControllerInfo);
  651. if (dwErr != ERROR_SUCCESS) {
  652. #if DBG
  653. if (DfsDebug)
  654. DbgPrint("DsGetDcName(%ws) returned %d\n", pPrimaryDomainInfo->DomainNameDns, dwErr);
  655. #endif
  656. goto Cleanup;
  657. }
  658. ENTER_NETDFS_API
  659. //
  660. // Add the Ds object and tell the server to join itself
  661. //
  662. dwErr = DfspCreateFtDfs(
  663. ServerName,
  664. &pDomainControllerInfo->DomainControllerName[2],
  665. TRUE,
  666. RootShare,
  667. FtDfsName,
  668. Comment,
  669. Flags);
  670. if (dwErr != ERROR_SUCCESS) {
  671. #if DBG
  672. if (DfsDebug)
  673. DbgPrint(" DfspCreateFtDfs returned %d\n", dwErr);
  674. #endif
  675. LEAVE_NETDFS_API
  676. goto Cleanup;
  677. }
  678. //
  679. // Tell the local MUP to crack ftdfs names using the selected DC
  680. //
  681. DfspSetDomainToDc(
  682. pPrimaryDomainInfo->DomainNameDns,
  683. &pDomainControllerInfo->DomainControllerName[2]);
  684. if (pPrimaryDomainInfo->DomainNameFlat != NULL) {
  685. PWCHAR wCp = &pDomainControllerInfo->DomainControllerName[2];
  686. for (; *wCp != L'\0' && *wCp != L'.'; wCp++)
  687. /* NOTHING */;
  688. *wCp = (*wCp == L'.') ? L'\0' : *wCp;
  689. DfspSetDomainToDc(
  690. pPrimaryDomainInfo->DomainNameFlat,
  691. &pDomainControllerInfo->DomainControllerName[2]);
  692. }
  693. LEAVE_NETDFS_API
  694. Cleanup:
  695. if (pPrimaryDomainInfo != NULL)
  696. DsRoleFreeMemory(pPrimaryDomainInfo);
  697. if (pDomainControllerInfo != NULL)
  698. NetApiBufferFree(pDomainControllerInfo);
  699. if (DcName != NULL)
  700. NetApiBufferFree(DcName);
  701. #if DBG
  702. if (DfsDebug)
  703. DbgPrint("NetDfsAddFtRoot returning %d\n", dwErr);
  704. #endif
  705. return( dwErr );
  706. }
  707. //+----------------------------------------------------------------------------
  708. //
  709. // Function: DfspCompareDsDomainControllerInfo1
  710. //
  711. // Synopsis: Helper/compare func for qsort of DsGetDomainControllerInfo's results
  712. //
  713. //-----------------------------------------------------------------------------
  714. INT
  715. _cdecl
  716. DfspCompareDsDomainControllerInfo1(
  717. const void *p1,
  718. const void *p2)
  719. {
  720. PDS_DOMAIN_CONTROLLER_INFO_1 pInfo1 = (PDS_DOMAIN_CONTROLLER_INFO_1)p1;
  721. PDS_DOMAIN_CONTROLLER_INFO_1 pInfo2 = (PDS_DOMAIN_CONTROLLER_INFO_1)p2;
  722. UNICODE_STRING s1;
  723. UNICODE_STRING s2;
  724. if (pInfo1->DnsHostName == NULL || pInfo2->DnsHostName == NULL)
  725. return 0;
  726. RtlInitUnicodeString(&s1, pInfo1->DnsHostName);
  727. RtlInitUnicodeString(&s2, pInfo2->DnsHostName);
  728. return RtlCompareUnicodeString(&s1,&s2,TRUE);
  729. }
  730. //+----------------------------------------------------------------------------
  731. //
  732. // Function: NetDfsAddStdRoot
  733. //
  734. // Synopsis: Creates a new Std Dfs.
  735. //
  736. // Arguments: [ServerName] -- Name of server to make a root.
  737. // existing Dfs.
  738. // [RootShare] -- Name of share hosting the storage.
  739. // [Comment] -- Optional comment
  740. // [Flags] -- Flags
  741. //
  742. // Returns: [NERR_Success] -- Successfully completed operation.
  743. //
  744. // [ERROR_INVALID_PARAMETER] -- ServerName and/or RootShare are incorrect.
  745. //
  746. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  747. //
  748. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  749. //
  750. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  751. // encountered at the server.
  752. //
  753. //-----------------------------------------------------------------------------
  754. NET_API_STATUS
  755. NetDfsAddStdRoot(
  756. IN LPWSTR ServerName,
  757. IN LPWSTR RootShare,
  758. IN LPWSTR Comment,
  759. IN DWORD Flags)
  760. {
  761. NET_API_STATUS dwErr;
  762. #if DBG
  763. if (DfsDebug)
  764. DbgPrint("NetDfsAddStdRoot(%ws,%ws,%ws,%d)\n",
  765. ServerName,
  766. RootShare,
  767. Comment,
  768. Flags);
  769. #endif
  770. //
  771. // Validate the string arguments so RPC won't complain...
  772. //
  773. if (!IS_VALID_STRING(ServerName) ||
  774. !IS_VALID_STRING(RootShare)) {
  775. return( ERROR_INVALID_PARAMETER );
  776. }
  777. ENTER_NETDFS_API
  778. //
  779. // We should have a valid ServerName. Lets try to bind to it,
  780. // and call the server.
  781. //
  782. dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
  783. if (dwErr == NERR_Success) {
  784. RpcTryExcept {
  785. dwErr = NetrDfsAddStdRoot(
  786. ServerName,
  787. RootShare,
  788. (Comment != NULL) ? Comment : L"",
  789. Flags);
  790. } RpcExcept(1) {
  791. dwErr = RpcExceptionCode();
  792. } RpcEndExcept;
  793. DfspFreeBinding( netdfs_bhandle );
  794. }
  795. LEAVE_NETDFS_API
  796. #if DBG
  797. if (DfsDebug)
  798. DbgPrint("NetDfsAddStdRoot returning %d\n", dwErr);
  799. #endif
  800. return( dwErr );
  801. }
  802. //+----------------------------------------------------------------------------
  803. //
  804. // Function: NetDfsAddStdRootForced
  805. //
  806. // Synopsis: Creates a new Std Dfs, also specifying the share
  807. //
  808. // Arguments: [ServerName] -- Name of server to make a root.
  809. // existing Dfs.
  810. // [RootShare] -- Name of share hosting the storage.
  811. // [Comment] -- Optional comment
  812. // [Share] -- Name of drive:\dir hosting the share
  813. //
  814. // Returns: [NERR_Success] -- Successfully completed operation.
  815. //
  816. // [ERROR_INVALID_PARAMETER] -- ServerName and/or RootShare are incorrect.
  817. //
  818. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  819. //
  820. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  821. //
  822. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  823. // encountered at the server.
  824. //
  825. //-----------------------------------------------------------------------------
  826. NET_API_STATUS
  827. NetDfsAddStdRootForced(
  828. IN LPWSTR ServerName,
  829. IN LPWSTR RootShare,
  830. IN LPWSTR Comment,
  831. IN LPWSTR Share)
  832. {
  833. NET_API_STATUS dwErr;
  834. #if DBG
  835. if (DfsDebug)
  836. DbgPrint("NetDfsAddStdRootForced(%ws,%ws,%ws,%ws)\n",
  837. ServerName,
  838. RootShare,
  839. Comment,
  840. Share);
  841. #endif
  842. //
  843. // Validate the string arguments so RPC won't complain...
  844. //
  845. if (!IS_VALID_STRING(ServerName) ||
  846. !IS_VALID_STRING(RootShare) ||
  847. !IS_VALID_STRING(Share)) {
  848. return( ERROR_INVALID_PARAMETER );
  849. }
  850. ENTER_NETDFS_API
  851. //
  852. // We should have a valid ServerName. Lets try to bind to it,
  853. // and call the server.
  854. //
  855. dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
  856. if (dwErr == NERR_Success) {
  857. RpcTryExcept {
  858. dwErr = NetrDfsAddStdRootForced(
  859. ServerName,
  860. RootShare,
  861. (Comment != NULL) ? Comment : L"",
  862. Share);
  863. } RpcExcept(1) {
  864. dwErr = RpcExceptionCode();
  865. } RpcEndExcept;
  866. DfspFreeBinding( netdfs_bhandle );
  867. }
  868. LEAVE_NETDFS_API
  869. #if DBG
  870. if (DfsDebug)
  871. DbgPrint("NetDfsAddStdRootForced returning %d\n", dwErr);
  872. #endif
  873. return( dwErr );
  874. }
  875. //+----------------------------------------------------------------------------
  876. //
  877. // Function: NetDfsGetDcAddress
  878. //
  879. // Synopsis: Asks a server for its DC to use to place the dfs blob to make
  880. // the server a root.
  881. //
  882. // Arguments: [ServerName] -- Name of server we will be making an FtDfs root
  883. // [DcName] -- DC Name
  884. // [IsRoot] -- TRUE if Server is a root, FALSE otherwise
  885. // [Timeout] -- Timeout the server is using
  886. //
  887. // Returns: [NERR_Success] -- Successfully completed operation.
  888. //
  889. // [ERROR_INVALID_PARAMETER] -- ServerName incorrect.
  890. //
  891. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  892. //
  893. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  894. //
  895. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  896. // encountered at the server.
  897. //
  898. //-----------------------------------------------------------------------------
  899. NET_API_STATUS
  900. NetDfsGetDcAddress(
  901. IN LPWSTR ServerName,
  902. IN OUT LPWSTR *DcName,
  903. IN OUT BOOLEAN *IsRoot,
  904. IN OUT ULONG *Timeout)
  905. {
  906. NET_API_STATUS dwErr;
  907. #if DBG
  908. if (DfsDebug)
  909. DbgPrint("NetDfsGetDcAddress(%ws)\n", ServerName);
  910. #endif
  911. //
  912. // Validate the string arguments so RPC won't complain...
  913. //
  914. if (!IS_VALID_STRING(ServerName)|| DcName == NULL || IsRoot == NULL || Timeout == NULL) {
  915. return( ERROR_INVALID_PARAMETER );
  916. }
  917. ENTER_NETDFS_API
  918. //
  919. // We should have a valid ServerName. Lets try to bind to it,
  920. // and call the server.
  921. //
  922. dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
  923. if (dwErr == NERR_Success) {
  924. RpcTryExcept {
  925. dwErr = NetrDfsGetDcAddress(
  926. ServerName,
  927. DcName,
  928. IsRoot,
  929. Timeout);
  930. } RpcExcept(1) {
  931. dwErr = RpcExceptionCode();
  932. } RpcEndExcept;
  933. DfspFreeBinding( netdfs_bhandle );
  934. }
  935. LEAVE_NETDFS_API
  936. #if DBG
  937. if (DfsDebug)
  938. DbgPrint("NetDfsGetDcAddress: returned %d\n", dwErr);
  939. #endif
  940. return( dwErr );
  941. }
  942. //+----------------------------------------------------------------------------
  943. //
  944. // Function: NetDfsRemove
  945. //
  946. // Synopsis: Deletes a Dfs volume, removes a replica from an existing
  947. // volume, or removes a link to another Dfs.
  948. //
  949. // Arguments: [DfsEntryPath] -- Name of volume/link to remove.
  950. // [ServerName] -- Name of server hosting the storage. Must be
  951. // NULL if removing Link.
  952. // [ShareName] -- Name of share hosting the storage. Must be
  953. // NULL if removing Link.
  954. //
  955. // Returns: [NERR_Success] -- Successfully completed operation.
  956. //
  957. // [ERROR_INVALID_PARAMETER] -- DfsEntryPath is incorrect.
  958. //
  959. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  960. //
  961. // [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
  962. //
  963. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  964. //
  965. // [NERR_DfsNoSuchVolume] -- DfsEntryPath does not correspond to
  966. // a valid entry path.
  967. //
  968. // [NERR_DfsNotALeafVolume] -- Unable to delete the volume
  969. // because it is not a leaf volume.
  970. //
  971. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  972. // encountered at the server.
  973. //
  974. //-----------------------------------------------------------------------------
  975. NET_API_STATUS
  976. NetDfsRemove(
  977. IN LPWSTR DfsEntryPath,
  978. IN LPWSTR ServerName,
  979. IN LPWSTR ShareName)
  980. {
  981. NET_API_STATUS dwErr;
  982. DWORD cwDfsEntryPath;
  983. LPWSTR pwszDfsName = NULL;
  984. #if DBG
  985. if (DfsDebug)
  986. DbgPrint("NetDfsRemove(%ws,%ws,%ws)\n",
  987. DfsEntryPath,
  988. ServerName,
  989. ShareName);
  990. #endif
  991. //
  992. // Validate the string arguments so RPC won't complain...
  993. //
  994. if (!IS_VALID_STRING(DfsEntryPath)) {
  995. return( ERROR_INVALID_PARAMETER );
  996. }
  997. cwDfsEntryPath = wcslen(DfsEntryPath);
  998. if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) &&
  999. !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) &&
  1000. !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) {
  1001. return( ERROR_INVALID_PARAMETER );
  1002. }
  1003. dwErr = DfspGetMachineNameFromEntryPath(
  1004. DfsEntryPath,
  1005. cwDfsEntryPath,
  1006. &pwszDfsName);
  1007. ENTER_NETDFS_API
  1008. if (dwErr == NERR_Success) {
  1009. dwErr = DfspBindRpc(pwszDfsName, &netdfs_bhandle);
  1010. if (dwErr == NERR_Success) {
  1011. RpcTryExcept {
  1012. dwErr = NetrDfsRemove(
  1013. DfsEntryPath,
  1014. ServerName,
  1015. ShareName);
  1016. } RpcExcept(1) {
  1017. dwErr = RpcExceptionCode();
  1018. } RpcEndExcept;
  1019. DfspFreeBinding( netdfs_bhandle );
  1020. }
  1021. }
  1022. LEAVE_NETDFS_API
  1023. //
  1024. // If we failed with ERROR_NOT_SUPPORTED, this is an NT5+ server,
  1025. // so we use the NetrDfsRemove2() call instead.
  1026. //
  1027. if (dwErr == ERROR_NOT_SUPPORTED) {
  1028. dwErr = NetpDfsRemove2(
  1029. pwszDfsName,
  1030. DfsEntryPath,
  1031. ServerName,
  1032. ShareName);
  1033. }
  1034. //
  1035. // If we removed things from a dfs, the local pkt
  1036. // may now be out of date. [92216]
  1037. // Flush the local pkt
  1038. //
  1039. if (dwErr == NERR_Success) {
  1040. DfspFlushPkt(DfsEntryPath);
  1041. }
  1042. if (pwszDfsName != NULL)
  1043. free( pwszDfsName );
  1044. #if DBG
  1045. if (DfsDebug)
  1046. DbgPrint("NetDfsRemove returning %d\n", dwErr);
  1047. #endif
  1048. return( dwErr );
  1049. }
  1050. DWORD
  1051. NetpDfsRemove2(
  1052. LPWSTR RootName,
  1053. LPWSTR DfsEntryPath,
  1054. LPWSTR ServerName,
  1055. LPWSTR ShareName)
  1056. {
  1057. NET_API_STATUS dwErr;
  1058. ULONG i;
  1059. ULONG NameCount;
  1060. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
  1061. PDS_DOMAIN_CONTROLLER_INFO_1 pDsDomainControllerInfo1 = NULL;
  1062. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  1063. HANDLE hDs = NULL;
  1064. #if DBG
  1065. if (DfsDebug)
  1066. DbgPrint("NetpDfsRemove2(%ws,%ws,%ws,%ws)\n",
  1067. RootName,
  1068. DfsEntryPath,
  1069. ServerName,
  1070. ShareName);
  1071. #endif
  1072. //
  1073. // Ask for its domain name
  1074. //
  1075. dwErr = DsRoleGetPrimaryDomainInformation(
  1076. RootName,
  1077. DsRolePrimaryDomainInfoBasic,
  1078. (PBYTE *)&pPrimaryDomainInfo);
  1079. if (dwErr != ERROR_SUCCESS) {
  1080. #if DBG
  1081. if (DfsDebug)
  1082. DbgPrint(" DsRoleGetPrimaryDomainInformation returned %d\n", dwErr);
  1083. #endif
  1084. goto Cleanup;
  1085. }
  1086. if (pPrimaryDomainInfo->DomainNameDns == NULL) {
  1087. #if DBG
  1088. if (DfsDebug)
  1089. DbgPrint(" DomainNameDns is NULL\n");
  1090. #endif
  1091. dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO;
  1092. goto Cleanup;
  1093. }
  1094. //
  1095. // Get the PDC in that domain
  1096. //
  1097. dwErr = DsGetDcName(
  1098. NULL,
  1099. pPrimaryDomainInfo->DomainNameDns,
  1100. NULL,
  1101. NULL,
  1102. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY,
  1103. &pDomainControllerInfo);
  1104. if (dwErr != ERROR_SUCCESS) {
  1105. #if DBG
  1106. if (DfsDebug)
  1107. DbgPrint(" DsGetDcName(%ws) returned %d\n", pPrimaryDomainInfo->DomainNameDns);
  1108. #endif
  1109. goto Cleanup;
  1110. }
  1111. ENTER_NETDFS_API
  1112. //
  1113. // Tell the root server to remove this server/share
  1114. //
  1115. dwErr = DfspRemove2(
  1116. RootName,
  1117. DfsEntryPath,
  1118. &pDomainControllerInfo->DomainControllerName[2],
  1119. ServerName,
  1120. ShareName);
  1121. LEAVE_NETDFS_API
  1122. if (dwErr != ERROR_SUCCESS) {
  1123. #if DBG
  1124. if (DfsDebug)
  1125. DbgPrint(" DfspRemove2 returned %d\n");
  1126. #endif
  1127. goto Cleanup;
  1128. }
  1129. Cleanup:
  1130. if (pDomainControllerInfo != NULL)
  1131. NetApiBufferFree(pDomainControllerInfo);
  1132. if (pPrimaryDomainInfo != NULL)
  1133. DsRoleFreeMemory(pPrimaryDomainInfo);
  1134. #if DBG
  1135. if (DfsDebug)
  1136. DbgPrint("NetpDfsRemove2 returning %d\n", dwErr);
  1137. #endif
  1138. return( dwErr );
  1139. }
  1140. DWORD
  1141. DfspRemove2(
  1142. LPWSTR RootName,
  1143. LPWSTR EntryPath,
  1144. LPWSTR DcName,
  1145. LPWSTR ServerName,
  1146. LPWSTR ShareName)
  1147. {
  1148. DWORD dwErr;
  1149. PDFSM_ROOT_LIST RootList = NULL;
  1150. #if DBG
  1151. if (DfsDebug)
  1152. DbgPrint("DfspRemove2(%ws,%ws,%ws,%ws,%ws)\n",
  1153. RootName,
  1154. EntryPath,
  1155. DcName,
  1156. ServerName,
  1157. ShareName);
  1158. #endif
  1159. dwErr = DfspBindRpc( RootName, &netdfs_bhandle );
  1160. if (dwErr == NERR_Success) {
  1161. RpcTryExcept {
  1162. dwErr = NetrDfsRemove2(
  1163. EntryPath,
  1164. DcName,
  1165. ServerName,
  1166. ShareName,
  1167. &RootList);
  1168. } RpcExcept(1) {
  1169. dwErr = RpcExceptionCode();
  1170. } RpcEndExcept;
  1171. DfspFreeBinding( netdfs_bhandle );
  1172. }
  1173. #if DBG
  1174. if (DfsDebug) {
  1175. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  1176. ULONG n;
  1177. DbgPrint("cEntries=%d\n", RootList->cEntries);
  1178. for (n = 0; n < RootList->cEntries; n++)
  1179. DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare);
  1180. }
  1181. }
  1182. #endif
  1183. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  1184. ULONG n;
  1185. for (n = 0; n < RootList->cEntries; n++) {
  1186. DfspNotifyFtRoot(
  1187. RootList->Entry[n].ServerShare,
  1188. DcName);
  1189. }
  1190. NetApiBufferFree(RootList);
  1191. }
  1192. #if DBG
  1193. if (DfsDebug)
  1194. DbgPrint("DfspRemove2 returning %d\n", dwErr);
  1195. #endif
  1196. return dwErr;
  1197. }
  1198. //+----------------------------------------------------------------------------
  1199. //
  1200. // Function: NetDfsRemoveFtRoot
  1201. //
  1202. // Synopsis: Deletes an FtDfs root, or unjoins a Server from an FtDfs as a root.
  1203. //
  1204. // Arguments: [ServerName] -- Name of server to unjoin from FtDfs.
  1205. // [RootShare] -- Name of share hosting the storage.
  1206. // [FtDfsName] -- Name of FtDfs to remove server from.
  1207. // [Flags] -- Flags to operation
  1208. //
  1209. // Returns: [NERR_Success] -- Successfully completed operation.
  1210. //
  1211. // [ERROR_INVALID_PARAMETER] -- ServerName and/or FtDfsName is incorrect.
  1212. //
  1213. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  1214. //
  1215. // [ERROR_DCNotFound] -- Unable to locate DC for ServerName
  1216. //
  1217. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  1218. //
  1219. // [NERR_DfsNoSuchVolume] -- FtDfsName does not correspond to
  1220. // a valid FtDfs.
  1221. //
  1222. // [NERR_DfsNotALeafVolume] -- Unable to delete the volume
  1223. // because it is not a leaf volume.
  1224. //
  1225. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  1226. // encountered at the server.
  1227. //
  1228. //-----------------------------------------------------------------------------
  1229. NET_API_STATUS
  1230. NetDfsRemoveFtRoot(
  1231. IN LPWSTR ServerName,
  1232. IN LPWSTR RootShare,
  1233. IN LPWSTR FtDfsName,
  1234. IN DWORD Flags)
  1235. {
  1236. NET_API_STATUS dwErr;
  1237. LPWSTR DcName = NULL;
  1238. BOOLEAN IsRoot = FALSE;
  1239. ULONG Timeout = 0;
  1240. ULONG i;
  1241. ULONG NameCount;
  1242. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
  1243. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  1244. PDFSM_ROOT_LIST RootList = NULL;
  1245. #if DBG
  1246. if (DfsDebug)
  1247. DbgPrint("NetDfsRemoveFtRoot(%ws,%ws,%ws,%d)\n",
  1248. ServerName,
  1249. RootShare,
  1250. FtDfsName,
  1251. Flags);
  1252. #endif
  1253. //
  1254. // Validate the string arguments so RPC won't complain...
  1255. //
  1256. if (!IS_VALID_STRING(ServerName) ||
  1257. !IS_VALID_STRING(RootShare) ||
  1258. !IS_VALID_STRING(FtDfsName)) {
  1259. return( ERROR_INVALID_PARAMETER );
  1260. }
  1261. while (*ServerName == L'\\') {
  1262. ServerName++;
  1263. }
  1264. if (wcschr(ServerName, L'\\') != NULL)
  1265. {
  1266. return (ERROR_INVALID_NAME);
  1267. }
  1268. //
  1269. // we first allow the server to do all the work, so pass in null
  1270. // as dc name and root list. If that fails with error_invalid_param
  1271. // we know we are dealing with a NT5 server, so go into compat mode.
  1272. //
  1273. ENTER_NETDFS_API
  1274. dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
  1275. if (dwErr == NERR_Success) {
  1276. RpcTryExcept {
  1277. dwErr = NetrDfsRemoveFtRoot(
  1278. ServerName,
  1279. L"",
  1280. RootShare,
  1281. FtDfsName,
  1282. Flags,
  1283. &RootList );
  1284. #if DBG
  1285. if (DfsDebug)
  1286. DbgPrint("NetrDfsAddFtRoot returned %d\n", dwErr);
  1287. #endif
  1288. } RpcExcept(1) {
  1289. dwErr = RpcExceptionCode();
  1290. } RpcEndExcept;
  1291. DfspFreeBinding( netdfs_bhandle );
  1292. }
  1293. LEAVE_NETDFS_API
  1294. if (dwErr != ERROR_INVALID_PARAMETER)
  1295. {
  1296. goto Cleanup;
  1297. }
  1298. //
  1299. // Contact the server and ask for the DC to work with
  1300. //
  1301. #if 0
  1302. dwErr = NetDfsGetDcAddress(
  1303. ServerName,
  1304. &DcName,
  1305. &IsRoot,
  1306. &Timeout);
  1307. if (dwErr != ERROR_SUCCESS) {
  1308. return dwErr;
  1309. }
  1310. if (IsRoot == FALSE) {
  1311. dwErr = ERROR_SERVICE_DOES_NOT_EXIST;
  1312. goto Cleanup;
  1313. }
  1314. #endif
  1315. //
  1316. // Now ask it for its dns and domain names
  1317. //
  1318. dwErr = DsRoleGetPrimaryDomainInformation(
  1319. ServerName,
  1320. DsRolePrimaryDomainInfoBasic,
  1321. (PBYTE *)&pPrimaryDomainInfo);
  1322. if (dwErr != ERROR_SUCCESS) {
  1323. #if DBG
  1324. if (DfsDebug)
  1325. DbgPrint("DsRoleGetPrimaryDomainInformation returned %d\n", dwErr);
  1326. #endif
  1327. goto Cleanup;
  1328. }
  1329. if (pPrimaryDomainInfo->DomainNameDns == NULL) {
  1330. #if DBG
  1331. if (DfsDebug)
  1332. DbgPrint("DsRoleGetPrimaryDomainInformation returned NULL domain name\n");
  1333. #endif
  1334. dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO;
  1335. goto Cleanup;
  1336. }
  1337. //
  1338. // Get the PDC in that domain
  1339. //
  1340. dwErr = DsGetDcName(
  1341. NULL,
  1342. pPrimaryDomainInfo->DomainNameDns,
  1343. NULL,
  1344. NULL,
  1345. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY,
  1346. &pDomainControllerInfo);
  1347. if (dwErr != ERROR_SUCCESS) {
  1348. #if DBG
  1349. if (DfsDebug)
  1350. DbgPrint(" DsGetDcName(%ws) returned %d\n", pPrimaryDomainInfo->DomainNameDns, dwErr);
  1351. #endif
  1352. goto Cleanup;
  1353. }
  1354. ENTER_NETDFS_API
  1355. //
  1356. // Tell the server to unjoin and update the Ds object
  1357. //
  1358. dwErr = DfspTearDownFtDfs(
  1359. ServerName,
  1360. &pDomainControllerInfo->DomainControllerName[2],
  1361. RootShare,
  1362. FtDfsName,
  1363. Flags);
  1364. if (dwErr != ERROR_SUCCESS) {
  1365. #if DBG
  1366. if (DfsDebug)
  1367. DbgPrint(" DfspTearDownFtDfs returned %d\n", dwErr);
  1368. #endif
  1369. LEAVE_NETDFS_API
  1370. goto Cleanup;
  1371. }
  1372. //
  1373. // Tell the local MUP to crack ftdfs names using the selected DC
  1374. //
  1375. DfspSetDomainToDc(
  1376. pPrimaryDomainInfo->DomainNameDns,
  1377. &pDomainControllerInfo->DomainControllerName[2]);
  1378. if (pPrimaryDomainInfo->DomainNameFlat != NULL) {
  1379. PWCHAR wCp = &pDomainControllerInfo->DomainControllerName[2];
  1380. for (; *wCp != L'\0' && *wCp != L'.'; wCp++)
  1381. /* NOTHING */;
  1382. *wCp = (*wCp == L'.') ? L'\0' : *wCp;
  1383. DfspSetDomainToDc(
  1384. pPrimaryDomainInfo->DomainNameFlat,
  1385. &pDomainControllerInfo->DomainControllerName[2]);
  1386. }
  1387. LEAVE_NETDFS_API
  1388. Cleanup:
  1389. if (pDomainControllerInfo != NULL)
  1390. NetApiBufferFree(pDomainControllerInfo);
  1391. if (DcName != NULL)
  1392. NetApiBufferFree(DcName);
  1393. #if DBG
  1394. if (DfsDebug)
  1395. DbgPrint("NetDfsRemoveFtRoot returning %d\n", dwErr);
  1396. #endif
  1397. return( dwErr );
  1398. }
  1399. //+----------------------------------------------------------------------------
  1400. //
  1401. // Function: NetDfsRemoveFtRootForced
  1402. //
  1403. // Synopsis: Deletes an FtDfs root, or unjoins a Server from an FtDfs as a root.
  1404. // Does not contact the root/server to do so - it simply updates the DS.
  1405. //
  1406. // Arguments: [DomainName] -- Name of domain the server is in.
  1407. // [ServerName] -- Name of server to unjoin from FtDfs.
  1408. // [RootShare] -- Name of share hosting the storage.
  1409. // [FtDfsName] -- Name of FtDfs to remove server from.
  1410. // [Flags] -- Flags to operation
  1411. //
  1412. // Returns: [NERR_Success] -- Successfully completed operation.
  1413. //
  1414. // [ERROR_INVALID_PARAMETER] -- ServerName and/or FtDfsName is incorrect.
  1415. //
  1416. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  1417. //
  1418. // [ERROR_DCNotFound] -- Unable to locate DC for ServerName
  1419. //
  1420. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  1421. //
  1422. // [NERR_DfsNoSuchVolume] -- FtDfsName does not correspond to
  1423. // a valid FtDfs.
  1424. //
  1425. // [NERR_DfsNotALeafVolume] -- Unable to delete the volume
  1426. // because it is not a leaf volume.
  1427. //
  1428. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  1429. // encountered at the server.
  1430. //
  1431. //-----------------------------------------------------------------------------
  1432. NET_API_STATUS
  1433. NetDfsRemoveFtRootForced(
  1434. IN LPWSTR DomainName,
  1435. IN LPWSTR ServerName,
  1436. IN LPWSTR RootShare,
  1437. IN LPWSTR FtDfsName,
  1438. IN DWORD Flags)
  1439. {
  1440. NET_API_STATUS dwErr;
  1441. LPWSTR DcName = NULL;
  1442. BOOLEAN IsRoot = FALSE;
  1443. ULONG Timeout = 0;
  1444. ULONG i;
  1445. ULONG NameCount;
  1446. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
  1447. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  1448. #if DBG
  1449. if (DfsDebug)
  1450. DbgPrint("NetDfsRemoveFtrootForced(%ws,%ws,%ws,%ws,%d)\n",
  1451. DomainName,
  1452. ServerName,
  1453. RootShare,
  1454. FtDfsName,
  1455. Flags);
  1456. #endif
  1457. //
  1458. // Validate the string arguments so RPC won't complain...
  1459. //
  1460. if (!IS_VALID_STRING(DomainName) ||
  1461. !IS_VALID_STRING(ServerName) ||
  1462. !IS_VALID_STRING(RootShare) ||
  1463. !IS_VALID_STRING(FtDfsName)) {
  1464. return( ERROR_INVALID_PARAMETER );
  1465. }
  1466. while (*ServerName == L'\\') {
  1467. ServerName++;
  1468. }
  1469. if (wcschr(ServerName, L'\\') != NULL)
  1470. {
  1471. return (ERROR_INVALID_NAME);
  1472. }
  1473. //
  1474. // Get the PDC in the domain
  1475. //
  1476. dwErr = DsGetDcName(
  1477. NULL,
  1478. DomainName,
  1479. NULL,
  1480. NULL,
  1481. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY,
  1482. &pDomainControllerInfo);
  1483. if (dwErr != ERROR_SUCCESS) {
  1484. #if DBG
  1485. if (DfsDebug)
  1486. DbgPrint(" DsGetDcName(%ws) returned %d\n", DomainName, dwErr);
  1487. #endif
  1488. goto Cleanup;
  1489. }
  1490. //
  1491. // Get the Dns name of the domain the DC is in
  1492. //
  1493. dwErr = DsRoleGetPrimaryDomainInformation(
  1494. &pDomainControllerInfo->DomainControllerName[2],
  1495. DsRolePrimaryDomainInfoBasic,
  1496. (PBYTE *)&pPrimaryDomainInfo);
  1497. if (dwErr != ERROR_SUCCESS) {
  1498. #if DBG
  1499. if (DfsDebug)
  1500. DbgPrint(" DsRoleGetPrimaryDomainInformation(%ws) returned %d\n",
  1501. &pDomainControllerInfo->DomainControllerName[2],
  1502. dwErr);
  1503. #endif
  1504. goto Cleanup;
  1505. }
  1506. if (pPrimaryDomainInfo->DomainNameDns == NULL) {
  1507. #if DBG
  1508. if (DfsDebug)
  1509. DbgPrint(" DomainNameDns is NULL\n");
  1510. #endif
  1511. dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO;
  1512. goto Cleanup;
  1513. }
  1514. ENTER_NETDFS_API
  1515. //
  1516. // Tell the DC to remove the server from the DS objects
  1517. //
  1518. dwErr = DfspTearDownFtDfs(
  1519. ServerName,
  1520. &pDomainControllerInfo->DomainControllerName[2],
  1521. RootShare,
  1522. FtDfsName,
  1523. Flags | DFS_FORCE_REMOVE);
  1524. if (dwErr != ERROR_SUCCESS) {
  1525. #if DBG
  1526. if (DfsDebug)
  1527. DbgPrint(" DfspTearDownFtDfs returned %d\n", dwErr);
  1528. #endif
  1529. LEAVE_NETDFS_API
  1530. goto Cleanup;
  1531. }
  1532. //
  1533. // Tell the local MUP to crack ftdfs names using the selected DC
  1534. //
  1535. DfspSetDomainToDc(
  1536. pPrimaryDomainInfo->DomainNameDns,
  1537. &pDomainControllerInfo->DomainControllerName[2]);
  1538. if (pPrimaryDomainInfo->DomainNameFlat != NULL) {
  1539. PWCHAR wCp = &pDomainControllerInfo->DomainControllerName[2];
  1540. for (; *wCp != L'\0' && *wCp != L'.'; wCp++)
  1541. /* NOTHING */;
  1542. *wCp = (*wCp == L'.') ? L'\0' : *wCp;
  1543. DfspSetDomainToDc(
  1544. pPrimaryDomainInfo->DomainNameFlat,
  1545. &pDomainControllerInfo->DomainControllerName[2]);
  1546. }
  1547. LEAVE_NETDFS_API
  1548. Cleanup:
  1549. if (pDomainControllerInfo != NULL)
  1550. NetApiBufferFree(pDomainControllerInfo);
  1551. if (pPrimaryDomainInfo != NULL)
  1552. DsRoleFreeMemory(pPrimaryDomainInfo);
  1553. if (DcName != NULL)
  1554. NetApiBufferFree(DcName);
  1555. #if DBG
  1556. if (DfsDebug)
  1557. DbgPrint("NetDfsRemoveFtRootForced returning %d\n", dwErr);
  1558. #endif
  1559. return( dwErr );
  1560. }
  1561. //+----------------------------------------------------------------------------
  1562. //
  1563. // Function: NetDfsRemoveStdRoot
  1564. //
  1565. // Synopsis: Deletes a Dfs root.
  1566. //
  1567. // Arguments: [ServerName] -- Name of server to unjoin from Dfs.
  1568. // [RootShare] -- Name of share hosting the storage.
  1569. // [Flags] -- Flags to operation
  1570. //
  1571. // Returns: [NERR_Success] -- Successfully completed operation.
  1572. //
  1573. // [ERROR_INVALID_PARAMETER] -- ServerName and/or RootShare is incorrect.
  1574. //
  1575. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  1576. //
  1577. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  1578. //
  1579. // [NERR_DfsNotALeafVolume] -- Unable to delete the volume
  1580. // because it is not a leaf volume.
  1581. //
  1582. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  1583. // encountered at the server.
  1584. //
  1585. //-----------------------------------------------------------------------------
  1586. NET_API_STATUS
  1587. NetDfsRemoveStdRoot(
  1588. IN LPWSTR ServerName,
  1589. IN LPWSTR RootShare,
  1590. IN DWORD Flags)
  1591. {
  1592. NET_API_STATUS dwErr;
  1593. #if DBG
  1594. if (DfsDebug)
  1595. DbgPrint("NetDfsRemoveStdRoot(%ws,%ws,%d)\n",
  1596. ServerName,
  1597. RootShare,
  1598. Flags);
  1599. #endif
  1600. //
  1601. // Validate the string arguments so RPC won't complain...
  1602. //
  1603. if (!IS_VALID_STRING(ServerName) ||
  1604. !IS_VALID_STRING(RootShare)) {
  1605. return( ERROR_INVALID_PARAMETER );
  1606. }
  1607. ENTER_NETDFS_API
  1608. dwErr = DfspBindToServer(ServerName, &netdfs_bhandle);
  1609. if (dwErr == NERR_Success) {
  1610. RpcTryExcept {
  1611. dwErr = NetrDfsRemoveStdRoot(
  1612. ServerName,
  1613. RootShare,
  1614. Flags);
  1615. } RpcExcept(1) {
  1616. dwErr = RpcExceptionCode();
  1617. } RpcEndExcept;
  1618. DfspFreeBinding( netdfs_bhandle );
  1619. }
  1620. LEAVE_NETDFS_API
  1621. #if DBG
  1622. if (DfsDebug)
  1623. DbgPrint("NetDfsRemoveStdRoot returning %d\n", dwErr);
  1624. #endif
  1625. return( dwErr );
  1626. }
  1627. //+----------------------------------------------------------------------------
  1628. //
  1629. // Function: NetDfsSetInfo
  1630. //
  1631. // Synopsis: Sets the comment or state of a Dfs volume or Replica.
  1632. //
  1633. // Arguments: [DfsEntryPath] -- Path to the volume. Implicityly indicates
  1634. // which server or domain to connect to.
  1635. // [ServerName] -- Optional. If specified, only the state of
  1636. // the server supporting this volume is modified.
  1637. // [ShareName] -- Optional. If specified, only the state of
  1638. // this share on the specified server is modified.
  1639. // [Level] -- Must be 100 or 101
  1640. // [Buffer] -- Pointer to DFS_INFO_100 or DFS_INFO_101
  1641. //
  1642. // Returns: [NERR_Success] -- If successfully set info.
  1643. //
  1644. // [ERROR_INVALID_LEVEL] -- Level is not 100 or 101, 102
  1645. //
  1646. // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL,
  1647. // or ShareName is specified but ServerName is not, or
  1648. // Buffer is NULL.
  1649. //
  1650. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  1651. //
  1652. // [ERROR_DCNotFound] -- Unable to locate DC for domain.
  1653. //
  1654. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  1655. //
  1656. // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
  1657. //
  1658. // [NERR_DfsNoSuchShare] -- The indicated ServerName/ShareName do
  1659. // not support this Dfs volume.
  1660. //
  1661. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  1662. // encountered at the server.
  1663. //
  1664. //-----------------------------------------------------------------------------
  1665. NET_API_STATUS NET_API_FUNCTION
  1666. NetDfsSetInfo(
  1667. IN LPWSTR DfsEntryPath,
  1668. IN LPWSTR ServerName OPTIONAL,
  1669. IN LPWSTR ShareName OPTIONAL,
  1670. IN DWORD Level,
  1671. IN LPBYTE Buffer)
  1672. {
  1673. NET_API_STATUS dwErr = NERR_Success;
  1674. LPWSTR pwszDfsName = NULL;
  1675. DWORD cwDfsEntryPath;
  1676. DFS_INFO_STRUCT DfsInfo;
  1677. #if DBG
  1678. if (DfsDebug)
  1679. DbgPrint("NetDfsSetInfo(%ws,%ws,%ws,%d)\n",
  1680. DfsEntryPath,
  1681. ServerName,
  1682. ShareName,
  1683. Level);
  1684. #endif
  1685. if (!IS_VALID_STRING(DfsEntryPath)) {
  1686. return( ERROR_INVALID_PARAMETER );
  1687. }
  1688. //
  1689. // Some elementary parameter checking to make sure we can proceed
  1690. // reasonably...
  1691. //
  1692. if (!(Level >= 100 && Level <= 102)) {
  1693. return( ERROR_INVALID_LEVEL );
  1694. }
  1695. cwDfsEntryPath = wcslen(DfsEntryPath);
  1696. if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) &&
  1697. !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) &&
  1698. !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) {
  1699. return( ERROR_INVALID_PARAMETER );
  1700. }
  1701. if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) {
  1702. return( ERROR_INVALID_PARAMETER );
  1703. }
  1704. if (Level == 101)
  1705. {
  1706. DFS_INFO_STRUCT DfsUseInfo;
  1707. DfsUseInfo.DfsInfo101 = (LPDFS_INFO_101)Buffer;
  1708. if ( (DfsUseInfo.DfsInfo101->State == DFS_VOLUME_STATE_RESYNCHRONIZE) ||
  1709. (DfsUseInfo.DfsInfo101->State == DFS_VOLUME_STATE_STANDBY) )
  1710. {
  1711. dwErr = DfspGetDfsNameFromEntryPath( DfsEntryPath,
  1712. cwDfsEntryPath,
  1713. &pwszDfsName );
  1714. }
  1715. }
  1716. if ((dwErr == NERR_Success) &&
  1717. (pwszDfsName == NULL))
  1718. {
  1719. dwErr = DfspGetMachineNameFromEntryPath(DfsEntryPath,
  1720. cwDfsEntryPath,
  1721. &pwszDfsName);
  1722. }
  1723. ENTER_NETDFS_API
  1724. if (dwErr == NERR_Success) {
  1725. //
  1726. // By now, we should have a valid pwszDfsName. Lets try to bind to it,
  1727. // and call the server.
  1728. //
  1729. dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
  1730. if (dwErr == NERR_Success) {
  1731. RpcTryExcept {
  1732. DfsInfo.DfsInfo100 = (LPDFS_INFO_100) Buffer;
  1733. dwErr = NetrDfsSetInfo(
  1734. DfsEntryPath,
  1735. ServerName,
  1736. ShareName,
  1737. Level,
  1738. &DfsInfo);
  1739. } RpcExcept( 1 ) {
  1740. dwErr = RpcExceptionCode();
  1741. } RpcEndExcept;
  1742. DfspFreeBinding( netdfs_bhandle );
  1743. }
  1744. }
  1745. LEAVE_NETDFS_API
  1746. //
  1747. // If we failed with ERROR_NOT_SUPPORTED, this is an NT5+ server,
  1748. // so we use the NetrDfsSetInfo2() call instead.
  1749. //
  1750. if (dwErr == ERROR_NOT_SUPPORTED) {
  1751. dwErr = NetpDfsSetInfo2(
  1752. pwszDfsName,
  1753. DfsEntryPath,
  1754. ServerName,
  1755. ShareName,
  1756. Level,
  1757. &DfsInfo);
  1758. }
  1759. if (pwszDfsName != NULL)
  1760. free(pwszDfsName);
  1761. #if DBG
  1762. if (DfsDebug)
  1763. DbgPrint("NetDfsSetInfo returning %d\n", dwErr);
  1764. #endif
  1765. return( dwErr );
  1766. }
  1767. DWORD
  1768. NetpDfsSetInfo2(
  1769. LPWSTR RootName,
  1770. LPWSTR DfsEntryPath,
  1771. LPWSTR ServerName,
  1772. LPWSTR ShareName,
  1773. DWORD Level,
  1774. LPDFS_INFO_STRUCT pDfsInfo)
  1775. {
  1776. NET_API_STATUS dwErr;
  1777. ULONG i;
  1778. ULONG NameCount;
  1779. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
  1780. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  1781. #if DBG
  1782. if (DfsDebug)
  1783. DbgPrint("NetpDfsSetInfo2(%ws,%ws,%ws,%ws,%d)\n",
  1784. RootName,
  1785. DfsEntryPath,
  1786. ServerName,
  1787. ShareName,
  1788. Level);
  1789. #endif
  1790. //
  1791. // Contact the server and ask for its domain name
  1792. //
  1793. dwErr = DsRoleGetPrimaryDomainInformation(
  1794. RootName,
  1795. DsRolePrimaryDomainInfoBasic,
  1796. (PBYTE *)&pPrimaryDomainInfo);
  1797. if (dwErr != ERROR_SUCCESS) {
  1798. #if DBG
  1799. if (DfsDebug)
  1800. DbgPrint("DsRoleGetPrimaryDomainInformation returned %d\n", dwErr);
  1801. #endif
  1802. goto Cleanup;
  1803. }
  1804. if (pPrimaryDomainInfo->DomainNameDns == NULL) {
  1805. #if DBG
  1806. if (DfsDebug)
  1807. DbgPrint(" DomainNameDns is NULL\n", NULL);
  1808. #endif
  1809. dwErr = ERROR_CANT_ACCESS_DOMAIN_INFO;
  1810. goto Cleanup;
  1811. }
  1812. //
  1813. // Get the PDC in that domain
  1814. //
  1815. dwErr = DsGetDcName(
  1816. NULL,
  1817. pPrimaryDomainInfo->DomainNameDns,
  1818. NULL,
  1819. NULL,
  1820. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY,
  1821. &pDomainControllerInfo);
  1822. if (dwErr != ERROR_SUCCESS) {
  1823. #if DBG
  1824. if (DfsDebug)
  1825. DbgPrint(" NetpDfsSetInfo2:DsGetDcName(%ws) returned %d\n",
  1826. pPrimaryDomainInfo->DomainNameDns,
  1827. dwErr);
  1828. #endif
  1829. goto Cleanup;
  1830. }
  1831. ENTER_NETDFS_API
  1832. //
  1833. // Call the server
  1834. //
  1835. dwErr = DfspSetInfo2(
  1836. RootName,
  1837. DfsEntryPath,
  1838. &pDomainControllerInfo->DomainControllerName[2],
  1839. ServerName,
  1840. ShareName,
  1841. Level,
  1842. pDfsInfo);
  1843. LEAVE_NETDFS_API
  1844. Cleanup:
  1845. if (pPrimaryDomainInfo != NULL)
  1846. DsRoleFreeMemory(pPrimaryDomainInfo);
  1847. if (pDomainControllerInfo != NULL)
  1848. NetApiBufferFree(pDomainControllerInfo);
  1849. #if DBG
  1850. if (DfsDebug)
  1851. DbgPrint("NetpDfsSetInfo2 returning %d\n", dwErr);
  1852. #endif
  1853. return( dwErr );
  1854. }
  1855. DWORD
  1856. DfspSetInfo2(
  1857. LPWSTR RootName,
  1858. LPWSTR EntryPath,
  1859. LPWSTR DcName,
  1860. LPWSTR ServerName,
  1861. LPWSTR ShareName,
  1862. DWORD Level,
  1863. LPDFS_INFO_STRUCT pDfsInfo)
  1864. {
  1865. DWORD dwErr;
  1866. PDFSM_ROOT_LIST RootList = NULL;
  1867. #if DBG
  1868. if (DfsDebug)
  1869. DbgPrint("DfspSetInfo2(%ws,%ws,%ws,%ws,%ws,%d)\n",
  1870. RootName,
  1871. EntryPath,
  1872. DcName,
  1873. ServerName,
  1874. ShareName,
  1875. Level);
  1876. #endif
  1877. dwErr = DfspBindRpc( RootName, &netdfs_bhandle );
  1878. if (dwErr == NERR_Success) {
  1879. RpcTryExcept {
  1880. dwErr = NetrDfsSetInfo2(
  1881. EntryPath,
  1882. DcName,
  1883. ServerName,
  1884. ShareName,
  1885. Level,
  1886. pDfsInfo,
  1887. &RootList);
  1888. } RpcExcept(1) {
  1889. dwErr = RpcExceptionCode();
  1890. } RpcEndExcept;
  1891. DfspFreeBinding( netdfs_bhandle );
  1892. }
  1893. #if DBG
  1894. if (DfsDebug) {
  1895. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  1896. ULONG n;
  1897. DbgPrint("cEntries=%d\n", RootList->cEntries);
  1898. for (n = 0; n < RootList->cEntries; n++)
  1899. DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare);
  1900. }
  1901. }
  1902. #endif
  1903. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  1904. ULONG n;
  1905. for (n = 0; n < RootList->cEntries; n++) {
  1906. DfspNotifyFtRoot(
  1907. RootList->Entry[n].ServerShare,
  1908. DcName);
  1909. }
  1910. NetApiBufferFree(RootList);
  1911. }
  1912. #if DBG
  1913. if (DfsDebug)
  1914. DbgPrint("DfspSetInfo2 returning %d\n", dwErr);
  1915. #endif
  1916. return dwErr;
  1917. }
  1918. //+----------------------------------------------------------------------------
  1919. //
  1920. // Function: NetDfsGetInfo
  1921. //
  1922. // Synopsis: Retrieves information about a particular Dfs volume.
  1923. //
  1924. // Arguments: [DfsEntryPath] -- Path to the volume. Implicitly indicates
  1925. // which server or domain to connect to.
  1926. // [ServerName] -- Optional. If specified, indicates the
  1927. // server supporting DfsEntryPath.
  1928. // [ShareName] -- Optional. If specified, indicates the share
  1929. // on ServerName for which info is desired.
  1930. // [Level] -- Indicates the level of info required.
  1931. // [Buffer] -- On successful return, will contain the buffer
  1932. // containing the required Info. This buffer should be
  1933. // freed using NetApiBufferFree.
  1934. //
  1935. // Returns: [NERR_Success] -- Info successfully returned.
  1936. //
  1937. // [ERROR_INVALID_LEVEL] -- Level is not 1,2,3 or 100
  1938. //
  1939. // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL,
  1940. // or ShareName is specified but ServerName is NULL.
  1941. //
  1942. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  1943. //
  1944. // [ERROR_DCNotFound] -- Unable to locate DC for domain.
  1945. //
  1946. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  1947. //
  1948. // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
  1949. //
  1950. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  1951. // encountered at the server.
  1952. //
  1953. //-----------------------------------------------------------------------------
  1954. NET_API_STATUS NET_API_FUNCTION
  1955. NetDfsGetInfo(
  1956. IN LPWSTR DfsEntryPath,
  1957. IN LPWSTR ServerName OPTIONAL,
  1958. IN LPWSTR ShareName OPTIONAL,
  1959. IN DWORD Level,
  1960. OUT LPBYTE* Buffer)
  1961. {
  1962. NET_API_STATUS dwErr;
  1963. LPWSTR pwszDfsName;
  1964. DWORD cwDfsEntryPath;
  1965. DFS_INFO_STRUCT DfsInfo;
  1966. #if DBG
  1967. if (DfsDebug)
  1968. DbgPrint("NetDfsGetInfo(%ws,%ws,%ws,%d)\n",
  1969. DfsEntryPath,
  1970. ServerName,
  1971. ShareName,
  1972. Level);
  1973. #endif
  1974. if (!IS_VALID_STRING(DfsEntryPath)) {
  1975. return( ERROR_INVALID_PARAMETER );
  1976. }
  1977. //
  1978. // Some elementary parameter checking to make sure we can proceed
  1979. // reasonably...
  1980. //
  1981. if (!(Level >= 1 && Level <= 4) && Level != 100) {
  1982. return( ERROR_INVALID_LEVEL );
  1983. }
  1984. cwDfsEntryPath = wcslen(DfsEntryPath);
  1985. if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) &&
  1986. !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) &&
  1987. !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) {
  1988. return( ERROR_INVALID_PARAMETER );
  1989. }
  1990. if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) {
  1991. return( ERROR_INVALID_PARAMETER );
  1992. }
  1993. dwErr = DfspGetMachineNameFromEntryPath(
  1994. DfsEntryPath,
  1995. cwDfsEntryPath,
  1996. &pwszDfsName);
  1997. ENTER_NETDFS_API
  1998. if (dwErr == NERR_Success) {
  1999. //
  2000. // By now, we should have a valid pwszDfsName. Lets try to bind to it,
  2001. // and call the server.
  2002. //
  2003. dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
  2004. if (dwErr == NERR_Success) {
  2005. RpcTryExcept {
  2006. DfsInfo.DfsInfo1 = NULL;
  2007. dwErr = NetrDfsGetInfo(
  2008. DfsEntryPath,
  2009. ServerName,
  2010. ShareName,
  2011. Level,
  2012. &DfsInfo);
  2013. if (dwErr == NERR_Success) {
  2014. *Buffer = (LPBYTE) DfsInfo.DfsInfo1;
  2015. }
  2016. } RpcExcept( 1 ) {
  2017. dwErr = RpcExceptionCode();
  2018. } RpcEndExcept;
  2019. DfspFreeBinding( netdfs_bhandle );
  2020. }
  2021. free( pwszDfsName );
  2022. }
  2023. LEAVE_NETDFS_API
  2024. #if DBG
  2025. if (DfsDebug)
  2026. DbgPrint("NetDfsGetInfo returning %d\n", dwErr);
  2027. #endif
  2028. return( dwErr );
  2029. }
  2030. //+----------------------------------------------------------------------------
  2031. //
  2032. // Function: NetDfsGetClientInfo
  2033. //
  2034. // Synopsis: Retrieves information about a particular Dfs volume, from the
  2035. // local PKT.
  2036. //
  2037. // Arguments: [DfsEntryPath] -- Path to the volume.
  2038. // [ServerName] -- Optional. If specified, indicates the
  2039. // server supporting DfsEntryPath.
  2040. // [ShareName] -- Optional. If specified, indicates the share
  2041. // on ServerName for which info is desired.
  2042. // [Level] -- Indicates the level of info required.
  2043. // [Buffer] -- On successful return, will contain the buffer
  2044. // containing the required Info. This buffer should be
  2045. // freed using NetApiBufferFree.
  2046. //
  2047. // Returns: [NERR_Success] -- Info successfully returned.
  2048. //
  2049. // [ERROR_INVALID_LEVEL] -- Level is not 1,2,3 or 4.
  2050. //
  2051. // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL,
  2052. // or ShareName is specified but ServerName is NULL.
  2053. //
  2054. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  2055. //
  2056. // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
  2057. //
  2058. // [NERR_DfsInternalError] -- Too many fsctrl attempts
  2059. //
  2060. //-----------------------------------------------------------------------------
  2061. NET_API_STATUS NET_API_FUNCTION
  2062. NetDfsGetClientInfo(
  2063. IN LPWSTR DfsEntryPath,
  2064. IN LPWSTR ServerName OPTIONAL,
  2065. IN LPWSTR ShareName OPTIONAL,
  2066. IN DWORD Level,
  2067. OUT LPBYTE* Buffer)
  2068. {
  2069. NET_API_STATUS dwErr;
  2070. NTSTATUS NtStatus;
  2071. LPWSTR pwszDfsName;
  2072. DWORD cwDfsEntryPath;
  2073. PDFS_GET_PKT_ENTRY_STATE_ARG OutBuffer;
  2074. HANDLE DriverHandle = NULL;
  2075. IO_STATUS_BLOCK IoStatusBlock;
  2076. OBJECT_ATTRIBUTES objectAttributes;
  2077. UNICODE_STRING DfsDriverName;
  2078. ULONG cbOutBuffer;
  2079. ULONG cbInBuffer;
  2080. PCHAR InBuffer;
  2081. ULONG cRetries;
  2082. #if DBG
  2083. if (DfsDebug)
  2084. DbgPrint("NetDfsGetClientInfo(%ws,%ws,%ws,%d)\n",
  2085. DfsEntryPath,
  2086. ServerName,
  2087. ShareName,
  2088. Level);
  2089. #endif
  2090. if (!IS_VALID_STRING(DfsEntryPath)) {
  2091. return( ERROR_INVALID_PARAMETER );
  2092. }
  2093. //
  2094. // Some elementary parameter checking to make sure we can proceed
  2095. // reasonably...
  2096. //
  2097. if (!(Level >= 1 && Level <= 4)) {
  2098. return( ERROR_INVALID_LEVEL );
  2099. }
  2100. cwDfsEntryPath = wcslen(DfsEntryPath);
  2101. if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) &&
  2102. !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) &&
  2103. !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) {
  2104. return( ERROR_INVALID_PARAMETER );
  2105. }
  2106. if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) {
  2107. return( ERROR_INVALID_PARAMETER );
  2108. }
  2109. //
  2110. // Calculate the size of the marshall buffer
  2111. cbOutBuffer = sizeof(DFS_GET_PKT_ENTRY_STATE_ARG) +
  2112. wcslen(DfsEntryPath) * sizeof(WCHAR);
  2113. if (ServerName) {
  2114. cbOutBuffer += wcslen(ServerName) * sizeof(WCHAR);
  2115. }
  2116. if (ShareName) {
  2117. cbOutBuffer += wcslen(ShareName) * sizeof(WCHAR);
  2118. }
  2119. OutBuffer = malloc(cbOutBuffer);
  2120. if (OutBuffer == NULL) {
  2121. return (ERROR_NOT_ENOUGH_MEMORY);
  2122. }
  2123. ZeroMemory(OutBuffer, cbOutBuffer);
  2124. //
  2125. // marshall the args
  2126. //
  2127. OutBuffer->DfsEntryPathLen = wcslen(DfsEntryPath) * sizeof(WCHAR);
  2128. wcscpy(OutBuffer->Buffer, DfsEntryPath);
  2129. if (ServerName) {
  2130. OutBuffer->ServerNameLen = wcslen(ServerName) * sizeof(WCHAR);
  2131. wcscat(OutBuffer->Buffer, ServerName);
  2132. }
  2133. if (ShareName) {
  2134. OutBuffer->ShareNameLen = wcslen(ShareName) * sizeof(WCHAR);
  2135. wcscat(OutBuffer->Buffer, ShareName);
  2136. }
  2137. //
  2138. // Construct name for opening driver
  2139. //
  2140. RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
  2141. InitializeObjectAttributes(
  2142. &objectAttributes,
  2143. &DfsDriverName,
  2144. OBJ_CASE_INSENSITIVE,
  2145. NULL,
  2146. NULL
  2147. );
  2148. //
  2149. // Open the driver
  2150. //
  2151. NtStatus = NtCreateFile(
  2152. &DriverHandle,
  2153. SYNCHRONIZE,
  2154. &objectAttributes,
  2155. &IoStatusBlock,
  2156. NULL,
  2157. FILE_ATTRIBUTE_NORMAL,
  2158. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2159. FILE_OPEN_IF,
  2160. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  2161. NULL,
  2162. 0
  2163. );
  2164. if (NT_SUCCESS(NtStatus)) {
  2165. //
  2166. // Now fsctl the request down
  2167. //
  2168. OutBuffer->Level = Level;
  2169. cbInBuffer = 0x400;
  2170. NtStatus = STATUS_BUFFER_OVERFLOW;
  2171. for (cRetries = 0;
  2172. NtStatus == STATUS_BUFFER_OVERFLOW && cRetries < 4;
  2173. cRetries++) {
  2174. dwErr = NetApiBufferAllocate(cbInBuffer, &InBuffer);
  2175. if (dwErr != ERROR_SUCCESS) {
  2176. free(OutBuffer);
  2177. NtClose(DriverHandle);
  2178. return(ERROR_NOT_ENOUGH_MEMORY);
  2179. }
  2180. NtStatus = NtFsControlFile(
  2181. DriverHandle,
  2182. NULL, // Event,
  2183. NULL, // ApcRoutine,
  2184. NULL, // ApcContext,
  2185. &IoStatusBlock,
  2186. FSCTL_DFS_GET_PKT_ENTRY_STATE,
  2187. OutBuffer,
  2188. cbOutBuffer,
  2189. InBuffer,
  2190. cbInBuffer
  2191. );
  2192. if (NtStatus == STATUS_BUFFER_OVERFLOW) {
  2193. cbInBuffer = *((PULONG)InBuffer);
  2194. NetApiBufferFree(InBuffer);
  2195. }
  2196. }
  2197. NtClose(DriverHandle);
  2198. //
  2199. // Too many attempts?
  2200. //
  2201. if (cRetries >= 4) {
  2202. NtStatus = STATUS_INTERNAL_ERROR;
  2203. }
  2204. }
  2205. if (NT_SUCCESS(NtStatus)) {
  2206. PDFS_INFO_3 pDfsInfo3;
  2207. PDFS_INFO_4 pDfsInfo4;
  2208. ULONG j;
  2209. pDfsInfo4 = (PDFS_INFO_4)InBuffer;
  2210. pDfsInfo3 = (PDFS_INFO_3)InBuffer;
  2211. try {
  2212. //
  2213. // EntryPath is common to all DFS_INFO_X's and is in the
  2214. // same location.
  2215. //
  2216. OFFSET_TO_POINTER(pDfsInfo4->EntryPath, InBuffer);
  2217. switch (Level) {
  2218. case 4:
  2219. OFFSET_TO_POINTER(pDfsInfo4->Storage, InBuffer);
  2220. for (j = 0; j < pDfsInfo4->NumberOfStorages; j++) {
  2221. OFFSET_TO_POINTER(pDfsInfo4->Storage[j].ServerName, InBuffer);
  2222. OFFSET_TO_POINTER(pDfsInfo4->Storage[j].ShareName, InBuffer);
  2223. }
  2224. break;
  2225. case 3:
  2226. OFFSET_TO_POINTER(pDfsInfo3->Storage, InBuffer);
  2227. for (j = 0; j < pDfsInfo3->NumberOfStorages; j++) {
  2228. OFFSET_TO_POINTER(pDfsInfo3->Storage[j].ServerName, InBuffer);
  2229. OFFSET_TO_POINTER(pDfsInfo3->Storage[j].ShareName, InBuffer);
  2230. }
  2231. }
  2232. *Buffer = (PBYTE)InBuffer;
  2233. dwErr = NERR_Success;
  2234. } except (EXCEPTION_EXECUTE_HANDLER) {
  2235. NtStatus = GetExceptionCode();
  2236. }
  2237. }
  2238. switch (NtStatus) {
  2239. case STATUS_SUCCESS:
  2240. dwErr = NERR_Success;
  2241. break;
  2242. case STATUS_OBJECT_NAME_NOT_FOUND:
  2243. dwErr = NERR_DfsNoSuchVolume;
  2244. NetApiBufferFree(InBuffer);
  2245. break;
  2246. case STATUS_INTERNAL_ERROR:
  2247. dwErr = NERR_DfsInternalError;
  2248. NetApiBufferFree(InBuffer);
  2249. break;
  2250. default:
  2251. dwErr = ERROR_INVALID_PARAMETER;
  2252. NetApiBufferFree(InBuffer);
  2253. break;
  2254. }
  2255. free(OutBuffer);
  2256. #if DBG
  2257. if (DfsDebug)
  2258. DbgPrint("NetDfsGetClientInfo returning %d\n", dwErr);
  2259. #endif
  2260. return( dwErr );
  2261. }
  2262. //+----------------------------------------------------------------------------
  2263. //
  2264. // Function: NetDfsSetClientInfo
  2265. //
  2266. // Synopsis: Associates information with the local PKT.
  2267. //
  2268. //
  2269. // Arguments: [DfsEntryPath] -- Path to the volume.
  2270. // [ServerName] -- Optional. If specified, indicates the
  2271. // server supporting DfsEntryPath.
  2272. // [ShareName] -- Optional. If specified, indicates the share
  2273. // on ServerName for which info is desired.
  2274. // [Level] -- Indicates the level of info required.
  2275. // [Buffer] -- Pointer to buffer containing information to set.
  2276. //
  2277. // Returns: [NERR_Success] -- Info successfully returned.
  2278. //
  2279. // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath is NULL,
  2280. // or ShareName is specified but ServerName is NULL.
  2281. //
  2282. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  2283. //
  2284. // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
  2285. //
  2286. //-----------------------------------------------------------------------------
  2287. NET_API_STATUS NET_API_FUNCTION
  2288. NetDfsSetClientInfo(
  2289. IN LPWSTR DfsEntryPath,
  2290. IN LPWSTR ServerName OPTIONAL,
  2291. IN LPWSTR ShareName OPTIONAL,
  2292. IN DWORD Level,
  2293. IN LPBYTE Buffer)
  2294. {
  2295. NET_API_STATUS dwErr;
  2296. NTSTATUS NtStatus;
  2297. LPWSTR pwszDfsName;
  2298. DWORD cwDfsEntryPath;
  2299. PDFS_SET_PKT_ENTRY_STATE_ARG OutBuffer;
  2300. PDFS_INFO_101 pDfsInfo101;
  2301. PDFS_INFO_102 pDfsInfo102;
  2302. HANDLE DriverHandle = NULL;
  2303. IO_STATUS_BLOCK IoStatusBlock;
  2304. OBJECT_ATTRIBUTES objectAttributes;
  2305. UNICODE_STRING DfsDriverName;
  2306. ULONG cbOutBuffer;
  2307. #if DBG
  2308. if (DfsDebug)
  2309. DbgPrint("NetDfsSetClientInfo(%ws,%ws,%ws,%d)\n",
  2310. DfsEntryPath,
  2311. ServerName,
  2312. ShareName,
  2313. Level);
  2314. #endif
  2315. if (!IS_VALID_STRING(DfsEntryPath)) {
  2316. return( ERROR_INVALID_PARAMETER );
  2317. }
  2318. //
  2319. // Some elementary parameter checking to make sure we can proceed
  2320. // reasonably...
  2321. //
  2322. if (!(Level >= 101 && Level <= 102)) {
  2323. return( ERROR_INVALID_LEVEL );
  2324. }
  2325. cwDfsEntryPath = wcslen(DfsEntryPath);
  2326. if (!IS_UNC_PATH(DfsEntryPath, cwDfsEntryPath) &&
  2327. !IS_VALID_PREFIX(DfsEntryPath, cwDfsEntryPath) &&
  2328. !IS_VALID_DFS_PATH(DfsEntryPath, cwDfsEntryPath)) {
  2329. return( ERROR_INVALID_PARAMETER );
  2330. }
  2331. if (!IS_VALID_STRING(ServerName) && IS_VALID_STRING(ShareName)) {
  2332. return( ERROR_INVALID_PARAMETER );
  2333. }
  2334. if (Buffer == NULL) {
  2335. return( ERROR_INVALID_PARAMETER );
  2336. }
  2337. //
  2338. // Calculate the size of the marshall buffer
  2339. //
  2340. cbOutBuffer = sizeof(DFS_SET_PKT_ENTRY_STATE_ARG) +
  2341. wcslen(DfsEntryPath) * sizeof(WCHAR);
  2342. if (ServerName) {
  2343. cbOutBuffer += wcslen(ServerName) * sizeof(WCHAR);
  2344. }
  2345. if (ShareName) {
  2346. cbOutBuffer += wcslen(ShareName) * sizeof(WCHAR);
  2347. }
  2348. OutBuffer = malloc(cbOutBuffer);
  2349. if (OutBuffer == NULL) {
  2350. return (ERROR_NOT_ENOUGH_MEMORY);
  2351. }
  2352. ZeroMemory(OutBuffer, cbOutBuffer);
  2353. //
  2354. // marshall the args
  2355. //
  2356. OutBuffer = (PDFS_SET_PKT_ENTRY_STATE_ARG) OutBuffer;
  2357. OutBuffer->DfsEntryPathLen = wcslen(DfsEntryPath) * sizeof(WCHAR);
  2358. wcscpy(OutBuffer->Buffer, DfsEntryPath);
  2359. OutBuffer->Level = Level;
  2360. if (ServerName) {
  2361. OutBuffer->ServerNameLen = wcslen(ServerName) * sizeof(WCHAR);
  2362. wcscat(OutBuffer->Buffer, ServerName);
  2363. }
  2364. if (ShareName) {
  2365. OutBuffer->ShareNameLen = wcslen(ShareName) * sizeof(WCHAR);
  2366. wcscat(OutBuffer->Buffer, ShareName);
  2367. }
  2368. switch (Level) {
  2369. case 101:
  2370. OutBuffer->State = ((PDFS_INFO_101)Buffer)->State;
  2371. break;
  2372. case 102:
  2373. OutBuffer->Timeout = (DWORD)((PDFS_INFO_102)Buffer)->Timeout;
  2374. break;
  2375. }
  2376. //
  2377. // Communicate with the driver
  2378. //
  2379. RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
  2380. InitializeObjectAttributes(
  2381. &objectAttributes,
  2382. &DfsDriverName,
  2383. OBJ_CASE_INSENSITIVE,
  2384. NULL,
  2385. NULL
  2386. );
  2387. NtStatus = NtCreateFile(
  2388. &DriverHandle,
  2389. SYNCHRONIZE | FILE_WRITE_DATA,
  2390. &objectAttributes,
  2391. &IoStatusBlock,
  2392. NULL,
  2393. FILE_ATTRIBUTE_NORMAL,
  2394. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2395. FILE_OPEN_IF,
  2396. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  2397. NULL,
  2398. 0
  2399. );
  2400. if (NT_SUCCESS(NtStatus)) {
  2401. NtStatus = NtFsControlFile(
  2402. DriverHandle,
  2403. NULL, // Event,
  2404. NULL, // ApcRoutine,
  2405. NULL, // ApcContext,
  2406. &IoStatusBlock,
  2407. FSCTL_DFS_SET_PKT_ENTRY_STATE,
  2408. OutBuffer,
  2409. cbOutBuffer,
  2410. NULL,
  2411. 0
  2412. );
  2413. NtClose(DriverHandle);
  2414. }
  2415. switch (NtStatus) {
  2416. case STATUS_SUCCESS:
  2417. dwErr = NERR_Success;
  2418. break;
  2419. case STATUS_OBJECT_NAME_NOT_FOUND:
  2420. dwErr = NERR_DfsNoSuchVolume;
  2421. break;
  2422. default:
  2423. dwErr = ERROR_INVALID_PARAMETER;
  2424. break;
  2425. }
  2426. free(OutBuffer);
  2427. #if DBG
  2428. if (DfsDebug)
  2429. DbgPrint("NetDfsSetClientInfo returning %d\n", dwErr);
  2430. #endif
  2431. return( dwErr );
  2432. }
  2433. //+----------------------------------------------------------------------------
  2434. //
  2435. // Function
  2436. //
  2437. // Synopsis: Enumerates the Dfs volumes.
  2438. //
  2439. // Arguments: [DfsName] -- Name of server or domain whose Dfs is being
  2440. // enumerated. A leading \\ is optional.
  2441. // [Level] -- Indicates the level of info needed back. Valid
  2442. // Levels are 1,2, and 3.
  2443. // [PrefMaxLen] -- Preferred maximum length of return buffer.
  2444. // [Buffer] -- On successful return, contains an array of
  2445. // DFS_INFO_X. This buffer should be freed with a call
  2446. // to NetApiBufferFree.
  2447. // [EntriesRead] -- On successful return, contains the number
  2448. // of entries read (and therefore, size of the array in
  2449. // Buffer).
  2450. // [ResumeHandle] -- Must be 0 on first call. On subsequent calls
  2451. // the value returned by the immediately preceding call.
  2452. //
  2453. // Returns: [NERR_Success] -- Enum data successfully returned.
  2454. //
  2455. // [ERROR_INVALID_LEVEL] -- The Level specified in invalid.
  2456. //
  2457. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  2458. //
  2459. // [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
  2460. //
  2461. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  2462. //
  2463. // [ERROR_NO_MORE_ITEMS] -- No more volumes to be enumerated.
  2464. //
  2465. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  2466. // encountered at the server.
  2467. //
  2468. //-----------------------------------------------------------------------------
  2469. NET_API_STATUS NET_API_FUNCTION
  2470. NetDfsEnum(
  2471. IN LPWSTR DfsName,
  2472. IN DWORD Level,
  2473. IN DWORD PrefMaxLen,
  2474. OUT LPBYTE* Buffer,
  2475. OUT LPDWORD EntriesRead,
  2476. IN OUT LPDWORD ResumeHandle)
  2477. {
  2478. NET_API_STATUS dwErr;
  2479. LPWSTR pwszMachineName = NULL;
  2480. LPWSTR pwszDomainName = NULL;
  2481. DFS_INFO_ENUM_STRUCT DfsEnum;
  2482. DFS_INFO_3_CONTAINER DfsInfo3Container;
  2483. PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
  2484. PWCHAR DCList;
  2485. DWORD Version;
  2486. #if DBG
  2487. if (DfsDebug)
  2488. DbgPrint("NetDfsEnum(%ws, %d)\n", DfsName, Level);
  2489. #endif
  2490. if (!IS_VALID_STRING(DfsName)) {
  2491. dwErr = ERROR_INVALID_PARAMETER;
  2492. goto AllDone;
  2493. }
  2494. //
  2495. // Check the Level Parameter first, or RPC won't know how to marshal the
  2496. // arguments.
  2497. //
  2498. if (!(Level >= 1 && Level <= 4) && (Level != 200) && (Level != 300)) {
  2499. dwErr = ERROR_INVALID_LEVEL;
  2500. goto AllDone;
  2501. }
  2502. //
  2503. // Handle names with leading '\\'
  2504. //
  2505. while (*DfsName == L'\\') {
  2506. DfsName++;
  2507. }
  2508. DfsInfo3Container.EntriesRead = 0;
  2509. DfsInfo3Container.Buffer = NULL;
  2510. DfsEnum.Level = Level;
  2511. DfsEnum.DfsInfoContainer.DfsInfo3Container = &DfsInfo3Container;
  2512. if (Level == 200)
  2513. {
  2514. if (wcschr(DfsName, L'\\') == NULL)
  2515. {
  2516. //
  2517. // Use the PDC to enum
  2518. //
  2519. dwErr = DsGetDcName( NULL,
  2520. DfsName,
  2521. NULL,
  2522. NULL,
  2523. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY,
  2524. &pDomainControllerInfo);
  2525. ENTER_NETDFS_API
  2526. if (dwErr == NERR_Success)
  2527. {
  2528. dwErr = DfspBindRpc(&pDomainControllerInfo->DomainControllerName[2],
  2529. &netdfs_bhandle);
  2530. }
  2531. if (dwErr == NERR_Success)
  2532. {
  2533. RpcTryExcept {
  2534. dwErr = NetrDfsEnumEx( DfsName,
  2535. Level,
  2536. PrefMaxLen,
  2537. &DfsEnum,
  2538. ResumeHandle);
  2539. #if DBG
  2540. if (DfsDebug)
  2541. DbgPrint("NetrDfsEnumEx returned %d\n", dwErr);
  2542. #endif
  2543. if (dwErr == NERR_Success) {
  2544. *EntriesRead =DfsInfo3Container.EntriesRead;
  2545. *Buffer = (LPBYTE) DfsInfo3Container.Buffer;
  2546. }
  2547. if (dwErr == ERROR_UNEXP_NET_ERR)
  2548. {
  2549. dwErr = ERROR_NO_MORE_ITEMS;
  2550. }
  2551. } RpcExcept( 1 ) {
  2552. dwErr = RpcExceptionCode();
  2553. } RpcEndExcept;
  2554. DfspFreeBinding( netdfs_bhandle );
  2555. }
  2556. LEAVE_NETDFS_API
  2557. }
  2558. else
  2559. {
  2560. dwErr = ERROR_INVALID_PARAMETER;
  2561. }
  2562. }
  2563. else
  2564. {
  2565. dwErr = DfspGetMachineNameFromEntryPath(
  2566. DfsName,
  2567. wcslen(DfsName),
  2568. &pwszMachineName );
  2569. ENTER_NETDFS_API
  2570. if (dwErr == NERR_Success) {
  2571. dwErr = DfspBindRpc( pwszMachineName, &netdfs_bhandle );
  2572. }
  2573. #if DBG
  2574. if (DfsDebug)
  2575. DbgPrint("DfspBindRpc returned %d\n", dwErr);
  2576. #endif
  2577. if (dwErr == NERR_Success) {
  2578. RpcTryExcept {
  2579. Version = NetrDfsManagerGetVersion();
  2580. } RpcExcept( 1 ) {
  2581. Version = 3;
  2582. } RpcEndExcept;
  2583. RpcTryExcept {
  2584. #if DBG
  2585. if (DfsDebug)
  2586. DbgPrint("Calling NetrDfsEnumEx (%d)\n", Level);
  2587. #endif
  2588. if (Version >= 4)
  2589. {
  2590. dwErr = NetrDfsEnumEx( DfsName,
  2591. Level,
  2592. PrefMaxLen,
  2593. &DfsEnum,
  2594. ResumeHandle );
  2595. }
  2596. else
  2597. {
  2598. dwErr = NetrDfsEnum( Level,
  2599. PrefMaxLen,
  2600. &DfsEnum,
  2601. ResumeHandle );
  2602. }
  2603. }
  2604. RpcExcept( 1 ) {
  2605. dwErr = RpcExceptionCode();
  2606. #if DBG
  2607. if (DfsDebug)
  2608. DbgPrint("RpcExeptionCode() err %d\n", dwErr);
  2609. #endif
  2610. } RpcEndExcept;
  2611. if (dwErr == NERR_Success) {
  2612. *EntriesRead =DfsInfo3Container.EntriesRead;
  2613. *Buffer = (LPBYTE) DfsInfo3Container.Buffer;
  2614. }
  2615. DfspFreeBinding( netdfs_bhandle );
  2616. }
  2617. LEAVE_NETDFS_API
  2618. }
  2619. AllDone:
  2620. if (pDomainControllerInfo != NULL)
  2621. NetApiBufferFree(pDomainControllerInfo);
  2622. if (pwszMachineName != NULL)
  2623. free(pwszMachineName);
  2624. if (pwszDomainName != NULL)
  2625. free(pwszDomainName);
  2626. #if DBG
  2627. if (DfsDebug)
  2628. DbgPrint("NetDfsEnum returning %d\n", dwErr);
  2629. #endif
  2630. return( dwErr );
  2631. }
  2632. //+----------------------------------------------------------------------------
  2633. //
  2634. // Function: NetDfsMove
  2635. //
  2636. // Synopsis: Moves a dfs volume to a new place in the Dfs hierarchy.
  2637. //
  2638. // Arguments: [DfsEntryPath] -- Current path to the volume.
  2639. // [NewDfsEntryPath] -- Desired new path to the volume.
  2640. //
  2641. // Returns: [NERR_Success] -- Info successfully returned.
  2642. //
  2643. // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath or
  2644. // NewDfsEntryPath are not valid.
  2645. //
  2646. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  2647. //
  2648. // [ERROR_DCNotFound] -- Unable to locate DC for domain.
  2649. //
  2650. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  2651. //
  2652. // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
  2653. //
  2654. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  2655. // encountered at the server.
  2656. //
  2657. //-----------------------------------------------------------------------------
  2658. NET_API_STATUS
  2659. NetDfsMove(
  2660. IN LPWSTR DfsEntryPath,
  2661. IN LPWSTR NewDfsEntryPath)
  2662. {
  2663. NET_API_STATUS dwErr;
  2664. DWORD cwEntryPath;
  2665. LPWSTR pwszDfsName;
  2666. return ERROR_NOT_SUPPORTED;
  2667. }
  2668. //+----------------------------------------------------------------------------
  2669. //
  2670. // Function: NetDfsRename
  2671. //
  2672. // Synopsis: Renames a path that is along a Dfs Volume Entry Path
  2673. //
  2674. // Arguments: [Path] -- Current path.
  2675. // [NewPath] -- Desired new path.
  2676. //
  2677. // Returns: [NERR_Success] -- Info successfully returned.
  2678. //
  2679. // [ERROR_INVALID_PARAMETER] -- Either DfsEntryPath or
  2680. // NewDfsEntryPath are not valid.
  2681. //
  2682. // [ERROR_INVALID_NAME] -- Unable to locate server or domain.
  2683. //
  2684. // [ERROR_DCNotFound] -- Unable to locate DC for domain.
  2685. //
  2686. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  2687. //
  2688. // [NERR_DfsNoSuchVolume] -- No volume matches DfsEntryPath.
  2689. //
  2690. // [NERR_DfsInternalCorruption] -- Corruption of Dfs data
  2691. // encountered at the server.
  2692. //
  2693. //-----------------------------------------------------------------------------
  2694. NET_API_STATUS
  2695. NetDfsRename(
  2696. IN LPWSTR Path,
  2697. IN LPWSTR NewPath)
  2698. {
  2699. NET_API_STATUS dwErr;
  2700. DWORD cwPath;
  2701. LPWSTR pwszDfsName;
  2702. return ERROR_NOT_SUPPORTED;
  2703. }
  2704. //+----------------------------------------------------------------------------
  2705. //
  2706. // Function: NetDfsManagerGetConfigInfo
  2707. //
  2708. // Synopsis: Given a DfsEntryPath and Guid of a local volume, this api
  2709. // remotes to the root server of the entry path and retrieves
  2710. // the config info from it.
  2711. //
  2712. // Arguments: [wszServer] -- Name of local machine
  2713. // [wszLocalVolumeEntryPath] -- Entry Path of local volume.
  2714. // [guidLocalVolume] -- Guid of local volume.
  2715. // [ppDfsmRelationInfo] -- On successful return, contains pointer
  2716. // to config info at the root server. Free using
  2717. // NetApiBufferFree.
  2718. //
  2719. // Returns: [NERR_Success] -- Info returned successfully.
  2720. //
  2721. // [ERROR_INVALID_PARAMETER] -- wszLocalVolumeEntryPath is
  2722. // invalid.
  2723. //
  2724. // [ERROR_INVALID_NAME] -- Unable to parse out server/domain name
  2725. // from wszLocalVolumeEntryPath
  2726. //
  2727. // [ERROR_DCNotFound] -- Unable to locate a DC for domain
  2728. //
  2729. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition
  2730. //
  2731. // [NERR_DfsNoSuchVolume] -- The root server did not recognize
  2732. // a volume with this guid/entrypath
  2733. //
  2734. // [NERR_DfsNoSuchServer] -- wszServer is not a valid server for
  2735. // wszLocalVolumeEntryPath
  2736. //
  2737. //-----------------------------------------------------------------------------
  2738. NET_API_STATUS
  2739. NetDfsManagerGetConfigInfo(
  2740. LPWSTR wszServer,
  2741. LPWSTR wszLocalVolumeEntryPath,
  2742. GUID guidLocalVolume,
  2743. LPDFSM_RELATION_INFO *ppDfsmRelationInfo)
  2744. {
  2745. NET_API_STATUS dwErr;
  2746. LPWSTR pwszDfsName = NULL;
  2747. DWORD cwDfsEntryPath;
  2748. #if DBG
  2749. if (DfsDebug)
  2750. DbgPrint("NetDfsManagerGetConfigInfo(%ws,%ws)\n",
  2751. wszServer,
  2752. wszLocalVolumeEntryPath);
  2753. #endif
  2754. if (!IS_VALID_STRING(wszServer) ||
  2755. !IS_VALID_STRING(wszLocalVolumeEntryPath)) {
  2756. return( ERROR_INVALID_PARAMETER );
  2757. }
  2758. //
  2759. // Some elementary parameter checking to make sure we can proceed
  2760. // reasonably...
  2761. //
  2762. cwDfsEntryPath = wcslen(wszLocalVolumeEntryPath);
  2763. if (!IS_UNC_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath) &&
  2764. !IS_VALID_PREFIX(wszLocalVolumeEntryPath, cwDfsEntryPath) &&
  2765. !IS_VALID_DFS_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath)) {
  2766. return( ERROR_INVALID_PARAMETER );
  2767. }
  2768. dwErr = DfspGetMachineNameFromEntryPath(
  2769. wszLocalVolumeEntryPath,
  2770. cwDfsEntryPath,
  2771. &pwszDfsName);
  2772. ENTER_NETDFS_API
  2773. if (dwErr == NERR_Success) {
  2774. //
  2775. // By now, we should have a valid pwszDfsName. Lets try to bind to it,
  2776. // and call the server.
  2777. //
  2778. dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
  2779. if (dwErr == NERR_Success) {
  2780. RpcTryExcept {
  2781. *ppDfsmRelationInfo = NULL;
  2782. dwErr = NetrDfsManagerGetConfigInfo(
  2783. wszServer,
  2784. wszLocalVolumeEntryPath,
  2785. guidLocalVolume,
  2786. ppDfsmRelationInfo);
  2787. } RpcExcept( 1 ) {
  2788. dwErr = RpcExceptionCode();
  2789. } RpcEndExcept;
  2790. DfspFreeBinding( netdfs_bhandle );
  2791. }
  2792. free( pwszDfsName );
  2793. }
  2794. LEAVE_NETDFS_API
  2795. #if DBG
  2796. if (DfsDebug)
  2797. DbgPrint("NetDfsManagerGetConfigInfo returning %d\n", dwErr);
  2798. #endif
  2799. return( dwErr );
  2800. }
  2801. //+----------------------------------------------------------------------------
  2802. //
  2803. // Function: NetDfsManagerInitialize
  2804. //
  2805. // Synopsis: Reinitialize the Dfs Manager on a remote machine
  2806. //
  2807. // Arguments: [ServerName] -- Name of server to remote to
  2808. // [Flags] -- Flags
  2809. //
  2810. // Returns: [NERR_Success] -- Successfully completed operation.
  2811. //
  2812. //-----------------------------------------------------------------------------
  2813. NET_API_STATUS
  2814. NetDfsManagerInitialize(
  2815. IN LPWSTR ServerName,
  2816. IN DWORD Flags)
  2817. {
  2818. NET_API_STATUS dwErr;
  2819. #if DBG
  2820. if (DfsDebug)
  2821. DbgPrint("NetDfsManagerInitialize(%ws,%d)\n",
  2822. ServerName,
  2823. Flags);
  2824. #endif
  2825. //
  2826. // Validate the string argument so RPC won't complain...
  2827. //
  2828. if (!IS_VALID_STRING(ServerName)) {
  2829. return( ERROR_INVALID_PARAMETER );
  2830. }
  2831. ENTER_NETDFS_API
  2832. //
  2833. // We should have a valid ServerName. Lets try to bind to it,
  2834. // and call the server.
  2835. //
  2836. dwErr = DfspBindToServer( ServerName, &netdfs_bhandle );
  2837. if (dwErr == NERR_Success) {
  2838. RpcTryExcept {
  2839. dwErr = NetrDfsManagerInitialize(
  2840. ServerName,
  2841. Flags);
  2842. } RpcExcept(1) {
  2843. dwErr = RpcExceptionCode();
  2844. } RpcEndExcept;
  2845. DfspFreeBinding( netdfs_bhandle );
  2846. }
  2847. LEAVE_NETDFS_API
  2848. #if DBG
  2849. if (DfsDebug)
  2850. DbgPrint("NetDfsManagerInitialize returning %d\n", dwErr);
  2851. #endif
  2852. return( dwErr );
  2853. }
  2854. //+----------------------------------------------------------------------------
  2855. //
  2856. // Function: NetDfsManagerSendSiteInfo
  2857. //
  2858. // Synopsis: Gets site information from a server
  2859. //
  2860. // Returns: [NERR_Success] -- Successfully completed operation.
  2861. //
  2862. //-----------------------------------------------------------------------------
  2863. NET_API_STATUS
  2864. NetDfsManagerSendSiteInfo(
  2865. LPWSTR wszServer,
  2866. LPWSTR wszLocalVolumeEntryPath,
  2867. LPDFS_SITELIST_INFO pSiteInfo)
  2868. {
  2869. NET_API_STATUS dwErr;
  2870. LPWSTR pwszDfsName = NULL;
  2871. DWORD cwDfsEntryPath;
  2872. #if DBG
  2873. if (DfsDebug)
  2874. DbgPrint("NetDfsManagerSendSiteInfo(%ws,%ws)\n",
  2875. wszServer,
  2876. wszLocalVolumeEntryPath);
  2877. #endif
  2878. if (!IS_VALID_STRING(wszServer) ||
  2879. !IS_VALID_STRING(wszLocalVolumeEntryPath)) {
  2880. return( ERROR_INVALID_PARAMETER );
  2881. }
  2882. //
  2883. // Some elementary parameter checking to make sure we can proceed
  2884. // reasonably...
  2885. //
  2886. cwDfsEntryPath = wcslen(wszLocalVolumeEntryPath);
  2887. if (!IS_UNC_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath) &&
  2888. !IS_VALID_PREFIX(wszLocalVolumeEntryPath, cwDfsEntryPath) &&
  2889. !IS_VALID_DFS_PATH(wszLocalVolumeEntryPath, cwDfsEntryPath)) {
  2890. return( ERROR_INVALID_PARAMETER );
  2891. }
  2892. dwErr = DfspGetMachineNameFromEntryPath(
  2893. wszLocalVolumeEntryPath,
  2894. cwDfsEntryPath,
  2895. &pwszDfsName);
  2896. ENTER_NETDFS_API
  2897. if (dwErr == NERR_Success) {
  2898. //
  2899. // By now, we should have a valid pwszDfsName. Lets try to bind to it,
  2900. // and call the server.
  2901. //
  2902. dwErr = DfspBindRpc( pwszDfsName, &netdfs_bhandle );
  2903. if (dwErr == NERR_Success) {
  2904. RpcTryExcept {
  2905. dwErr = NetrDfsManagerSendSiteInfo(
  2906. wszServer,
  2907. pSiteInfo);
  2908. } RpcExcept( 1 ) {
  2909. dwErr = RpcExceptionCode();
  2910. } RpcEndExcept;
  2911. DfspFreeBinding( netdfs_bhandle );
  2912. }
  2913. free( pwszDfsName );
  2914. }
  2915. LEAVE_NETDFS_API
  2916. #if DBG
  2917. if (DfsDebug)
  2918. DbgPrint("NetDfsManagerSendSiteInfo returning %d\n", dwErr);
  2919. #endif
  2920. return( dwErr );
  2921. }
  2922. //+----------------------------------------------------------------------------
  2923. //
  2924. // Function: DfspGetMachineNameFromEntryPath
  2925. //
  2926. // Synopsis: Given a DfsEntryPath, this routine returns the name of the
  2927. // FtDfs Root.
  2928. //
  2929. // Arguments: [wszEntryPath] -- Pointer to EntryPath to parse.
  2930. //
  2931. // [cwEntryPath] -- Length in WCHAR of wszEntryPath.
  2932. //
  2933. // [ppwszMachineName] -- Name of a root machine; allocated using malloc;
  2934. // caller resposible for freeing it.
  2935. //
  2936. // Returns: [NERR_Success] -- Successfully determinded
  2937. //
  2938. // [ERROR_INVALID_NAME] -- Unable to parse wszEntryPath.
  2939. //
  2940. // [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for
  2941. // ppwszMachineName.
  2942. //
  2943. //-----------------------------------------------------------------------------
  2944. NET_API_STATUS
  2945. DfspGetMachineNameFromEntryPath(
  2946. LPWSTR wszEntryPath,
  2947. DWORD cwEntryPath,
  2948. LPWSTR *ppwszMachineName)
  2949. {
  2950. NTSTATUS NtStatus;
  2951. LPWSTR pwszDfsName, pwszFirst, pwszLast;
  2952. LPWSTR pwszMachineName;
  2953. DWORD cwDfsName;
  2954. DWORD cwSlash;
  2955. DWORD dwErr;
  2956. #if DBG
  2957. if (DfsDebug)
  2958. DbgPrint("DfspGetMachineNameFromEntryPath(%ws,%d\n", wszEntryPath, cwEntryPath);
  2959. #endif
  2960. if (!IS_VALID_STRING(wszEntryPath)) {
  2961. return( ERROR_INVALID_PARAMETER );
  2962. }
  2963. if (IS_UNC_PATH(wszEntryPath, cwEntryPath)) {
  2964. pwszFirst = &wszEntryPath[2];
  2965. } else if (IS_VALID_PREFIX(wszEntryPath, cwEntryPath)) {
  2966. pwszFirst = &wszEntryPath[1];
  2967. } else if (IS_VALID_DFS_PATH(wszEntryPath, cwEntryPath)) {
  2968. pwszFirst = &wszEntryPath[0];
  2969. } else {
  2970. return( ERROR_INVALID_NAME );
  2971. }
  2972. dwErr = DfspGetDfsNameFromEntryPath(
  2973. wszEntryPath,
  2974. cwEntryPath,
  2975. &pwszMachineName);
  2976. if (dwErr != NERR_Success) {
  2977. #if DBG
  2978. if (DfsDebug)
  2979. DbgPrint("DfspGetMachineNameFromEntryPath: returning %d\n", dwErr);
  2980. #endif
  2981. return( dwErr);
  2982. }
  2983. for (cwDfsName = cwSlash = 0, pwszLast = pwszFirst;
  2984. *pwszLast != UNICODE_NULL;
  2985. pwszLast++, cwDfsName++) {
  2986. if (*pwszLast == L'\\')
  2987. cwSlash++;
  2988. if (cwSlash >= 2)
  2989. break;
  2990. }
  2991. if (cwSlash == 0) {
  2992. *ppwszMachineName = pwszMachineName;
  2993. dwErr = NERR_Success;
  2994. return dwErr;
  2995. }
  2996. cwDfsName += 3;
  2997. pwszDfsName = malloc(cwDfsName * sizeof(WCHAR));
  2998. if (pwszDfsName != NULL) {
  2999. ZeroMemory((PCHAR)pwszDfsName, cwDfsName * sizeof(WCHAR));
  3000. wcscpy(pwszDfsName, L"\\\\");
  3001. CopyMemory(&pwszDfsName[2], pwszFirst, (PCHAR)pwszLast - (PCHAR)pwszFirst);
  3002. NtStatus = DfspIsThisADfsPath(&pwszDfsName[1]);
  3003. if (NT_SUCCESS(NtStatus)) {
  3004. GetFileAttributes(pwszDfsName);
  3005. }
  3006. dwErr = DfspDfsPathToRootMachine(pwszDfsName, ppwszMachineName);
  3007. if (NtStatus != STATUS_SUCCESS || dwErr != NERR_Success) {
  3008. *ppwszMachineName = pwszMachineName;
  3009. dwErr = NERR_Success;
  3010. } else {
  3011. free(pwszMachineName);
  3012. }
  3013. free(pwszDfsName);
  3014. } else {
  3015. free(pwszMachineName);
  3016. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  3017. }
  3018. #if DBG
  3019. if (DfsDebug)
  3020. DbgPrint("DfspGetMachineNameFromEntryPath returning %d\n", dwErr);
  3021. #endif
  3022. return( dwErr );
  3023. }
  3024. //+----------------------------------------------------------------------------
  3025. //
  3026. // Function: DfspGetDfsNameFromEntryPath
  3027. //
  3028. // Synopsis: Given a DfsEntryPath, this routine returns the name of the
  3029. // Dfs Root.
  3030. //
  3031. // Arguments: [wszEntryPath] -- Pointer to EntryPath to parse.
  3032. //
  3033. // [cwEntryPath] -- Length in WCHAR of wszEntryPath.
  3034. //
  3035. // [ppwszDfsName] -- Name of Dfs root is returned here. Memory
  3036. // is allocated using malloc; caller resposible for
  3037. // freeing it.
  3038. //
  3039. // Returns: [NERR_Success] -- Successfully parsed out Dfs Root.
  3040. //
  3041. // [ERROR_INVALID_NAME] -- Unable to parse wszEntryPath.
  3042. //
  3043. // [ERROR_NOT_ENOUGH_MEMORY] -- Unable to allocate memory for
  3044. // ppwszDfsName.
  3045. //
  3046. //-----------------------------------------------------------------------------
  3047. NET_API_STATUS
  3048. DfspGetDfsNameFromEntryPath(
  3049. LPWSTR wszEntryPath,
  3050. DWORD cwEntryPath,
  3051. LPWSTR *ppwszDfsName)
  3052. {
  3053. LPWSTR pwszDfsName, pwszFirst, pwszLast;
  3054. DWORD cwDfsName;
  3055. #if DBG
  3056. if (DfsDebug)
  3057. DbgPrint("DfspGetDfsNameFromEntryPath(%ws,%d)\n", wszEntryPath, cwEntryPath);
  3058. #endif
  3059. if (!IS_VALID_STRING(wszEntryPath)) {
  3060. #if DBG
  3061. if (DfsDebug)
  3062. DbgPrint("DfspGetDfsNameFromEntryPath returning ERROR_INVALID_PARAMETER\n");
  3063. #endif
  3064. return( ERROR_INVALID_PARAMETER );
  3065. }
  3066. if (IS_UNC_PATH(wszEntryPath, cwEntryPath)) {
  3067. pwszFirst = &wszEntryPath[2];
  3068. } else if (IS_VALID_PREFIX(wszEntryPath, cwEntryPath)) {
  3069. pwszFirst = &wszEntryPath[1];
  3070. } else if (IS_VALID_DFS_PATH(wszEntryPath, cwEntryPath)) {
  3071. pwszFirst = &wszEntryPath[0];
  3072. } else {
  3073. #if DBG
  3074. if (DfsDebug)
  3075. DbgPrint("DfspGetDfsNameFromEntryPath returning ERROR_INVALID_NAME\n");
  3076. #endif
  3077. return( ERROR_INVALID_NAME );
  3078. }
  3079. for (cwDfsName = 0, pwszLast = pwszFirst;
  3080. *pwszLast != UNICODE_NULL && *pwszLast != L'\\';
  3081. pwszLast++, cwDfsName++) {
  3082. ;
  3083. }
  3084. ++cwDfsName;
  3085. pwszDfsName = malloc( cwDfsName * sizeof(WCHAR) );
  3086. if (pwszDfsName != NULL) {
  3087. pwszDfsName[ cwDfsName - 1 ] = 0;
  3088. for (cwDfsName--; cwDfsName > 0; cwDfsName--) {
  3089. pwszDfsName[ cwDfsName - 1 ] = pwszFirst[ cwDfsName - 1 ];
  3090. }
  3091. *ppwszDfsName = pwszDfsName;
  3092. #if DBG
  3093. if (DfsDebug)
  3094. DbgPrint("DfspGetDfsNameFromEntryPath returning %ws\n", pwszDfsName);
  3095. #endif
  3096. return( NERR_Success );
  3097. } else {
  3098. #if DBG
  3099. if (DfsDebug)
  3100. DbgPrint("DfspGetDfsNameFromEntryPath returning ERROR_NOT_ENOUGH_MEMORY\n");
  3101. #endif
  3102. return( ERROR_NOT_ENOUGH_MEMORY );
  3103. }
  3104. }
  3105. //+----------------------------------------------------------------------------
  3106. //
  3107. // Function: DfspBindRpc
  3108. //
  3109. // Synopsis: Given a server or domain name, this API will bind to the
  3110. // appropriate Dfs Manager service.
  3111. //
  3112. // Arguments: [DfsName] -- Name of domain or server. Leading \\ is optional
  3113. //
  3114. // [BindingHandle] -- On successful return, the binding handle
  3115. // is returned here.
  3116. //
  3117. // Returns: [NERR_Success] -- Binding handle successfull returned.
  3118. //
  3119. // [RPC_S_SERVER_NOT_AVAILABLE] -- Unable to bind to NetDfs
  3120. // interface on the named server or domain.
  3121. //
  3122. // [ERROR_INVALID_NAME] -- Unable to parse DfsName as a valid
  3123. // server or domain name.
  3124. //
  3125. // [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
  3126. //
  3127. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  3128. //
  3129. //-----------------------------------------------------------------------------
  3130. NET_API_STATUS
  3131. DfspBindRpc(
  3132. IN LPWSTR DfsName,
  3133. OUT RPC_BINDING_HANDLE *BindingHandle)
  3134. {
  3135. LPWSTR wszProtocolSeq = L"ncacn_np";
  3136. LPWSTR wszEndPoint = L"\\pipe\\netdfs";
  3137. LPWSTR pwszRpcBindingString = NULL;
  3138. LPWSTR pwszDCName = NULL;
  3139. NET_API_STATUS dwErr;
  3140. PWCHAR DCList = NULL;
  3141. PWCHAR DCListToFree = NULL;
  3142. BOOLEAN IsDomainName = FALSE;
  3143. #if DBG
  3144. if (DfsDebug)
  3145. DbgPrint("DfspBindRpc(%ws)\n", DfsName);
  3146. #endif
  3147. //
  3148. // First, see if this is a domain name.
  3149. //
  3150. dwErr = DfspIsThisADomainName( DfsName, &DCListToFree );
  3151. DCList = DCListToFree;
  3152. if (dwErr == ERROR_SUCCESS && DCList != NULL && *DCList != UNICODE_NULL) {
  3153. //
  3154. // It's a domain name. Use the DC list as a list of servers to try to bind to.
  3155. //
  3156. IsDomainName = TRUE;
  3157. pwszDCName = DCList + 1; // Skip '+' or '-'
  3158. dwErr = ERROR_SUCCESS;
  3159. } else {
  3160. //
  3161. // Lets see if this is a machine-based Dfs
  3162. //
  3163. pwszDCName = DfsName;
  3164. dwErr = ERROR_SUCCESS;
  3165. }
  3166. Try_Connect:
  3167. if (dwErr == ERROR_SUCCESS) {
  3168. #if DBG
  3169. if (DfsDebug)
  3170. DbgPrint("Calling RpcBindingCompose(%ws)\n", pwszDCName);
  3171. #endif
  3172. dwErr = RpcStringBindingCompose(
  3173. NULL, // Object UUID
  3174. wszProtocolSeq, // Protocol Sequence
  3175. pwszDCName, // Network Address
  3176. wszEndPoint, // RPC Endpoint
  3177. NULL, // RPC Options
  3178. &pwszRpcBindingString); // Returned binding string
  3179. if (dwErr == RPC_S_OK) {
  3180. dwErr = RpcBindingFromStringBinding(
  3181. pwszRpcBindingString,
  3182. BindingHandle);
  3183. #if DBG
  3184. if (DfsDebug)
  3185. DbgPrint("RpcBindingFromStringBinding() returned %d\n", dwErr);
  3186. #endif
  3187. if (dwErr == RPC_S_OK) {
  3188. dwErr = DfspVerifyBinding();
  3189. if (dwErr != RPC_S_OK)
  3190. {
  3191. DfspFreeBinding(*BindingHandle);
  3192. }
  3193. #if DBG
  3194. if (DfsDebug)
  3195. DbgPrint("DfspVerifyBinding() returned %d\n", dwErr);
  3196. #endif
  3197. } else {
  3198. dwErr = ERROR_INVALID_NAME;
  3199. }
  3200. }
  3201. }
  3202. if (pwszRpcBindingString != NULL) {
  3203. RpcStringFree( &pwszRpcBindingString );
  3204. }
  3205. if (dwErr == RPC_S_OUT_OF_MEMORY) {
  3206. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  3207. }
  3208. //
  3209. // If we couldn't connect and we have a domain name and a list of DC's,
  3210. // try the next DC in the list.
  3211. //
  3212. if (dwErr != NERR_Success && DCList != NULL && IsDomainName == TRUE) {
  3213. DCList += wcslen(DCList) + 1;
  3214. if (*DCList != UNICODE_NULL) {
  3215. pwszDCName = DCList + 1;
  3216. dwErr = ERROR_SUCCESS;
  3217. goto Try_Connect;
  3218. }
  3219. }
  3220. if (DCListToFree != NULL) {
  3221. free(DCListToFree);
  3222. }
  3223. return( dwErr );
  3224. }
  3225. //+----------------------------------------------------------------------------
  3226. //
  3227. // Function: DfspFreeBinding
  3228. //
  3229. // Synopsis: Frees a binding created by DfspBindRpc
  3230. //
  3231. // Arguments: [BindingHandle] -- The handle to free.
  3232. //
  3233. // Returns: Nothing
  3234. //
  3235. //-----------------------------------------------------------------------------
  3236. VOID
  3237. DfspFreeBinding(
  3238. RPC_BINDING_HANDLE BindingHandle)
  3239. {
  3240. DWORD dwErr;
  3241. dwErr = RpcBindingFree( &BindingHandle );
  3242. }
  3243. //+----------------------------------------------------------------------------
  3244. //
  3245. // Function: DfspVerifyBinding
  3246. //
  3247. // Synopsis: Verifies that the binding can be used by doing a
  3248. // NetrDfsManagerGetVersion call on the binding.
  3249. //
  3250. // Arguments: None
  3251. //
  3252. // Returns: [NERR_Success] -- Server connnected to.
  3253. //
  3254. // [RPC_S_SERVER_UNAVAILABLE] -- The server is not available.
  3255. //
  3256. // Other RPC error from calling the remote server.
  3257. //
  3258. //-----------------------------------------------------------------------------
  3259. NET_API_STATUS
  3260. DfspVerifyBinding()
  3261. {
  3262. NET_API_STATUS status = NERR_Success;
  3263. DWORD Version;
  3264. RpcTryExcept {
  3265. Version = NetrDfsManagerGetVersion();
  3266. } RpcExcept(1) {
  3267. status = RpcExceptionCode();
  3268. } RpcEndExcept;
  3269. return( status );
  3270. }
  3271. //+----------------------------------------------------------------------------
  3272. //
  3273. // Function: DfspBindToServer
  3274. //
  3275. // Synopsis: Given a server name, this API will bind to the
  3276. // appropriate Dfs Manager service.
  3277. //
  3278. // Arguments: [DfsName] -- Name of server. Leading \\ is optional
  3279. //
  3280. // [BindingHandle] -- On successful return, the binding handle
  3281. // is returned here.
  3282. //
  3283. // Returns: [NERR_Success] -- Binding handle successfull returned.
  3284. //
  3285. // [RPC_S_SERVER_NOT_AVAILABLE] -- Unable to bind to NetDfs
  3286. // interface on the named server or domain.
  3287. //
  3288. // [ERROR_INVALID_NAME] -- Unable to parse DfsName as a valid
  3289. // server or domain name.
  3290. //
  3291. // [ERROR_DCNotFound] -- Unable to locate DC for DfsName.
  3292. //
  3293. // [ERROR_NOT_ENOUGH_MEMORY] -- Out of memory condition.
  3294. //
  3295. //-----------------------------------------------------------------------------
  3296. NET_API_STATUS
  3297. DfspBindToServer(
  3298. IN LPWSTR ServerName,
  3299. OUT RPC_BINDING_HANDLE *BindingHandle)
  3300. {
  3301. LPWSTR wszProtocolSeq = L"ncacn_np";
  3302. LPWSTR wszEndPoint = L"\\pipe\\netdfs";
  3303. LPWSTR pwszRpcBindingString = NULL;
  3304. NET_API_STATUS dwErr;
  3305. dwErr = RpcStringBindingCompose(
  3306. NULL, // Object UUID
  3307. wszProtocolSeq, // Protocol Sequence
  3308. ServerName, // Network Address
  3309. wszEndPoint, // RPC Endpoint
  3310. NULL, // RPC Options
  3311. &pwszRpcBindingString); // Returned binding string
  3312. if (dwErr == RPC_S_OK) {
  3313. dwErr = RpcBindingFromStringBinding(
  3314. pwszRpcBindingString,
  3315. BindingHandle);
  3316. if (dwErr == RPC_S_OK) {
  3317. dwErr = DfspVerifyBinding();
  3318. if (dwErr != RPC_S_OK)
  3319. {
  3320. DfspFreeBinding(*BindingHandle);
  3321. }
  3322. } else {
  3323. dwErr = ERROR_INVALID_NAME;
  3324. }
  3325. }
  3326. if (pwszRpcBindingString != NULL) {
  3327. RpcStringFree( &pwszRpcBindingString );
  3328. }
  3329. if (dwErr == RPC_S_OUT_OF_MEMORY) {
  3330. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  3331. }
  3332. return( dwErr );
  3333. }
  3334. //+----------------------------------------------------------------------------
  3335. //
  3336. // Function: DfspFlushPkt
  3337. //
  3338. // Synopsis: Flushes the local pkt
  3339. //
  3340. // Arguments: DfsEntryPath or NULL
  3341. //
  3342. // Returns: The fsctrl's code
  3343. //
  3344. //-----------------------------------------------------------------------------
  3345. VOID
  3346. DfspFlushPkt(
  3347. LPWSTR DfsEntryPath)
  3348. {
  3349. NTSTATUS NtStatus;
  3350. HANDLE DriverHandle = NULL;
  3351. IO_STATUS_BLOCK IoStatusBlock;
  3352. OBJECT_ATTRIBUTES objectAttributes;
  3353. UNICODE_STRING DfsDriverName;
  3354. RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
  3355. InitializeObjectAttributes(
  3356. &objectAttributes,
  3357. &DfsDriverName,
  3358. OBJ_CASE_INSENSITIVE,
  3359. NULL,
  3360. NULL
  3361. );
  3362. NtStatus = NtCreateFile(
  3363. &DriverHandle,
  3364. SYNCHRONIZE | FILE_WRITE_DATA,
  3365. &objectAttributes,
  3366. &IoStatusBlock,
  3367. NULL,
  3368. FILE_ATTRIBUTE_NORMAL,
  3369. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3370. FILE_OPEN_IF,
  3371. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  3372. NULL,
  3373. 0);
  3374. if (NT_SUCCESS(NtStatus)) {
  3375. if (DfsEntryPath != NULL) {
  3376. NtStatus = NtFsControlFile(
  3377. DriverHandle,
  3378. NULL, // Event,
  3379. NULL, // ApcRoutine,
  3380. NULL, // ApcContext,
  3381. &IoStatusBlock,
  3382. FSCTL_DFS_PKT_FLUSH_CACHE,
  3383. DfsEntryPath,
  3384. wcslen(DfsEntryPath) * sizeof(WCHAR),
  3385. NULL,
  3386. 0);
  3387. } else {
  3388. NtStatus = NtFsControlFile(
  3389. DriverHandle,
  3390. NULL, // Event,
  3391. NULL, // ApcRoutine,
  3392. NULL, // ApcContext,
  3393. &IoStatusBlock,
  3394. FSCTL_DFS_PKT_FLUSH_CACHE,
  3395. L"*",
  3396. sizeof(WCHAR),
  3397. NULL,
  3398. 0);
  3399. }
  3400. NtClose(DriverHandle);
  3401. }
  3402. }
  3403. //+----------------------------------------------------------------------------
  3404. //
  3405. // Function: DfspDfsPathToRootMachine
  3406. //
  3407. // Synopsis: Turns a dfs root path into a machine name
  3408. // Ex: \\jharperdomain\FtDfs -> jharperdc1
  3409. // \\jharpera\d -> jharpera
  3410. //
  3411. // Arguments: pwszDfsName - Dfs root path to get machine for
  3412. // ppwszMachineName - The machine, if one found. Space is
  3413. // malloc'd, caller must free.
  3414. //
  3415. // Returns: [NERR_Success] -- Resolved ok
  3416. //
  3417. //-----------------------------------------------------------------------------
  3418. DWORD
  3419. DfspDfsPathToRootMachine(
  3420. LPWSTR pwszDfsName,
  3421. LPWSTR *ppwszMachineName)
  3422. {
  3423. NTSTATUS NtStatus;
  3424. HANDLE DriverHandle = NULL;
  3425. IO_STATUS_BLOCK IoStatusBlock;
  3426. OBJECT_ATTRIBUTES objectAttributes;
  3427. UNICODE_STRING DfsDriverName;
  3428. WCHAR ServerName[0x100];
  3429. DWORD dwErr;
  3430. ULONG i;
  3431. #if DBG
  3432. if (DfsDebug)
  3433. DbgPrint("DfspDfsPathToRootMachine(%ws)\n", pwszDfsName);
  3434. #endif
  3435. for (i = 0; i < sizeof(ServerName) / sizeof(WCHAR); i++)
  3436. ServerName[i] = UNICODE_NULL;
  3437. RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
  3438. InitializeObjectAttributes(
  3439. &objectAttributes,
  3440. &DfsDriverName,
  3441. OBJ_CASE_INSENSITIVE,
  3442. NULL,
  3443. NULL
  3444. );
  3445. NtStatus = NtCreateFile(
  3446. &DriverHandle,
  3447. SYNCHRONIZE,
  3448. &objectAttributes,
  3449. &IoStatusBlock,
  3450. NULL,
  3451. FILE_ATTRIBUTE_NORMAL,
  3452. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3453. FILE_OPEN_IF,
  3454. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  3455. NULL,
  3456. 0
  3457. );
  3458. if (NT_SUCCESS(NtStatus)) {
  3459. NtStatus = NtFsControlFile(
  3460. DriverHandle,
  3461. NULL, // Event,
  3462. NULL, // ApcRoutine,
  3463. NULL, // ApcContext,
  3464. &IoStatusBlock,
  3465. FSCTL_DFS_GET_SERVER_NAME,
  3466. pwszDfsName,
  3467. wcslen(pwszDfsName) * sizeof(WCHAR),
  3468. ServerName,
  3469. sizeof(ServerName)
  3470. );
  3471. NtClose(DriverHandle);
  3472. }
  3473. if (NT_SUCCESS(NtStatus)) {
  3474. LPWSTR wcpStart;
  3475. LPWSTR wcpEnd;
  3476. for (wcpStart = ServerName; *wcpStart == L'\\'; wcpStart++)
  3477. ;
  3478. for (wcpEnd = wcpStart; *wcpEnd != L'\\' && *wcpEnd != UNICODE_NULL; wcpEnd++)
  3479. ;
  3480. *wcpEnd = UNICODE_NULL;
  3481. *ppwszMachineName = malloc((wcslen(wcpStart) + 1) * sizeof(WCHAR));
  3482. if (*ppwszMachineName != NULL) {
  3483. wcscpy(*ppwszMachineName, wcpStart);
  3484. dwErr = NERR_Success;
  3485. } else {
  3486. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  3487. }
  3488. } else {
  3489. #if DBG
  3490. if (DfsDebug)
  3491. DbgPrint("DfspDfsPathToRootMachine NtStatus=0x%x\n", NtStatus);
  3492. #endif
  3493. dwErr = ERROR_INVALID_PARAMETER;
  3494. }
  3495. #if DBG
  3496. if (DfsDebug) {
  3497. if (dwErr == NERR_Success)
  3498. DbgPrint("DfspDfsPathToRootMachine returning %ws\n", *ppwszMachineName);
  3499. else
  3500. DbgPrint("DfspDfsPathToRootMachine returning %d\n", dwErr);
  3501. }
  3502. #endif
  3503. return dwErr;
  3504. }
  3505. //+----------------------------------------------------------------------------
  3506. //
  3507. // Function: DfspIsThisADfsPath
  3508. //
  3509. // Synopsis: Checks (via IOCTL to driver) if the path passed in
  3510. // is a Dfs path.
  3511. //
  3512. // Arguments: pwszPathName - Path to check (ex: \ntbuilds\release)
  3513. //
  3514. // Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
  3515. //
  3516. //-----------------------------------------------------------------------------
  3517. NTSTATUS
  3518. DfspIsThisADfsPath(
  3519. LPWSTR pwszPathName)
  3520. {
  3521. NTSTATUS NtStatus;
  3522. HANDLE DriverHandle = NULL;
  3523. IO_STATUS_BLOCK IoStatusBlock;
  3524. OBJECT_ATTRIBUTES objectAttributes;
  3525. UNICODE_STRING DfsDriverName;
  3526. PDFS_IS_VALID_PREFIX_ARG pPrefixArg = NULL;
  3527. ULONG Size;
  3528. #if DBG
  3529. if (DfsDebug)
  3530. DbgPrint("DfspIsThisADfsPath(%ws)\n", pwszPathName);
  3531. #endif
  3532. Size = sizeof(DFS_IS_VALID_PREFIX_ARG) +
  3533. (wcslen(pwszPathName) + 1) * sizeof(WCHAR);
  3534. pPrefixArg = (PDFS_IS_VALID_PREFIX_ARG) malloc(Size);
  3535. if (pPrefixArg == NULL) {
  3536. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  3537. goto exit_with_status;
  3538. }
  3539. pPrefixArg->CSCAgentCreate = FALSE;
  3540. pPrefixArg->RemoteNameLen = wcslen(pwszPathName) * sizeof(WCHAR);
  3541. wcscpy(&pPrefixArg->RemoteName[0], pwszPathName);
  3542. RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
  3543. InitializeObjectAttributes(
  3544. &objectAttributes,
  3545. &DfsDriverName,
  3546. OBJ_CASE_INSENSITIVE,
  3547. NULL,
  3548. NULL
  3549. );
  3550. NtStatus = NtCreateFile(
  3551. &DriverHandle,
  3552. SYNCHRONIZE,
  3553. &objectAttributes,
  3554. &IoStatusBlock,
  3555. NULL,
  3556. FILE_ATTRIBUTE_NORMAL,
  3557. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3558. FILE_OPEN_IF,
  3559. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  3560. NULL,
  3561. 0
  3562. );
  3563. if (NT_SUCCESS(NtStatus)) {
  3564. NtStatus = NtFsControlFile(
  3565. DriverHandle,
  3566. NULL, // Event,
  3567. NULL, // ApcRoutine,
  3568. NULL, // ApcContext,
  3569. &IoStatusBlock,
  3570. FSCTL_DFS_IS_VALID_PREFIX,
  3571. pPrefixArg,
  3572. Size,
  3573. NULL,
  3574. 0
  3575. );
  3576. NtClose(DriverHandle);
  3577. }
  3578. exit_with_status:
  3579. if (pPrefixArg != NULL) {
  3580. free(pPrefixArg);
  3581. }
  3582. #if DBG
  3583. if (DfsDebug)
  3584. DbgPrint("DfspIsThisADfsPath returning 0x%x\n", NtStatus);
  3585. #endif
  3586. return NtStatus;
  3587. }
  3588. //+----------------------------------------------------------------------------
  3589. //
  3590. // Function: DfspCreateFtDfs
  3591. //
  3592. // Synopsis: Creates/updates a Ds object representing the FtDfs, then rpc's
  3593. // to the server and has it update the DS object, thus completing
  3594. // the setup.
  3595. //
  3596. // Arguments: wszServerName - Name of server we'll be adding
  3597. // wszDcName - DC to use
  3598. // fIsPdc - TRUE if DC is the PDC
  3599. // wszRootShare - Share to become the root share
  3600. // wszFtDfsName - Name of FtDfs we are creating
  3601. // wszComment -- Comment for the root
  3602. // dwFlags - 0
  3603. //
  3604. // Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
  3605. //
  3606. //-----------------------------------------------------------------------------
  3607. DWORD
  3608. DfspCreateFtDfs(
  3609. LPWSTR wszServerName,
  3610. LPWSTR wszDcName,
  3611. BOOLEAN fIsPdc,
  3612. LPWSTR wszRootShare,
  3613. LPWSTR wszFtDfsName,
  3614. LPWSTR wszComment,
  3615. DWORD dwFlags)
  3616. {
  3617. DWORD dwErr = ERROR_SUCCESS;
  3618. DWORD dwErr2 = ERROR_SUCCESS;
  3619. DWORD i, j;
  3620. LPWSTR wszDfsConfigDN = NULL;
  3621. LPWSTR wszConfigurationDN = NULL;
  3622. PDFSM_ROOT_LIST RootList = NULL;
  3623. LDAP *pldap = NULL;
  3624. PLDAPMessage pMsg = NULL;
  3625. LDAPModW ldapModClass, ldapModCN, ldapModPkt, ldapModPktGuid, ldapModServer;
  3626. LDAP_BERVAL ldapPkt, ldapPktGuid;
  3627. PLDAP_BERVAL rgModPktVals[2];
  3628. PLDAP_BERVAL rgModPktGuidVals[2];
  3629. LPWSTR rgModClassVals[2];
  3630. LPWSTR rgModCNVals[2];
  3631. LPWSTR rgModServerVals[5];
  3632. LPWSTR rgAttrs[5];
  3633. PLDAPModW rgldapMods[6];
  3634. BOOLEAN fNewFTDfs = FALSE;
  3635. LDAPMessage *pmsgServers;
  3636. PWCHAR *rgServers;
  3637. DWORD cServers;
  3638. ULONG Size;
  3639. #if DBG
  3640. if (DfsDebug)
  3641. DbgPrint("DfspCreateFtDfs(%ws,%ws,%s,%ws,%ws,%ws,%d)\n",
  3642. wszServerName,
  3643. wszDcName,
  3644. fIsPdc ? "TRUE" : "FALSE",
  3645. wszRootShare,
  3646. wszFtDfsName,
  3647. wszComment,
  3648. dwFlags);
  3649. #endif
  3650. dwErr = DfspLdapOpen(
  3651. wszDcName,
  3652. &pldap,
  3653. &wszConfigurationDN);
  3654. if (dwErr != ERROR_SUCCESS) {
  3655. goto Cleanup;
  3656. }
  3657. //
  3658. // See if the DfsConfiguration object exists; if not and this is the
  3659. // PDC, create it.
  3660. //
  3661. rgAttrs[0] = L"cn";
  3662. rgAttrs[1] = NULL;
  3663. dwErr = ldap_search_sW(
  3664. pldap,
  3665. wszConfigurationDN,
  3666. LDAP_SCOPE_BASE,
  3667. L"(objectClass=*)",
  3668. rgAttrs,
  3669. 0,
  3670. &pMsg);
  3671. if (pMsg != NULL) {
  3672. ldap_msgfree(pMsg);
  3673. pMsg = NULL;
  3674. }
  3675. #if DBG
  3676. if (DfsDebug)
  3677. DbgPrint("ldap_search_sW(1) returned 0x%x\n", dwErr);
  3678. #endif
  3679. if (dwErr == LDAP_NO_SUCH_OBJECT && fIsPdc == TRUE) {
  3680. rgModClassVals[0] = L"dfsConfiguration";
  3681. rgModClassVals[1] = NULL;
  3682. ldapModClass.mod_op = LDAP_MOD_ADD;
  3683. ldapModClass.mod_type = L"objectClass";
  3684. ldapModClass.mod_vals.modv_strvals = rgModClassVals;
  3685. rgModCNVals[0] = L"Dfs-Configuration";
  3686. rgModCNVals[1] = NULL;
  3687. ldapModCN.mod_op = LDAP_MOD_ADD;
  3688. ldapModCN.mod_type = L"cn";
  3689. ldapModCN.mod_vals.modv_strvals = rgModCNVals;
  3690. rgldapMods[0] = &ldapModClass;
  3691. rgldapMods[1] = &ldapModCN;
  3692. rgldapMods[2] = NULL;
  3693. dwErr = ldap_add_sW(
  3694. pldap,
  3695. wszConfigurationDN,
  3696. rgldapMods);
  3697. #if DBG
  3698. if (DfsDebug)
  3699. DbgPrint("ldap_add_sW(1) returned 0x%x\n", dwErr);
  3700. #endif
  3701. }
  3702. if (dwErr != LDAP_SUCCESS) {
  3703. dwErr = LdapMapErrorToWin32(dwErr);
  3704. goto Cleanup;
  3705. }
  3706. //
  3707. // Check to see if we are joining an FTDfs or creating a new one.
  3708. //
  3709. Size = wcslen(L"CN=") +
  3710. wcslen(wszFtDfsName) +
  3711. wcslen(L",") +
  3712. wcslen(wszConfigurationDN);
  3713. if (Size > MAX_PATH) {
  3714. dwErr = ERROR_DS_NAME_TOO_LONG;
  3715. goto Cleanup;
  3716. }
  3717. wszDfsConfigDN = malloc((Size+1) * sizeof(WCHAR));
  3718. if (wszDfsConfigDN == NULL) {
  3719. dwErr = ERROR_OUTOFMEMORY;
  3720. goto Cleanup;
  3721. }
  3722. wcscpy(wszDfsConfigDN,L"CN=");
  3723. wcscat(wszDfsConfigDN,wszFtDfsName);
  3724. wcscat(wszDfsConfigDN,L",");
  3725. wcscat(wszDfsConfigDN,wszConfigurationDN);
  3726. rgAttrs[0] = L"remoteServerName";
  3727. rgAttrs[1] = NULL;
  3728. dwErr = ldap_search_sW(
  3729. pldap,
  3730. wszDfsConfigDN,
  3731. LDAP_SCOPE_BASE,
  3732. L"(objectClass=*)",
  3733. rgAttrs,
  3734. 0,
  3735. &pMsg);
  3736. #if DBG
  3737. if (DfsDebug)
  3738. DbgPrint("ldap_search_sW(2) returned 0x%x\n", dwErr);
  3739. #endif
  3740. if (dwErr == LDAP_NO_SUCH_OBJECT) {
  3741. GUID idPkt;
  3742. DWORD dwPktVersion = 1;
  3743. //
  3744. // We are creating a new FTDfs, create a container to hold the Dfs
  3745. // configuration for it.
  3746. //
  3747. fNewFTDfs = TRUE;
  3748. //
  3749. // Generate the class and CN attributes
  3750. //
  3751. rgModClassVals[0] = L"ftDfs";
  3752. rgModClassVals[1] = NULL;
  3753. ldapModClass.mod_op = LDAP_MOD_ADD;
  3754. ldapModClass.mod_type = L"objectClass";
  3755. ldapModClass.mod_vals.modv_strvals = rgModClassVals;
  3756. rgModCNVals[0] = wszFtDfsName;
  3757. rgModCNVals[1] = NULL;
  3758. ldapModCN.mod_op = LDAP_MOD_ADD;
  3759. ldapModCN.mod_type = L"cn";
  3760. ldapModCN.mod_vals.modv_strvals = rgModCNVals;
  3761. //
  3762. // Generate the null PKT attribute
  3763. //
  3764. ldapPkt.bv_len = sizeof(DWORD);
  3765. ldapPkt.bv_val = (PCHAR) &dwPktVersion;
  3766. rgModPktVals[0] = &ldapPkt;
  3767. rgModPktVals[1] = NULL;
  3768. ldapModPkt.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  3769. ldapModPkt.mod_type = L"pKT";
  3770. ldapModPkt.mod_vals.modv_bvals = rgModPktVals;
  3771. //
  3772. // Generate a PKT Guid attribute
  3773. //
  3774. UuidCreate( &idPkt );
  3775. ldapPktGuid.bv_len = sizeof(GUID);
  3776. ldapPktGuid.bv_val = (PCHAR) &idPkt;
  3777. rgModPktGuidVals[0] = &ldapPktGuid;
  3778. rgModPktGuidVals[1] = NULL;
  3779. ldapModPktGuid.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
  3780. ldapModPktGuid.mod_type = L"pKTGuid";
  3781. ldapModPktGuid.mod_vals.modv_bvals = rgModPktGuidVals;
  3782. //
  3783. // Generate a Remote-Server-Name attribute
  3784. //
  3785. rgModServerVals[0] = L"*";
  3786. rgModServerVals[1] = NULL;
  3787. ldapModServer.mod_op = LDAP_MOD_ADD;
  3788. ldapModServer.mod_type = L"remoteServerName";
  3789. ldapModServer.mod_vals.modv_strvals = rgModServerVals;
  3790. //
  3791. // Assemble all the LDAPMod structures
  3792. //
  3793. rgldapMods[0] = &ldapModClass;
  3794. rgldapMods[1] = &ldapModCN;
  3795. rgldapMods[2] = &ldapModPkt;
  3796. rgldapMods[3] = &ldapModPktGuid;
  3797. rgldapMods[4] = &ldapModServer;
  3798. rgldapMods[5] = NULL;
  3799. //
  3800. // Create the Dfs metadata object.
  3801. //
  3802. dwErr = ldap_add_sW( pldap, wszDfsConfigDN, rgldapMods );
  3803. #if DBG
  3804. if (DfsDebug)
  3805. DbgPrint("ldap_add_sW(2) returned 0x%x\n", dwErr);
  3806. #endif
  3807. }
  3808. if (dwErr != LDAP_SUCCESS) {
  3809. dwErr = LdapMapErrorToWin32(dwErr);
  3810. goto Cleanup;
  3811. }
  3812. //
  3813. // Create a machine ACE
  3814. //
  3815. dwErr = DfsAddMachineAce(
  3816. pldap,
  3817. wszDcName,
  3818. wszDfsConfigDN,
  3819. wszServerName);
  3820. if (dwErr != ERROR_SUCCESS)
  3821. {
  3822. goto Cleanup;
  3823. }
  3824. //
  3825. // Tell the server to add itself to the object
  3826. //
  3827. dwErr = DfspBindToServer( wszServerName, &netdfs_bhandle );
  3828. #if DBG
  3829. if (DfsDebug)
  3830. DbgPrint("DfspBindToServer returned %d\n", dwErr);
  3831. #endif
  3832. if (dwErr == NERR_Success) {
  3833. RpcTryExcept {
  3834. dwErr = NetrDfsAddFtRoot(
  3835. wszServerName,
  3836. wszDcName,
  3837. wszRootShare,
  3838. wszFtDfsName,
  3839. (wszComment != NULL) ? wszComment : L"",
  3840. wszDfsConfigDN,
  3841. fNewFTDfs,
  3842. dwFlags,
  3843. &RootList);
  3844. #if DBG
  3845. if (DfsDebug)
  3846. DbgPrint("NetrDfsAddFtRoot returned %d\n", dwErr);
  3847. #endif
  3848. } RpcExcept(1) {
  3849. dwErr = RpcExceptionCode();
  3850. } RpcEndExcept;
  3851. DfspFreeBinding( netdfs_bhandle );
  3852. }
  3853. #if DBG
  3854. if (DfsDebug) {
  3855. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  3856. ULONG n;
  3857. DbgPrint("cEntries=%d\n", RootList->cEntries);
  3858. for (n = 0; n < RootList->cEntries; n++)
  3859. DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare);
  3860. }
  3861. }
  3862. #endif
  3863. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  3864. ULONG n;
  3865. for (n = 0; n < RootList->cEntries; n++) {
  3866. DfspNotifyFtRoot(
  3867. RootList->Entry[n].ServerShare,
  3868. wszDcName);
  3869. }
  3870. NetApiBufferFree(RootList);
  3871. }
  3872. if (dwErr == ERROR_ALREADY_EXISTS) {
  3873. goto Cleanup;
  3874. } else if (dwErr != ERROR_SUCCESS) {
  3875. goto TearDown;
  3876. }
  3877. //
  3878. // Have the DC flush the Ft table
  3879. //
  3880. DfspFlushFtTable(
  3881. wszDcName,
  3882. wszFtDfsName);
  3883. //
  3884. // Flush the local Pkt
  3885. //
  3886. DfspFlushPkt(NULL);
  3887. goto Cleanup;
  3888. TearDown:
  3889. //
  3890. // At this point we have added an ACE to the acl list to allow
  3891. // this machine to write the Dfs BLOB. But the add failed, so we
  3892. // need to remove the ACE we set earlier. If this fails we continue
  3893. // on anyway.
  3894. //
  3895. dwErr2 = DfsRemoveMachineAce(
  3896. pldap,
  3897. wszDcName,
  3898. wszDfsConfigDN,
  3899. wszServerName);
  3900. rgAttrs[0] = L"remoteServerName";
  3901. rgAttrs[1] = NULL;
  3902. if (pMsg != NULL) {
  3903. ldap_msgfree(pMsg);
  3904. pMsg = NULL;
  3905. }
  3906. dwErr2 = ldap_search_sW(
  3907. pldap,
  3908. wszDfsConfigDN,
  3909. LDAP_SCOPE_BASE,
  3910. L"(objectClass=*)",
  3911. rgAttrs,
  3912. 0,
  3913. &pMsg);
  3914. if (dwErr2 != LDAP_SUCCESS) {
  3915. dwErr2 = LdapMapErrorToWin32(dwErr2);
  3916. goto Cleanup;
  3917. }
  3918. dwErr2 = ERROR_SUCCESS;
  3919. pmsgServers = ldap_first_entry(pldap, pMsg);
  3920. if (pmsgServers != NULL) {
  3921. rgServers = ldap_get_valuesW(
  3922. pldap,
  3923. pmsgServers,
  3924. L"remoteServerName");
  3925. if (rgServers != NULL) {
  3926. cServers = ldap_count_valuesW( rgServers );
  3927. if (cServers == 1) {
  3928. //
  3929. // Delete the Dfs metadata object.
  3930. //
  3931. ULONG RetryCount = MAX_DFS_LDAP_RETRY;
  3932. do
  3933. {
  3934. dwErr2 = ldap_delete_sW( pldap, wszDfsConfigDN);
  3935. #if DBG
  3936. if (dwErr2 == LDAP_BUSY)
  3937. {
  3938. if (DfsDebug)
  3939. DbgPrint("delete object returning %d\n", dwErr2);
  3940. }
  3941. #endif
  3942. } while ( RetryCount-- && (dwErr2 == LDAP_BUSY) );
  3943. }
  3944. ldap_value_freeW( rgServers );
  3945. } else {
  3946. dwErr2 = ERROR_OUTOFMEMORY;
  3947. }
  3948. } else {
  3949. dwErr2 = ERROR_OUTOFMEMORY;
  3950. }
  3951. if (dwErr2 != ERROR_SUCCESS) {
  3952. goto Cleanup;
  3953. }
  3954. ldap_msgfree(pMsg);
  3955. pMsg = NULL;
  3956. Cleanup:
  3957. if (pMsg != NULL)
  3958. ldap_msgfree(pMsg);
  3959. if (pldap != NULL)
  3960. ldap_unbind( pldap );
  3961. if (wszConfigurationDN != NULL)
  3962. free(wszConfigurationDN);
  3963. if (wszDfsConfigDN != NULL)
  3964. free(wszDfsConfigDN);
  3965. #if DBG
  3966. if (DfsDebug)
  3967. DbgPrint("DfspCreateFtDfs returning %d\n", dwErr);
  3968. #endif
  3969. return( dwErr );
  3970. }
  3971. //+----------------------------------------------------------------------------
  3972. //
  3973. // Function: DfspTearDownFtDfs
  3974. //
  3975. // Synopsis: Updates/deletes the Ds object representing the FtDfs
  3976. //
  3977. // Arguments: wszServerName - Name of server we're removing
  3978. // wszDcName - DC to use
  3979. // wszRootShare - Root share
  3980. // wszFtDfsName - Name of FtDfs we are modifying
  3981. // dwFlags - 0
  3982. //
  3983. // Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
  3984. //
  3985. //-----------------------------------------------------------------------------
  3986. DWORD
  3987. DfspTearDownFtDfs(
  3988. IN LPWSTR wszServerName,
  3989. IN LPWSTR wszDcName,
  3990. IN LPWSTR wszRootShare,
  3991. IN LPWSTR wszFtDfsName,
  3992. IN DWORD dwFlags)
  3993. {
  3994. DWORD dwErr = ERROR_SUCCESS;
  3995. LPWSTR wszDfsConfigDN = NULL;
  3996. LPWSTR wszConfigurationDN = NULL;
  3997. PDFSM_ROOT_LIST RootList = NULL;
  3998. LDAP *pldap = NULL;
  3999. PLDAPMessage pMsg = NULL;
  4000. LDAPModW ldapModServer;
  4001. LPWSTR rgAttrs[5];
  4002. PLDAPModW rgldapMods[6];
  4003. LDAPMessage *pmsgServers;
  4004. PWCHAR *rgServers;
  4005. DWORD cServers;
  4006. ULONG Size;
  4007. #if DBG
  4008. if (DfsDebug)
  4009. DbgPrint("DfspTearDownFtDfs(%ws,%ws,%ws,%ws,%d)\n",
  4010. wszServerName,
  4011. wszDcName,
  4012. wszRootShare,
  4013. wszFtDfsName,
  4014. dwFlags);
  4015. #endif
  4016. dwErr = DfspLdapOpen(
  4017. wszDcName,
  4018. &pldap,
  4019. &wszConfigurationDN);
  4020. if (dwErr != ERROR_SUCCESS) {
  4021. goto Cleanup;
  4022. }
  4023. if ((dwFlags & DFS_FORCE_REMOVE) != 0) {
  4024. dwErr = DfspBindToServer(wszDcName, &netdfs_bhandle);
  4025. } else {
  4026. dwErr = DfspBindToServer(wszServerName, &netdfs_bhandle);
  4027. }
  4028. if (dwErr == NERR_Success) {
  4029. RpcTryExcept {
  4030. dwErr = NetrDfsRemoveFtRoot(
  4031. wszServerName,
  4032. wszDcName,
  4033. wszRootShare,
  4034. wszFtDfsName,
  4035. dwFlags,
  4036. &RootList);
  4037. #if DBG
  4038. if (DfsDebug)
  4039. DbgPrint("NetrDfsRemoveFtRoot returned %d\n", dwErr);
  4040. #endif
  4041. } RpcExcept(1) {
  4042. dwErr = RpcExceptionCode();
  4043. } RpcEndExcept;
  4044. DfspFreeBinding( netdfs_bhandle );
  4045. }
  4046. #if DBG
  4047. if (DfsDebug) {
  4048. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  4049. ULONG n;
  4050. DbgPrint("cEntries=%d\n", RootList->cEntries);
  4051. for (n = 0; n < RootList->cEntries; n++)
  4052. DbgPrint("[%d]%ws\n", n, RootList->Entry[n].ServerShare);
  4053. }
  4054. }
  4055. #endif
  4056. if (dwErr == ERROR_SUCCESS && RootList != NULL) {
  4057. ULONG n;
  4058. for (n = 0; n < RootList->cEntries; n++) {
  4059. DfspNotifyFtRoot(
  4060. RootList->Entry[n].ServerShare,
  4061. wszDcName);
  4062. }
  4063. NetApiBufferFree(RootList);
  4064. }
  4065. if (dwErr != ERROR_SUCCESS) {
  4066. goto Cleanup;
  4067. }
  4068. //
  4069. // Build the name of the object representing the FtDfs
  4070. //
  4071. Size = wcslen(L"CN=") +
  4072. wcslen(wszFtDfsName) +
  4073. wcslen(L",") +
  4074. wcslen(wszConfigurationDN);
  4075. if (Size > MAX_PATH) {
  4076. dwErr = ERROR_DS_NAME_TOO_LONG;
  4077. goto Cleanup;
  4078. }
  4079. wszDfsConfigDN = malloc((Size+1) * sizeof(WCHAR));
  4080. if (wszDfsConfigDN == NULL) {
  4081. dwErr = ERROR_OUTOFMEMORY;
  4082. goto Cleanup;
  4083. }
  4084. wcscpy(wszDfsConfigDN,L"CN=");
  4085. wcscat(wszDfsConfigDN,wszFtDfsName);
  4086. wcscat(wszDfsConfigDN,L",");
  4087. wcscat(wszDfsConfigDN,wszConfigurationDN);
  4088. //
  4089. // Remove machine ACE
  4090. //
  4091. dwErr = DfsRemoveMachineAce(
  4092. pldap,
  4093. wszDcName,
  4094. wszDfsConfigDN,
  4095. wszServerName);
  4096. //
  4097. // If this was the last root, remove DS obj representing this FtDfs
  4098. //
  4099. rgAttrs[0] = L"remoteServerName";
  4100. rgAttrs[1] = NULL;
  4101. dwErr = ldap_search_sW(
  4102. pldap,
  4103. wszDfsConfigDN,
  4104. LDAP_SCOPE_BASE,
  4105. L"(objectClass=*)",
  4106. rgAttrs,
  4107. 0,
  4108. &pMsg);
  4109. if (dwErr != LDAP_SUCCESS) {
  4110. dwErr = LdapMapErrorToWin32(dwErr);
  4111. goto Cleanup;
  4112. }
  4113. dwErr = ERROR_SUCCESS;
  4114. pmsgServers = ldap_first_entry(pldap, pMsg);
  4115. if (pmsgServers != NULL) {
  4116. rgServers = ldap_get_valuesW(
  4117. pldap,
  4118. pmsgServers,
  4119. L"remoteServerName");
  4120. if (rgServers != NULL) {
  4121. cServers = ldap_count_valuesW( rgServers );
  4122. if (cServers == 1) {
  4123. //
  4124. // Delete the Dfs metadata object.
  4125. //
  4126. ULONG RetryCount = MAX_DFS_LDAP_RETRY;
  4127. do
  4128. {
  4129. dwErr = ldap_delete_sW( pldap, wszDfsConfigDN);
  4130. #if DBG
  4131. if (dwErr == LDAP_BUSY)
  4132. {
  4133. if (DfsDebug)
  4134. DbgPrint("delete object returning %d\n", dwErr);
  4135. }
  4136. #endif
  4137. } while ( RetryCount-- && (dwErr == LDAP_BUSY) );
  4138. if (dwErr != LDAP_SUCCESS) {
  4139. dwErr = LdapMapErrorToWin32(dwErr);
  4140. } else {
  4141. dwErr = ERROR_SUCCESS;
  4142. }
  4143. }
  4144. ldap_value_freeW( rgServers );
  4145. } else {
  4146. dwErr = ERROR_OUTOFMEMORY;
  4147. }
  4148. } else {
  4149. dwErr = ERROR_OUTOFMEMORY;
  4150. }
  4151. ldap_msgfree( pMsg );
  4152. pMsg = NULL;
  4153. if (dwErr != ERROR_SUCCESS) {
  4154. goto Cleanup;
  4155. }
  4156. //
  4157. // Have the DC flush the Ft table
  4158. //
  4159. DfspFlushFtTable(
  4160. wszDcName,
  4161. wszFtDfsName);
  4162. //
  4163. // Flush the local Pkt
  4164. //
  4165. DfspFlushPkt(NULL);
  4166. Cleanup:
  4167. #if DBG
  4168. if (DfsDebug)
  4169. DbgPrint("DfspTearDownFtDfs at Cleanup:\n");
  4170. #endif
  4171. if (pMsg != NULL)
  4172. ldap_msgfree( pMsg );
  4173. if (pldap != NULL)
  4174. ldap_unbind( pldap );
  4175. if (wszConfigurationDN != NULL)
  4176. free(wszConfigurationDN);
  4177. if (wszDfsConfigDN != NULL)
  4178. free(wszDfsConfigDN);
  4179. #if DBG
  4180. if (DfsDebug)
  4181. DbgPrint("DfspTearDownFtDfs returning %d\n", dwErr);
  4182. #endif
  4183. return( dwErr );
  4184. }
  4185. //+----------------------------------------------------------------------------
  4186. //
  4187. // Function: DfspFlushFtTable
  4188. //
  4189. // Synopsis: Goes to a DC and flushes an entry from its FtDfs name cache
  4190. //
  4191. // Arguments: wszDcName - Name of DC
  4192. // wszFtDfsName - The FtDfs name to flush
  4193. //
  4194. // Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
  4195. //
  4196. //-----------------------------------------------------------------------------
  4197. VOID
  4198. DfspFlushFtTable(
  4199. LPWSTR wszDcName,
  4200. LPWSTR wszFtDfsName)
  4201. {
  4202. DWORD dwErr;
  4203. //
  4204. // We should have a valid ServerName. Lets try to bind to it,
  4205. // and call the server.
  4206. //
  4207. dwErr = DfspBindToServer( wszDcName, &netdfs_bhandle );
  4208. if (dwErr == NERR_Success) {
  4209. RpcTryExcept {
  4210. dwErr = NetrDfsFlushFtTable(
  4211. wszDcName,
  4212. wszFtDfsName);
  4213. } RpcExcept(1) {
  4214. dwErr = RpcExceptionCode();
  4215. } RpcEndExcept;
  4216. DfspFreeBinding( netdfs_bhandle );
  4217. }
  4218. }
  4219. //+----------------------------------------------------------------------------
  4220. //
  4221. // Function: DfspSetDomainToDc
  4222. //
  4223. // Synopsis: Sets a DC in the special table to 'active'.
  4224. //
  4225. // Arguments: DomainName -- Domain of DC to set active
  4226. // DcName -- Dc to make active
  4227. //
  4228. // Returns: NTSTATUS of the call (STATUS_SUCCESS or error)
  4229. //
  4230. //-----------------------------------------------------------------------------
  4231. NTSTATUS
  4232. DfspSetDomainToDc(
  4233. LPWSTR DomainName,
  4234. LPWSTR DcName)
  4235. {
  4236. PDFS_SPECIAL_SET_DC_INPUT_ARG arg = NULL;
  4237. NTSTATUS NtStatus;
  4238. HANDLE DriverHandle = NULL;
  4239. IO_STATUS_BLOCK IoStatusBlock;
  4240. OBJECT_ATTRIBUTES objectAttributes;
  4241. UNICODE_STRING DfsDriverName;
  4242. PDFS_IS_VALID_PREFIX_ARG pPrefixArg = NULL;
  4243. PCHAR cp;
  4244. ULONG Size;
  4245. if (DomainName == NULL || DcName == NULL) {
  4246. NtStatus = STATUS_INVALID_PARAMETER;
  4247. goto exit_with_status;
  4248. }
  4249. Size = sizeof(DFS_SPECIAL_SET_DC_INPUT_ARG) +
  4250. wcslen(DomainName) * sizeof(WCHAR) +
  4251. wcslen(DcName) * sizeof(WCHAR);
  4252. arg = (PDFS_SPECIAL_SET_DC_INPUT_ARG) malloc(Size);
  4253. if (arg == NULL) {
  4254. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  4255. goto exit_with_status;
  4256. }
  4257. RtlZeroMemory(arg, Size);
  4258. arg->SpecialName.Length = wcslen(DomainName) * sizeof(WCHAR);
  4259. arg->SpecialName.MaximumLength = arg->SpecialName.Length;
  4260. arg->DcName.Length = wcslen(DcName) * sizeof(WCHAR);
  4261. arg->DcName.MaximumLength = arg->DcName.Length;
  4262. cp = (PCHAR)arg + sizeof(DFS_SPECIAL_SET_DC_INPUT_ARG);
  4263. arg->SpecialName.Buffer = (WCHAR *)cp;
  4264. RtlCopyMemory(cp, DomainName, arg->SpecialName.Length);
  4265. cp += arg->SpecialName.Length;
  4266. arg->DcName.Buffer = (WCHAR *)cp;
  4267. RtlCopyMemory(cp, DcName, arg->DcName.Length);
  4268. POINTER_TO_OFFSET(arg->SpecialName.Buffer, arg);
  4269. POINTER_TO_OFFSET(arg->DcName.Buffer, arg);
  4270. RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
  4271. InitializeObjectAttributes(
  4272. &objectAttributes,
  4273. &DfsDriverName,
  4274. OBJ_CASE_INSENSITIVE,
  4275. NULL,
  4276. NULL
  4277. );
  4278. NtStatus = NtCreateFile(
  4279. &DriverHandle,
  4280. SYNCHRONIZE | FILE_WRITE_DATA,
  4281. &objectAttributes,
  4282. &IoStatusBlock,
  4283. NULL,
  4284. FILE_ATTRIBUTE_NORMAL,
  4285. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  4286. FILE_OPEN_IF,
  4287. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  4288. NULL,
  4289. 0);
  4290. if (NT_SUCCESS(NtStatus)) {
  4291. NtStatus = NtFsControlFile(
  4292. DriverHandle,
  4293. NULL, // Event,
  4294. NULL, // ApcRoutine,
  4295. NULL, // ApcContext,
  4296. &IoStatusBlock,
  4297. FSCTL_DFS_SPECIAL_SET_DC,
  4298. arg,
  4299. Size,
  4300. NULL,
  4301. 0);
  4302. NtClose(DriverHandle);
  4303. }
  4304. exit_with_status:
  4305. if (arg != NULL) {
  4306. free(arg);
  4307. }
  4308. return NtStatus;
  4309. }
  4310. //+----------------------------------------------------------------------------
  4311. //
  4312. // Function: I_NetDfsIsThisADomainName
  4313. //
  4314. // Synopsis: Checks the special name table to see if the
  4315. // name matches a domain name.
  4316. //
  4317. // Arguments: [wszName] -- Name to check
  4318. //
  4319. // Returns: [ERROR_SUCCESS] -- Name is indeed a domain name.
  4320. //
  4321. // [ERROR_FILE_NOT_FOUND] -- Name is not a domain name
  4322. //
  4323. //-----------------------------------------------------------------------------
  4324. DWORD
  4325. I_NetDfsIsThisADomainName(
  4326. LPWSTR wszName)
  4327. {
  4328. DWORD dwErr;
  4329. PWCHAR DCList = NULL;
  4330. dwErr = DfspIsThisADomainName(
  4331. wszName,
  4332. &DCList);
  4333. if (DCList != NULL) {
  4334. free(DCList);
  4335. }
  4336. return dwErr;
  4337. }
  4338. //+----------------------------------------------------------------------------
  4339. //
  4340. // Function: DfspNotifyFtRoot
  4341. //
  4342. // Synopsis: Rpc's to a supposed FtDfs root
  4343. // and tells it a DC to reinit from.
  4344. //
  4345. // Arguments: wszServerShare - The server to go to, in a form of \\server\share
  4346. // wszDcName - DC to use
  4347. //
  4348. // Returns: Nothing
  4349. //
  4350. //-----------------------------------------------------------------------------
  4351. VOID
  4352. DfspNotifyFtRoot(
  4353. LPWSTR wszServerShare,
  4354. LPWSTR wszDcName)
  4355. {
  4356. DWORD dwErr;
  4357. ULONG i;
  4358. #if DBG
  4359. if (DfsDebug)
  4360. DbgPrint("DfspNotifyFtRoot(%ws,%ws)\n",
  4361. wszServerShare,
  4362. wszDcName);
  4363. #endif
  4364. if (wszServerShare == NULL || wszServerShare[1] != L'\\') {
  4365. return;
  4366. }
  4367. for (i = 2; wszServerShare[i] != UNICODE_NULL && wszServerShare[i] != L'\\'; i++) {
  4368. NOTHING;
  4369. }
  4370. if (wszServerShare[i] == L'\\') {
  4371. wszServerShare[i] = UNICODE_NULL;
  4372. //
  4373. // We should have a valid ServerName. Lets try to bind to it,
  4374. // and call the server.
  4375. //
  4376. dwErr = DfspBindToServer( &wszServerShare[2], &netdfs_bhandle );
  4377. if (dwErr == NERR_Success) {
  4378. RpcTryExcept {
  4379. dwErr = NetrDfsSetDcAddress(
  4380. &wszServerShare[2],
  4381. wszDcName,
  4382. 60 * 60 * 2, // 2 hours
  4383. (NET_DFS_SETDC_TIMEOUT | NET_DFS_SETDC_INITPKT)
  4384. );
  4385. } RpcExcept(1) {
  4386. dwErr = RpcExceptionCode();
  4387. } RpcEndExcept;
  4388. DfspFreeBinding( netdfs_bhandle );
  4389. }
  4390. wszServerShare[i] = L'\\';
  4391. }
  4392. #if DBG
  4393. if (DfsDebug)
  4394. DbgPrint("DfspNotifyFtRoot dwErr=%d\n", dwErr);
  4395. #endif
  4396. }
  4397. //+----------------------------------------------------------------------------
  4398. //
  4399. // Function: DfspIsThisADomainName
  4400. //
  4401. // Synopsis: Calls the mup to have it check the special name table to see if the
  4402. // name matches a domain name. Returns a list of DC's in the domain,
  4403. // as a list of strings. The list is terminated with a double-null.
  4404. //
  4405. // Arguments: [wszName] -- Name to check
  4406. // [ppList] -- Pointer to pointer for results.
  4407. //
  4408. // Returns: [ERROR_SUCCESS] -- Name is indeed a domain name.
  4409. //
  4410. // [ERROR_FILE_NOT_FOUND] -- Name is not a domain name
  4411. //
  4412. //-----------------------------------------------------------------------------
  4413. DWORD
  4414. DfspIsThisADomainName(
  4415. LPWSTR wszName,
  4416. PWCHAR *ppList)
  4417. {
  4418. NTSTATUS NtStatus;
  4419. IO_STATUS_BLOCK IoStatusBlock;
  4420. OBJECT_ATTRIBUTES objectAttributes;
  4421. UNICODE_STRING DfsDriverName;
  4422. HANDLE DriverHandle = NULL;
  4423. DWORD dwErr;
  4424. PCHAR OutBuf = NULL;
  4425. ULONG Size = 0x100;
  4426. ULONG Count = 0;
  4427. RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
  4428. InitializeObjectAttributes(
  4429. &objectAttributes,
  4430. &DfsDriverName,
  4431. OBJ_CASE_INSENSITIVE,
  4432. NULL,
  4433. NULL
  4434. );
  4435. NtStatus = NtCreateFile(
  4436. &DriverHandle,
  4437. SYNCHRONIZE,
  4438. &objectAttributes,
  4439. &IoStatusBlock,
  4440. NULL,
  4441. FILE_ATTRIBUTE_NORMAL,
  4442. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  4443. FILE_OPEN_IF,
  4444. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  4445. NULL,
  4446. 0
  4447. );
  4448. if (!NT_SUCCESS(NtStatus)) {
  4449. return ERROR_FILE_NOT_FOUND;
  4450. }
  4451. Retry:
  4452. OutBuf = malloc(Size);
  4453. if (OutBuf == NULL) {
  4454. NtClose(DriverHandle);
  4455. return ERROR_NOT_ENOUGH_MEMORY;
  4456. }
  4457. NtStatus = NtFsControlFile(
  4458. DriverHandle,
  4459. NULL, // Event,
  4460. NULL, // ApcRoutine,
  4461. NULL, // ApcContext,
  4462. &IoStatusBlock,
  4463. FSCTL_DFS_GET_SPC_TABLE,
  4464. wszName,
  4465. (wcslen(wszName) + 1) * sizeof(WCHAR),
  4466. OutBuf,
  4467. Size
  4468. );
  4469. if (NtStatus == STATUS_SUCCESS) {
  4470. dwErr = ERROR_SUCCESS;
  4471. } else if (NtStatus == STATUS_BUFFER_OVERFLOW && ++Count < 5) {
  4472. Size = *((ULONG *)OutBuf);
  4473. free(OutBuf);
  4474. goto Retry;
  4475. } else {
  4476. dwErr = ERROR_FILE_NOT_FOUND;
  4477. }
  4478. NtClose(DriverHandle);
  4479. *ppList = (WCHAR *)OutBuf;
  4480. return dwErr;
  4481. }
  4482. DWORD
  4483. DfspLdapOpen(
  4484. LPWSTR wszDcName,
  4485. LDAP **ppldap,
  4486. LPWSTR *pwszObjectName)
  4487. {
  4488. DWORD dwErr;
  4489. DWORD i;
  4490. ULONG Size;
  4491. ULONG Len;
  4492. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  4493. PLDAPMessage pMsg = NULL;
  4494. LDAP *pldap = NULL;
  4495. LPWSTR wszConfigurationDN = NULL;
  4496. LPWSTR rgAttrs[5];
  4497. if (wszDcName == NULL ||
  4498. wcslen(wszDcName) == 0 ||
  4499. ppldap == NULL ||
  4500. pwszObjectName == NULL
  4501. ) {
  4502. dwErr = ERROR_INVALID_PARAMETER;
  4503. goto Cleanup;
  4504. }
  4505. #if DBG
  4506. if (DfsDebug)
  4507. DbgPrint("DfspLdapOpen(%ws)\n", wszDcName);
  4508. #endif
  4509. pldap = ldap_init(wszDcName, LDAP_PORT);
  4510. if (pldap == NULL) {
  4511. #if DBG
  4512. if (DfsDebug)
  4513. DbgPrint("DfspLdapOpen:ldap_init failed\n");
  4514. #endif
  4515. dwErr = ERROR_INVALID_NAME;
  4516. goto Cleanup;
  4517. }
  4518. dwErr = ldap_set_option(pldap, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_ON);
  4519. if (dwErr != LDAP_SUCCESS) {
  4520. pldap = NULL;
  4521. goto Cleanup;
  4522. }
  4523. dwErr = ldap_bind_s(pldap, NULL, NULL, LDAP_AUTH_SSPI);
  4524. if (dwErr != LDAP_SUCCESS) {
  4525. #if DBG
  4526. if (DfsDebug)
  4527. DbgPrint("ldap_bind_s failed with ldap error %d\n", dwErr);
  4528. #endif
  4529. pldap = NULL;
  4530. dwErr = LdapMapErrorToWin32(dwErr);
  4531. goto Cleanup;
  4532. }
  4533. //
  4534. // Get attribute "defaultNameContext" containing name of entry we'll be
  4535. // using for our DN
  4536. //
  4537. rgAttrs[0] = L"defaultnamingContext";
  4538. rgAttrs[1] = NULL;
  4539. dwErr = ldap_search_s(
  4540. pldap,
  4541. L"",
  4542. LDAP_SCOPE_BASE,
  4543. L"(objectClass=*)",
  4544. rgAttrs,
  4545. 0,
  4546. &pMsg);
  4547. if (dwErr == LDAP_SUCCESS) {
  4548. PLDAPMessage pEntry = NULL;
  4549. PWCHAR *rgszNamingContexts = NULL;
  4550. DWORD i, cNamingContexts;
  4551. dwErr = ERROR_SUCCESS;
  4552. if ((pEntry = ldap_first_entry(pldap, pMsg)) != NULL &&
  4553. (rgszNamingContexts = ldap_get_values(pldap, pEntry, rgAttrs[0])) != NULL &&
  4554. (cNamingContexts = ldap_count_values(rgszNamingContexts)) > 0) {
  4555. wszConfigurationDN = malloc((wcslen(rgszNamingContexts[0]) + 1) * sizeof(WCHAR));
  4556. if (wszConfigurationDN != NULL)
  4557. wcscpy( wszConfigurationDN, rgszNamingContexts[0]);
  4558. else
  4559. dwErr = ERROR_OUTOFMEMORY;
  4560. } else {
  4561. dwErr = ERROR_UNEXP_NET_ERR;
  4562. }
  4563. if (rgszNamingContexts != NULL)
  4564. ldap_value_free( rgszNamingContexts );
  4565. } else {
  4566. dwErr = LdapMapErrorToWin32(dwErr);
  4567. }
  4568. if (dwErr != ERROR_SUCCESS) {
  4569. #if DBG
  4570. if (DfsDebug)
  4571. DbgPrint("Unable to find Configuration naming context\n");
  4572. #endif
  4573. goto Cleanup;
  4574. }
  4575. //
  4576. // Create string with full object name
  4577. //
  4578. Size = wcslen(DfsConfigContainer) * sizeof(WCHAR) +
  4579. sizeof(WCHAR) +
  4580. wcslen(wszConfigurationDN) * sizeof(WCHAR) +
  4581. sizeof(WCHAR);
  4582. *pwszObjectName = malloc(Size);
  4583. if (*pwszObjectName == NULL) {
  4584. dwErr = ERROR_OUTOFMEMORY;
  4585. goto Cleanup;
  4586. }
  4587. wcscpy(*pwszObjectName,DfsConfigContainer);
  4588. wcscat(*pwszObjectName,L",");
  4589. wcscat(*pwszObjectName,wszConfigurationDN);
  4590. #if DBG
  4591. if (DfsDebug)
  4592. DbgPrint("DfsLdapOpen:object name=[%ws]\n", *pwszObjectName);
  4593. #endif
  4594. Cleanup:
  4595. if (pDCInfo != NULL)
  4596. NetApiBufferFree( pDCInfo );
  4597. if (dwErr != ERROR_SUCCESS) {
  4598. ldap_unbind( pldap );
  4599. pldap = NULL;
  4600. }
  4601. if (wszConfigurationDN != NULL)
  4602. free(wszConfigurationDN);
  4603. if (pMsg != NULL)
  4604. ldap_msgfree(pMsg);
  4605. *ppldap = pldap;
  4606. #if DBG
  4607. if (DfsDebug)
  4608. DbgPrint("DfsLdapOpen:returning %d\n", dwErr);
  4609. #endif
  4610. return( dwErr );
  4611. }
  4612. //+----------------------------------------------------------------------------
  4613. //
  4614. // Function: DfspIsInvalidName, local
  4615. //
  4616. // Synopsis: Sees if a DomDfs name is Invalid
  4617. //
  4618. // Arguments: [DomDfsName] -- Name test.
  4619. //
  4620. // Returns: TRUE if invalid, FALSE otherwise.
  4621. //
  4622. //-----------------------------------------------------------------------------
  4623. BOOLEAN
  4624. DfspIsInvalidName(
  4625. LPWSTR ShareName)
  4626. {
  4627. ULONG i;
  4628. for (i = 0; InvalidNames[i] != NULL; i++) {
  4629. if (_wcsicmp(InvalidNames[i], ShareName) == 0) {
  4630. return TRUE;
  4631. }
  4632. }
  4633. return FALSE;
  4634. }