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.

1604 lines
45 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: logroot.c
  6. //
  7. // Contents: This module implements the logical root handling functions.
  8. //
  9. // Functions: DfsInitializeLogicalRoot -
  10. // DfsDeleteLogicalRoot -
  11. // DfspLogRootNameToPath -
  12. //
  13. // History: 14-June-1994 SudK Created (Most stuff moved from Dsinit.c)
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "dfsprocs.h"
  17. #include "creds.h"
  18. #include "dnr.h"
  19. #include "fcbsup.h"
  20. #include <stdio.h>
  21. #define Dbg DEBUG_TRACE_LOGROOT
  22. NTSTATUS
  23. DfsDefineDosDevice(
  24. IN WCHAR Device,
  25. IN PUNICODE_STRING Target);
  26. NTSTATUS
  27. DfsUndefineDosDevice(
  28. IN WCHAR Device);
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text( PAGE, DfsFindLogicalRoot )
  31. #pragma alloc_text( PAGE, DfsInitializeLogicalRoot )
  32. #pragma alloc_text( PAGE, DfsDeleteLogicalRoot )
  33. #pragma alloc_text( PAGE, DfspLogRootNameToPath )
  34. #pragma alloc_text( PAGE, DfsGetResourceFromVcb )
  35. #pragma alloc_text( PAGE, DfsGetResourceFromDevlessRoot )
  36. #pragma alloc_text( PAGE, DfsLogicalRootExists )
  37. #endif
  38. #ifdef TERMSRV
  39. //
  40. // Maximum character string length of a session Id (decimal)
  41. //
  42. #define SESSIONID_MAX_LEN 10
  43. //
  44. // Maximum characters string length of a session ID [10] (decimal) or
  45. // logon ID [16] (hex, base 16)
  46. //
  47. #define ID_MAX_LEN 16
  48. #endif // TERMSRV
  49. //
  50. // Global that denotes whether LUID device maps are enabled
  51. // TRUE - LUID device maps are enabled
  52. // FALSE - LUID device maps are not enabled
  53. // Defined in nt\base\fs\mup\dfsinit.c
  54. //
  55. extern BOOL DfsLUIDDeviceMapsEnabled;
  56. //+-------------------------------------------------------------------------
  57. //
  58. // Function: DfsFindLogicalRoot, local
  59. //
  60. // Synopsis: DfsFindLogicalRoot takes as input a DS path name in
  61. // the standard form (root:\file\path\name), looks up
  62. // the DFS_VCB associated with the logical root, and returns
  63. // a string pointing to beyond the logical root part
  64. // of the input string.
  65. //
  66. // Arguments: [PrefixPath] -- Input path name
  67. // [Vcb] -- Returns DFS_VCB which corresponds to logical root
  68. // in PrefixPath
  69. // [RemainingPath] -- Returns with portion of PrefixPath
  70. // after the logical root name and colon
  71. //
  72. // Returns: NTSTATUS:
  73. // STATUS_SUCCESS if Vcb found
  74. // STATUS_OBJECT_PATH_SYNTAX_BAD - no logical root name
  75. // STATUS_NO_SUCH_DEVICE - logical root name not found
  76. //
  77. //--------------------------------------------------------------------------
  78. #ifdef TERMSRV
  79. NTSTATUS
  80. DfsFindLogicalRoot(
  81. IN PUNICODE_STRING PrefixPath,
  82. IN ULONG SessionID,
  83. IN PLUID LogonID,
  84. OUT PDFS_VCB *Vcb,
  85. OUT PUNICODE_STRING RemainingPath
  86. )
  87. #else // TERMSRV
  88. NTSTATUS
  89. DfsFindLogicalRoot(
  90. IN PUNICODE_STRING PrefixPath,
  91. IN PLUID LogonID,
  92. OUT PDFS_VCB *Vcb,
  93. OUT PUNICODE_STRING RemainingPath
  94. )
  95. #endif // TERMSRV
  96. {
  97. PLIST_ENTRY Link;
  98. unsigned int i;
  99. NTSTATUS Status = STATUS_SUCCESS;
  100. NETRESOURCE testnt;
  101. DfsDbgTrace(+1, Dbg, "DfsFindLogicalRoot...\n", 0);
  102. *RemainingPath = *PrefixPath;
  103. for (i = 0; i < RemainingPath->Length/sizeof(WCHAR); i++) {
  104. if ((RemainingPath->Buffer[i] == (WCHAR)':') ||
  105. (RemainingPath->Buffer[i] == UNICODE_PATH_SEP))
  106. break;
  107. }
  108. if ((i*sizeof(WCHAR) >= RemainingPath->Length) ||
  109. (RemainingPath->Buffer[i] == UNICODE_PATH_SEP)) {
  110. Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
  111. DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  112. return(Status);
  113. }
  114. RemainingPath->Length = (USHORT)(i * sizeof (WCHAR));
  115. //
  116. // Search for the logical root in all known DFS_VCBs
  117. //
  118. ExAcquireResourceSharedLite(&DfsData.Resource, TRUE);
  119. for ( Link = DfsData.VcbQueue.Flink;
  120. Link != &DfsData.VcbQueue;
  121. Link = Link->Flink ) {
  122. *Vcb = CONTAINING_RECORD( Link, DFS_VCB, VcbLinks );
  123. #ifdef TERMSRV
  124. if ((SessionID == INVALID_SESSIONID) ||
  125. (SessionID == (*Vcb)->SessionID)) {
  126. #endif
  127. if ( RtlEqualLuid(LogonID, &(*Vcb)->LogonID) ) {
  128. if (RtlEqualString( (PSTRING)&(*Vcb)->LogicalRoot,
  129. (PSTRING)RemainingPath, (BOOLEAN)TRUE) ) {
  130. break;
  131. }
  132. }
  133. #ifdef TERMSRV
  134. }
  135. #endif // TERMSRV
  136. }
  137. if (Link == &DfsData.VcbQueue) {
  138. Status = STATUS_NO_SUCH_DEVICE;
  139. ExReleaseResourceLite(&DfsData.Resource);
  140. DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  141. return(Status);
  142. }
  143. //
  144. // Adjust remaining path to point beyond the logical root name
  145. //
  146. RemainingPath->Buffer = (WCHAR*)((char*) (RemainingPath->Buffer) +
  147. RemainingPath->Length + sizeof (WCHAR) );
  148. RemainingPath->Length = PrefixPath->Length -
  149. (RemainingPath->Length + sizeof (WCHAR));
  150. if (RemainingPath->Length <= 0 ||
  151. RemainingPath->Buffer[0] != UNICODE_PATH_SEP) {
  152. Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
  153. ExReleaseResourceLite(&DfsData.Resource);
  154. DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  155. return(Status);
  156. }
  157. ExReleaseResourceLite(&DfsData.Resource);
  158. DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  159. return(Status);
  160. }
  161. //+-------------------------------------------------------------------------
  162. //
  163. // Function: DfsInitializeLogicalRoot, public
  164. //
  165. // Synopsis: Allocate and initialize storage for a logical root.
  166. // This includes creating a device object and DFS_VCB for it.
  167. //
  168. // Effects: A logical root device object is created. A corresponding
  169. // DFS_VCB is also created and linked into the list of known
  170. // DFS_VCBs.
  171. //
  172. // Arguments: [Name] -- name of logical root.
  173. // [Prefix] -- Prefix to be prepended to file names opened
  174. // via the logical root being created before
  175. // they can be resolved in the DFS name space.
  176. // [Credentials] -- The credentials to use when accessing files
  177. // via this logical root.
  178. // [VcbFlags] -- To be OR'd into the VcbState field of the
  179. // DFS_VCB of the newly created logical root device.
  180. //
  181. // Requires: DfsData must first be set up. Also an EXCLUSIVE LOCK on
  182. // DfsData.Resource must be acquired.
  183. //
  184. // Returns: NTSTATUS - STATUS_SUCCESS unless there is some problem.
  185. //
  186. // History: 25 Jan 1992 alanw created
  187. //
  188. //--------------------------------------------------------------------------
  189. #ifdef TERMSRV
  190. NTSTATUS
  191. DfsInitializeLogicalRoot(
  192. IN LPCWSTR Name,
  193. IN PUNICODE_STRING Prefix OPTIONAL,
  194. IN PDFS_CREDENTIALS Credentials OPTIONAL,
  195. IN USHORT VcbFlags,
  196. IN ULONG SessionID,
  197. IN PLUID LogonID
  198. )
  199. #else // TERMSRV
  200. NTSTATUS
  201. DfsInitializeLogicalRoot(
  202. IN LPCWSTR Name,
  203. IN PUNICODE_STRING Prefix OPTIONAL,
  204. IN PDFS_CREDENTIALS Credentials OPTIONAL,
  205. IN USHORT VcbFlags,
  206. IN PLUID LogonID
  207. )
  208. #endif // TERMSRV
  209. {
  210. UNICODE_STRING UnicodeString = DfsData.LogRootDevName;
  211. UNICODE_STRING LogRootPrefix;
  212. UNICODE_STRING RootName, RemainingPath;
  213. UNICODE_STRING LogicalRoot;
  214. #ifdef TERMSRV
  215. //
  216. // The SessionID suffix is :SessionID where SessionID is 10 digits max.
  217. //
  218. UNICODE_STRING DeviceString;
  219. WCHAR DeviceBuffer[MAX_LOGICAL_ROOT_LEN + ID_MAX_LEN + sizeof(WCHAR)];
  220. UNICODE_STRING IDString;
  221. WCHAR IDBuffer[ID_MAX_LEN + 1]; // +1 for UNICODE_NULL
  222. #endif // TERMSRV
  223. WCHAR *TmpBuf;
  224. PDFS_VCB Vcb;
  225. WCHAR RootBuffer[MAX_LOGICAL_ROOT_LEN];
  226. PDFS_PKT_ENTRY pktEntry = NULL;
  227. LPCWSTR pstr = Name;
  228. PWSTR pdst;
  229. PLOGICAL_ROOT_DEVICE_OBJECT DeviceObject = NULL;
  230. NTSTATUS Status;
  231. DfsDbgTrace(0, Dbg, "DfsInitializeLogicalRoot -> %ws\n", Name);
  232. DfsDbgTrace(0, Dbg, "DfsInitializeLogicalRoot -> %wZ\n", Prefix);
  233. //
  234. // First, see if a logical root by the given name already exists
  235. //
  236. ASSERT(ARGUMENT_PRESENT(Name));
  237. RootName.Buffer = RootBuffer;
  238. RootName.MaximumLength = sizeof(RootBuffer);
  239. Status = DfspLogRootNameToPath(Name, &RootName);
  240. if (!NT_SUCCESS(Status)) {
  241. return(Status);
  242. }
  243. #ifdef TERMSRV
  244. Status = DfsFindLogicalRoot(&RootName, SessionID, LogonID, &Vcb, &RemainingPath);
  245. #else
  246. Status = DfsFindLogicalRoot(&RootName, &Vcb, LogonID, &RemainingPath);
  247. #endif
  248. ASSERT(Status != STATUS_OBJECT_PATH_SYNTAX_BAD);
  249. if (Status != STATUS_NO_SUCH_DEVICE) {
  250. return(STATUS_OBJECT_NAME_COLLISION);
  251. }
  252. #ifdef TERMSRV
  253. //
  254. // For multiuser,
  255. // If LUID device maps are enabled,
  256. // then we add the LogonID to the devicename - e.g.
  257. // net use f: to a DFS share for logon ID 0x000000000003a3f0 will create
  258. // a symbolic link with the following format:
  259. // \??\f: -> \Device\WinDfs\f:000000000003a3f0
  260. //
  261. // If LUID device maps are not enabled,
  262. // then we add the SessionID to the devicename - e.g.
  263. // net use f: to a DFS share for session ID 3 will create a symbolic link
  264. // \DosDevices\f::3 -> \device\WinDfs\f:3
  265. // In the VCB we store the SessionID for matching purposes.
  266. // Both the symbolic link and the object name shall contain the SessionID
  267. // in the name. However, in deviceObject->Vcb.LogicalRoot.Buffer, the
  268. // name does not contain the SessionID. To find a matching VCB, both the name
  269. // and SessionID must match.
  270. //
  271. DeviceString.Buffer = DeviceBuffer;
  272. DeviceString.MaximumLength = sizeof(DeviceBuffer);
  273. DeviceString.Length = 0;
  274. //
  275. // Build the UnicodeString without the SessionID or LogonID
  276. //
  277. RtlAppendUnicodeToString(&UnicodeString, (LPWSTR)Name);
  278. if( SessionID != INVALID_SESSIONID) {
  279. if( (DfsLUIDDeviceMapsEnabled == TRUE) &&
  280. (LogonID != NULL) &&
  281. (sizeof(*LogonID) == sizeof(LUID)) ) {
  282. //
  283. // Build the DeviceString with the LogonID
  284. //
  285. _snwprintf( IDBuffer,
  286. sizeof(IDBuffer)/sizeof(WCHAR),
  287. L"%08x%08x",
  288. LogonID->HighPart,
  289. LogonID->LowPart );
  290. IDBuffer[ID_MAX_LEN] = UNICODE_NULL;
  291. RtlInitUnicodeString( &IDString, IDBuffer );
  292. }
  293. else {
  294. //
  295. // Build the DeviceString with the SessionID
  296. //
  297. IDString.Buffer = IDBuffer;
  298. IDString.MaximumLength = sizeof(IDBuffer);
  299. IDString.Length = 0;
  300. RtlIntegerToUnicodeString(SessionID, 10, &IDString);
  301. }
  302. RtlCopyUnicodeString(&DeviceString, &DfsData.LogRootDevName);
  303. RtlAppendUnicodeToString(&DeviceString, (LPWSTR)Name);
  304. RtlAppendUnicodeToString(&DeviceString,L":");
  305. RtlAppendUnicodeStringToString(&DeviceString, &IDString);
  306. DeviceString.MaximumLength = DeviceString.Length;
  307. //
  308. // Next, try to setup the Dos Device link
  309. //
  310. if (Prefix) {
  311. Status = DfsDefineDosDevice( Name[0], &DeviceString );
  312. if (!NT_SUCCESS(Status)) {
  313. return( Status );
  314. }
  315. }
  316. }
  317. else {
  318. ASSERT( Prefix == FALSE );
  319. }
  320. #else // TERMSRV
  321. //
  322. // DfsData.LogRootDevName is initialized to be L"\Device\WinDfs\"
  323. // Here, we tack on the name of the Logical root we are creating
  324. // to the above string, so that the string becomes, for example,
  325. // L"\Device\WinDfs\Root". Note that at this point, we are scribbling
  326. // into the buffer belonging to DfsData.LogRootDevName, but this
  327. // should be ok, since we are not changing the Length field of that
  328. // Unicode string! BTW, we need a string of this form to create the
  329. // device object.
  330. //
  331. pdst = &UnicodeString.Buffer[UnicodeString.Length/sizeof (WCHAR)];
  332. while (*pstr != UNICODE_NULL) {
  333. *pdst++ = *pstr++;
  334. UnicodeString.Length += sizeof (WCHAR);
  335. }
  336. //
  337. // Next, try to setup the Dos Device link
  338. //
  339. if (Prefix) {
  340. Status = DfsDefineDosDevice( Name[0], &UnicodeString );
  341. if (!NT_SUCCESS(Status)) {
  342. return( Status );
  343. }
  344. }
  345. #endif // TERMSRV
  346. //
  347. // Before we initialize the Vcb, we need to allocate space for the
  348. // Prefix. PagedPool should be fine here. We need to reallocate because
  349. // we will store this permanently in the DFS_VCB.
  350. //
  351. LogRootPrefix.Buffer = NULL;
  352. if (Prefix && Prefix->Length > 0) {
  353. LogRootPrefix.Length = Prefix->Length;
  354. LogRootPrefix.MaximumLength = LogRootPrefix.Length + sizeof(WCHAR);
  355. LogRootPrefix.Buffer = ExAllocatePoolWithTag(
  356. PagedPool,
  357. LogRootPrefix.MaximumLength,
  358. ' puM');
  359. if (LogRootPrefix.Buffer != NULL) {
  360. RtlMoveMemory(LogRootPrefix.Buffer,
  361. Prefix->Buffer,
  362. Prefix->MaximumLength);
  363. LogRootPrefix.Buffer[Prefix->Length/sizeof(WCHAR)] = UNICODE_NULL;
  364. } else {
  365. //
  366. // Couldn't allocate memory! Ok to return with error code, since
  367. // we haven't changed the state of the IO subsystem yet.
  368. //
  369. if (Prefix) {
  370. NTSTATUS DeleteStatus;
  371. DeleteStatus = DfsUndefineDosDevice( Name[0] );
  372. ASSERT(NT_SUCCESS(DeleteStatus));
  373. }
  374. return(STATUS_INSUFFICIENT_RESOURCES);
  375. }
  376. } else {
  377. RtlInitUnicodeString(&LogRootPrefix, NULL);
  378. }
  379. //
  380. // Save the logical root name for the DFS_VCB structure. Remember, above
  381. // we had UnicodeString to be of the form L"\Device\WinDfs\org". Now,
  382. // we copy UnicodeString, then adjust the buffer and length fields so that
  383. // the Buffer points to the beginning of the L"org"; Then, we allocate
  384. // space for LogicalRootBuffer, and copy the name to it!
  385. //
  386. LogicalRoot = UnicodeString;
  387. LogicalRoot.Buffer = &LogicalRoot.Buffer[ DfsData.LogRootDevName.Length/sizeof (WCHAR) ];
  388. LogicalRoot.Length -= DfsData.LogRootDevName.Length;
  389. LogicalRoot.MaximumLength -= DfsData.LogRootDevName.Length;
  390. //
  391. // Now dup the buffer that LogicalRoot uses
  392. //
  393. TmpBuf = ExAllocatePoolWithTag( PagedPool,
  394. LogicalRoot.Length,
  395. ' puM');
  396. if (TmpBuf == NULL) {
  397. //
  398. // Couldn't allocate memory! Ok to return with error code, since
  399. // we still haven't changed the state of the IO subsystem yet.
  400. //
  401. if (LogRootPrefix.Buffer != NULL) {
  402. ExFreePool(LogRootPrefix.Buffer);
  403. }
  404. if (Prefix) {
  405. NTSTATUS DeleteStatus;
  406. DeleteStatus = DfsUndefineDosDevice( Name[0] );
  407. ASSERT(NT_SUCCESS(DeleteStatus));
  408. }
  409. return(STATUS_INSUFFICIENT_RESOURCES);
  410. } else {
  411. RtlMoveMemory( TmpBuf,
  412. LogicalRoot.Buffer,
  413. LogicalRoot.Length );
  414. LogicalRoot.Buffer = TmpBuf;
  415. }
  416. //
  417. // Create the device object for the logical root.
  418. //
  419. #ifdef TERMSRV
  420. Status = IoCreateDevice( DfsData.DriverObject,
  421. sizeof( LOGICAL_ROOT_DEVICE_OBJECT ) -
  422. sizeof( DEVICE_OBJECT ),
  423. (SessionID != INVALID_SESSIONID) ?
  424. &DeviceString : &UnicodeString,
  425. FILE_DEVICE_DFS,
  426. FILE_REMOTE_DEVICE,
  427. FALSE,
  428. (PDEVICE_OBJECT *) &DeviceObject );
  429. #else // TERMSRV
  430. Status = IoCreateDevice( DfsData.DriverObject,
  431. sizeof( LOGICAL_ROOT_DEVICE_OBJECT ) -
  432. sizeof( DEVICE_OBJECT ),
  433. &UnicodeString,
  434. FILE_DEVICE_DFS,
  435. FILE_REMOTE_DEVICE,
  436. FALSE,
  437. (PDEVICE_OBJECT *) &DeviceObject );
  438. #endif // TERMSRV
  439. if ( !NT_SUCCESS( Status ) ) {
  440. if (LogRootPrefix.Buffer) {
  441. ExFreePool(LogRootPrefix.Buffer);
  442. ExFreePool(LogicalRoot.Buffer);
  443. }
  444. if (Prefix) {
  445. NTSTATUS DeleteStatus;
  446. DeleteStatus = DfsUndefineDosDevice( Name[0] );
  447. ASSERT(NT_SUCCESS(DeleteStatus));
  448. }
  449. return Status;
  450. }
  451. //
  452. // Pin the pkt entry in the cache by incrementing the Usecount
  453. //
  454. if (LogRootPrefix.Buffer != NULL && LogRootPrefix.Length > 0) {
  455. UNICODE_STRING prefix = LogRootPrefix;
  456. USHORT i, j;
  457. //
  458. // We want to work with the \server\share part of the prefix only,
  459. // so count up to 3 backslashes, then stop.
  460. //
  461. for (i = j = 0; i < prefix.Length/sizeof(WCHAR) && j < 3; i++) {
  462. if (prefix.Buffer[i] == UNICODE_PATH_SEP) {
  463. j++;
  464. }
  465. }
  466. prefix.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
  467. pktEntry = PktLookupEntryByPrefix(&DfsData.Pkt,
  468. &prefix,
  469. &RemainingPath);
  470. if (pktEntry != NULL && RemainingPath.Length == 0) {
  471. InterlockedIncrement(&pktEntry->UseCount);
  472. }
  473. else {
  474. pktEntry = NULL;
  475. }
  476. }
  477. DeviceObject->DeviceObject.StackSize = 5;
  478. DfsInitializeVcb ( NULL,
  479. &DeviceObject->Vcb,
  480. &LogRootPrefix,
  481. Credentials,
  482. (PDEVICE_OBJECT)DeviceObject );
  483. DeviceObject->Vcb.VcbState |= VcbFlags;
  484. #ifdef TERMSRV
  485. DeviceObject->Vcb.SessionID = SessionID;
  486. #endif
  487. DeviceObject->Vcb.pktEntry = pktEntry;
  488. RtlCopyLuid(&DeviceObject->Vcb.LogonID, LogonID);
  489. //
  490. // Above we preallocated the buffer we need here. So just use it.
  491. //
  492. DeviceObject->Vcb.LogicalRoot = LogicalRoot;
  493. //
  494. // This is not documented anywhere, but calling IoCreateDevice has set
  495. // the DO_DEVICE_INITIALIZING flag in DeviceObject->Flags. Normally,
  496. // device objects are created only at driver init time, and IoLoadDriver
  497. // will clear this bit for all device objects created at init time.
  498. // Since in Dfs, we need to create and delete devices on the fly (ie,
  499. // via FsCtl), we need to manually clear this bit.
  500. //
  501. DeviceObject->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
  502. return STATUS_SUCCESS;
  503. }
  504. //+----------------------------------------------------------------------------
  505. //
  506. // Function: DfsDeleteLogicalRoot
  507. //
  508. // Synopsis: Removes a logical root if found and possible.
  509. //
  510. // Arguments: [Name] -- Name of the Logical Root
  511. // [fForce] -- Whether to Forcibly delete logical root inspite of
  512. // open files.
  513. //
  514. // Returns: STATUS_SUCCESS -- If successfully deleted logical root
  515. //
  516. // STATUS_NO_SUCH_DEVICE -- If there is no logical root to
  517. // delete.
  518. //
  519. // STATUS_DEVICE_BUSY -- If fForce is false and there are open
  520. // files via this logical root.
  521. //
  522. //-----------------------------------------------------------------------------
  523. #ifdef TERMSRV
  524. NTSTATUS
  525. DfsDeleteLogicalRoot(
  526. IN PWSTR Name,
  527. IN BOOLEAN fForce,
  528. IN ULONG SessionID,
  529. IN PLUID LogonID
  530. )
  531. #else // TERMSRV
  532. NTSTATUS
  533. DfsDeleteLogicalRoot(
  534. IN PWSTR Name,
  535. IN BOOLEAN fForce,
  536. IN PLUID LogonID
  537. )
  538. #endif // TERMSRV
  539. {
  540. UNICODE_STRING RootName;
  541. UNICODE_STRING RemainingPath;
  542. WCHAR RootBuffer[MAX_LOGICAL_ROOT_LEN + 2];
  543. PDFS_PKT_ENTRY PktEntry;
  544. PDFS_VCB Vcb;
  545. NTSTATUS Status;
  546. PLOGICAL_ROOT_DEVICE_OBJECT DeviceObject;
  547. BOOLEAN pktLocked;
  548. PDFS_PKT_ENTRY pktEntry;
  549. //
  550. // The 2 extra spots are for holding :\ to form a path out of a
  551. // root name; ie, to go from root to a root:\ form.
  552. //
  553. DfsDbgTrace(0, Dbg, "DfsDeleteLogicalRoot -> %ws\n", Name);
  554. DfsDbgTrace(0, Dbg, "DfsDeleteLogicalRoot -> %s\n", fForce ? "TRUE":"FALSE");
  555. //
  556. // First see if the logical root even exists.
  557. //
  558. ASSERT(ARGUMENT_PRESENT(Name));
  559. RootName.Buffer = RootBuffer;
  560. RootName.MaximumLength = sizeof(RootBuffer);
  561. Status = DfspLogRootNameToPath(Name, &RootName);
  562. if (!NT_SUCCESS(Status))
  563. return(Status);
  564. //
  565. // Acquire Pkt and DfsData, wait till we do so.
  566. //
  567. PktAcquireExclusive(TRUE, &pktLocked);
  568. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  569. #ifdef TERMSRV
  570. Status = DfsFindLogicalRoot(&RootName, SessionID, LogonID, &Vcb, &RemainingPath);
  571. #else // TERMSRV
  572. Status = DfsFindLogicalRoot(&RootName, LogonID, &Vcb, &RemainingPath);
  573. #endif // TERMSRV
  574. if (!NT_SUCCESS(Status)) {
  575. goto Cleanup;
  576. }
  577. //
  578. // Check to see if there are open files via this volume.
  579. //
  580. if (!fForce &&
  581. ((Vcb->DirectAccessOpenCount != 0) ||
  582. (Vcb->OpenFileCount != 0))) {
  583. Status = STATUS_DEVICE_BUSY;
  584. goto Cleanup;
  585. }
  586. //
  587. // Delete the credentials used by this connection
  588. //
  589. if (Vcb->Credentials != NULL) {
  590. DfsDeleteCredentials( Vcb->Credentials );
  591. }
  592. //
  593. // Get rid of the Dos Device
  594. //
  595. DfsUndefineDosDevice( Name[0] );
  596. //
  597. // Dec ref count on pkt entry
  598. //
  599. if (Vcb->pktEntry != NULL) {
  600. InterlockedDecrement(&Vcb->pktEntry->UseCount);
  601. Vcb->pktEntry = NULL;
  602. }
  603. //
  604. // Now, get rid of the Device itself. This is a bit tricky, because there
  605. // might be files open on this device. So, we reference the device and
  606. // call ObMakeTemporaryObject. This causes the object to be removed from
  607. // the NT Object table, but, since atleast our reference is active,
  608. // prevents the object from being freed. Then, we insert this object into
  609. // our DeletedVcb list. The timer routine will periodically wake up and
  610. // see if all references to this device have been released, at which
  611. // point the device will be finally freed.
  612. //
  613. RemoveEntryList(&Vcb->VcbLinks);
  614. InsertTailList( &DfsData.DeletedVcbQueue, &Vcb->VcbLinks );
  615. DeviceObject = CONTAINING_RECORD( Vcb, LOGICAL_ROOT_DEVICE_OBJECT, Vcb);
  616. ObReferenceObjectByPointer( DeviceObject, 0, NULL, KernelMode );
  617. ObMakeTemporaryObject((PVOID) DeviceObject);
  618. DeviceObject->DeviceObject.Flags &= ~DO_DEVICE_HAS_NAME;
  619. Cleanup:
  620. ExReleaseResourceLite(&DfsData.Resource);
  621. PktRelease();
  622. return(Status);
  623. }
  624. //+----------------------------------------------------------------------------
  625. //
  626. // Function: DfspLogRootNameToPath
  627. //
  628. // Synopsis: Amazingly enough, all it does it takes a PWSTR, copies it into
  629. // a Unicode string's buffer, and appends a \ to the tail of the
  630. // buffer, thus making a path out of a Logical root name.
  631. //
  632. // Arguments: [Name] -- Name of logical root, like L"org"
  633. // [RootName] -- Destination for L"org\\"
  634. //
  635. // Returns: STATUS_BUFFER_OVERFLOW, STATUS_SUCCESS
  636. //
  637. //-----------------------------------------------------------------------------
  638. NTSTATUS
  639. DfspLogRootNameToPath(
  640. IN LPCWSTR Name,
  641. OUT PUNICODE_STRING RootName
  642. )
  643. {
  644. unsigned short i, nMaxNameLen;
  645. //
  646. // The two extra spots are required to append a ":\" after the root name.
  647. //
  648. nMaxNameLen = (RootName->MaximumLength/sizeof(WCHAR)) - 2;
  649. //
  650. // Copy the name
  651. //
  652. for (i = 0; Name[i] != UNICODE_NULL && i < nMaxNameLen; i++) {
  653. RootName->Buffer[i] = Name[i];
  654. }
  655. //
  656. // Make sure entire name was copied before we ran out of space
  657. //
  658. if (Name[i] != UNICODE_NULL) {
  659. //
  660. // Someone sent in a name bigger than allowed.
  661. //
  662. return(STATUS_BUFFER_OVERFLOW);
  663. }
  664. //
  665. // Append the ":\" to form a path
  666. //
  667. RootName->Length = i * sizeof(WCHAR);
  668. return(RtlAppendUnicodeToString(RootName, L":\\"));
  669. }
  670. #define PackMem(buf, str, len, pulen) { \
  671. ASSERT(*(pulen) >= (len)); \
  672. RtlMoveMemory((buf) + *(pulen) - (len), (str), (len)); \
  673. *(pulen) -= (len); \
  674. }
  675. //+----------------------------------------------------------------------------
  676. //
  677. // Function: DfsGetResourceFromVcb
  678. //
  679. // Synopsis: Given a DFS_VCB it constructs a NETRESOURCE struct into the buffer
  680. // passed in. At the same time it uses the end of the buffer to
  681. // fill in a string. If the buffer is insufficient in size the
  682. // required size is returned in "pulen". If everything succeeds
  683. // then the pulen arg is decremented to indicate remaining size
  684. // of buffer.
  685. //
  686. // Arguments: [Vcb] -- The source DFS_VCB
  687. // [ProviderName] -- Provider Name to stuff in the NETRESOURCE
  688. // [BufBegin] -- Start of actual buffer for computing offsets
  689. // [Buf] -- The NETRESOURCE structure to fill
  690. // [BufSize] -- On entry, size of buf. On return, contains
  691. // remaining size of buf.
  692. //
  693. // Returns: [STATUS_SUCCESS] -- Operation completed successfully.
  694. // [STATUS_BUFFER_OVERFLOW] -- buf is not big enough.
  695. //
  696. // Notes: This routine fills in a NETRESOURCE structure starting at
  697. // Buf. The strings in the NETRESOURCE are filled in starting
  698. // from the *end* (ie, starting at Buf + *BufSize)
  699. //
  700. //-----------------------------------------------------------------------------
  701. #if defined (_WIN64)
  702. typedef struct _DFS_NETRESOURCE32 {
  703. DWORD dwScope;
  704. DWORD dwType;
  705. DWORD dwDisplayType;
  706. DWORD dwUsage;
  707. ULONG lpLocalName;
  708. ULONG lpRemoteName;
  709. ULONG lpComment ;
  710. ULONG lpProvider;
  711. }DFS_NETRESOURCE32, *PDFS_NETRESOURCE32;
  712. #endif
  713. NTSTATUS
  714. DfsGetResourceFromVcb(
  715. PIRP pIrp,
  716. PDFS_VCB Vcb,
  717. PUNICODE_STRING ProviderName,
  718. PUCHAR BufBegin,
  719. PUCHAR Buf,
  720. PULONG BufSize,
  721. PULONG pResourceSize
  722. )
  723. {
  724. LPNETRESOURCE netResource = (LPNETRESOURCE) Buf;
  725. ULONG sizeRequired = 0, ResourceSize;
  726. WCHAR localDrive[ 3 ];
  727. ULONG32 CommentOffset, ProviderOffset, LocalNameOffset, RemoteNameOffset;
  728. #if defined (_WIN64)
  729. if (IoIs32bitProcess(pIrp)) {
  730. ResourceSize = sizeof(DFS_NETRESOURCE32);
  731. }
  732. else
  733. #endif
  734. ResourceSize = sizeof(NETRESOURCE);
  735. *pResourceSize = ResourceSize;
  736. sizeRequired = ResourceSize +
  737. ProviderName->Length +
  738. sizeof(UNICODE_NULL) +
  739. 3 * sizeof(WCHAR) + // lpLocalName D: etc.
  740. sizeof(UNICODE_PATH_SEP) +
  741. Vcb->LogRootPrefix.Length +
  742. sizeof(UNICODE_NULL);
  743. if (*BufSize < sizeRequired) {
  744. *BufSize = sizeRequired;
  745. return(STATUS_BUFFER_OVERFLOW);
  746. }
  747. //
  748. // Buffer is big enough, fill in the NETRESOURCE structure
  749. //
  750. Buf += ResourceSize;
  751. *BufSize -= ResourceSize;
  752. netResource->dwScope = RESOURCE_CONNECTED;
  753. netResource->dwType = RESOURCETYPE_DISK;
  754. netResource->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  755. netResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
  756. CommentOffset = 0;
  757. //
  758. // Fill in the provider name
  759. //
  760. PackMem(Buf, L"", sizeof(L""), BufSize);
  761. PackMem(Buf, ProviderName->Buffer, ProviderName->Length, BufSize);
  762. ProviderOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  763. //
  764. // Fill in the local name next
  765. //
  766. localDrive[0] = Vcb->LogicalRoot.Buffer[0];
  767. localDrive[1] = UNICODE_DRIVE_SEP;
  768. localDrive[2] = UNICODE_NULL;
  769. PackMem(Buf, localDrive, sizeof(localDrive), BufSize);
  770. LocalNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  771. //
  772. // Fill in the remote name last
  773. //
  774. PackMem(Buf, L"", sizeof(L""), BufSize);
  775. PackMem(Buf, Vcb->LogRootPrefix.Buffer, Vcb->LogRootPrefix.Length, BufSize);
  776. PackMem(Buf, UNICODE_PATH_SEP_STR, sizeof(UNICODE_PATH_SEP), BufSize);
  777. RemoteNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  778. #if defined (_WIN64)
  779. if (IoIs32bitProcess(pIrp)) {
  780. PDFS_NETRESOURCE32 pNetResource32 = (PDFS_NETRESOURCE32)netResource;
  781. pNetResource32->lpComment = CommentOffset;
  782. pNetResource32->lpProvider = ProviderOffset;
  783. pNetResource32->lpLocalName = LocalNameOffset;
  784. pNetResource32->lpRemoteName = RemoteNameOffset;
  785. }
  786. else {
  787. #endif
  788. netResource->lpComment = (LPWSTR)UIntToPtr( CommentOffset );
  789. netResource->lpProvider = (LPWSTR)UIntToPtr( ProviderOffset );
  790. netResource->lpLocalName = (LPWSTR)UIntToPtr( LocalNameOffset );
  791. netResource->lpRemoteName = (LPWSTR)UIntToPtr( RemoteNameOffset );
  792. #if defined (_WIN64)
  793. }
  794. #endif
  795. return(STATUS_SUCCESS);
  796. }
  797. //+----------------------------------------------------------------------------
  798. //
  799. // Function: DfsGetResourceFromDevlessRoot
  800. //
  801. // Synopsis: Builds a NETRESOURCE structure for a device-less connection.
  802. // The LPWSTR members of NETRESOURCE actually contain offsets
  803. // from the BufBegin parameter.
  804. //
  805. // Arguments: [Drt] -- The DevicelessRoot structure
  806. // [ProviderName] -- Provider Name to stuff in the NETRESOURCE
  807. // [BufBegin] -- Start of actual buffer for computing offsets
  808. // [Buf] -- The NETRESOURCE structure to fill
  809. // [BufSize] -- On entry, size of buf. On return, contains
  810. // remaining size of buf.
  811. //
  812. // Returns: [STATUS_SUCCESS] -- Operation completed successfully.
  813. // [STATUS_BUFFER_OVERFLOW] -- buf is not big enough.
  814. //
  815. // Notes: This routine fills in a NETRESOURCE structure starting at
  816. // Buf. The strings in the NETRESOURCE are filled in starting
  817. // from the *end* (ie, starting at Buf + *BufSize)
  818. //
  819. //-----------------------------------------------------------------------------
  820. NTSTATUS
  821. DfsGetResourceFromDevlessRoot(
  822. PIRP pIrp,
  823. PDFS_DEVLESS_ROOT pDrt,
  824. PUNICODE_STRING ProviderName,
  825. PUCHAR BufBegin,
  826. PUCHAR Buf,
  827. PULONG BufSize,
  828. PULONG pResourceSize)
  829. {
  830. LPNETRESOURCE netResource = (LPNETRESOURCE) Buf;
  831. ULONG sizeRequired = 0, ResourceSize;
  832. WCHAR localDrive[ 3 ];
  833. ULONG32 CommentOffset, ProviderOffset, LocalNameOffset, RemoteNameOffset;
  834. #if defined (_WIN64)
  835. if (IoIs32bitProcess(pIrp)) {
  836. ResourceSize = sizeof(DFS_NETRESOURCE32);
  837. }
  838. else
  839. #endif
  840. ResourceSize = sizeof(NETRESOURCE);
  841. *pResourceSize = ResourceSize;
  842. sizeRequired = ResourceSize +
  843. ProviderName->Length +
  844. sizeof(UNICODE_NULL) +
  845. 2 * sizeof(UNICODE_PATH_SEP) +
  846. pDrt->DevlessPath.Length +
  847. sizeof(UNICODE_NULL);
  848. if (*BufSize < sizeRequired) {
  849. *BufSize = sizeRequired;
  850. return(STATUS_BUFFER_OVERFLOW);
  851. }
  852. //
  853. // Buffer is big enough, fill in the NETRESOURCE structure
  854. //
  855. Buf += ResourceSize;
  856. *BufSize -= ResourceSize;
  857. netResource->dwScope = RESOURCE_CONNECTED;
  858. netResource->dwType = RESOURCETYPE_DISK;
  859. netResource->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  860. netResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
  861. CommentOffset = 0;
  862. LocalNameOffset = 0;
  863. //
  864. // Fill in the provider name
  865. //
  866. PackMem(Buf, L"", sizeof(L""), BufSize);
  867. PackMem(Buf, ProviderName->Buffer, ProviderName->Length, BufSize);
  868. ProviderOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  869. //
  870. // Fill in the remote name last
  871. //
  872. PackMem(Buf, L"", sizeof(L""), BufSize);
  873. PackMem(Buf, pDrt->DevlessPath.Buffer, pDrt->DevlessPath.Length, BufSize);
  874. PackMem(Buf, UNICODE_PATH_SEP_STR, sizeof(UNICODE_PATH_SEP), BufSize);
  875. RemoteNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  876. #if defined (_WIN64)
  877. if (IoIs32bitProcess(pIrp)) {
  878. PDFS_NETRESOURCE32 pNetResource32 = (PDFS_NETRESOURCE32)netResource;
  879. pNetResource32->lpComment = CommentOffset;
  880. pNetResource32->lpProvider = ProviderOffset;
  881. pNetResource32->lpLocalName = LocalNameOffset;
  882. pNetResource32->lpRemoteName = RemoteNameOffset;
  883. }
  884. else {
  885. #endif
  886. netResource->lpComment = (LPWSTR)UIntToPtr( CommentOffset );
  887. netResource->lpProvider = (LPWSTR)UIntToPtr( ProviderOffset );
  888. netResource->lpLocalName = (LPWSTR)UIntToPtr( LocalNameOffset );
  889. netResource->lpRemoteName = (LPWSTR)UIntToPtr( RemoteNameOffset );
  890. #if defined (_WIN64)
  891. }
  892. #endif
  893. return(STATUS_SUCCESS);
  894. }
  895. #ifdef TERMSRV
  896. BOOLEAN
  897. DfsLogicalRootExists(
  898. IN PWSTR pwszName,
  899. IN ULONG SessionID,
  900. IN PLUID LogonID
  901. )
  902. #else // TERMSRV
  903. BOOLEAN
  904. DfsLogicalRootExists(
  905. IN PWSTR pwszName,
  906. IN PLUID LogonID
  907. )
  908. #endif // TERMSRV
  909. {
  910. UNICODE_STRING RootName;
  911. UNICODE_STRING RemainingPath;
  912. WCHAR RootBuffer[MAX_LOGICAL_ROOT_LEN + 2];
  913. PDFS_VCB Vcb;
  914. NTSTATUS Status;
  915. ASSERT(ARGUMENT_PRESENT(pwszName));
  916. RootName.Buffer = RootBuffer;
  917. RootName.MaximumLength = sizeof(RootBuffer);
  918. Status = DfspLogRootNameToPath(pwszName, &RootName);
  919. if (!NT_SUCCESS(Status)) {
  920. return(FALSE);
  921. }
  922. #ifdef TERMSRV
  923. Status = DfsFindLogicalRoot(&RootName, SessionID, LogonID, &Vcb, &RemainingPath);
  924. #else // TERMSRV
  925. Status = DfsFindLogicalRoot(&RootName, LogonId, &Vcb, &RemainingPath);
  926. #endif // TERMSRV
  927. if (!NT_SUCCESS(Status)) {
  928. //
  929. // If this asserts, we need to fix the code above that creates the
  930. // Logical Root name, or fix DfsFindLogicalRoot.
  931. //
  932. ASSERT(Status != STATUS_OBJECT_PATH_SYNTAX_BAD);
  933. return(FALSE);
  934. }
  935. else {
  936. return(TRUE);
  937. }
  938. }
  939. //+----------------------------------------------------------------------------
  940. //
  941. // Function: DfsDefineDosDevice
  942. //
  943. // Synopsis: Creates a dos device to a logical root
  944. //
  945. // Arguments:
  946. //
  947. // Returns:
  948. //
  949. //-----------------------------------------------------------------------------
  950. NTSTATUS
  951. DfsDefineDosDevice(
  952. IN WCHAR Device,
  953. IN PUNICODE_STRING Target)
  954. {
  955. NTSTATUS status;
  956. HANDLE device;
  957. OBJECT_ATTRIBUTES ob;
  958. UNICODE_STRING deviceName;
  959. WCHAR Buf[25];
  960. wcscpy(Buf, L"\\??\\X:");
  961. RtlInitUnicodeString( &deviceName, Buf);
  962. deviceName.Buffer[ deviceName.Length/sizeof(WCHAR) - 2] = Device;
  963. InitializeObjectAttributes(
  964. &ob,
  965. &deviceName,
  966. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
  967. NULL,
  968. NULL);
  969. status = ZwCreateSymbolicLinkObject(
  970. &device,
  971. SYMBOLIC_LINK_ALL_ACCESS,
  972. &ob,
  973. Target);
  974. if (NT_SUCCESS(status))
  975. ZwClose( device );
  976. return( status );
  977. }
  978. //+----------------------------------------------------------------------------
  979. //
  980. // Function: DfsUndefineDosDevice
  981. //
  982. // Synopsis: Undefines a dos device
  983. //
  984. // Arguments:
  985. //
  986. // Returns:
  987. //
  988. //-----------------------------------------------------------------------------
  989. NTSTATUS
  990. DfsUndefineDosDevice(
  991. IN WCHAR Device
  992. )
  993. {
  994. NTSTATUS status;
  995. HANDLE device;
  996. OBJECT_ATTRIBUTES ob;
  997. UNICODE_STRING deviceName;
  998. WCHAR Buf[25];
  999. wcscpy(Buf, L"\\??\\X:");
  1000. RtlInitUnicodeString( &deviceName, Buf);
  1001. deviceName.Buffer[ deviceName.Length/sizeof(WCHAR) - 2] = Device;
  1002. InitializeObjectAttributes(
  1003. &ob,
  1004. &deviceName,
  1005. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
  1006. NULL,
  1007. NULL);
  1008. status = ZwOpenSymbolicLinkObject(
  1009. &device,
  1010. SYMBOLIC_LINK_QUERY | DELETE,
  1011. &ob);
  1012. if (NT_SUCCESS(status)) {
  1013. status = ZwMakeTemporaryObject( device );
  1014. ZwClose( device );
  1015. }
  1016. return( status );
  1017. }
  1018. //+-------------------------------------------------------------------------
  1019. //
  1020. // Function: DfsFindDevlessRoot, local
  1021. //
  1022. // Synopsis: DfsFindDevlessRoot takes as input a UNC name
  1023. // looks up the DFS_DEVLESS_ROOT associated with the root,
  1024. // and returns the DevlessRoot
  1025. //
  1026. // Arguments: [Path] -- Input path name
  1027. // [Drt] -- Returns DFS_DEVLESS_ROOT which corresponds to
  1028. // the root for the Path
  1029. //
  1030. // Returns: NTSTATUS:
  1031. // STATUS_SUCCESS if Drt found
  1032. // STATUS_NO_SUCH_DEVICE - root name not found
  1033. //
  1034. //--------------------------------------------------------------------------
  1035. #ifdef TERMSRV
  1036. NTSTATUS
  1037. DfsFindDevlessRoot(
  1038. IN PUNICODE_STRING Path,
  1039. IN ULONG SessionID,
  1040. IN PLUID LogonID,
  1041. OUT PDFS_DEVLESS_ROOT *Drt
  1042. )
  1043. #else // TERMSRV
  1044. NTSTATUS
  1045. DfsFindDevlessRoot(
  1046. IN PUNICODE_STRING Path,
  1047. IN PLUID LogonID,
  1048. OUT PDFS_DEVLESS_ROOT *Drt,
  1049. )
  1050. #endif // TERMSRV
  1051. {
  1052. PLIST_ENTRY Link;
  1053. NTSTATUS Status = STATUS_SUCCESS;
  1054. DfsDbgTrace(+1, Dbg, "DfsFindDevlessRoot...%wZ\n", Path);
  1055. //
  1056. // Search for the devless ROOT.
  1057. //
  1058. ExAcquireResourceSharedLite(&DfsData.Resource, TRUE);
  1059. for ( Link = DfsData.DrtQueue.Flink;
  1060. Link != &DfsData.DrtQueue;
  1061. Link = Link->Flink ) {
  1062. *Drt = CONTAINING_RECORD( Link, DFS_DEVLESS_ROOT, DrtLinks );
  1063. #ifdef TERMSRV
  1064. if ((SessionID == INVALID_SESSIONID) ||
  1065. (SessionID == (*Drt)->SessionID)) {
  1066. #endif
  1067. if ( RtlEqualLuid(LogonID, &(*Drt)->LogonID) ) {
  1068. if (RtlEqualString( (PSTRING)&(*Drt)->DevlessPath,
  1069. (PSTRING)Path, (BOOLEAN)TRUE) ) {
  1070. break;
  1071. }
  1072. }
  1073. #ifdef TERMSRV
  1074. }
  1075. #endif // TERMSRV
  1076. }
  1077. if (Link == &DfsData.DrtQueue) {
  1078. Status = STATUS_NO_SUCH_DEVICE;
  1079. ExReleaseResourceLite(&DfsData.Resource);
  1080. DfsDbgTrace(-1, Dbg, "DfsFindDevlessRoot -> %08lx\n", ULongToPtr(Status) );
  1081. return(Status);
  1082. }
  1083. ExReleaseResourceLite(&DfsData.Resource);
  1084. DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1085. return(Status);
  1086. }
  1087. //+-------------------------------------------------------------------------
  1088. //
  1089. // Function: DfsInitializeDevlessRoot, public
  1090. //
  1091. // Synopsis: Allocate and initialize storage for a Deviceless root.
  1092. //
  1093. // Effects: A DFS_DEVLESS_ROOT structure is created.
  1094. //
  1095. // Arguments: [Name] -- Pathname that is the deviceless root.
  1096. // [Credentials] -- The credentials to use when accessing files
  1097. // via this logical root.
  1098. //
  1099. // Requires: DfsData must first be set up. Also an EXCLUSIVE LOCK on
  1100. // DfsData.Resource must be acquired.
  1101. //
  1102. // Returns: NTSTATUS - STATUS_SUCCESS unless there is some problem.
  1103. //
  1104. //--------------------------------------------------------------------------
  1105. #ifdef TERMSRV
  1106. NTSTATUS
  1107. DfsInitializeDevlessRoot(
  1108. IN PUNICODE_STRING Name,
  1109. IN PDFS_CREDENTIALS Credentials OPTIONAL,
  1110. IN ULONG SessionID,
  1111. IN PLUID LogonID
  1112. )
  1113. #else // TERMSRV
  1114. NTSTATUS
  1115. DfsInitializeDevlessRoot(
  1116. IN PUNICODE_STRING Name,
  1117. IN PDFS_CREDENTIALS Credentials OPTIONAL,
  1118. IN PLUID LogonID
  1119. )
  1120. #endif // TERMSRV
  1121. {
  1122. PDFS_DEVLESS_ROOT Drt;
  1123. PDFS_PKT_ENTRY pktEntry = NULL;
  1124. UNICODE_STRING DevlessRootName;
  1125. NTSTATUS Status;
  1126. DfsDbgTrace(0, Dbg, "DfsInitializeDevlessRoot -> %wZ\n", Name);
  1127. #ifdef TERMSRV
  1128. Status = DfsFindDevlessRoot(Name, SessionID, LogonID, &Drt);
  1129. #else
  1130. Status = DfsFindDevlessRoot(Name, LogonID, &Drt);
  1131. #endif
  1132. if (Status != STATUS_NO_SUCH_DEVICE) {
  1133. //
  1134. // this means we found a device. In the devless Root case, this means
  1135. // we dont have to do any more work. Just return a success response.
  1136. // However, we still have the credentials which the caller assumes
  1137. // we will be using. Get rid of it here and return success.
  1138. //
  1139. DfsDeleteCredentials(Credentials);
  1140. return(STATUS_SUCCESS);
  1141. }
  1142. Drt = ExAllocatePoolWithTag( PagedPool,
  1143. sizeof(DFS_DEVLESS_ROOT),
  1144. ' puM');
  1145. if (Drt == NULL) {
  1146. return(STATUS_INSUFFICIENT_RESOURCES);
  1147. }
  1148. //
  1149. // Before we initialize the Drt, we need to allocate space for the
  1150. // Prefix. PagedPool should be fine here. We need to reallocate because
  1151. // we will store this permanently in the DFS_DEVLESS_ROOT.
  1152. //
  1153. DevlessRootName.Length = Name->Length;
  1154. DevlessRootName.MaximumLength = DevlessRootName.Length + sizeof(WCHAR);
  1155. DevlessRootName.Buffer = ExAllocatePoolWithTag(
  1156. PagedPool,
  1157. DevlessRootName.MaximumLength,
  1158. ' puM');
  1159. if (DevlessRootName.Buffer != NULL) {
  1160. RtlMoveMemory(DevlessRootName.Buffer,
  1161. Name->Buffer,
  1162. Name->MaximumLength);
  1163. DevlessRootName.Buffer[Name->Length/sizeof(WCHAR)] = UNICODE_NULL;
  1164. } else {
  1165. ExFreePool(Drt);
  1166. return(STATUS_INSUFFICIENT_RESOURCES);
  1167. }
  1168. //
  1169. // Pin the pkt entry in the cache by incrementing the Usecount
  1170. //
  1171. if (DevlessRootName.Buffer != NULL && DevlessRootName.Length > 0) {
  1172. UNICODE_STRING prefix = DevlessRootName;
  1173. USHORT i, j;
  1174. UNICODE_STRING RemainingPath;
  1175. //
  1176. // We want to work with the \server\share part of the prefix only,
  1177. // so count up to 3 backslashes, then stop.
  1178. //
  1179. for (i = j = 0; i < prefix.Length/sizeof(WCHAR) && j < 3; i++) {
  1180. if (prefix.Buffer[i] == UNICODE_PATH_SEP) {
  1181. j++;
  1182. }
  1183. }
  1184. prefix.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
  1185. pktEntry = PktLookupEntryByPrefix(&DfsData.Pkt,
  1186. &prefix,
  1187. &RemainingPath);
  1188. if (pktEntry != NULL && RemainingPath.Length == 0) {
  1189. InterlockedIncrement(&pktEntry->UseCount);
  1190. }
  1191. else {
  1192. pktEntry = NULL;
  1193. }
  1194. }
  1195. DfsInitializeDrt ( Drt,
  1196. &DevlessRootName,
  1197. Credentials);
  1198. #ifdef TERMSRV
  1199. Drt->SessionID = SessionID;
  1200. #endif
  1201. Drt->pktEntry = pktEntry;
  1202. RtlCopyLuid(&Drt->LogonID, LogonID);
  1203. return STATUS_SUCCESS;
  1204. }
  1205. //+----------------------------------------------------------------------------
  1206. //
  1207. // Function: DfsDeleteDevlessRoot
  1208. //
  1209. // Synopsis: Removes a Devless root if found and possible.
  1210. //
  1211. // Arguments: [Name] -- Name of the Logical Root
  1212. //
  1213. // Returns: STATUS_SUCCESS -- If successfully deleted logical root
  1214. //
  1215. // STATUS_NO_SUCH_DEVICE -- If there is no logical root to
  1216. // delete.
  1217. //
  1218. //
  1219. //-----------------------------------------------------------------------------
  1220. #ifdef TERMSRV
  1221. NTSTATUS
  1222. DfsDeleteDevlessRoot(
  1223. IN PUNICODE_STRING Name,
  1224. IN ULONG SessionID,
  1225. IN PLUID LogonID
  1226. )
  1227. #else // TERMSRV
  1228. NTSTATUS
  1229. DfsDeleteDevlessRoot(
  1230. IN PUNICODE_STRING Name,
  1231. IN PLUID LogonID
  1232. )
  1233. #endif // TERMSRV
  1234. {
  1235. PDFS_PKT_ENTRY PktEntry;
  1236. PDFS_DEVLESS_ROOT Drt;
  1237. NTSTATUS Status;
  1238. BOOLEAN pktLocked;
  1239. PDFS_PKT_ENTRY pktEntry;
  1240. DfsDbgTrace(0, Dbg, "DfsDeleteDevlessRoot -> %wZ\n", Name);
  1241. //
  1242. // Acquire Pkt and DfsData, wait till we do so.
  1243. //
  1244. PktAcquireExclusive(TRUE, &pktLocked);
  1245. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  1246. #ifdef TERMSRV
  1247. Status = DfsFindDevlessRoot(Name, SessionID, LogonID, &Drt);
  1248. #else // TERMSRV
  1249. Status = DfsFindDevlessRoot(Name, LogonID, &Drt);
  1250. #endif // TERMSRV
  1251. if (!NT_SUCCESS(Status)) {
  1252. goto Cleanup;
  1253. }
  1254. //
  1255. // Delete the credentials used by this connection
  1256. //
  1257. DfsDeleteCredentials( Drt->Credentials );
  1258. if (Drt->pktEntry != NULL) {
  1259. InterlockedDecrement(&Drt->pktEntry->UseCount);
  1260. Drt->pktEntry = NULL;
  1261. }
  1262. RemoveEntryList(&Drt->DrtLinks);
  1263. if (Drt->DevlessPath.Buffer) {
  1264. ExFreePool(Drt->DevlessPath.Buffer);
  1265. }
  1266. ExFreePool(Drt);
  1267. Cleanup:
  1268. ExReleaseResourceLite(&DfsData.Resource);
  1269. PktRelease();
  1270. return(Status);
  1271. }