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

1602 lines
44 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. RtlInitUnicodeString( &IDString, IDBuffer );
  291. }
  292. else {
  293. //
  294. // Build the DeviceString with the SessionID
  295. //
  296. IDString.Buffer = IDBuffer;
  297. IDString.MaximumLength = sizeof(IDBuffer);
  298. IDString.Length = 0;
  299. RtlIntegerToUnicodeString(SessionID, 10, &IDString);
  300. }
  301. RtlCopyUnicodeString(&DeviceString, &DfsData.LogRootDevName);
  302. RtlAppendUnicodeToString(&DeviceString, (LPWSTR)Name);
  303. RtlAppendUnicodeToString(&DeviceString,L":");
  304. RtlAppendUnicodeStringToString(&DeviceString, &IDString);
  305. DeviceString.MaximumLength = DeviceString.Length;
  306. //
  307. // Next, try to setup the Dos Device link
  308. //
  309. if (Prefix) {
  310. Status = DfsDefineDosDevice( Name[0], &DeviceString );
  311. if (!NT_SUCCESS(Status)) {
  312. return( Status );
  313. }
  314. }
  315. }
  316. else {
  317. ASSERT( Prefix == FALSE );
  318. }
  319. #else // TERMSRV
  320. //
  321. // DfsData.LogRootDevName is initialized to be L"\Device\WinDfs\"
  322. // Here, we tack on the name of the Logical root we are creating
  323. // to the above string, so that the string becomes, for example,
  324. // L"\Device\WinDfs\Root". Note that at this point, we are scribbling
  325. // into the buffer belonging to DfsData.LogRootDevName, but this
  326. // should be ok, since we are not changing the Length field of that
  327. // Unicode string! BTW, we need a string of this form to create the
  328. // device object.
  329. //
  330. pdst = &UnicodeString.Buffer[UnicodeString.Length/sizeof (WCHAR)];
  331. while (*pstr != UNICODE_NULL) {
  332. *pdst++ = *pstr++;
  333. UnicodeString.Length += sizeof (WCHAR);
  334. }
  335. //
  336. // Next, try to setup the Dos Device link
  337. //
  338. if (Prefix) {
  339. Status = DfsDefineDosDevice( Name[0], &UnicodeString );
  340. if (!NT_SUCCESS(Status)) {
  341. return( Status );
  342. }
  343. }
  344. #endif // TERMSRV
  345. //
  346. // Before we initialize the Vcb, we need to allocate space for the
  347. // Prefix. PagedPool should be fine here. We need to reallocate because
  348. // we will store this permanently in the DFS_VCB.
  349. //
  350. LogRootPrefix.Buffer = NULL;
  351. if (Prefix && Prefix->Length > 0) {
  352. LogRootPrefix.Length = Prefix->Length;
  353. LogRootPrefix.MaximumLength = LogRootPrefix.Length + sizeof(WCHAR);
  354. LogRootPrefix.Buffer = ExAllocatePoolWithTag(
  355. PagedPool,
  356. LogRootPrefix.MaximumLength,
  357. ' puM');
  358. if (LogRootPrefix.Buffer != NULL) {
  359. RtlMoveMemory(LogRootPrefix.Buffer,
  360. Prefix->Buffer,
  361. Prefix->MaximumLength);
  362. LogRootPrefix.Buffer[Prefix->Length/sizeof(WCHAR)] = UNICODE_NULL;
  363. } else {
  364. //
  365. // Couldn't allocate memory! Ok to return with error code, since
  366. // we haven't changed the state of the IO subsystem yet.
  367. //
  368. if (Prefix) {
  369. NTSTATUS DeleteStatus;
  370. DeleteStatus = DfsUndefineDosDevice( Name[0] );
  371. ASSERT(NT_SUCCESS(DeleteStatus));
  372. }
  373. return(STATUS_INSUFFICIENT_RESOURCES);
  374. }
  375. } else {
  376. RtlInitUnicodeString(&LogRootPrefix, NULL);
  377. }
  378. //
  379. // Save the logical root name for the DFS_VCB structure. Remember, above
  380. // we had UnicodeString to be of the form L"\Device\WinDfs\org". Now,
  381. // we copy UnicodeString, then adjust the buffer and length fields so that
  382. // the Buffer points to the beginning of the L"org"; Then, we allocate
  383. // space for LogicalRootBuffer, and copy the name to it!
  384. //
  385. LogicalRoot = UnicodeString;
  386. LogicalRoot.Buffer = &LogicalRoot.Buffer[ DfsData.LogRootDevName.Length/sizeof (WCHAR) ];
  387. LogicalRoot.Length -= DfsData.LogRootDevName.Length;
  388. LogicalRoot.MaximumLength -= DfsData.LogRootDevName.Length;
  389. //
  390. // Now dup the buffer that LogicalRoot uses
  391. //
  392. TmpBuf = ExAllocatePoolWithTag( PagedPool,
  393. LogicalRoot.Length,
  394. ' puM');
  395. if (TmpBuf == NULL) {
  396. //
  397. // Couldn't allocate memory! Ok to return with error code, since
  398. // we still haven't changed the state of the IO subsystem yet.
  399. //
  400. if (LogRootPrefix.Buffer != NULL) {
  401. ExFreePool(LogRootPrefix.Buffer);
  402. }
  403. if (Prefix) {
  404. NTSTATUS DeleteStatus;
  405. DeleteStatus = DfsUndefineDosDevice( Name[0] );
  406. ASSERT(NT_SUCCESS(DeleteStatus));
  407. }
  408. return(STATUS_INSUFFICIENT_RESOURCES);
  409. } else {
  410. RtlMoveMemory( TmpBuf,
  411. LogicalRoot.Buffer,
  412. LogicalRoot.Length );
  413. LogicalRoot.Buffer = TmpBuf;
  414. }
  415. //
  416. // Create the device object for the logical root.
  417. //
  418. #ifdef TERMSRV
  419. Status = IoCreateDevice( DfsData.DriverObject,
  420. sizeof( LOGICAL_ROOT_DEVICE_OBJECT ) -
  421. sizeof( DEVICE_OBJECT ),
  422. (SessionID != INVALID_SESSIONID) ?
  423. &DeviceString : &UnicodeString,
  424. FILE_DEVICE_DFS,
  425. FILE_REMOTE_DEVICE,
  426. FALSE,
  427. (PDEVICE_OBJECT *) &DeviceObject );
  428. #else // TERMSRV
  429. Status = IoCreateDevice( DfsData.DriverObject,
  430. sizeof( LOGICAL_ROOT_DEVICE_OBJECT ) -
  431. sizeof( DEVICE_OBJECT ),
  432. &UnicodeString,
  433. FILE_DEVICE_DFS,
  434. FILE_REMOTE_DEVICE,
  435. FALSE,
  436. (PDEVICE_OBJECT *) &DeviceObject );
  437. #endif // TERMSRV
  438. if ( !NT_SUCCESS( Status ) ) {
  439. if (LogRootPrefix.Buffer) {
  440. ExFreePool(LogRootPrefix.Buffer);
  441. ExFreePool(LogicalRoot.Buffer);
  442. }
  443. if (Prefix) {
  444. NTSTATUS DeleteStatus;
  445. DeleteStatus = DfsUndefineDosDevice( Name[0] );
  446. ASSERT(NT_SUCCESS(DeleteStatus));
  447. }
  448. return Status;
  449. }
  450. //
  451. // Pin the pkt entry in the cache by incrementing the Usecount
  452. //
  453. if (LogRootPrefix.Buffer != NULL && LogRootPrefix.Length > 0) {
  454. UNICODE_STRING prefix = LogRootPrefix;
  455. USHORT i, j;
  456. //
  457. // We want to work with the \server\share part of the prefix only,
  458. // so count up to 3 backslashes, then stop.
  459. //
  460. for (i = j = 0; i < prefix.Length/sizeof(WCHAR) && j < 3; i++) {
  461. if (prefix.Buffer[i] == UNICODE_PATH_SEP) {
  462. j++;
  463. }
  464. }
  465. prefix.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
  466. pktEntry = PktLookupEntryByPrefix(&DfsData.Pkt,
  467. &prefix,
  468. &RemainingPath);
  469. if (pktEntry != NULL && RemainingPath.Length == 0) {
  470. InterlockedIncrement(&pktEntry->UseCount);
  471. }
  472. else {
  473. pktEntry = NULL;
  474. }
  475. }
  476. DeviceObject->DeviceObject.StackSize = 5;
  477. DfsInitializeVcb ( NULL,
  478. &DeviceObject->Vcb,
  479. &LogRootPrefix,
  480. Credentials,
  481. (PDEVICE_OBJECT)DeviceObject );
  482. DeviceObject->Vcb.VcbState |= VcbFlags;
  483. #ifdef TERMSRV
  484. DeviceObject->Vcb.SessionID = SessionID;
  485. #endif
  486. DeviceObject->Vcb.pktEntry = pktEntry;
  487. RtlCopyLuid(&DeviceObject->Vcb.LogonID, LogonID);
  488. //
  489. // Above we preallocated the buffer we need here. So just use it.
  490. //
  491. DeviceObject->Vcb.LogicalRoot = LogicalRoot;
  492. //
  493. // This is not documented anywhere, but calling IoCreateDevice has set
  494. // the DO_DEVICE_INITIALIZING flag in DeviceObject->Flags. Normally,
  495. // device objects are created only at driver init time, and IoLoadDriver
  496. // will clear this bit for all device objects created at init time.
  497. // Since in Dfs, we need to create and delete devices on the fly (ie,
  498. // via FsCtl), we need to manually clear this bit.
  499. //
  500. DeviceObject->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
  501. return STATUS_SUCCESS;
  502. }
  503. //+----------------------------------------------------------------------------
  504. //
  505. // Function: DfsDeleteLogicalRoot
  506. //
  507. // Synopsis: Removes a logical root if found and possible.
  508. //
  509. // Arguments: [Name] -- Name of the Logical Root
  510. // [fForce] -- Whether to Forcibly delete logical root inspite of
  511. // open files.
  512. //
  513. // Returns: STATUS_SUCCESS -- If successfully deleted logical root
  514. //
  515. // STATUS_NO_SUCH_DEVICE -- If there is no logical root to
  516. // delete.
  517. //
  518. // STATUS_DEVICE_BUSY -- If fForce is false and there are open
  519. // files via this logical root.
  520. //
  521. //-----------------------------------------------------------------------------
  522. #ifdef TERMSRV
  523. NTSTATUS
  524. DfsDeleteLogicalRoot(
  525. IN PWSTR Name,
  526. IN BOOLEAN fForce,
  527. IN ULONG SessionID,
  528. IN PLUID LogonID
  529. )
  530. #else // TERMSRV
  531. NTSTATUS
  532. DfsDeleteLogicalRoot(
  533. IN PWSTR Name,
  534. IN BOOLEAN fForce,
  535. IN PLUID LogonID
  536. )
  537. #endif // TERMSRV
  538. {
  539. UNICODE_STRING RootName;
  540. UNICODE_STRING RemainingPath;
  541. WCHAR RootBuffer[MAX_LOGICAL_ROOT_LEN + 2];
  542. PDFS_PKT_ENTRY PktEntry;
  543. PDFS_VCB Vcb;
  544. NTSTATUS Status;
  545. PLOGICAL_ROOT_DEVICE_OBJECT DeviceObject;
  546. BOOLEAN pktLocked;
  547. PDFS_PKT_ENTRY pktEntry;
  548. //
  549. // The 2 extra spots are for holding :\ to form a path out of a
  550. // root name; ie, to go from root to a root:\ form.
  551. //
  552. DfsDbgTrace(0, Dbg, "DfsDeleteLogicalRoot -> %ws\n", Name);
  553. DfsDbgTrace(0, Dbg, "DfsDeleteLogicalRoot -> %s\n", fForce ? "TRUE":"FALSE");
  554. //
  555. // First see if the logical root even exists.
  556. //
  557. ASSERT(ARGUMENT_PRESENT(Name));
  558. RootName.Buffer = RootBuffer;
  559. RootName.MaximumLength = sizeof(RootBuffer);
  560. Status = DfspLogRootNameToPath(Name, &RootName);
  561. if (!NT_SUCCESS(Status))
  562. return(Status);
  563. //
  564. // Acquire Pkt and DfsData, wait till we do so.
  565. //
  566. PktAcquireExclusive(TRUE, &pktLocked);
  567. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  568. #ifdef TERMSRV
  569. Status = DfsFindLogicalRoot(&RootName, SessionID, LogonID, &Vcb, &RemainingPath);
  570. #else // TERMSRV
  571. Status = DfsFindLogicalRoot(&RootName, LogonID, &Vcb, &RemainingPath);
  572. #endif // TERMSRV
  573. if (!NT_SUCCESS(Status)) {
  574. goto Cleanup;
  575. }
  576. //
  577. // Check to see if there are open files via this volume.
  578. //
  579. if (!fForce &&
  580. ((Vcb->DirectAccessOpenCount != 0) ||
  581. (Vcb->OpenFileCount != 0))) {
  582. Status = STATUS_DEVICE_BUSY;
  583. goto Cleanup;
  584. }
  585. //
  586. // Delete the credentials used by this connection
  587. //
  588. if (Vcb->Credentials != NULL) {
  589. DfsDeleteCredentials( Vcb->Credentials );
  590. }
  591. //
  592. // Get rid of the Dos Device
  593. //
  594. DfsUndefineDosDevice( Name[0] );
  595. //
  596. // Dec ref count on pkt entry
  597. //
  598. if (Vcb->pktEntry != NULL) {
  599. InterlockedDecrement(&Vcb->pktEntry->UseCount);
  600. Vcb->pktEntry = NULL;
  601. }
  602. //
  603. // Now, get rid of the Device itself. This is a bit tricky, because there
  604. // might be files open on this device. So, we reference the device and
  605. // call ObMakeTemporaryObject. This causes the object to be removed from
  606. // the NT Object table, but, since atleast our reference is active,
  607. // prevents the object from being freed. Then, we insert this object into
  608. // our DeletedVcb list. The timer routine will periodically wake up and
  609. // see if all references to this device have been released, at which
  610. // point the device will be finally freed.
  611. //
  612. RemoveEntryList(&Vcb->VcbLinks);
  613. InsertTailList( &DfsData.DeletedVcbQueue, &Vcb->VcbLinks );
  614. DeviceObject = CONTAINING_RECORD( Vcb, LOGICAL_ROOT_DEVICE_OBJECT, Vcb);
  615. ObReferenceObjectByPointer( DeviceObject, 0, NULL, KernelMode );
  616. ObMakeTemporaryObject((PVOID) DeviceObject);
  617. DeviceObject->DeviceObject.Flags &= ~DO_DEVICE_HAS_NAME;
  618. Cleanup:
  619. ExReleaseResourceLite(&DfsData.Resource);
  620. PktRelease();
  621. return(Status);
  622. }
  623. //+----------------------------------------------------------------------------
  624. //
  625. // Function: DfspLogRootNameToPath
  626. //
  627. // Synopsis: Amazingly enough, all it does it takes a PWSTR, copies it into
  628. // a Unicode string's buffer, and appends a \ to the tail of the
  629. // buffer, thus making a path out of a Logical root name.
  630. //
  631. // Arguments: [Name] -- Name of logical root, like L"org"
  632. // [RootName] -- Destination for L"org\\"
  633. //
  634. // Returns: STATUS_BUFFER_OVERFLOW, STATUS_SUCCESS
  635. //
  636. //-----------------------------------------------------------------------------
  637. NTSTATUS
  638. DfspLogRootNameToPath(
  639. IN LPCWSTR Name,
  640. OUT PUNICODE_STRING RootName
  641. )
  642. {
  643. unsigned short i, nMaxNameLen;
  644. //
  645. // The two extra spots are required to append a ":\" after the root name.
  646. //
  647. nMaxNameLen = (RootName->MaximumLength/sizeof(WCHAR)) - 2;
  648. //
  649. // Copy the name
  650. //
  651. for (i = 0; Name[i] != UNICODE_NULL && i < nMaxNameLen; i++) {
  652. RootName->Buffer[i] = Name[i];
  653. }
  654. //
  655. // Make sure entire name was copied before we ran out of space
  656. //
  657. if (Name[i] != UNICODE_NULL) {
  658. //
  659. // Someone sent in a name bigger than allowed.
  660. //
  661. return(STATUS_BUFFER_OVERFLOW);
  662. }
  663. //
  664. // Append the ":\" to form a path
  665. //
  666. RootName->Length = i * sizeof(WCHAR);
  667. return(RtlAppendUnicodeToString(RootName, L":\\"));
  668. }
  669. #define PackMem(buf, str, len, pulen) { \
  670. ASSERT(*(pulen) >= (len)); \
  671. RtlMoveMemory((buf) + *(pulen) - (len), (str), (len)); \
  672. *(pulen) -= (len); \
  673. }
  674. //+----------------------------------------------------------------------------
  675. //
  676. // Function: DfsGetResourceFromVcb
  677. //
  678. // Synopsis: Given a DFS_VCB it constructs a NETRESOURCE struct into the buffer
  679. // passed in. At the same time it uses the end of the buffer to
  680. // fill in a string. If the buffer is insufficient in size the
  681. // required size is returned in "pulen". If everything succeeds
  682. // then the pulen arg is decremented to indicate remaining size
  683. // of buffer.
  684. //
  685. // Arguments: [Vcb] -- The source DFS_VCB
  686. // [ProviderName] -- Provider Name to stuff in the NETRESOURCE
  687. // [BufBegin] -- Start of actual buffer for computing offsets
  688. // [Buf] -- The NETRESOURCE structure to fill
  689. // [BufSize] -- On entry, size of buf. On return, contains
  690. // remaining size of buf.
  691. //
  692. // Returns: [STATUS_SUCCESS] -- Operation completed successfully.
  693. // [STATUS_BUFFER_OVERFLOW] -- buf is not big enough.
  694. //
  695. // Notes: This routine fills in a NETRESOURCE structure starting at
  696. // Buf. The strings in the NETRESOURCE are filled in starting
  697. // from the *end* (ie, starting at Buf + *BufSize)
  698. //
  699. //-----------------------------------------------------------------------------
  700. #if defined (_WIN64)
  701. typedef struct _DFS_NETRESOURCE32 {
  702. DWORD dwScope;
  703. DWORD dwType;
  704. DWORD dwDisplayType;
  705. DWORD dwUsage;
  706. ULONG lpLocalName;
  707. ULONG lpRemoteName;
  708. ULONG lpComment ;
  709. ULONG lpProvider;
  710. }DFS_NETRESOURCE32, *PDFS_NETRESOURCE32;
  711. #endif
  712. NTSTATUS
  713. DfsGetResourceFromVcb(
  714. PIRP pIrp,
  715. PDFS_VCB Vcb,
  716. PUNICODE_STRING ProviderName,
  717. PUCHAR BufBegin,
  718. PUCHAR Buf,
  719. PULONG BufSize,
  720. PULONG pResourceSize
  721. )
  722. {
  723. LPNETRESOURCE netResource = (LPNETRESOURCE) Buf;
  724. ULONG sizeRequired = 0, ResourceSize;
  725. WCHAR localDrive[ 3 ];
  726. ULONG32 CommentOffset, ProviderOffset, LocalNameOffset, RemoteNameOffset;
  727. #if defined (_WIN64)
  728. if (IoIs32bitProcess(pIrp)) {
  729. ResourceSize = sizeof(DFS_NETRESOURCE32);
  730. }
  731. else
  732. #endif
  733. ResourceSize = sizeof(NETRESOURCE);
  734. *pResourceSize = ResourceSize;
  735. sizeRequired = ResourceSize +
  736. ProviderName->Length +
  737. sizeof(UNICODE_NULL) +
  738. 3 * sizeof(WCHAR) + // lpLocalName D: etc.
  739. sizeof(UNICODE_PATH_SEP) +
  740. Vcb->LogRootPrefix.Length +
  741. sizeof(UNICODE_NULL);
  742. if (*BufSize < sizeRequired) {
  743. *BufSize = sizeRequired;
  744. return(STATUS_BUFFER_OVERFLOW);
  745. }
  746. //
  747. // Buffer is big enough, fill in the NETRESOURCE structure
  748. //
  749. Buf += ResourceSize;
  750. *BufSize -= ResourceSize;
  751. netResource->dwScope = RESOURCE_CONNECTED;
  752. netResource->dwType = RESOURCETYPE_DISK;
  753. netResource->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  754. netResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
  755. CommentOffset = 0;
  756. //
  757. // Fill in the provider name
  758. //
  759. PackMem(Buf, L"", sizeof(L""), BufSize);
  760. PackMem(Buf, ProviderName->Buffer, ProviderName->Length, BufSize);
  761. ProviderOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  762. //
  763. // Fill in the local name next
  764. //
  765. localDrive[0] = Vcb->LogicalRoot.Buffer[0];
  766. localDrive[1] = UNICODE_DRIVE_SEP;
  767. localDrive[2] = UNICODE_NULL;
  768. PackMem(Buf, localDrive, sizeof(localDrive), BufSize);
  769. LocalNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  770. //
  771. // Fill in the remote name last
  772. //
  773. PackMem(Buf, L"", sizeof(L""), BufSize);
  774. PackMem(Buf, Vcb->LogRootPrefix.Buffer, Vcb->LogRootPrefix.Length, BufSize);
  775. PackMem(Buf, UNICODE_PATH_SEP_STR, sizeof(UNICODE_PATH_SEP), BufSize);
  776. RemoteNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  777. #if defined (_WIN64)
  778. if (IoIs32bitProcess(pIrp)) {
  779. PDFS_NETRESOURCE32 pNetResource32 = (PDFS_NETRESOURCE32)netResource;
  780. pNetResource32->lpComment = CommentOffset;
  781. pNetResource32->lpProvider = ProviderOffset;
  782. pNetResource32->lpLocalName = LocalNameOffset;
  783. pNetResource32->lpRemoteName = RemoteNameOffset;
  784. }
  785. else {
  786. #endif
  787. netResource->lpComment = (LPWSTR)UIntToPtr( CommentOffset );
  788. netResource->lpProvider = (LPWSTR)UIntToPtr( ProviderOffset );
  789. netResource->lpLocalName = (LPWSTR)UIntToPtr( LocalNameOffset );
  790. netResource->lpRemoteName = (LPWSTR)UIntToPtr( RemoteNameOffset );
  791. #if defined (_WIN64)
  792. }
  793. #endif
  794. return(STATUS_SUCCESS);
  795. }
  796. //+----------------------------------------------------------------------------
  797. //
  798. // Function: DfsGetResourceFromDevlessRoot
  799. //
  800. // Synopsis: Builds a NETRESOURCE structure for a device-less connection.
  801. // The LPWSTR members of NETRESOURCE actually contain offsets
  802. // from the BufBegin parameter.
  803. //
  804. // Arguments: [Drt] -- The DevicelessRoot structure
  805. // [ProviderName] -- Provider Name to stuff in the NETRESOURCE
  806. // [BufBegin] -- Start of actual buffer for computing offsets
  807. // [Buf] -- The NETRESOURCE structure to fill
  808. // [BufSize] -- On entry, size of buf. On return, contains
  809. // remaining size of buf.
  810. //
  811. // Returns: [STATUS_SUCCESS] -- Operation completed successfully.
  812. // [STATUS_BUFFER_OVERFLOW] -- buf is not big enough.
  813. //
  814. // Notes: This routine fills in a NETRESOURCE structure starting at
  815. // Buf. The strings in the NETRESOURCE are filled in starting
  816. // from the *end* (ie, starting at Buf + *BufSize)
  817. //
  818. //-----------------------------------------------------------------------------
  819. NTSTATUS
  820. DfsGetResourceFromDevlessRoot(
  821. PIRP pIrp,
  822. PDFS_DEVLESS_ROOT pDrt,
  823. PUNICODE_STRING ProviderName,
  824. PUCHAR BufBegin,
  825. PUCHAR Buf,
  826. PULONG BufSize,
  827. PULONG pResourceSize)
  828. {
  829. LPNETRESOURCE netResource = (LPNETRESOURCE) Buf;
  830. ULONG sizeRequired = 0, ResourceSize;
  831. WCHAR localDrive[ 3 ];
  832. ULONG32 CommentOffset, ProviderOffset, LocalNameOffset, RemoteNameOffset;
  833. #if defined (_WIN64)
  834. if (IoIs32bitProcess(pIrp)) {
  835. ResourceSize = sizeof(DFS_NETRESOURCE32);
  836. }
  837. else
  838. #endif
  839. ResourceSize = sizeof(NETRESOURCE);
  840. *pResourceSize = ResourceSize;
  841. sizeRequired = ResourceSize +
  842. ProviderName->Length +
  843. sizeof(UNICODE_NULL) +
  844. 2 * sizeof(UNICODE_PATH_SEP) +
  845. pDrt->DevlessPath.Length +
  846. sizeof(UNICODE_NULL);
  847. if (*BufSize < sizeRequired) {
  848. *BufSize = sizeRequired;
  849. return(STATUS_BUFFER_OVERFLOW);
  850. }
  851. //
  852. // Buffer is big enough, fill in the NETRESOURCE structure
  853. //
  854. Buf += ResourceSize;
  855. *BufSize -= ResourceSize;
  856. netResource->dwScope = RESOURCE_CONNECTED;
  857. netResource->dwType = RESOURCETYPE_DISK;
  858. netResource->dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  859. netResource->dwUsage = RESOURCEUSAGE_CONNECTABLE;
  860. CommentOffset = 0;
  861. LocalNameOffset = 0;
  862. //
  863. // Fill in the provider name
  864. //
  865. PackMem(Buf, L"", sizeof(L""), BufSize);
  866. PackMem(Buf, ProviderName->Buffer, ProviderName->Length, BufSize);
  867. ProviderOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  868. //
  869. // Fill in the remote name last
  870. //
  871. PackMem(Buf, L"", sizeof(L""), BufSize);
  872. PackMem(Buf, pDrt->DevlessPath.Buffer, pDrt->DevlessPath.Length, BufSize);
  873. PackMem(Buf, UNICODE_PATH_SEP_STR, sizeof(UNICODE_PATH_SEP), BufSize);
  874. RemoteNameOffset = (ULONG32)(Buf + *BufSize - BufBegin);
  875. #if defined (_WIN64)
  876. if (IoIs32bitProcess(pIrp)) {
  877. PDFS_NETRESOURCE32 pNetResource32 = (PDFS_NETRESOURCE32)netResource;
  878. pNetResource32->lpComment = CommentOffset;
  879. pNetResource32->lpProvider = ProviderOffset;
  880. pNetResource32->lpLocalName = LocalNameOffset;
  881. pNetResource32->lpRemoteName = RemoteNameOffset;
  882. }
  883. else {
  884. #endif
  885. netResource->lpComment = (LPWSTR)UIntToPtr( CommentOffset );
  886. netResource->lpProvider = (LPWSTR)UIntToPtr( ProviderOffset );
  887. netResource->lpLocalName = (LPWSTR)UIntToPtr( LocalNameOffset );
  888. netResource->lpRemoteName = (LPWSTR)UIntToPtr( RemoteNameOffset );
  889. #if defined (_WIN64)
  890. }
  891. #endif
  892. return(STATUS_SUCCESS);
  893. }
  894. #ifdef TERMSRV
  895. BOOLEAN
  896. DfsLogicalRootExists(
  897. IN PWSTR pwszName,
  898. IN ULONG SessionID,
  899. IN PLUID LogonID
  900. )
  901. #else // TERMSRV
  902. BOOLEAN
  903. DfsLogicalRootExists(
  904. IN PWSTR pwszName,
  905. IN PLUID LogonID
  906. )
  907. #endif // TERMSRV
  908. {
  909. UNICODE_STRING RootName;
  910. UNICODE_STRING RemainingPath;
  911. WCHAR RootBuffer[MAX_LOGICAL_ROOT_LEN + 2];
  912. PDFS_VCB Vcb;
  913. NTSTATUS Status;
  914. ASSERT(ARGUMENT_PRESENT(pwszName));
  915. RootName.Buffer = RootBuffer;
  916. RootName.MaximumLength = sizeof(RootBuffer);
  917. Status = DfspLogRootNameToPath(pwszName, &RootName);
  918. if (!NT_SUCCESS(Status)) {
  919. return(FALSE);
  920. }
  921. #ifdef TERMSRV
  922. Status = DfsFindLogicalRoot(&RootName, SessionID, LogonID, &Vcb, &RemainingPath);
  923. #else // TERMSRV
  924. Status = DfsFindLogicalRoot(&RootName, LogonId, &Vcb, &RemainingPath);
  925. #endif // TERMSRV
  926. if (!NT_SUCCESS(Status)) {
  927. //
  928. // If this asserts, we need to fix the code above that creates the
  929. // Logical Root name, or fix DfsFindLogicalRoot.
  930. //
  931. ASSERT(Status != STATUS_OBJECT_PATH_SYNTAX_BAD);
  932. return(FALSE);
  933. }
  934. else {
  935. return(TRUE);
  936. }
  937. }
  938. //+----------------------------------------------------------------------------
  939. //
  940. // Function: DfsDefineDosDevice
  941. //
  942. // Synopsis: Creates a dos device to a logical root
  943. //
  944. // Arguments:
  945. //
  946. // Returns:
  947. //
  948. //-----------------------------------------------------------------------------
  949. NTSTATUS
  950. DfsDefineDosDevice(
  951. IN WCHAR Device,
  952. IN PUNICODE_STRING Target)
  953. {
  954. NTSTATUS status;
  955. HANDLE device;
  956. OBJECT_ATTRIBUTES ob;
  957. UNICODE_STRING deviceName;
  958. WCHAR Buf[25];
  959. wcscpy(Buf, L"\\??\\X:");
  960. RtlInitUnicodeString( &deviceName, Buf);
  961. deviceName.Buffer[ deviceName.Length/sizeof(WCHAR) - 2] = Device;
  962. InitializeObjectAttributes(
  963. &ob,
  964. &deviceName,
  965. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  966. NULL,
  967. NULL);
  968. status = ZwCreateSymbolicLinkObject(
  969. &device,
  970. SYMBOLIC_LINK_ALL_ACCESS,
  971. &ob,
  972. Target);
  973. if (NT_SUCCESS(status))
  974. ZwClose( device );
  975. return( status );
  976. }
  977. //+----------------------------------------------------------------------------
  978. //
  979. // Function: DfsUndefineDosDevice
  980. //
  981. // Synopsis: Undefines a dos device
  982. //
  983. // Arguments:
  984. //
  985. // Returns:
  986. //
  987. //-----------------------------------------------------------------------------
  988. NTSTATUS
  989. DfsUndefineDosDevice(
  990. IN WCHAR Device
  991. )
  992. {
  993. NTSTATUS status;
  994. HANDLE device;
  995. OBJECT_ATTRIBUTES ob;
  996. UNICODE_STRING deviceName;
  997. WCHAR Buf[25];
  998. wcscpy(Buf, L"\\??\\X:");
  999. RtlInitUnicodeString( &deviceName, Buf);
  1000. deviceName.Buffer[ deviceName.Length/sizeof(WCHAR) - 2] = Device;
  1001. InitializeObjectAttributes(
  1002. &ob,
  1003. &deviceName,
  1004. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  1005. NULL,
  1006. NULL);
  1007. status = ZwOpenSymbolicLinkObject(
  1008. &device,
  1009. SYMBOLIC_LINK_QUERY | DELETE,
  1010. &ob);
  1011. if (NT_SUCCESS(status)) {
  1012. status = ZwMakeTemporaryObject( device );
  1013. ZwClose( device );
  1014. }
  1015. return( status );
  1016. }
  1017. //+-------------------------------------------------------------------------
  1018. //
  1019. // Function: DfsFindDevlessRoot, local
  1020. //
  1021. // Synopsis: DfsFindDevlessRoot takes as input a UNC name
  1022. // looks up the DFS_DEVLESS_ROOT associated with the root,
  1023. // and returns the DevlessRoot
  1024. //
  1025. // Arguments: [Path] -- Input path name
  1026. // [Drt] -- Returns DFS_DEVLESS_ROOT which corresponds to
  1027. // the root for the Path
  1028. //
  1029. // Returns: NTSTATUS:
  1030. // STATUS_SUCCESS if Drt found
  1031. // STATUS_NO_SUCH_DEVICE - root name not found
  1032. //
  1033. //--------------------------------------------------------------------------
  1034. #ifdef TERMSRV
  1035. NTSTATUS
  1036. DfsFindDevlessRoot(
  1037. IN PUNICODE_STRING Path,
  1038. IN ULONG SessionID,
  1039. IN PLUID LogonID,
  1040. OUT PDFS_DEVLESS_ROOT *Drt
  1041. )
  1042. #else // TERMSRV
  1043. NTSTATUS
  1044. DfsFindDevlessRoot(
  1045. IN PUNICODE_STRING Path,
  1046. IN PLUID LogonID,
  1047. OUT PDFS_DEVLESS_ROOT *Drt,
  1048. )
  1049. #endif // TERMSRV
  1050. {
  1051. PLIST_ENTRY Link;
  1052. NTSTATUS Status = STATUS_SUCCESS;
  1053. DfsDbgTrace(+1, Dbg, "DfsFindDevlessRoot...%wZ\n", Path);
  1054. //
  1055. // Search for the devless ROOT.
  1056. //
  1057. ExAcquireResourceSharedLite(&DfsData.Resource, TRUE);
  1058. for ( Link = DfsData.DrtQueue.Flink;
  1059. Link != &DfsData.DrtQueue;
  1060. Link = Link->Flink ) {
  1061. *Drt = CONTAINING_RECORD( Link, DFS_DEVLESS_ROOT, DrtLinks );
  1062. #ifdef TERMSRV
  1063. if ((SessionID == INVALID_SESSIONID) ||
  1064. (SessionID == (*Drt)->SessionID)) {
  1065. #endif
  1066. if ( RtlEqualLuid(LogonID, &(*Drt)->LogonID) ) {
  1067. if (RtlEqualString( (PSTRING)&(*Drt)->DevlessPath,
  1068. (PSTRING)Path, (BOOLEAN)TRUE) ) {
  1069. break;
  1070. }
  1071. }
  1072. #ifdef TERMSRV
  1073. }
  1074. #endif // TERMSRV
  1075. }
  1076. if (Link == &DfsData.DrtQueue) {
  1077. Status = STATUS_NO_SUCH_DEVICE;
  1078. ExReleaseResourceLite(&DfsData.Resource);
  1079. DfsDbgTrace(-1, Dbg, "DfsFindDevlessRoot -> %08lx\n", ULongToPtr(Status) );
  1080. return(Status);
  1081. }
  1082. ExReleaseResourceLite(&DfsData.Resource);
  1083. DfsDbgTrace(-1, Dbg, "DfsFindLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1084. return(Status);
  1085. }
  1086. //+-------------------------------------------------------------------------
  1087. //
  1088. // Function: DfsInitializeDevlessRoot, public
  1089. //
  1090. // Synopsis: Allocate and initialize storage for a Deviceless root.
  1091. //
  1092. // Effects: A DFS_DEVLESS_ROOT structure is created.
  1093. //
  1094. // Arguments: [Name] -- Pathname that is the deviceless root.
  1095. // [Credentials] -- The credentials to use when accessing files
  1096. // via this logical root.
  1097. //
  1098. // Requires: DfsData must first be set up. Also an EXCLUSIVE LOCK on
  1099. // DfsData.Resource must be acquired.
  1100. //
  1101. // Returns: NTSTATUS - STATUS_SUCCESS unless there is some problem.
  1102. //
  1103. //--------------------------------------------------------------------------
  1104. #ifdef TERMSRV
  1105. NTSTATUS
  1106. DfsInitializeDevlessRoot(
  1107. IN PUNICODE_STRING Name,
  1108. IN PDFS_CREDENTIALS Credentials OPTIONAL,
  1109. IN ULONG SessionID,
  1110. IN PLUID LogonID
  1111. )
  1112. #else // TERMSRV
  1113. NTSTATUS
  1114. DfsInitializeDevlessRoot(
  1115. IN PUNICODE_STRING Name,
  1116. IN PDFS_CREDENTIALS Credentials OPTIONAL,
  1117. IN PLUID LogonID
  1118. )
  1119. #endif // TERMSRV
  1120. {
  1121. PDFS_DEVLESS_ROOT Drt;
  1122. PDFS_PKT_ENTRY pktEntry = NULL;
  1123. UNICODE_STRING DevlessRootName;
  1124. NTSTATUS Status;
  1125. DfsDbgTrace(0, Dbg, "DfsInitializeDevlessRoot -> %wZ\n", Name);
  1126. #ifdef TERMSRV
  1127. Status = DfsFindDevlessRoot(Name, SessionID, LogonID, &Drt);
  1128. #else
  1129. Status = DfsFindDevlessRoot(Name, LogonID, &Drt);
  1130. #endif
  1131. if (Status != STATUS_NO_SUCH_DEVICE) {
  1132. //
  1133. // this means we found a device. In the devless Root case, this means
  1134. // we dont have to do any more work. Just return a success response.
  1135. // However, we still have the credentials which the caller assumes
  1136. // we will be using. Get rid of it here and return success.
  1137. //
  1138. DfsDeleteCredentials(Credentials);
  1139. return(STATUS_SUCCESS);
  1140. }
  1141. Drt = ExAllocatePoolWithTag( PagedPool,
  1142. sizeof(DFS_DEVLESS_ROOT),
  1143. ' puM');
  1144. if (Drt == NULL) {
  1145. return(STATUS_INSUFFICIENT_RESOURCES);
  1146. }
  1147. //
  1148. // Before we initialize the Drt, we need to allocate space for the
  1149. // Prefix. PagedPool should be fine here. We need to reallocate because
  1150. // we will store this permanently in the DFS_DEVLESS_ROOT.
  1151. //
  1152. DevlessRootName.Length = Name->Length;
  1153. DevlessRootName.MaximumLength = DevlessRootName.Length + sizeof(WCHAR);
  1154. DevlessRootName.Buffer = ExAllocatePoolWithTag(
  1155. PagedPool,
  1156. DevlessRootName.MaximumLength,
  1157. ' puM');
  1158. if (DevlessRootName.Buffer != NULL) {
  1159. RtlMoveMemory(DevlessRootName.Buffer,
  1160. Name->Buffer,
  1161. Name->MaximumLength);
  1162. DevlessRootName.Buffer[Name->Length/sizeof(WCHAR)] = UNICODE_NULL;
  1163. } else {
  1164. ExFreePool(Drt);
  1165. return(STATUS_INSUFFICIENT_RESOURCES);
  1166. }
  1167. //
  1168. // Pin the pkt entry in the cache by incrementing the Usecount
  1169. //
  1170. if (DevlessRootName.Buffer != NULL && DevlessRootName.Length > 0) {
  1171. UNICODE_STRING prefix = DevlessRootName;
  1172. USHORT i, j;
  1173. UNICODE_STRING RemainingPath;
  1174. //
  1175. // We want to work with the \server\share part of the prefix only,
  1176. // so count up to 3 backslashes, then stop.
  1177. //
  1178. for (i = j = 0; i < prefix.Length/sizeof(WCHAR) && j < 3; i++) {
  1179. if (prefix.Buffer[i] == UNICODE_PATH_SEP) {
  1180. j++;
  1181. }
  1182. }
  1183. prefix.Length = (j >= 3) ? (i-1) * sizeof(WCHAR) : i * sizeof(WCHAR);
  1184. pktEntry = PktLookupEntryByPrefix(&DfsData.Pkt,
  1185. &prefix,
  1186. &RemainingPath);
  1187. if (pktEntry != NULL && RemainingPath.Length == 0) {
  1188. InterlockedIncrement(&pktEntry->UseCount);
  1189. }
  1190. else {
  1191. pktEntry = NULL;
  1192. }
  1193. }
  1194. DfsInitializeDrt ( Drt,
  1195. &DevlessRootName,
  1196. Credentials);
  1197. #ifdef TERMSRV
  1198. Drt->SessionID = SessionID;
  1199. #endif
  1200. Drt->pktEntry = pktEntry;
  1201. RtlCopyLuid(&Drt->LogonID, LogonID);
  1202. return STATUS_SUCCESS;
  1203. }
  1204. //+----------------------------------------------------------------------------
  1205. //
  1206. // Function: DfsDeleteDevlessRoot
  1207. //
  1208. // Synopsis: Removes a Devless root if found and possible.
  1209. //
  1210. // Arguments: [Name] -- Name of the Logical Root
  1211. //
  1212. // Returns: STATUS_SUCCESS -- If successfully deleted logical root
  1213. //
  1214. // STATUS_NO_SUCH_DEVICE -- If there is no logical root to
  1215. // delete.
  1216. //
  1217. //
  1218. //-----------------------------------------------------------------------------
  1219. #ifdef TERMSRV
  1220. NTSTATUS
  1221. DfsDeleteDevlessRoot(
  1222. IN PUNICODE_STRING Name,
  1223. IN ULONG SessionID,
  1224. IN PLUID LogonID
  1225. )
  1226. #else // TERMSRV
  1227. NTSTATUS
  1228. DfsDeleteDevlessRoot(
  1229. IN PUNICODE_STRING Name,
  1230. IN PLUID LogonID
  1231. )
  1232. #endif // TERMSRV
  1233. {
  1234. PDFS_PKT_ENTRY PktEntry;
  1235. PDFS_DEVLESS_ROOT Drt;
  1236. NTSTATUS Status;
  1237. BOOLEAN pktLocked;
  1238. PDFS_PKT_ENTRY pktEntry;
  1239. DfsDbgTrace(0, Dbg, "DfsDeleteDevlessRoot -> %wZ\n", Name);
  1240. //
  1241. // Acquire Pkt and DfsData, wait till we do so.
  1242. //
  1243. PktAcquireExclusive(TRUE, &pktLocked);
  1244. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  1245. #ifdef TERMSRV
  1246. Status = DfsFindDevlessRoot(Name, SessionID, LogonID, &Drt);
  1247. #else // TERMSRV
  1248. Status = DfsFindDevlessRoot(Name, LogonID, &Drt);
  1249. #endif // TERMSRV
  1250. if (!NT_SUCCESS(Status)) {
  1251. goto Cleanup;
  1252. }
  1253. //
  1254. // Delete the credentials used by this connection
  1255. //
  1256. DfsDeleteCredentials( Drt->Credentials );
  1257. if (Drt->pktEntry != NULL) {
  1258. InterlockedDecrement(&Drt->pktEntry->UseCount);
  1259. Drt->pktEntry = NULL;
  1260. }
  1261. RemoveEntryList(&Drt->DrtLinks);
  1262. if (Drt->DevlessPath.Buffer) {
  1263. ExFreePool(Drt->DevlessPath.Buffer);
  1264. }
  1265. ExFreePool(Drt);
  1266. Cleanup:
  1267. ExReleaseResourceLite(&DfsData.Resource);
  1268. PktRelease();
  1269. return(Status);
  1270. }