Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2355 lines
69 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsApiFrontEnd.cxx
  6. //
  7. // Contents: Contains the support routines for the administering DFS
  8. // The DFS api server implementation uses this.
  9. // Also, any other admin tool that does not use the API
  10. // can use the facilities provided here to administer DFS.
  11. //
  12. // Classes: none.
  13. //
  14. // History: Feb. 8 2000, Author: udayh
  15. //
  16. //-----------------------------------------------------------------------------
  17. #include "DfsRootFolder.hxx"
  18. #include "DfsReferral.hxx"
  19. #include "lm.h"
  20. #include "lmdfs.h"
  21. #include "DfsRegistryStore.hxx"
  22. #include "DfsADBlobStore.hxx"
  23. #include "DfsADBlobRootFolder.hxx"
  24. #include "DfsEnterpriseStore.hxx"
  25. #include "DfsInit.hxx"
  26. #include "netdfs.h"
  27. #include "DomainControllerSupport.hxx"
  28. #include "dfsfsctl.h"
  29. //
  30. // logging specific includes
  31. //
  32. #include "DfsApiFrontEnd.tmh"
  33. DFSSTATUS
  34. DfsDirectApiAllocContext(
  35. OUT PDFS_DIRECT_API_CONTEXT *ppApiContext,
  36. IN PUNICODE_STRING pDfsPathName,
  37. IN PUNICODE_STRING pServerName,
  38. IN PUNICODE_STRING pShareName);
  39. VOID
  40. DfsDirectApiFreeContext(
  41. PDFS_DIRECT_API_CONTEXT pApiContext);
  42. //
  43. //dfsdev: validate input arguments.
  44. //
  45. #define API_VALIDATE_ARGUMENTS(_a, _b, _c, _d) \
  46. { \
  47. if ((((_b) != NULL) && (IS_VALID_SERVER_TOKEN(_b, wcslen(_b)) == FALSE))) \
  48. { \
  49. (_d) = ERROR_INVALID_NAME; \
  50. } \
  51. else \
  52. { \
  53. (_d) = ERROR_SUCCESS; \
  54. } \
  55. }
  56. //
  57. // Valid link states as published by lmdfs.h.
  58. // dfsdev: migrate this to the header file eventually.
  59. //
  60. inline BOOLEAN
  61. IsValidReplicaState( DWORD State )
  62. {
  63. return ( State == DFS_STORAGE_STATE_OFFLINE ||
  64. State == DFS_STORAGE_STATE_ONLINE );
  65. }
  66. //
  67. // Unfortunately these values are such that bitwise OR isn't
  68. // sufficient.
  69. //
  70. inline BOOLEAN
  71. IsValidLinkState( DWORD State )
  72. {
  73. return ( State == DFS_VOLUME_STATE_OK ||
  74. State == DFS_VOLUME_STATE_OFFLINE ||
  75. State == DFS_VOLUME_STATE_ONLINE );
  76. }
  77. inline BOOLEAN
  78. IsValidGetInfoLevel( DWORD Level )
  79. {
  80. return ((Level >= 100 && Level <= 102) ||
  81. (Level >= 1 && Level <= 4));
  82. }
  83. inline BOOLEAN
  84. IsValidSetInfoLevel( DWORD Level )
  85. {
  86. return (Level >= 100 && Level <= 102);
  87. }
  88. DFSSTATUS
  89. DfsAddValidate(
  90. LPWSTR DfsPathName,
  91. LPWSTR ServerName,
  92. LPWSTR ShareName,
  93. LPWSTR Comment,
  94. DWORD Flags )
  95. {
  96. DFSSTATUS Status = ERROR_SUCCESS;
  97. API_VALIDATE_ARGUMENTS( DfsPathName, ServerName, ShareName, Status);
  98. if (Status == ERROR_SUCCESS)
  99. {
  100. //
  101. // Null or empty server/share names are illegal.
  102. // The DfsPathName needs to have all three components \\x\y\z
  103. // but that'll get indirectly validated when we do DfsGetRootFolder.
  104. //
  105. if ((IsEmptyString( ServerName )) ||
  106. (IsEmptyString( ShareName )) ||
  107. (IsEmptyString( DfsPathName )))
  108. {
  109. Status = ERROR_INVALID_PARAMETER;
  110. }
  111. }
  112. if (Status == ERROR_SUCCESS)
  113. {
  114. //
  115. // Check for valid flags.
  116. //
  117. if (Flags &&
  118. (Flags & ~(DFS_ADD_VOLUME | DFS_RESTORE_VOLUME)))
  119. {
  120. Status = ERROR_INVALID_PARAMETER;
  121. }
  122. }
  123. if (Status == ERROR_SUCCESS)
  124. {
  125. StripTrailingSpacesFromPath(DfsPathName);
  126. }
  127. return Status;
  128. }
  129. //+----------------------------------------------------------------------------
  130. //
  131. // Function: DfsAdd
  132. //
  133. // Arguments: DfsPathName - the pathname that is being added or updated
  134. // ServerName - Name of server being added as target
  135. // ShareName - Name of share on ServerName backing the link
  136. // Comment - Comment associated if this is a new link
  137. // Flags - If DFS_ADD_VOLUME, fail this request if link exists
  138. //
  139. // Returns: ERROR_SUCCESS
  140. // Error code other wise.
  141. //
  142. //-----------------------------------------------------------------------------
  143. DFSSTATUS
  144. DfsAdd(
  145. LPWSTR DfsPathName,
  146. LPWSTR ServerName,
  147. LPWSTR ShareName,
  148. LPWSTR Comment,
  149. DWORD Flags )
  150. {
  151. DFSSTATUS Status = ERROR_SUCCESS;
  152. DfsRootFolder *pRoot = NULL;
  153. UNICODE_STRING DfsPath, LinkName;
  154. DFS_TRACE_NORM(API, "[%!FUNC!]DfsAdd for path %ws, Server %ws Share %ws\n",
  155. DfsPathName, ServerName, ShareName);
  156. //
  157. // Null or empty server/share names are illegal.
  158. // The DfsPathName needs to have all three components \\x\y\z
  159. // but that'll get indirectly validated when we do DfsGetRootFolder.
  160. //
  161. if ((IsEmptyString( ServerName )) ||
  162. (IsEmptyString( ShareName )) ||
  163. (IsEmptyString( DfsPathName )))
  164. {
  165. Status = ERROR_INVALID_PARAMETER;
  166. goto done;
  167. }
  168. //
  169. // One or two leading '\'s are valid components of a ServerName here.
  170. //
  171. if (ServerName[0] == UNICODE_PATH_SEP)
  172. {
  173. // advance past a max of two '\'s.
  174. ServerName++;
  175. if (ServerName[0] == UNICODE_PATH_SEP)
  176. {
  177. ServerName++;
  178. }
  179. }
  180. API_VALIDATE_ARGUMENTS( DfsPathName, ServerName, ShareName, Status);
  181. if (Status != ERROR_SUCCESS)
  182. goto done;
  183. //
  184. // Check for valid flags.
  185. //
  186. if (Flags &&
  187. (Flags & ~(DFS_ADD_VOLUME | DFS_RESTORE_VOLUME)))
  188. {
  189. Status = ERROR_INVALID_PARAMETER;
  190. goto done;
  191. }
  192. StripTrailingSpacesFromPath(DfsPathName);
  193. Status = DfsRtlInitUnicodeStringEx( &DfsPath, DfsPathName );
  194. if (Status != ERROR_SUCCESS)
  195. {
  196. goto done;
  197. }
  198. //
  199. // Get a root folder for the passed in path name.
  200. //
  201. Status = DfsGetRootFolder( &DfsPath,
  202. &LinkName,
  203. &pRoot );
  204. if (Status == ERROR_SUCCESS)
  205. {
  206. //
  207. // Let the root folder know that a new api request is coming in
  208. // This will give it a chance to let us know if api requests
  209. // are allowed, and to synchronize with the metadata as necessary.
  210. //
  211. // For callers linking with the server library directly, this is a no-op.
  212. // This is because they are supposed to perform a Initialize, Open,
  213. // Synchronize, Close sequence.
  214. //
  215. if (!DfsCheckDirectMode())
  216. {
  217. Status = pRoot->RootApiRequestPrologue( TRUE );
  218. }
  219. //
  220. // If we got a root folder, see if there is a link that matches
  221. // the rest of the name beyond the root.
  222. //
  223. if (Status == ERROR_SUCCESS) {
  224. //
  225. // Check if this is a valid link name. A valid link is one that
  226. // either is a perfect match of the LinkName, or the LinkName
  227. // does not encompass as existing link.
  228. //
  229. Status = pRoot->ValidateLinkName( &LinkName );
  230. //
  231. // If validate link name succeeds, we can add the servername
  232. // and share name as a target to this link
  233. //
  234. if (Status == ERROR_SUCCESS)
  235. {
  236. //
  237. // If someone wanted to create this as a new link, we fail the request here.
  238. // the link already exists.
  239. //
  240. if (Flags & DFS_ADD_VOLUME)
  241. {
  242. Status = ERROR_FILE_EXISTS;
  243. }
  244. else
  245. {
  246. //
  247. // Add the target to this link.
  248. //
  249. Status = pRoot->AddMetadataLinkReplica( &LinkName,
  250. ServerName,
  251. ShareName );
  252. }
  253. }
  254. else if (Status == ERROR_NOT_FOUND)
  255. {
  256. //
  257. // If the link was not found, at this point we are assured that this link is
  258. // neither a prefix of an existing link not is any link a prefix of this link
  259. // name (validate prefix above provides that assurance)
  260. // We add a new link to this root.
  261. //
  262. Status = pRoot->AddMetadataLink( &DfsPath,
  263. ServerName,
  264. ShareName,
  265. Comment );
  266. }
  267. //
  268. // We are done with this request, so release our reference on the root folder.
  269. //
  270. if (!DfsCheckDirectMode())
  271. {
  272. pRoot->RootApiRequestEpilogue( TRUE, Status );
  273. }
  274. }
  275. pRoot->ReleaseReference();
  276. }
  277. done:
  278. DFS_TRACE_ERROR_NORM(Status, API, "[%!FUNC!]for path %ws, Status %x\n",
  279. DfsPathName, Status );
  280. return Status;
  281. }
  282. //+----------------------------------------------------------------------------
  283. //
  284. // Function: DfsRemove
  285. //
  286. // Arguments: DfsPathName - the pathname that is being added or updated
  287. // ServerName - Name of server being added as target
  288. // ShareName - Name of share on ServerName backing the link
  289. //
  290. // Returns: ERROR_SUCCESS
  291. // Error code other wise.
  292. //
  293. //-----------------------------------------------------------------------------
  294. DFSSTATUS
  295. DfsRemove(
  296. LPWSTR DfsPathName,
  297. LPWSTR ServerName,
  298. LPWSTR ShareName )
  299. {
  300. DFSSTATUS Status = ERROR_SUCCESS;
  301. DfsRootFolder *pRoot = NULL;
  302. BOOLEAN LastReplica = FALSE;
  303. UNICODE_STRING DfsPath, LinkName;
  304. DFS_TRACE_NORM(API, "[%!FUNC!] for path %ws, Server=%ws Share=%ws \n", DfsPathName, ServerName, ShareName);
  305. //
  306. // One or two leading '\'s are valid components of a ServerName here.
  307. //
  308. if ((ServerName != NULL) && (ServerName[0] == UNICODE_PATH_SEP))
  309. {
  310. // advance past a max of two '\'s.
  311. ServerName++;
  312. if (ServerName[0] == UNICODE_PATH_SEP)
  313. {
  314. ServerName++;
  315. }
  316. }
  317. //
  318. // It is legal for the ServerName and the ShareName to be NULL. DfsPathName should
  319. // have all its \\x\y\z components, but that gets validated below in DfsGetRootFolder.
  320. //
  321. API_VALIDATE_ARGUMENTS( DfsPathName, ServerName, ShareName, Status);
  322. if (Status != ERROR_SUCCESS)
  323. {
  324. goto done;
  325. }
  326. Status = DfsRtlInitUnicodeStringEx( &DfsPath, DfsPathName );
  327. if (Status != ERROR_SUCCESS)
  328. {
  329. goto done;
  330. }
  331. if (IsEmptyUnicodeString( &DfsPath ))
  332. {
  333. Status = ERROR_INVALID_PARAMETER;
  334. goto done;
  335. }
  336. if (((ServerName == NULL) && (ShareName != NULL)) ||
  337. ((ServerName != NULL) && (ShareName == NULL)))
  338. {
  339. Status = ERROR_INVALID_PARAMETER;
  340. goto done;
  341. }
  342. //
  343. //Get the root folder matching this name. We get a referenced root folder.
  344. //
  345. Status = DfsGetRootFolder( &DfsPath,
  346. &LinkName,
  347. &pRoot );
  348. if (Status == ERROR_SUCCESS)
  349. {
  350. //
  351. // Let the root folder know that a new api request is coming in
  352. // This will give it a chance to let us know if api requests
  353. // are allowed, and to synchronize with the metadata as necessary.
  354. //
  355. if (!DfsCheckDirectMode())
  356. {
  357. Status = pRoot->RootApiRequestPrologue( TRUE );
  358. }
  359. //
  360. // If we got a root folder, see if there is a link that matches
  361. // the rest of the name beyond the root.
  362. //
  363. if (Status == ERROR_SUCCESS)
  364. {
  365. if ((ServerName != NULL) && (ShareName != NULL))
  366. {
  367. //
  368. // If the servername/sharename was provided, we just remove the matching target.
  369. // If the serername/sharename was not provided, we remove the link itself.
  370. //
  371. Status = pRoot->RemoveMetadataLinkReplica( &LinkName,
  372. ServerName,
  373. ShareName,
  374. &LastReplica );
  375. //
  376. // DFSDEV: REMOVE THIS FROM THE API!!!
  377. //
  378. if ((Status == ERROR_LAST_ADMIN) && (LastReplica == TRUE))
  379. {
  380. Status = pRoot->RemoveMetadataLink( &LinkName );
  381. }
  382. }
  383. else
  384. {
  385. Status = pRoot->RemoveMetadataLink( &LinkName );
  386. }
  387. //
  388. // We now release the reference that we have on the root.
  389. //
  390. if (!DfsCheckDirectMode())
  391. {
  392. pRoot->RootApiRequestEpilogue( TRUE, Status );
  393. }
  394. }
  395. pRoot->ReleaseReference();
  396. }
  397. done:
  398. DFS_TRACE_ERROR_NORM(Status, API, "DfsRemove for path %ws, Server=%ws Share=%ws, LastReplica=%d, Status %x\n",
  399. DfsPathName, ServerName, ShareName, LastReplica, Status);
  400. return Status;
  401. }
  402. //+----------------------------------------------------------------------------
  403. //
  404. // Function: DfsEnumerate
  405. //
  406. // Arguments:
  407. // LPWSTR DfsPathName - the pathname that is being added or updated
  408. // DWORD Level - the level of information requested
  409. // DWORD PrefMaxLen - a hint as to how many items to enumerate.
  410. // LPBYTE pBuffer - the buffer to fill, passed in by the caller.
  411. // LONG BufferSize, - the size of passed in buffer.
  412. // LPDWORD pEntriesRead - the number of entries read, set on return
  413. // LPDWORD pResumeHandle - the entry to start from, set to new value on return
  414. // PLONG pNextSizeRequired - size required to successfully complete this call.
  415. // usefule when this call return buffer overflow.
  416. //
  417. // Returns: ERROR_SUCCESS
  418. // Error code other wise.
  419. //
  420. //-----------------------------------------------------------------------------
  421. DFSSTATUS
  422. DfsEnumerate(
  423. LPWSTR DfsPathName,
  424. DWORD Level,
  425. DWORD PrefMaxLen,
  426. LPBYTE pBuffer,
  427. LONG BufferSize,
  428. LPDWORD pEntriesRead,
  429. LPDWORD pResumeHandle,
  430. PLONG pNextSizeRequired )
  431. {
  432. DFSSTATUS Status = ERROR_SUCCESS;
  433. DfsRootFolder *pRoot = NULL;
  434. LONG LevelInfoSize = 0;
  435. DWORD EntriesToRead = 0;
  436. UNICODE_STRING DfsPath, LinkName;
  437. UNICODE_STRING DfsServer, DfsShare;
  438. DFS_TRACE_NORM(API, "Dfs Enumerate for path %ws Level %d ResumeHandle %d PrefMaxLen %d Size %d\n",
  439. DfsPathName, Level, pResumeHandle ? *pResumeHandle : 0, PrefMaxLen, BufferSize);
  440. //
  441. // validate the input parameters.
  442. //
  443. API_VALIDATE_ARGUMENTS( DfsPathName, NULL, NULL, Status);
  444. if (Status != ERROR_SUCCESS)
  445. {
  446. goto done;
  447. }
  448. //
  449. // Get the unicode dfs path.
  450. //
  451. Status = DfsRtlInitUnicodeStringEx( &DfsPath, DfsPathName );
  452. if (Status != ERROR_SUCCESS)
  453. {
  454. goto done;
  455. }
  456. if(!pEntriesRead || !pNextSizeRequired || !pBuffer)
  457. {
  458. Status = ERROR_INVALID_PARAMETER;
  459. goto done;
  460. }
  461. Status = DfsApiSizeLevelHeader(Level, &LevelInfoSize);
  462. if (Status != ERROR_SUCCESS)
  463. {
  464. goto done;
  465. }
  466. Status = DfsGetPathComponents( &DfsPath,
  467. &DfsServer,
  468. &DfsShare,
  469. NULL );
  470. //
  471. // For legacy reasons, we need to support this call coming in with a null name.
  472. // This is where the server would host a single root, and we always knew which root
  473. // we wanted.
  474. // To workaround this situation, if we get a null pathname, we get the first root
  475. // folder and use that.
  476. //
  477. if (DfsShare.Length != 0)
  478. {
  479. Status = DfsGetRootFolder( &DfsPath,
  480. &LinkName,
  481. &pRoot );
  482. }
  483. else
  484. {
  485. Status = DfsGetOnlyRootFolder( &pRoot );
  486. }
  487. if (Status == ERROR_SUCCESS)
  488. {
  489. //
  490. // Let the root folder know that a new api request is coming in
  491. // This will give it a chance to let us know if api requests
  492. // are allowed, and to synchronize with the metadata as necessary.
  493. //
  494. // For callers linking with the server library directly, this is a no-op.
  495. // This is because they are supposed to perform a Initialize, Open,
  496. // Synchronize, Close sequence.
  497. //
  498. if (!DfsCheckDirectMode())
  499. {
  500. Status = pRoot->RootApiRequestPrologue( FALSE );
  501. }
  502. //
  503. // If we got a root folder, see if there is a link that matches
  504. // the rest of the name beyond the root.
  505. //
  506. if (Status == ERROR_SUCCESS)
  507. {
  508. //
  509. // If PrefMAxLen is 0xffffffff, we need to read all entries. OTherwise we need
  510. // to read a subset of the entries. Let PrefMaxLen decide the number in the array
  511. // of info parameters we pass back. (This is how we document our NEtDfsEnum api)
  512. //
  513. EntriesToRead = PrefMaxLen / LevelInfoSize;
  514. if (EntriesToRead == 0) {
  515. EntriesToRead = 1;
  516. }
  517. //
  518. // Things could be in a state of flux: if the request is for more than twice what we
  519. // already know about, limit it to 2 times our link count.
  520. //
  521. if (EntriesToRead > pRoot->RootEnumerationCount() * 2)
  522. {
  523. EntriesToRead = pRoot->RootEnumerationCount() * 2;
  524. }
  525. *pEntriesRead = EntriesToRead;
  526. //
  527. // Now enumerate the entries in the root in the passed in buffer.
  528. //
  529. Status = pRoot->EnumerateApiLinks( DfsPathName,
  530. Level,
  531. pBuffer,
  532. BufferSize,
  533. pEntriesRead,
  534. pResumeHandle,
  535. pNextSizeRequired );
  536. //
  537. // Release the root reference, and return status back to the caller.
  538. //
  539. if (!DfsCheckDirectMode())
  540. {
  541. pRoot->RootApiRequestEpilogue( FALSE, Status );
  542. }
  543. }
  544. pRoot->ReleaseReference();
  545. }
  546. done:
  547. DFS_TRACE_ERROR_NORM(Status, API, "Dfs Enumerate for path %ws EntriesRead %d ResumeHandle %d Status %x Size %d\n",
  548. DfsPathName, pEntriesRead ? *pEntriesRead : 0,
  549. pResumeHandle ? *pResumeHandle : 0,
  550. Status,
  551. pNextSizeRequired ? *pNextSizeRequired : 0);
  552. return Status;
  553. }
  554. //+----------------------------------------------------------------------------
  555. //
  556. // Function: DfsGetInfo
  557. //
  558. // Arguments:
  559. // LPWSTR DfsPathName - the pathname that is of interest.
  560. // DWORD Level - the level of information requested
  561. // LPBYTE pBuffer - the buffer to fill, passed in by caller
  562. // LONG BufferSize, - the size of passed in buffer.
  563. // PLONG pSizeRequired - size required to successfully complete this call.
  564. // usefule when this call return buffer overflow.
  565. //
  566. // Returns: ERROR_SUCCESS
  567. // Error code other wise.
  568. //
  569. //-----------------------------------------------------------------------------
  570. DFSSTATUS
  571. DfsGetInfo(
  572. LPWSTR DfsPathName,
  573. DWORD Level,
  574. LPBYTE pBuffer,
  575. LONG BufferSize,
  576. PLONG pSizeRequired )
  577. {
  578. DFSSTATUS Status = ERROR_SUCCESS;
  579. UNICODE_STRING DfsPath, LinkName;
  580. DfsRootFolder *pRoot = NULL;
  581. DFS_TRACE_NORM(API, "Dfs get info for path %ws Level %d\n",
  582. DfsPathName, Level );
  583. Status = DfsRtlInitUnicodeStringEx( &DfsPath, DfsPathName );
  584. if (Status != ERROR_SUCCESS)
  585. {
  586. goto done;
  587. }
  588. //
  589. // Validate the input parameters.
  590. //
  591. API_VALIDATE_ARGUMENTS( DfsPathName, NULL, NULL, Status);
  592. if (Status != ERROR_SUCCESS)
  593. {
  594. goto done;
  595. }
  596. if (!pSizeRequired || !pBuffer || (IsEmptyUnicodeString( &DfsPath )))
  597. {
  598. Status = ERROR_INVALID_PARAMETER;
  599. goto done;
  600. }
  601. //
  602. // Level has to be 100...102 or 1...4 currently.
  603. //
  604. if (!IsValidGetInfoLevel( Level ))
  605. {
  606. Status = ERROR_INVALID_PARAMETER;
  607. goto done;
  608. }
  609. //
  610. // Get a referenced root folder for the passed in path.
  611. //
  612. Status = DfsGetRootFolder( &DfsPath,
  613. &LinkName,
  614. &pRoot );
  615. if (Status == ERROR_SUCCESS)
  616. {
  617. if (!DfsCheckDirectMode())
  618. {
  619. Status = pRoot->RootApiRequestPrologue( FALSE );
  620. }
  621. //
  622. // If we got a root folder, see if there is a link that matches
  623. // the rest of the name beyond the root.
  624. //
  625. if (Status == ERROR_SUCCESS) {
  626. //
  627. // If we got a root folder, get the requested information into the passed
  628. // in buffer.
  629. //
  630. Status = pRoot->GetApiInformation( &DfsPath,
  631. &LinkName,
  632. Level,
  633. pBuffer,
  634. BufferSize,
  635. pSizeRequired );
  636. //
  637. //WE are done: release our reference on the root.
  638. //
  639. if (!DfsCheckDirectMode())
  640. {
  641. pRoot->RootApiRequestEpilogue( FALSE, Status );
  642. }
  643. }
  644. pRoot->ReleaseReference();
  645. }
  646. done:
  647. DFS_TRACE_ERROR_NORM(Status, API, "Dfs get info for path %ws Status %x\n",
  648. DfsPathName, Status );
  649. return Status;
  650. }
  651. //+----------------------------------------------------------------------------
  652. //
  653. // Function: DfsSetInfo
  654. //
  655. // Arguments:
  656. // LPWSTR DfsPathName - the pathname that is being updated
  657. // LPWSTR Server - the servername (optional) whose info is being set.
  658. // LPWSTR Share - the share on the server.
  659. // DWORD Level - the level of information being set
  660. // LPBYTE pBuffer - the buffer holding the information to be set
  661. //
  662. // Returns: ERROR_SUCCESS
  663. // Error code other wise.
  664. //
  665. //-----------------------------------------------------------------------------
  666. DFSSTATUS
  667. DfsSetInfo(
  668. LPWSTR DfsPathName,
  669. LPWSTR Server,
  670. LPWSTR Share,
  671. DWORD Level,
  672. LPBYTE pBuffer)
  673. {
  674. return DfsSetInfoCheckAccess( DfsPathName,
  675. Server,
  676. Share,
  677. Level,
  678. pBuffer,
  679. ERROR_SUCCESS );
  680. }
  681. //+----------------------------------------------------------------------------
  682. //
  683. // Function: DfsSetInfoCheckAccess
  684. //
  685. // Arguments:
  686. // LPWSTR DfsPathName - the pathname that is being updated
  687. // LPWSTR Server - the servername (optional) whose info is being set.
  688. // LPWSTR Share - the share on the server.
  689. // DWORD Level - the level of information being set
  690. // LPBYTE pBuffer - the buffer holding the information to be set
  691. // DFSSTATUS Status - access status if any.
  692. //
  693. // Returns: ERROR_SUCCESS
  694. // Error code other wise.
  695. //
  696. //-----------------------------------------------------------------------------
  697. DFSSTATUS
  698. DfsSetInfoCheckAccess(
  699. LPWSTR DfsPathName,
  700. LPWSTR Server,
  701. LPWSTR Share,
  702. DWORD Level,
  703. LPBYTE pBuffer,
  704. DFSSTATUS AccessCheckStatus )
  705. {
  706. DFSSTATUS Status = ERROR_SUCCESS;
  707. DfsRootFolder *pRoot = NULL;
  708. UNICODE_STRING DfsPath, LinkName;
  709. DFS_TRACE_NORM(API, "[%!FUNC!]Dfs set info for path %ws AccessCheck Status %x Level %d\n",
  710. DfsPathName, AccessCheckStatus, Level);
  711. Status = DfsRtlInitUnicodeStringEx( &DfsPath, DfsPathName );
  712. if (Status != ERROR_SUCCESS)
  713. {
  714. goto done;
  715. }
  716. //
  717. //validate the input arguments.
  718. //
  719. API_VALIDATE_ARGUMENTS( DfsPathName, NULL, NULL, Status);
  720. if (Status != ERROR_SUCCESS)
  721. {
  722. goto done;
  723. }
  724. //
  725. // It is legal for the Server and Share args to be NULL,
  726. // but the DfsPath must have \\x\y\z components. DfsGetRootFolder
  727. // will validate that.
  728. //
  729. if (!pBuffer || !(*(PULONG)pBuffer) || (IsEmptyUnicodeString( &DfsPath )))
  730. {
  731. Status = ERROR_INVALID_PARAMETER;
  732. goto done;
  733. }
  734. // Server may have leading \\.
  735. if ((Server != NULL) && (Server[0] == UNICODE_PATH_SEP))
  736. {
  737. // advance past a max of two '\'s.
  738. Server++;
  739. if (Server[0] == UNICODE_PATH_SEP)
  740. {
  741. Server++;
  742. }
  743. }
  744. //
  745. // Level has to be 100...102 currently.
  746. //
  747. if (!IsValidSetInfoLevel( Level ))
  748. {
  749. Status = ERROR_INVALID_PARAMETER;
  750. goto done;
  751. }
  752. //
  753. // Get a referenced root folder for the passed in path.
  754. //
  755. Status = DfsGetRootFolder( &DfsPath,
  756. &LinkName,
  757. &pRoot );
  758. //
  759. // For cluster, checkpointing may add stuff to the registry which
  760. // we had not found when we started off. So, make an attempt
  761. // to look into the registry.
  762. // In future, this should work across all the roots, but for now
  763. // this is sort of a quick means of getting clusters going.
  764. //
  765. if (Status == ERROR_NOT_FOUND)
  766. {
  767. DfsRegistryStore *pRegStore = NULL;
  768. UNICODE_STRING DfsServer, DfsShare, NewDfsShare;
  769. Status = DfsGetRegistryStore( &pRegStore );
  770. if (Status == ERROR_SUCCESS)
  771. {
  772. Status = DfsGetPathComponents( &DfsPath,
  773. &DfsServer,
  774. &DfsShare,
  775. NULL );
  776. if (Status == ERROR_SUCCESS)
  777. {
  778. Status = DfsCreateUnicodeString( &NewDfsShare,
  779. &DfsShare );
  780. }
  781. if (Status == ERROR_SUCCESS)
  782. {
  783. Status = pRegStore->LookupNewRootByName( NewDfsShare.Buffer,
  784. &pRoot );
  785. DfsFreeUnicodeString( &NewDfsShare );
  786. }
  787. pRegStore->ReleaseReference();
  788. }
  789. }
  790. //
  791. // dfsdev: special case master and standby here.
  792. //
  793. // We call into the service with the appropriate bits to
  794. // set the root in a standby mode or a master mode.
  795. //
  796. if (Status == ERROR_SUCCESS)
  797. {
  798. BOOLEAN Done = FALSE;
  799. if (Level == 101)
  800. {
  801. PDFS_INFO_101 pInfo101 = (PDFS_INFO_101)*((PULONG_PTR)pBuffer);
  802. DFS_TRACE_NORM(API, "Dfs set info for path %ws Level %d State is %d\n",
  803. DfsPathName, Level, pInfo101->State);
  804. if (pInfo101->State == DFS_VOLUME_STATE_RESYNCHRONIZE)
  805. {
  806. DFS_TRACE_NORM(API, "[%!FUNC!]Root folder set to Master\n");
  807. //
  808. // Check if resynchronize should succeed of fail, based
  809. // on the passed in access check status.
  810. //
  811. Status = pRoot->CheckResynchronizeAccess(AccessCheckStatus);
  812. if (Status == ERROR_SUCCESS)
  813. {
  814. Status = pRoot->SetRootResynchronize();
  815. }
  816. Done = TRUE;
  817. }
  818. else if (pInfo101->State == DFS_VOLUME_STATE_STANDBY)
  819. {
  820. ASSERT(Status == ERROR_SUCCESS);
  821. Status = AccessCheckStatus;
  822. if (Status == ERROR_SUCCESS)
  823. {
  824. if (DfsIsMachineCluster())
  825. {
  826. DFS_TRACE_NORM(API, "[%!FUNC!]Root folder set to standby\n");
  827. pRoot->SetRootStandby();
  828. }
  829. else
  830. {
  831. Status = ERROR_NOT_SUPPORTED;
  832. }
  833. }
  834. //
  835. // Ideally, we should purge the referral(s) for this root and all its links.
  836. // For that we'll have to iterate over all its links (among other things).
  837. // That can be expensive and might even lead to DoS attacks. However
  838. //
  839. Done = TRUE;
  840. }
  841. else
  842. {
  843. if ((Server == NULL) && (Share == NULL))
  844. {
  845. if (!IsValidLinkState(pInfo101->State))
  846. {
  847. Done = TRUE;
  848. Status = ERROR_INVALID_PARAMETER;
  849. }
  850. }
  851. else
  852. {
  853. if (!IsValidReplicaState(pInfo101->State))
  854. {
  855. Done = TRUE;
  856. Status = ERROR_INVALID_PARAMETER;
  857. }
  858. }
  859. }
  860. }
  861. if (Done)
  862. {
  863. goto done;
  864. }
  865. }
  866. //
  867. // At this point, if we are to be denied access, we should not
  868. // proceed.
  869. //
  870. if (Status == ERROR_SUCCESS)
  871. {
  872. Status = AccessCheckStatus;
  873. }
  874. if (Status == ERROR_SUCCESS)
  875. {
  876. //
  877. // Check if the root folder is available for api calls. If not,
  878. // we return an error back to the caller:
  879. // dfsdev: check if this error is a valid one to return.
  880. //
  881. if (!DfsCheckDirectMode())
  882. {
  883. Status = pRoot->RootApiRequestPrologue( TRUE );
  884. }
  885. if (Status == ERROR_SUCCESS)
  886. {
  887. //
  888. // If we successfully got a root folder, set the specifed information
  889. // on the passed in path/server/share combination.
  890. //
  891. Status = pRoot->SetApiInformation( &LinkName,
  892. Server,
  893. Share,
  894. Level,
  895. pBuffer );
  896. //
  897. // release our reference on the root folder.
  898. //
  899. if (!DfsCheckDirectMode())
  900. {
  901. pRoot->RootApiRequestEpilogue( TRUE, Status );
  902. }
  903. }
  904. }
  905. done:
  906. if(pRoot)
  907. {
  908. pRoot->ReleaseReference();
  909. }
  910. DFS_TRACE_ERROR_NORM(Status, API, "Dfs set info for path %ws Status %x\n",
  911. DfsPathName, Status );
  912. return Status;
  913. }
  914. //+----------------------------------------------------------------------------
  915. //
  916. // Function: DfsAddStandaloneRoot
  917. //
  918. // Arguments:
  919. // LPWSTR ShareName - the share name to use
  920. // LPWSTR Comment - the comment for this root
  921. // DWORD Flags - the flags for this root
  922. //
  923. // Returns: ERROR_SUCCESS
  924. // Error code other wise.
  925. //
  926. //-----------------------------------------------------------------------------
  927. DFSSTATUS
  928. DfsAddStandaloneRoot(
  929. LPWSTR MachineName,
  930. LPWSTR ShareName,
  931. LPWSTR Comment,
  932. DWORD Flags )
  933. {
  934. DFS_TRACE_NORM(API, "Dfs add standalone root Machine Share %ws\n",
  935. ShareName);
  936. //
  937. // dfsdev: use these parameters.
  938. //
  939. UNREFERENCED_PARAMETER(Comment);
  940. UNREFERENCED_PARAMETER(Flags);
  941. DfsRegistryStore *pRegStore;
  942. DFSSTATUS Status;
  943. //
  944. // It's legal to get a NULL MachineName to signify '.', but the
  945. // ShareName can't be empty.
  946. //
  947. if (IsEmptyString( ShareName ))
  948. {
  949. Status = ERROR_INVALID_PARAMETER;
  950. goto done;
  951. }
  952. Status = DfsCheckServerRootHandlingCapability();
  953. if (Status != ERROR_SUCCESS)
  954. {
  955. goto done;
  956. }
  957. //
  958. // This is a registry store specific function. So finf the registry store.
  959. // This gives us a referenced registry store pointer.
  960. //
  961. Status = DfsGetRegistryStore( &pRegStore );
  962. if (Status == ERROR_SUCCESS)
  963. {
  964. //
  965. // Create the standalone root, and release our reference on the registry
  966. // store.
  967. //
  968. Status = pRegStore->CreateStandaloneRoot( MachineName,
  969. ShareName,
  970. Comment );
  971. pRegStore->ReleaseReference();
  972. }
  973. done:
  974. DFS_TRACE_ERROR_NORM(Status, API, "Dfs add standalone root status %x Machine Share %ws\n",
  975. Status, ShareName);
  976. return Status;
  977. }
  978. //+----------------------------------------------------------------------------
  979. //
  980. // Function: DfsDeleteStandaloneRoot
  981. //
  982. // Arguments:
  983. // LPWSTR ShareName - the root to delete
  984. //
  985. // Returns: ERROR_SUCCESS
  986. // Error code other wise.
  987. //
  988. //-----------------------------------------------------------------------------
  989. DFSSTATUS
  990. DfsDeleteStandaloneRoot(
  991. LPWSTR ServerName,
  992. LPWSTR ShareName )
  993. {
  994. DfsRegistryStore *pRegStore;
  995. DFSSTATUS Status;
  996. DFS_TRACE_NORM(API, "Dfs delete standalone root Machine Share %ws\n",
  997. ShareName);
  998. if (IsEmptyString( ServerName ))
  999. {
  1000. Status = ERROR_INVALID_PARAMETER;
  1001. return Status;
  1002. }
  1003. if (IsEmptyString( ShareName ))
  1004. {
  1005. Status = ERROR_INVALID_PARAMETER;
  1006. return Status;
  1007. }
  1008. //
  1009. // This is registry store specific function, so get the registry store.
  1010. //
  1011. Status = DfsGetRegistryStore( &pRegStore );
  1012. if (Status == ERROR_SUCCESS)
  1013. {
  1014. //
  1015. // Delete the standalone root specified by the passed in sharename
  1016. // and release our reference on the registry store.
  1017. //
  1018. Status = pRegStore->DeleteStandaloneRoot( NULL,
  1019. ShareName );
  1020. pRegStore->ReleaseReference();
  1021. }
  1022. DFS_TRACE_ERROR_NORM(Status, API, "Dfs delete standalone root status %x Machine Share %ws\n",
  1023. Status, ShareName);
  1024. return Status;
  1025. }
  1026. DFSSTATUS
  1027. DfsEnumerateLocalRoots(
  1028. LPWSTR MachineName,
  1029. BOOLEAN DomainRoots,
  1030. LPBYTE pBuffer,
  1031. ULONG BufferSize,
  1032. PULONG pEntriesRead,
  1033. DWORD MaxEntriesToRead,
  1034. LPDWORD pResumeHandle,
  1035. PULONG pSizeRequired )
  1036. {
  1037. UNREFERENCED_PARAMETER(MachineName);
  1038. DFSSTATUS Status = ERROR_SUCCESS;
  1039. ULONG TotalSize = 0;
  1040. ULONG EntriesRead = 0;
  1041. ULONG_PTR CurrentBuffer = (ULONG_PTR)pBuffer;
  1042. ULONG CurrentSize = BufferSize;
  1043. DfsStore *pStore;
  1044. ULONG CurrentNumRoots = 0;
  1045. BOOLEAN OverFlow = FALSE;
  1046. ASSERT(pBuffer != NULL);
  1047. ASSERT(pEntriesRead != NULL);
  1048. ASSERT(pSizeRequired != NULL);
  1049. DFS_TRACE_NORM(API, "[%!FUNC!]for path %ws\n", MachineName);
  1050. //
  1051. // Call the store enumerator of each registered store.
  1052. //
  1053. for (pStore = DfsServerGlobalData.pRegisteredStores;
  1054. (pStore != NULL) && (Status == ERROR_SUCCESS);
  1055. pStore = pStore->pNextRegisteredStore) {
  1056. Status = pStore->EnumerateRoots( DomainRoots,
  1057. &CurrentBuffer,
  1058. &CurrentSize,
  1059. &EntriesRead,
  1060. MaxEntriesToRead,
  1061. &CurrentNumRoots,
  1062. pResumeHandle,
  1063. &TotalSize );
  1064. if (Status == ERROR_BUFFER_OVERFLOW)
  1065. {
  1066. OverFlow = TRUE;
  1067. Status = ERROR_SUCCESS;
  1068. }
  1069. }
  1070. if (Status == ERROR_SUCCESS)
  1071. {
  1072. if (OverFlow == TRUE)
  1073. {
  1074. Status = ERROR_BUFFER_OVERFLOW;
  1075. }
  1076. else if (EntriesRead == 0)
  1077. {
  1078. //
  1079. // We should never return SUCCESS if we aren't
  1080. // returning entries.
  1081. //
  1082. Status = ERROR_NO_MORE_ITEMS;
  1083. }
  1084. else if (pResumeHandle)
  1085. {
  1086. *pResumeHandle = CurrentNumRoots;
  1087. }
  1088. *pEntriesRead = EntriesRead;
  1089. *pSizeRequired = TotalSize;
  1090. }
  1091. DFS_TRACE_ERROR_NORM(Status, API, "[%!FUNC!]for path %ws, Status %x\n",
  1092. MachineName, Status );
  1093. return Status;
  1094. }
  1095. //+----------------------------------------------------------------------------
  1096. //
  1097. // Function: DfsEnumerateRoots
  1098. //
  1099. // Arguments:
  1100. // LPBYTE pBuffer - the buffer to fill, passed in by teh caller
  1101. // LONG BufferSize, - the size of passed in buffer.
  1102. // LPDWORD pEntriesRead - the number of entries read, set on return
  1103. // LPDWORD pResumeHandle - the entry to start from, set to new value on return
  1104. // PLONG pSizeRequired - size required to successfully complete this call.
  1105. // usefule when this call return buffer overflow.
  1106. //
  1107. // Returns: ERROR_SUCCESS
  1108. // Error code other wise.
  1109. //
  1110. //-----------------------------------------------------------------------------
  1111. DFSSTATUS
  1112. DfsEnumerateRoots(
  1113. IN LPWSTR DfsName,
  1114. IN BOOLEAN DomainRoots,
  1115. IN DWORD PrefMaxLen,
  1116. IN LPBYTE pBuffer,
  1117. IN ULONG BufferSize,
  1118. OUT PULONG pEntriesRead,
  1119. IN OUT PULONG pResumeHandle,
  1120. OUT PULONG pSizeRequired )
  1121. {
  1122. DFSSTATUS Status = ERROR_SUCCESS;
  1123. UNICODE_STRING DfsPath;
  1124. UNICODE_STRING NameContext;
  1125. UNICODE_STRING RemainingPart;
  1126. DWORD MaxEntriesToRead = 0;
  1127. LONG LevelInfoSize = 0;
  1128. DFS_TRACE_NORM(API, "Dfs enumerate roots: resume handle %d\n",
  1129. pResumeHandle ? *pResumeHandle : 0);
  1130. if(!pEntriesRead || !pSizeRequired || !pBuffer)
  1131. {
  1132. Status = ERROR_INVALID_PARAMETER;
  1133. goto done;
  1134. }
  1135. Status = DfsRtlInitUnicodeStringEx( &DfsPath, DfsName );
  1136. if (Status != ERROR_SUCCESS)
  1137. {
  1138. goto done;
  1139. }
  1140. if (IsEmptyUnicodeString( &DfsPath ))
  1141. {
  1142. Status = ERROR_INVALID_PARAMETER;
  1143. goto done;
  1144. }
  1145. Status = DfsGetFirstComponent( &DfsPath,
  1146. &NameContext,
  1147. &RemainingPart );
  1148. if (Status == ERROR_SUCCESS)
  1149. {
  1150. if (RemainingPart.Length != 0)
  1151. {
  1152. //
  1153. // return not found for now... dfsdev: fix on client.
  1154. //
  1155. Status = ERROR_PATH_NOT_FOUND;
  1156. }
  1157. }
  1158. Status = DfsApiSizeLevelHeader( (DomainRoots == TRUE) ? 200 : 300, &LevelInfoSize);
  1159. if (Status != ERROR_SUCCESS)
  1160. {
  1161. goto done;
  1162. }
  1163. //
  1164. // If PrefMAxLen is 0xffffffff, we need to read all entries. OTherwise we need
  1165. // to read a subset of the entries. Let PrefMaxLen decide the number in the array
  1166. // of info parameters we pass back. (This is how we document our NEtDfsEnum api)
  1167. //
  1168. MaxEntriesToRead = PrefMaxLen / LevelInfoSize;
  1169. if (MaxEntriesToRead == 0) {
  1170. MaxEntriesToRead = 1;
  1171. }
  1172. //
  1173. // Things could be in a state of flux: if the request is for more than the maximum
  1174. // number of roots allowed on a single server, then cap it right there.
  1175. //
  1176. else if (MaxEntriesToRead > MAX_DFS_NAMESPACES)
  1177. {
  1178. MaxEntriesToRead = MAX_DFS_NAMESPACES;
  1179. }
  1180. if (Status == ERROR_SUCCESS)
  1181. {
  1182. if (DfsIsMachineDC() &&
  1183. DfsIsNameContextDomainName(&NameContext))
  1184. {
  1185. if (DomainRoots != TRUE)
  1186. {
  1187. Status = ERROR_INVALID_NAME;
  1188. }
  1189. else
  1190. {
  1191. Status = DfsDcEnumerateRoots( NULL,
  1192. pBuffer,
  1193. BufferSize,
  1194. pEntriesRead,
  1195. MaxEntriesToRead,
  1196. pResumeHandle,
  1197. pSizeRequired);
  1198. }
  1199. }
  1200. else
  1201. {
  1202. if (DomainRoots == TRUE)
  1203. {
  1204. Status = ERROR_INVALID_NAME;
  1205. }
  1206. else
  1207. {
  1208. Status = DfsEnumerateLocalRoots( NULL,
  1209. DomainRoots,
  1210. pBuffer,
  1211. BufferSize,
  1212. pEntriesRead,
  1213. MaxEntriesToRead,
  1214. pResumeHandle,
  1215. pSizeRequired );
  1216. }
  1217. }
  1218. }
  1219. DFS_TRACE_ERROR_NORM(Status, API, "Dfs enumerate roots, status %x\n",
  1220. Status );
  1221. done:
  1222. return Status;
  1223. }
  1224. //+----------------------------------------------------------------------------
  1225. //
  1226. // Function: DfsAddADBlobRoot
  1227. //
  1228. // Arguments:
  1229. // LPWSTR MachineName,
  1230. // LPWSTR DcName,
  1231. // LPWSTR ShareName,
  1232. // LPWSTR LogicalShare,
  1233. // LPWSTR Comment,
  1234. // DWORD Flags,
  1235. // PDFSM_ROOT_LIST *ppRootList )
  1236. //
  1237. // Returns: ERROR_SUCCESS
  1238. // Error code other wise.
  1239. //
  1240. //-----------------------------------------------------------------------------
  1241. DFSSTATUS
  1242. DfsAddADBlobRoot(
  1243. LPWSTR MachineName,
  1244. LPWSTR DcName,
  1245. LPWSTR ShareName,
  1246. LPWSTR LogicalShare,
  1247. LPWSTR Comment,
  1248. BOOLEAN NewFtDfs,
  1249. DWORD Flags,
  1250. PVOID ppList )
  1251. {
  1252. DFS_TRACE_NORM(API, "Dfs add ad blob root Machine Share %ws\n",
  1253. ShareName);
  1254. PDFSM_ROOT_LIST *ppRootList = (PDFSM_ROOT_LIST *)ppList;
  1255. DfsADBlobStore *pADBlobStore = NULL;
  1256. DFSSTATUS Status = ERROR_SUCCESS;
  1257. UNICODE_STRING UseMachineName;
  1258. size_t LogicalShareLength = 0;
  1259. Status = DfsRtlInitUnicodeStringEx(&UseMachineName, NULL);
  1260. if (Status != ERROR_SUCCESS)
  1261. {
  1262. goto done;
  1263. }
  1264. //
  1265. // dfsdev: use these parameters.
  1266. //
  1267. UNREFERENCED_PARAMETER(MachineName);
  1268. UNREFERENCED_PARAMETER(Comment);
  1269. UNREFERENCED_PARAMETER(Flags);
  1270. //
  1271. // MachineName and ppList passed in are unused. ShareName
  1272. // and LogicalShare must be valid args.
  1273. //
  1274. if (IsEmptyString( ShareName ) ||
  1275. IsEmptyString( LogicalShare ))
  1276. {
  1277. Status = ERROR_INVALID_PARAMETER;
  1278. goto done;
  1279. }
  1280. Status = DfsStringCchLength( LogicalShare, MAXUSHORT, &LogicalShareLength );
  1281. if (Status != ERROR_SUCCESS)
  1282. {
  1283. goto done;
  1284. }
  1285. //
  1286. // Logical share cannot have illegal characters. These are currently the
  1287. // STANDARD_ILLEGAL_CHARS. Therefore, SPACE is a valid character.
  1288. //
  1289. if (!IS_VALID_TOKEN( LogicalShare, LogicalShareLength ))
  1290. {
  1291. Status = ERROR_INVALID_NAME;
  1292. goto done;
  1293. }
  1294. //
  1295. // This is a registry store specific function. So find the registry store.
  1296. // This gives us a referenced registry store pointer.
  1297. //
  1298. Status = DfsGetADBlobStore( &pADBlobStore );
  1299. if (Status == ERROR_SUCCESS)
  1300. {
  1301. Status = DfsGetMachineName( &UseMachineName);
  1302. if (Status == ERROR_SUCCESS) {
  1303. Status = pADBlobStore->CreateADBlobRoot( UseMachineName.Buffer,
  1304. DcName,
  1305. ShareName,
  1306. LogicalShare,
  1307. Comment,
  1308. NewFtDfs);
  1309. DfsReleaseMachineName(&UseMachineName);
  1310. }
  1311. pADBlobStore->ReleaseReference();
  1312. }
  1313. done:
  1314. DFS_TRACE_ERROR_NORM(Status, API, "Dfs add ad blob root status %x Machine Share %ws\n",
  1315. Status, ShareName);
  1316. return Status;
  1317. }
  1318. //+----------------------------------------------------------------------------
  1319. //
  1320. // Function: DfsDeleteADBlobRoot
  1321. //
  1322. // Arguments:
  1323. // LPWSTR MachineName,
  1324. // LPWSTR DcName,
  1325. // LPWSTR ShareName,
  1326. // LPWSTR LogicalShare,
  1327. // DWORD Flags,
  1328. // PDFSM_ROOT_LIST *ppRootList )
  1329. //
  1330. // Returns: ERROR_SUCCESS
  1331. // Error code other wise.
  1332. //
  1333. //-----------------------------------------------------------------------------
  1334. DFSSTATUS
  1335. DfsDeleteADBlobRoot(
  1336. LPWSTR MachineName,
  1337. LPWSTR DcName,
  1338. LPWSTR ShareName,
  1339. LPWSTR LogicalShare,
  1340. DWORD Flags,
  1341. PVOID ppList )
  1342. {
  1343. DFS_TRACE_NORM(API, "Dfs delete ad blob root Machine Share %ws\n",
  1344. ShareName);
  1345. UNREFERENCED_PARAMETER(ppList);
  1346. DfsADBlobStore *pADBlobStore = NULL;
  1347. DFSSTATUS Status = ERROR_SUCCESS;
  1348. UNICODE_STRING UseMachineName;
  1349. Status = DfsRtlInitUnicodeStringEx(&UseMachineName, NULL);
  1350. if (Status != ERROR_SUCCESS)
  1351. {
  1352. goto done;
  1353. }
  1354. //
  1355. // MachineName and ppList passed in are unused. ShareName
  1356. // and LogicalShare must be valid args.
  1357. //
  1358. if (IsEmptyString( ShareName ) ||
  1359. IsEmptyString( LogicalShare ))
  1360. {
  1361. Status = ERROR_INVALID_PARAMETER;
  1362. goto done;
  1363. }
  1364. //
  1365. // This gives us a referenced ad blob store pointer.
  1366. //
  1367. Status = DfsGetADBlobStore( &pADBlobStore );
  1368. if (Status == ERROR_SUCCESS)
  1369. {
  1370. if ((Flags & DFS_FORCE_REMOVE) == DFS_FORCE_REMOVE)
  1371. {
  1372. if ((DfsServerGlobalData.IsDc == FALSE) ||
  1373. (IsEmptyString(MachineName)))
  1374. {
  1375. Status = ERROR_INVALID_PARAMETER;
  1376. }
  1377. else
  1378. {
  1379. Status = pADBlobStore->DeleteADBlobRootForced( MachineName,
  1380. DcName,
  1381. ShareName,
  1382. LogicalShare );
  1383. }
  1384. }
  1385. else
  1386. {
  1387. Status = DfsGetMachineName( &UseMachineName);
  1388. if (Status == ERROR_SUCCESS) {
  1389. Status = pADBlobStore->DeleteADBlobRoot( UseMachineName.Buffer,
  1390. DcName,
  1391. ShareName,
  1392. LogicalShare );
  1393. DfsReleaseMachineName(&UseMachineName);
  1394. }
  1395. }
  1396. pADBlobStore->ReleaseReference();
  1397. }
  1398. done:
  1399. DFS_TRACE_ERROR_NORM(Status, API, "Dfs delete ad blob root status %x Machine Share %ws\n",
  1400. Status, ShareName);
  1401. return Status;
  1402. }
  1403. //+-------------------------------------------------------------------------
  1404. //
  1405. // Function: DfsClean
  1406. //
  1407. // Arguments:
  1408. // HostServerName - target server name to contact
  1409. // ShareNameToClean - name of the unwanted to share
  1410. //
  1411. //
  1412. // Returns: Status:
  1413. //
  1414. // Description: This function contacts the registry of a given machine to remove
  1415. // its references to an obsolete root name in its registry. The root
  1416. // can be standalone or fault-tolerant.
  1417. // This is primarily a utility function. We don't assume that the roots
  1418. // are recognized or even that the stores registered. CleanRegEntry
  1419. // are static functions.
  1420. //+-------------------------------------------------------------------------
  1421. DFSSTATUS
  1422. DfsClean(
  1423. LPWSTR HostServerName,
  1424. LPWSTR ShareNameToClean
  1425. )
  1426. {
  1427. DFSSTATUS Status = ERROR_NOT_FOUND;
  1428. DFSSTATUS CleanStatus;
  1429. DFS_TRACE_LOW(REFERRAL_SERVER, "DfsClean: \\%ws\\%ws\n",
  1430. HostServerName, ShareNameToClean);
  1431. if ( IsEmptyString(HostServerName) ||
  1432. IsEmptyString(ShareNameToClean))
  1433. {
  1434. return ERROR_INVALID_PARAMETER;
  1435. }
  1436. //
  1437. // Ask each store registered to remove this share
  1438. // from this server's registry. Each store will take care of
  1439. // \Domain \Standalone and \Enterprise portions of the
  1440. // reg keys.
  1441. //
  1442. CleanStatus = DfsADBlobStore::CleanRegEntry( HostServerName,
  1443. ShareNameToClean );
  1444. //
  1445. // Return SUCCESS if at least one store managed to do
  1446. // the clean successfully.
  1447. //
  1448. if (CleanStatus == ERROR_SUCCESS)
  1449. {
  1450. Status = CleanStatus;
  1451. }
  1452. CleanStatus = DfsRegistryStore::CleanRegEntry( HostServerName,
  1453. ShareNameToClean );
  1454. if (CleanStatus == ERROR_SUCCESS)
  1455. {
  1456. Status = CleanStatus;
  1457. }
  1458. // no-op.
  1459. CleanStatus = DfsEnterpriseStore::CleanRegEntry( HostServerName,
  1460. ShareNameToClean );
  1461. if (CleanStatus == ERROR_SUCCESS)
  1462. {
  1463. Status = CleanStatus;
  1464. }
  1465. DFS_TRACE_ERROR_NORM(Status, API, "DfsClean: \\%ws\\%ws Status = %x\n",
  1466. HostServerName, ShareNameToClean, Status );
  1467. return Status;
  1468. }
  1469. DFSSTATUS
  1470. DfsEnum(
  1471. IN LPWSTR DfsName,
  1472. IN DWORD Level,
  1473. IN DWORD PrefMaxLen,
  1474. OUT LPBYTE *pBuffer,
  1475. OUT LPDWORD pEntriesRead,
  1476. IN OUT LPDWORD pResumeHandle)
  1477. {
  1478. LONG BufferSize = 0;
  1479. LONG SizeRequired = 0;
  1480. ULONG MaxRetry = 0;
  1481. ULONG EntriesRead = 0;
  1482. DFSSTATUS Status = ERROR_SUCCESS;
  1483. LPDFS_INFO_1 pInfo1 = NULL;
  1484. DFS_TRACE_LOW( API, "DfsEnum from ApiFrontEnd %ws\n", DfsName);
  1485. MaxRetry = 5;
  1486. BufferSize = sizeof(DFS_INFO_1);
  1487. if(!pEntriesRead || !pBuffer || (Level == 0))
  1488. {
  1489. Status = ERROR_INVALID_PARAMETER;
  1490. goto done;
  1491. }
  1492. do
  1493. {
  1494. pInfo1 = (LPDFS_INFO_1) MIDL_user_allocate( BufferSize );
  1495. if (pInfo1 == NULL)
  1496. {
  1497. Status = ERROR_NOT_ENOUGH_MEMORY;
  1498. break;
  1499. }
  1500. if (Level != 200 && Level != 300)
  1501. {
  1502. Status = DfsEnumerate( DfsName,
  1503. Level,
  1504. PrefMaxLen,
  1505. (LPBYTE)pInfo1,
  1506. BufferSize,
  1507. &EntriesRead,
  1508. pResumeHandle,
  1509. &SizeRequired );
  1510. } else {
  1511. //
  1512. // Level 200 takes in a domain and 300, the root server.
  1513. //
  1514. Status = DfsEnumerateRoots( DfsName,
  1515. (Level == 200) ? TRUE : FALSE,
  1516. PrefMaxLen,
  1517. (LPBYTE)pInfo1,
  1518. BufferSize,
  1519. &EntriesRead,
  1520. pResumeHandle,
  1521. (PULONG)&SizeRequired ); // xxx supw
  1522. }
  1523. if (Status != ERROR_SUCCESS)
  1524. {
  1525. MIDL_user_free( pInfo1 );
  1526. }
  1527. if (Status == ERROR_BUFFER_OVERFLOW)
  1528. {
  1529. BufferSize = SizeRequired;
  1530. }
  1531. } while ( (Status == ERROR_BUFFER_OVERFLOW) && (MaxRetry--) );
  1532. if (Status == ERROR_SUCCESS)
  1533. {
  1534. *pEntriesRead = EntriesRead;
  1535. *pBuffer = (LPBYTE)pInfo1;
  1536. }
  1537. done:
  1538. DFS_TRACE_ERROR_HIGH( Status, API, "DfsEnum from ApiFrontEnd %ws, Status %x\n", DfsName, Status);
  1539. return Status;
  1540. }
  1541. //+----------------------------------------------------------------------------
  1542. //
  1543. // Function: DfsRenameLinks
  1544. //
  1545. // Arguments: DfsPathName - the root that is affected
  1546. // OldName - Old domain name
  1547. // NewName - new domain name
  1548. //
  1549. // Returns: ERROR_SUCCESS
  1550. // Error code otherwise.
  1551. //
  1552. // Description: Given the old domain name and a new one to replace it with
  1553. // this iterates through all the links in the given namespace and
  1554. // fixes obsolete references to the old domain.
  1555. //-----------------------------------------------------------------------------
  1556. DFSSTATUS
  1557. DfsRenameLinks(
  1558. IN LPWSTR DfsPathString,
  1559. IN LPWSTR OldDomainName,
  1560. IN LPWSTR NewDomainName)
  1561. {
  1562. DFSSTATUS Status = ERROR_SUCCESS;
  1563. DfsRootFolder *pRoot = NULL;
  1564. UNICODE_STRING DfsPathName;
  1565. Status = DfsRtlInitUnicodeStringEx( &DfsPathName, DfsPathString);
  1566. if (Status != ERROR_SUCCESS)
  1567. {
  1568. return Status;
  1569. }
  1570. API_VALIDATE_ARGUMENTS( DfsPathName, OldDomainName, NewDomainName, Status );
  1571. if (Status != ERROR_SUCCESS)
  1572. {
  1573. return Status;
  1574. }
  1575. //
  1576. // Null or empty server/share names are illegal.
  1577. // The DfsPathName needs to have all three components \\x\y\z
  1578. // but that'll get indirectly validated when we do DfsGetRootFolder.
  1579. //
  1580. if ((IsEmptyUnicodeString( &DfsPathName )) ||
  1581. (IsEmptyString( OldDomainName )) ||
  1582. (IsEmptyString( NewDomainName )))
  1583. {
  1584. Status = ERROR_INVALID_PARAMETER;
  1585. return Status;
  1586. }
  1587. //
  1588. // Get the root folder matching the given namespace.
  1589. // We get a referenced root folder.
  1590. //
  1591. Status = DfsGetRootFolder( &DfsPathName,
  1592. NULL,
  1593. &pRoot );
  1594. if (Status == ERROR_SUCCESS)
  1595. {
  1596. //
  1597. // Let the root folder know that a new api request is coming in
  1598. // This will give it a chance to let us know if api requests
  1599. // are allowed, and to synchronize with the metadata as necessary.
  1600. //
  1601. if (!DfsCheckDirectMode())
  1602. {
  1603. Status = pRoot->RootApiRequestPrologue( TRUE );
  1604. }
  1605. if (Status == ERROR_SUCCESS) {
  1606. //
  1607. // Replace all references to OldDomainName with the new.
  1608. //
  1609. Status = pRoot->RenameLinks( OldDomainName,
  1610. NewDomainName );
  1611. //
  1612. // We are done: release our reference on the root.
  1613. //
  1614. if (!DfsCheckDirectMode())
  1615. {
  1616. pRoot->RootApiRequestEpilogue( FALSE, Status );
  1617. }
  1618. }
  1619. pRoot->ReleaseReference();
  1620. }
  1621. return Status;
  1622. }
  1623. //+----------------------------------------------------------------------------
  1624. //
  1625. // Function: DfsDirectApiOpen
  1626. //
  1627. // Arguments: DfsPath - the root that is affected
  1628. // Returns: ERROR_SUCCESS
  1629. // Error code otherwise.
  1630. //
  1631. // Description: The most important task this does is to perform LdapConnect.
  1632. // Callers are supposed to perform a corresponding DirectApiClose when done.
  1633. // This protocol is handy because direct-mode users may execute many
  1634. // api requests in between an DirectApiOpen and its DirectApiClose. There's no
  1635. // need to synchronize per each such request.
  1636. //-----------------------------------------------------------------------------
  1637. DFSSTATUS
  1638. DfsDirectApiOpen(
  1639. IN LPWSTR DfsNameSpace,
  1640. IN LPWSTR DCName,
  1641. OUT PVOID *pLibHandle)
  1642. {
  1643. DFSSTATUS Status = ERROR_SUCCESS;
  1644. DfsRootFolder *pRoot = NULL;
  1645. PDFS_DIRECT_API_CONTEXT pApiContext = NULL;
  1646. UNICODE_STRING DfsPathName;
  1647. UNICODE_STRING ServerName, ShareName;
  1648. LPWSTR UseDCName = NULL;
  1649. UNICODE_STRING DomainName;
  1650. DfsString *pPDC;
  1651. Status = DfsRtlInitUnicodeStringEx( &DfsPathName, DfsNameSpace);
  1652. if (Status != ERROR_SUCCESS)
  1653. {
  1654. return Status;
  1655. }
  1656. *pLibHandle = NULL;
  1657. do {
  1658. //
  1659. // We must have a valid-looking root.
  1660. //
  1661. Status = DfsGetPathComponents(&DfsPathName,
  1662. &ServerName,
  1663. &ShareName,
  1664. NULL );
  1665. if ( Status != ERROR_SUCCESS ||
  1666. ServerName.Length == 0 || ShareName.Length == 0 )
  1667. {
  1668. Status = ERROR_INVALID_PARAMETER;
  1669. break;
  1670. }
  1671. Status = DfsCreateUnicodeString( &DomainName, &ServerName);
  1672. //
  1673. // tread very carefully here:
  1674. // this is to fix a bug that we should fix in a better
  1675. // way in future, by changing the core of DFS to handle
  1676. // any domain name, instead of assuming all accesses are
  1677. // to the local domain
  1678. //
  1679. // all of dfs code assumes that we are running in the local
  1680. // domain. This does not work well for dfsutil.
  1681. // Here we are working around this by doing a couple of things:
  1682. // 1) we force a DC for the domain of interest. This gets stored
  1683. // in our global data structures, for all other accesses.
  1684. // 2) We force a new ad name context for this domain, again
  1685. // this gets stored in our global data structures, for all
  1686. // other accesses.
  1687. //
  1688. // Once we have created the object and have cached it we dont
  1689. // need this information anymore. The next direct open will
  1690. // overwrite this global information.
  1691. //
  1692. // this code is based on certain assumptions as to how the
  1693. // rest of the code works. If those assumptions are violated,
  1694. // things will break.
  1695. //
  1696. // assumption 1: RootApiPrologue will accept a DC name, and not
  1697. // forcefully get a new dc name.
  1698. // assumption 2: RootApiPrologue will cache the ldap connection
  1699. // to the DC, for the entire request till we call epilogue.
  1700. // assumption 3: Once we have created a root in this code,
  1701. // no other global information will be necessary when we
  1702. // flush out the information at a later point.
  1703. //
  1704. //
  1705. if (Status == ERROR_SUCCESS)
  1706. {
  1707. if (DfsIsThisADomainName(DomainName.Buffer) == ERROR_SUCCESS)
  1708. {
  1709. if (DCName != NULL)
  1710. {
  1711. Status = DfsSetBlobPDCName( DCName,
  1712. &pPDC);
  1713. }
  1714. else
  1715. {
  1716. Status = DfsGetBlobPDCName( &pPDC,
  1717. DFS_FORCE_DC_QUERY,
  1718. DomainName.Buffer);
  1719. }
  1720. if (Status == ERROR_SUCCESS)
  1721. {
  1722. UseDCName = pPDC->GetString();
  1723. }
  1724. if (Status == ERROR_SUCCESS)
  1725. {
  1726. LPWSTR ADContext;
  1727. extern LPWSTR DfsGetDfsAdNameContextStringForDomain(LPWSTR UseDC);
  1728. ADContext = DfsGetDfsAdNameContextStringForDomain(UseDCName);
  1729. }
  1730. }
  1731. DfsFreeUnicodeString(&DomainName);
  1732. }
  1733. if (Status != ERROR_SUCCESS)
  1734. {
  1735. break;
  1736. }
  1737. Status = DfsDirectApiAllocContext( &pApiContext,
  1738. &DfsPathName,
  1739. &ServerName,
  1740. &ShareName );
  1741. if (Status != ERROR_SUCCESS)
  1742. {
  1743. break;
  1744. }
  1745. //
  1746. // Now see if any of the stores recognizes this root.
  1747. // The store will read in the root's metadata in to the cache.
  1748. //
  1749. Status = DfsRecognize( pApiContext->ServerName.Buffer, &pApiContext->ShareName );
  1750. if (Status != ERROR_SUCCESS)
  1751. {
  1752. break;
  1753. }
  1754. //
  1755. // Get the root folder matching the given namespace.
  1756. // We get a referenced root folder.
  1757. //
  1758. Status = DfsGetRootFolder( &pApiContext->RootName,
  1759. NULL,
  1760. &pRoot );
  1761. if (Status != ERROR_SUCCESS)
  1762. {
  1763. break;
  1764. }
  1765. //
  1766. // ApiRequestPrologue will open AD object
  1767. // and get us ready for incoming API requests. All direct
  1768. // mode opens are considered WRITE requests, although currently,
  1769. // that makes no difference as CommonRequestPrologue ignores it.
  1770. //
  1771. Status = pRoot->RootApiRequestPrologue( TRUE,
  1772. UseDCName );
  1773. if (Status != ERROR_SUCCESS)
  1774. {
  1775. pRoot->ReleaseReference();
  1776. break;
  1777. }
  1778. //
  1779. // Return a valid 'handle' on success.
  1780. //
  1781. pApiContext->pObject = (PVOID)pRoot;
  1782. pApiContext->IsInitialized = TRUE;
  1783. pApiContext->IsWriteable = FALSE;
  1784. *pLibHandle = (PVOID)pApiContext;
  1785. } while (FALSE);
  1786. if (Status != ERROR_SUCCESS)
  1787. {
  1788. //
  1789. // Clean up the DirectApiContext if we hit errors.
  1790. // We have been careful not to do any operations that might fail
  1791. // after we do the RootApiRequestPrologue.
  1792. //
  1793. if (pApiContext != NULL)
  1794. {
  1795. DfsDirectApiFreeContext( pApiContext );
  1796. }
  1797. }
  1798. return Status;
  1799. }
  1800. DFSSTATUS
  1801. DfsDirectApiCommitChanges(
  1802. IN PVOID Handle)
  1803. {
  1804. DFS_SERVER_LIB_HANDLE LibHandle = (DFS_SERVER_LIB_HANDLE)Handle;
  1805. DFSSTATUS Status = ERROR_SUCCESS;
  1806. PDFS_DIRECT_API_CONTEXT pApiContext = (PDFS_DIRECT_API_CONTEXT)LibHandle;
  1807. DfsRootFolder *pRoot;
  1808. if ((pApiContext == NULL) ||
  1809. (pApiContext->IsInitialized == FALSE) ||
  1810. (pApiContext->pObject == NULL))
  1811. {
  1812. Status = ERROR_INVALID_PARAMETER;
  1813. return Status;
  1814. }
  1815. if (pApiContext->IsWriteable == FALSE)
  1816. {
  1817. return ERROR_ACCESS_DENIED;
  1818. }
  1819. pRoot = (DfsRootFolder *)pApiContext->pObject;
  1820. Status = pRoot->Flush();
  1821. return Status;
  1822. }
  1823. DFSSTATUS
  1824. DfsDirectApiClose(
  1825. IN PVOID Handle)
  1826. {
  1827. DFS_SERVER_LIB_HANDLE LibHandle = (DFS_SERVER_LIB_HANDLE)Handle;
  1828. DFSSTATUS Status = ERROR_SUCCESS;
  1829. DfsRootFolder *pRoot;
  1830. PDFS_DIRECT_API_CONTEXT pApiContext = (PDFS_DIRECT_API_CONTEXT)LibHandle;
  1831. do {
  1832. //
  1833. // Check for valid handle
  1834. //
  1835. if ((pApiContext == NULL) ||
  1836. (pApiContext->IsInitialized == FALSE) ||
  1837. (pApiContext->pObject == NULL))
  1838. {
  1839. Status = ERROR_INVALID_PARAMETER;
  1840. break;
  1841. }
  1842. pRoot = (DfsRootFolder *)pApiContext->pObject;
  1843. pRoot->RootApiRequestEpilogue( TRUE, Status );
  1844. pRoot->ReleaseReference();
  1845. } while (FALSE);
  1846. //
  1847. // Free the DirectApiContext on our way out.
  1848. //
  1849. if (pApiContext != NULL)
  1850. {
  1851. DfsDirectApiFreeContext( pApiContext );
  1852. }
  1853. return Status;
  1854. }
  1855. DFSSTATUS
  1856. DfsDirectApiAllocContext(
  1857. OUT PDFS_DIRECT_API_CONTEXT *ppApiContext,
  1858. IN PUNICODE_STRING pDfsPathName,
  1859. IN PUNICODE_STRING pServerName,
  1860. IN PUNICODE_STRING pShareName)
  1861. {
  1862. DFSSTATUS Status = ERROR_SUCCESS;
  1863. PDFS_DIRECT_API_CONTEXT pApiContext = NULL;
  1864. do {
  1865. pApiContext = (PDFS_DIRECT_API_CONTEXT) MIDL_user_allocate(sizeof(DFS_DIRECT_API_CONTEXT));
  1866. if (pApiContext == NULL)
  1867. {
  1868. Status = ERROR_NOT_ENOUGH_MEMORY;
  1869. break;
  1870. }
  1871. RtlZeroMemory( pApiContext, sizeof( DFS_DIRECT_API_CONTEXT ));
  1872. Status = DfsCreateUnicodeString( &pApiContext->RootName, pDfsPathName );
  1873. if (Status != ERROR_SUCCESS)
  1874. {
  1875. break;
  1876. }
  1877. //
  1878. // dfsdev: we really need to standardize on the LPWSTR vs. UNICODE issue.
  1879. //
  1880. Status = DfsCreateUnicodeString( &pApiContext->ServerName, pServerName );
  1881. if (Status != ERROR_SUCCESS)
  1882. {
  1883. break;
  1884. }
  1885. Status = DfsCreateUnicodeString( &pApiContext->ShareName, pShareName );
  1886. if (Status != ERROR_SUCCESS)
  1887. {
  1888. break;
  1889. }
  1890. *ppApiContext = pApiContext;
  1891. } while (FALSE);
  1892. if (Status != ERROR_SUCCESS)
  1893. {
  1894. if (pApiContext != NULL)
  1895. {
  1896. DfsDirectApiFreeContext( pApiContext );
  1897. }
  1898. }
  1899. return Status;
  1900. }
  1901. VOID
  1902. DfsDirectApiFreeContext(
  1903. PDFS_DIRECT_API_CONTEXT pApiContext)
  1904. {
  1905. if (pApiContext != NULL)
  1906. {
  1907. if (pApiContext->RootName.Buffer != NULL)
  1908. {
  1909. DfsFreeUnicodeString( &pApiContext->RootName );
  1910. RtlInitUnicodeString( &pApiContext->RootName, NULL );
  1911. }
  1912. if (pApiContext->ServerName.Buffer != NULL)
  1913. {
  1914. DfsFreeUnicodeString( &pApiContext->ServerName );
  1915. RtlInitUnicodeString( &pApiContext->ServerName, NULL );
  1916. }
  1917. if (pApiContext->ShareName.Buffer != NULL)
  1918. {
  1919. DfsFreeUnicodeString( &pApiContext->ShareName );
  1920. RtlInitUnicodeString( &pApiContext->ShareName, NULL );
  1921. }
  1922. pApiContext->pObject = NULL;
  1923. pApiContext->IsInitialized = FALSE;
  1924. pApiContext->IsWriteable = FALSE;
  1925. MIDL_user_free( pApiContext );
  1926. }
  1927. return;
  1928. }
  1929. DFSSTATUS
  1930. DfsExtendedRootAttributes(
  1931. IN PVOID Handle,
  1932. PULONG pAttr,
  1933. PUNICODE_STRING pRemaining,
  1934. BOOLEAN Set )
  1935. {
  1936. DFS_SERVER_LIB_HANDLE LibHandle = (DFS_SERVER_LIB_HANDLE)Handle;
  1937. DFSSTATUS Status = ERROR_SUCCESS;
  1938. PDFS_DIRECT_API_CONTEXT pApiContext = (PDFS_DIRECT_API_CONTEXT)LibHandle;
  1939. DfsRootFolder *pRoot;
  1940. if ((pApiContext == NULL) ||
  1941. (pApiContext->IsInitialized == FALSE) ||
  1942. (pApiContext->pObject == NULL))
  1943. {
  1944. Status = ERROR_INVALID_PARAMETER;
  1945. return Status;
  1946. }
  1947. pRoot = (DfsRootFolder *)pApiContext->pObject;
  1948. Status = pRoot->ExtendedRootAttributes( pAttr, pRemaining, Set);
  1949. return Status;
  1950. }
  1951. //
  1952. // Get the size of the blob.
  1953. //
  1954. DFSSTATUS
  1955. DfsGetBlobSize(
  1956. IN PVOID Handle,
  1957. OUT PULONG pBlobSize )
  1958. {
  1959. DFS_SERVER_LIB_HANDLE LibHandle = (DFS_SERVER_LIB_HANDLE)Handle;
  1960. DFSSTATUS Status = ERROR_SUCCESS;
  1961. PDFS_DIRECT_API_CONTEXT pApiContext = (PDFS_DIRECT_API_CONTEXT)LibHandle;
  1962. DfsRootFolder *pRoot;
  1963. if ((pApiContext == NULL) ||
  1964. (pApiContext->IsInitialized == FALSE) ||
  1965. (pApiContext->pObject == NULL))
  1966. {
  1967. Status = ERROR_INVALID_PARAMETER;
  1968. return Status;
  1969. }
  1970. pRoot = (DfsRootFolder *)pApiContext->pObject;
  1971. //
  1972. // Now ask the root get the blob from the cache.
  1973. //
  1974. *pBlobSize = pRoot->GetBlobSize();
  1975. return Status;
  1976. }
  1977. //
  1978. // Get the size of the blob.
  1979. //
  1980. DFSSTATUS
  1981. DfsGetSiteBlob(
  1982. IN PVOID Handle,
  1983. OUT PVOID *ppBlob,
  1984. OUT PULONG pBlobSize )
  1985. {
  1986. DFS_SERVER_LIB_HANDLE LibHandle = (DFS_SERVER_LIB_HANDLE)Handle;
  1987. DFSSTATUS Status = ERROR_SUCCESS;
  1988. PDFS_DIRECT_API_CONTEXT pApiContext = (PDFS_DIRECT_API_CONTEXT)LibHandle;
  1989. DfsRootFolder *pRoot;
  1990. if ((pApiContext == NULL) ||
  1991. (pApiContext->IsInitialized == FALSE) ||
  1992. (pApiContext->pObject == NULL))
  1993. {
  1994. Status = ERROR_INVALID_PARAMETER;
  1995. return Status;
  1996. }
  1997. pRoot = (DfsRootFolder *)pApiContext->pObject;
  1998. //
  1999. // Now ask the root get the blob from the cache.
  2000. //
  2001. Status = pRoot->GetSiteBlob(ppBlob, pBlobSize);
  2002. return Status;
  2003. }
  2004. //
  2005. // Get the size of the blob.
  2006. //
  2007. DFSSTATUS
  2008. DfsSetSiteBlob(
  2009. IN PVOID Handle,
  2010. IN PVOID pBlob,
  2011. IN ULONG BlobSize )
  2012. {
  2013. DFS_SERVER_LIB_HANDLE LibHandle = (DFS_SERVER_LIB_HANDLE)Handle;
  2014. DFSSTATUS Status = ERROR_SUCCESS;
  2015. PDFS_DIRECT_API_CONTEXT pApiContext = (PDFS_DIRECT_API_CONTEXT)LibHandle;
  2016. DfsRootFolder *pRoot;
  2017. if ((pApiContext == NULL) ||
  2018. (pApiContext->IsInitialized == FALSE) ||
  2019. (pApiContext->pObject == NULL))
  2020. {
  2021. Status = ERROR_INVALID_PARAMETER;
  2022. return Status;
  2023. }
  2024. pRoot = (DfsRootFolder *)pApiContext->pObject;
  2025. //
  2026. // Now ask the root get the blob from the cache.
  2027. //
  2028. Status = pRoot->SetSiteBlob(pBlob, BlobSize);
  2029. return Status;
  2030. }