Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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