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.

5302 lines
139 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: FSCTRL.C
  6. //
  7. // Contents:
  8. // This module implements the File System Control routines for Dfs.
  9. //
  10. // Functions:
  11. // DfsFsdFileSystemControl
  12. // DfsFspFileSystemControl
  13. // DfsCommonFileSystemControl, local
  14. // DfsUserFsctl, local
  15. // DfsOplockRequest, local
  16. // DfsFsctrlDefineLogicalRoot - Define a new logical root
  17. // DfsFsctrlUndefineLogicalRoot - Undefine an existing root
  18. // DfsFsctrlGetLogicalRootPrefix - Retrieve prefix that logical
  19. // root maps to.
  20. // DfsFsctrlGetConnectedResources -
  21. // DfsFsctrlDefineProvider - Define a file service provider
  22. // DfsFsctrlGetServerName - Get name of server given prefix
  23. // DfsFsctrlReadMem - return an internal data struct (debug)
  24. // DfsCompleteMountRequest - Completion routine for mount IRP
  25. // DfsCompleteLoadFsRequest - Completion routine for Load FS IRP
  26. // DfsFsctrlGetPkt
  27. // DfsFsctrlGetPktEntryState
  28. // DfsGetEntryStateSize - local
  29. // DfsGetEntryStateMarshall - local
  30. // DfsFsctrlSetPktEntryState
  31. // DfsSetPktEntryActive
  32. // DfsSetPktEntryTimeout
  33. //
  34. //-----------------------------------------------------------------------------
  35. #include "dfsprocs.h"
  36. #include "creds.h"
  37. #include "dnr.h"
  38. #include "know.h"
  39. #include "fsctrl.h"
  40. #include "mupwml.h"
  41. #ifdef TERMSRV
  42. NTKERNELAPI
  43. NTSTATUS
  44. IoGetRequestorSessionId(
  45. IN PIRP Irp,
  46. OUT PULONG pSessionId
  47. );
  48. #endif
  49. //
  50. // The local debug trace level
  51. //
  52. #define Dbg (DEBUG_TRACE_FSCTRL)
  53. //
  54. // Local procedure prototypes
  55. //
  56. NTSTATUS
  57. DfsCommonFileSystemControl (
  58. IN PDEVICE_OBJECT DeviceObject,
  59. IN PIRP_CONTEXT IrpContext,
  60. IN PIRP Irp
  61. );
  62. NTSTATUS
  63. DfsUserFsctl (
  64. IN PIRP_CONTEXT IrpContext,
  65. IN PIRP Irp
  66. );
  67. NTSTATUS
  68. DfsOplockRequest (
  69. IN PIRP_CONTEXT IrpContext,
  70. IN PIRP Irp
  71. );
  72. NTSTATUS
  73. DfsFsctrlDefineLogicalRoot (
  74. IN PIRP_CONTEXT IrpContext,
  75. IN PIRP Irp,
  76. IN PFILE_DFS_DEF_ROOT_BUFFER pDlrParam,
  77. IN ULONG InputBufferLength
  78. );
  79. NTSTATUS
  80. DfsFsctrlDefineRootCredentials(
  81. IN PIRP_CONTEXT IrpContext,
  82. IN PIRP Irp,
  83. IN PUCHAR InputBuffer,
  84. IN ULONG InputBufferLength);
  85. NTSTATUS
  86. DfsFsctrlUndefineLogicalRoot (
  87. IN PIRP_CONTEXT IrpContext,
  88. IN PIRP Irp,
  89. IN PFILE_DFS_DEF_ROOT_BUFFER pDlrParam,
  90. IN ULONG InputBufferLength
  91. );
  92. NTSTATUS
  93. DfsFsctrlGetLogicalRootPrefix (
  94. IN PIRP_CONTEXT IrpContext,
  95. IN PIRP Irp,
  96. IN PFILE_DFS_DEF_ROOT_BUFFER pDlrParam,
  97. IN ULONG InputBufferLength,
  98. IN OUT PUCHAR OutputBuffer,
  99. IN ULONG OutputBufferLength);
  100. NTSTATUS
  101. DfsFsctrlGetConnectedResources(
  102. IN PIRP_CONTEXT IrpContext,
  103. IN PIRP Irp,
  104. IN PUCHAR InputBuffer,
  105. IN ULONG cbInput,
  106. IN PUCHAR OutputBuffer,
  107. IN ULONG OutputBufferLength);
  108. NTSTATUS
  109. DfsFsctrlGetServerName(
  110. IN PIRP_CONTEXT IrpContext,
  111. IN PIRP Irp,
  112. IN PUCHAR InputBuffer,
  113. IN ULONG InputBufferLength,
  114. IN PUCHAR OutputBuffer,
  115. IN ULONG OutputBufferLength);
  116. NTSTATUS
  117. DfsFsctrlReadMem (
  118. IN PIRP_CONTEXT IrpContext,
  119. IN PIRP Irp,
  120. IN PFILE_DFS_READ_MEM Request,
  121. IN ULONG InputBufferLength,
  122. IN OUT PUCHAR OutputBuffer,
  123. IN ULONG OutputBufferLength
  124. );
  125. NTSTATUS
  126. DfsFsctrlGetPktEntryState(
  127. IN PIRP_CONTEXT IrpContext,
  128. IN PIRP Irp,
  129. IN PUCHAR InputBuffer,
  130. IN ULONG cbInput,
  131. IN PUCHAR OutputBuffer,
  132. IN ULONG OutputBufferLength);
  133. NTSTATUS
  134. DfsFsctrlGetPkt(
  135. IN PIRP_CONTEXT IrpContext,
  136. IN PIRP Irp,
  137. IN PUCHAR OutputBuffer,
  138. IN ULONG OutputBufferLength);
  139. NTSTATUS
  140. DfsGetEntryStateSize(
  141. IN ULONG Level,
  142. IN PUNICODE_STRING ServerName,
  143. IN PUNICODE_STRING ShareName,
  144. IN PDFS_PKT_ENTRY pktEntry,
  145. IN PULONG pcbOutBuffer);
  146. NTSTATUS
  147. DfsGetEntryStateMarshall(
  148. IN ULONG Level,
  149. IN PUNICODE_STRING ServerName,
  150. IN PUNICODE_STRING ShareName,
  151. IN PDFS_PKT_ENTRY pktEntry,
  152. IN PBYTE OutputBuffer,
  153. IN ULONG cbOutBuffer);
  154. NTSTATUS
  155. DfsFsctrlSetPktEntryState(
  156. IN PIRP_CONTEXT IrpContext,
  157. IN PIRP Irp,
  158. IN PUCHAR InputBuffer,
  159. IN ULONG cbInput);
  160. NTSTATUS
  161. DfsFsctrlGetSpcTable(
  162. IN PIRP_CONTEXT IrpContext,
  163. IN PIRP Irp,
  164. IN PUCHAR InputBuffer,
  165. IN ULONG InputBufferLength,
  166. IN PUCHAR OutputBuffer,
  167. IN ULONG OutputBufferLength);
  168. NTSTATUS
  169. DfsSetPktEntryActive(
  170. IN PUNICODE_STRING ServerName,
  171. IN PUNICODE_STRING ShareName,
  172. IN PDFS_PKT_ENTRY pktEntry,
  173. IN DWORD State);
  174. NTSTATUS
  175. DfsSetPktEntryTimeout(
  176. IN PDFS_PKT_ENTRY pktEntry,
  177. IN ULONG Timeout);
  178. NTSTATUS
  179. DfsGetPktSize(
  180. OUT PULONG pSize);
  181. NTSTATUS
  182. DfsGetPktMarshall(
  183. IN PBYTE Buffer,
  184. IN ULONG Size);
  185. NTSTATUS
  186. DfsGetSpcTableNames(
  187. PIRP Irp,
  188. PUCHAR OutputBuffer,
  189. ULONG OutputBufferLength);
  190. NTSTATUS
  191. DfsExpSpcTableName(
  192. LPWSTR SpcName,
  193. PIRP Irp,
  194. PUCHAR OutputBuffer,
  195. ULONG OutputBufferLength);
  196. NTSTATUS
  197. DfsGetSpcDcInfo(
  198. PIRP Irp,
  199. PUCHAR OutputBuffer,
  200. ULONG OutputBufferLength);
  201. NTSTATUS
  202. DfsFsctrlSpcSetDc(
  203. IN PIRP_CONTEXT IrpContext,
  204. IN PIRP Irp,
  205. IN PUCHAR InputBuffer,
  206. IN ULONG cbInput);
  207. NTSTATUS
  208. DfsTreeConnectGetConnectionInfo(
  209. IN PDFS_SERVICE Service,
  210. IN PDFS_CREDENTIALS Creds,
  211. IN OUT PUCHAR OutputBuffer,
  212. IN ULONG OutputBufferLength,
  213. OUT PULONG InfoLen);
  214. NTSTATUS
  215. DfsFsctrlGetConnectionPerfInfo(
  216. IN PIRP_CONTEXT IrpContext,
  217. IN PIRP Irp,
  218. IN PUCHAR InputBuffer,
  219. IN ULONG InputBufferLength,
  220. IN OUT PUCHAR OutputBuffer,
  221. IN ULONG OutputBufferLength);
  222. NTSTATUS
  223. DfsFsctrlCscServerOffline(
  224. IN PIRP_CONTEXT IrpContext,
  225. IN PIRP Irp,
  226. IN PUCHAR InputBuffer,
  227. IN ULONG InputBufferLength,
  228. IN OUT PUCHAR OutputBuffer,
  229. IN ULONG OutputBufferLength);
  230. NTSTATUS
  231. DfsFsctrlCscServerOnline(
  232. IN PIRP_CONTEXT IrpContext,
  233. IN PIRP Irp,
  234. IN PUCHAR InputBuffer,
  235. IN ULONG InputBufferLength,
  236. IN OUT PUCHAR OutputBuffer,
  237. IN ULONG OutputBufferLength);
  238. NTSTATUS
  239. DfsFsctrlSpcRefresh (
  240. IN PIRP_CONTEXT IrpContext,
  241. IN PIRP Irp,
  242. IN PUCHAR InputBuffer,
  243. IN ULONG InputBufferLength);
  244. VOID
  245. MupGetDebugFlags(VOID);
  246. VOID
  247. DfsGetEventLogValue(VOID);
  248. VOID
  249. DfsStopDfs();
  250. void
  251. DfsDumpBuf(
  252. PCHAR cp,
  253. ULONG len
  254. );
  255. BOOLEAN
  256. DfspIsSpecialShare(
  257. PUNICODE_STRING ShareName);
  258. BOOLEAN
  259. DfspIsSysVolShare(
  260. PUNICODE_STRING ShareName);
  261. extern
  262. BOOLEAN DfsIsSpecialName( PUNICODE_STRING pName);
  263. #define UNICODE_STRING_STRUCT(s) \
  264. {sizeof(s) - sizeof(WCHAR), sizeof(s) - sizeof(WCHAR), (s)}
  265. static UNICODE_STRING SpecialShares[] = {
  266. UNICODE_STRING_STRUCT(L"PIPE"),
  267. UNICODE_STRING_STRUCT(L"IPC$"),
  268. UNICODE_STRING_STRUCT(L"ADMIN$"),
  269. UNICODE_STRING_STRUCT(L"MAILSLOT")
  270. };
  271. static UNICODE_STRING SysVolShares[] = {
  272. UNICODE_STRING_STRUCT(L"SYSVOL"),
  273. UNICODE_STRING_STRUCT(L"NETLOGON")
  274. };
  275. #ifdef ALLOC_PRAGMA
  276. #pragma alloc_text( PAGE, DfsFsdFileSystemControl )
  277. #pragma alloc_text( PAGE, DfsFspFileSystemControl )
  278. #pragma alloc_text( PAGE, DfsCommonFileSystemControl )
  279. #pragma alloc_text( PAGE, DfsUserFsctl )
  280. #pragma alloc_text( PAGE, DfsFsctrlIsThisADfsPath )
  281. #pragma alloc_text( PAGE, DfsOplockRequest )
  282. #pragma alloc_text( PAGE, DfsFsctrlDefineLogicalRoot )
  283. #pragma alloc_text( PAGE, DfsFsctrlDefineRootCredentials )
  284. #pragma alloc_text( PAGE, DfsFsctrlUndefineLogicalRoot )
  285. #pragma alloc_text( PAGE, DfsFsctrlGetLogicalRootPrefix )
  286. #pragma alloc_text( PAGE, DfsFsctrlGetConnectedResources )
  287. #pragma alloc_text( PAGE, DfsFsctrlGetServerName )
  288. #pragma alloc_text( PAGE, DfsFsctrlReadMem )
  289. #pragma alloc_text( PAGE, DfsStopDfs )
  290. #pragma alloc_text( PAGE, DfspIsSpecialShare )
  291. #pragma alloc_text( PAGE, DfspIsSysVolShare )
  292. #pragma alloc_text( PAGE, DfsFsctrlGetPkt )
  293. #pragma alloc_text( PAGE, DfsFsctrlGetPktEntryState )
  294. #pragma alloc_text( PAGE, DfsGetEntryStateSize )
  295. #pragma alloc_text( PAGE, DfsGetEntryStateMarshall )
  296. #pragma alloc_text( PAGE, DfsFsctrlSetPktEntryState )
  297. #pragma alloc_text( PAGE, DfsSetPktEntryActive )
  298. #pragma alloc_text( PAGE, DfsSetPktEntryTimeout )
  299. #pragma alloc_text( PAGE, DfsGetPktSize )
  300. #pragma alloc_text( PAGE, DfsGetPktMarshall )
  301. #pragma alloc_text( PAGE, DfsFsctrlGetSpcTable )
  302. #pragma alloc_text( PAGE, DfsGetSpcTableNames )
  303. #pragma alloc_text( PAGE, DfsExpSpcTableName )
  304. #pragma alloc_text( PAGE, DfsGetSpcDcInfo )
  305. #pragma alloc_text( PAGE, DfsFsctrlSpcSetDc )
  306. #pragma alloc_text( PAGE, DfsTreeConnectGetConnectionInfo)
  307. #pragma alloc_text( PAGE, DfsFsctrlGetConnectionPerfInfo)
  308. #pragma alloc_text( PAGE, DfsFsctrlCscServerOffline)
  309. #pragma alloc_text( PAGE, DfsFsctrlCscServerOnline)
  310. #pragma alloc_text( PAGE, DfsFsctrlSpcRefresh)
  311. #endif // ALLOC_PRAGMA
  312. //+-------------------------------------------------------------------
  313. //
  314. // Function: DfsFsdFileSystemControl, public
  315. //
  316. // Synopsis: This routine implements the FSD part of FileSystem
  317. // control operations
  318. //
  319. // Arguments: [DeviceObject] -- Supplies the volume device object
  320. // where the file exists
  321. // [Irp] -- Supplies the Irp being processed
  322. //
  323. // Returns: [NTSTATUS] -- The FSD status for the IRP
  324. //
  325. //--------------------------------------------------------------------
  326. NTSTATUS
  327. DfsFsdFileSystemControl (
  328. IN PDEVICE_OBJECT DeviceObject,
  329. IN PIRP Irp
  330. ) {
  331. BOOLEAN Wait;
  332. NTSTATUS Status;
  333. PIRP_CONTEXT IrpContext = NULL;
  334. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  335. ULONG FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  336. DfsDbgTrace(+1, Dbg, "DfsFsdFileSystemControl\n", 0);
  337. //
  338. // Call the common FileSystem Control routine, with blocking allowed
  339. // if synchronous. This opeation needs to special case the mount
  340. // and verify suboperations because we know they are allowed to block.
  341. // We identify these suboperations by looking at the file object field
  342. // and seeing if it's null.
  343. //
  344. if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL) {
  345. Wait = TRUE;
  346. } else {
  347. Wait = CanFsdWait( Irp );
  348. }
  349. FsRtlEnterFileSystem();
  350. try {
  351. IrpContext = DfsCreateIrpContext( Irp, Wait );
  352. if (IrpContext == NULL)
  353. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  354. Status = DfsCommonFileSystemControl( DeviceObject, IrpContext, Irp );
  355. } except( DfsExceptionFilter( IrpContext, GetExceptionCode(), GetExceptionInformation() )) {
  356. //
  357. // We had some trouble trying to perform the requested
  358. // operation, so we'll abort the I/O request with
  359. // the error status that we get back from the
  360. // execption code
  361. //
  362. Status = DfsProcessException( IrpContext, Irp, GetExceptionCode() );
  363. }
  364. FsRtlExitFileSystem();
  365. //
  366. // And return to our caller
  367. //
  368. DfsDbgTrace(-1, Dbg, "DfsFsdFileSystemControl -> %08lx\n", ULongToPtr(Status));
  369. return Status;
  370. }
  371. //+-------------------------------------------------------------------
  372. //
  373. // Function: DfsFspFileSystemControl, public
  374. //
  375. // Synopsis: This routine implements the FSP part of the file system
  376. // control operations
  377. //
  378. // Arguments: [Irp] -- Supplies the Irp being processed
  379. //
  380. // Returns: Nothing.
  381. //
  382. //--------------------------------------------------------------------
  383. VOID
  384. DfsFspFileSystemControl (
  385. IN PIRP_CONTEXT IrpContext,
  386. IN PIRP Irp
  387. ) {
  388. DfsDbgTrace(+1, Dbg, "DfsFspFileSystemControl\n", 0);
  389. //
  390. // Call the common FileSystem Control routine.
  391. //
  392. DfsCommonFileSystemControl( NULL, IrpContext, Irp );
  393. //
  394. // And return to our caller
  395. //
  396. DfsDbgTrace(-1, Dbg, "DfsFspFileSystemControl -> VOID\n", 0 );
  397. return;
  398. }
  399. //+-------------------------------------------------------------------
  400. //
  401. // Function: DfsCommonFileSystemControl, local
  402. //
  403. // Synopsis: This is the common routine for doing FileSystem control
  404. // operations called by both the FSD and FSP threads
  405. //
  406. // Arguments: [DeviceObject] -- The one used to enter our FSD Routine
  407. // [IrpContext] -- Context associated with the Irp
  408. // [Irp] -- Supplies the Irp to process
  409. //
  410. // Returns: NTSTATUS - The return status for the operation
  411. //--------------------------------------------------------------------
  412. NTSTATUS
  413. DfsCommonFileSystemControl (
  414. IN PDEVICE_OBJECT DeviceObject,
  415. IN PIRP_CONTEXT IrpContext,
  416. IN PIRP Irp
  417. ) {
  418. NTSTATUS Status;
  419. PIO_STACK_LOCATION IrpSp, NextIrpSp;
  420. ULONG FsControlCode;
  421. PFILE_OBJECT FileObject;
  422. //
  423. // Get a pointer to the current Irp stack location
  424. //
  425. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  426. FileObject = IrpSp->FileObject;
  427. DfsDbgTrace(+1, Dbg, "DfsCommonFileSystemControl\n", 0);
  428. DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  429. DfsDbgTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);
  430. //
  431. // We know this is a file system control so we'll case on the
  432. // minor function, and call a internal worker routine to complete
  433. // the irp.
  434. //
  435. switch (IrpSp->MinorFunction) {
  436. case IRP_MN_USER_FS_REQUEST:
  437. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  438. //
  439. // If the DFS FSCTL is issued via a device that is not the DFS
  440. // file system device object, then reject the request.
  441. //
  442. if ((IS_DFS_CTL_CODE(FsControlCode) == 0) ||
  443. (DeviceObject == DfsData.FileSysDeviceObject)) {
  444. Status = DfsUserFsctl( IrpContext, Irp );
  445. }
  446. else {
  447. DfsDbgTrace(0, Dbg, "Invalid Device object for FS control %08lx\n",
  448. DeviceObject);
  449. DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  450. Status = STATUS_INVALID_DEVICE_REQUEST;
  451. }
  452. break;
  453. case IRP_MN_MOUNT_VOLUME:
  454. case IRP_MN_VERIFY_VOLUME:
  455. //
  456. // We are processing a MOUNT/VERIFY request being directed to our
  457. // our File System Device Object. We don't directly support
  458. // disk volumes, so we simply reject.
  459. //
  460. ASSERT(DeviceObject->DeviceType == FILE_DEVICE_DFS_FILE_SYSTEM);
  461. Status = STATUS_NOT_SUPPORTED;
  462. DfsCompleteRequest( IrpContext, Irp, Status );
  463. break;
  464. default:
  465. {
  466. PDFS_FCB Fcb;
  467. PDFS_VCB Vcb;
  468. if (DfsDecodeFileObject(IrpSp->FileObject, &Vcb, &Fcb) != RedirectedFileOpen) {
  469. DfsDbgTrace(0, Dbg, "Invalid FS Control Minor Function %08lx\n",
  470. IrpSp->MinorFunction);
  471. DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  472. Status = STATUS_INVALID_DEVICE_REQUEST;
  473. }
  474. else {
  475. //
  476. // Copy the stack from one to the next...
  477. //
  478. NextIrpSp = IoGetNextIrpStackLocation(Irp);
  479. (*NextIrpSp) = (*IrpSp);
  480. IoSetCompletionRoutine( Irp,
  481. NULL,
  482. NULL,
  483. FALSE,
  484. FALSE,
  485. FALSE);
  486. //
  487. // Call to the real device for the file object.
  488. //
  489. Status = IoCallDriver( Fcb->TargetDevice, Irp );
  490. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsCommonFileSystemControl_Error_IoCallDriver,
  491. LOGSTATUS(Status)
  492. LOGPTR(Irp)
  493. LOGPTR(FileObject)
  494. LOGPTR(DeviceObject));
  495. //
  496. // The IRP will be completed by the called driver. We have
  497. // no need for the IrpContext in the completion routine.
  498. //
  499. DfsDeleteIrpContext(IrpContext);
  500. IrpContext = NULL;
  501. Irp = NULL;
  502. }
  503. break;
  504. }
  505. }
  506. DfsDbgTrace(-1, Dbg, "DfsCommonFileSystemControl -> %08lx\n", ULongToPtr(Status) );
  507. return Status;
  508. }
  509. //+-------------------------------------------------------------------
  510. //
  511. // Function: DfsUserFsctl, local
  512. //
  513. // Synopsis: This is the common routine for implementing the user's
  514. // requests made through NtFsControlFile.
  515. //
  516. // Arguments: [Irp] -- Supplies the Irp being processed
  517. //
  518. // Returns: NTSTATUS - The return status for the operation
  519. //
  520. //--------------------------------------------------------------------
  521. NTSTATUS
  522. DfsUserFsctl (
  523. IN PIRP_CONTEXT IrpContext,
  524. IN PIRP Irp
  525. ) {
  526. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  527. PFILE_OBJECT FileObject = IrpSp->FileObject;
  528. PIO_STACK_LOCATION NextIrpSp;
  529. NTSTATUS Status;
  530. ULONG FsControlCode;
  531. ULONG cbOutput;
  532. ULONG cbInput;
  533. PUCHAR InputBuffer;
  534. PUCHAR OutputBuffer;
  535. PDFS_FCB Fcb;
  536. PDFS_VCB Vcb;
  537. #ifdef TERMSRV
  538. ULONG SessionID;
  539. #endif
  540. //
  541. // Just in case some-one (cough) forgets about it...
  542. // ...zero information status now!
  543. //
  544. Irp->IoStatus.Information = 0L;
  545. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  546. cbInput = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  547. cbOutput = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  548. DfsDbgTrace(+1, Dbg, "DfsUserFsctl: Entered\n", 0);
  549. DfsDbgTrace( 0, Dbg, "DfsUserFsctl: Cntrl Code -> %08lx\n", ULongToPtr(FsControlCode) );
  550. DfsDbgTrace( 0, Dbg, "DfsUserFsctl: cbInput -> %08lx\n", ULongToPtr(cbInput) );
  551. DfsDbgTrace( 0, Dbg, "DfsUserFsctl: cbOutput -> %08lx\n", ULongToPtr(cbOutput) );
  552. //
  553. // All DFS FsControlCodes use METHOD_BUFFERED, so the SystemBuffer
  554. // is used for both the input and output.
  555. //
  556. InputBuffer = OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
  557. DfsDbgTrace( 0, Dbg, "DfsUserFsctl: InputBuffer -> %08lx\n", InputBuffer);
  558. DfsDbgTrace( 0, Dbg, "DfsUserFsctl: UserBuffer -> %08lx\n", Irp->UserBuffer);
  559. //
  560. // Case on the control code.
  561. //
  562. switch ( FsControlCode ) {
  563. case FSCTL_REQUEST_OPLOCK_LEVEL_1:
  564. case FSCTL_REQUEST_OPLOCK_LEVEL_2:
  565. case FSCTL_REQUEST_BATCH_OPLOCK:
  566. case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
  567. case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
  568. case FSCTL_OPLOCK_BREAK_NOTIFY:
  569. Status = DfsOplockRequest( IrpContext, Irp );
  570. break;
  571. case FSCTL_DISMOUNT_VOLUME:
  572. Status = STATUS_NOT_SUPPORTED;
  573. DfsCompleteRequest(IrpContext, Irp, Status);
  574. break;
  575. case FSCTL_DFS_GET_VERSION:
  576. if (OutputBuffer != NULL &&
  577. cbOutput >= sizeof(DFS_GET_VERSION_ARG)) {
  578. PDFS_GET_VERSION_ARG parg =
  579. (PDFS_GET_VERSION_ARG) OutputBuffer;
  580. parg->Version = 1;
  581. Status = STATUS_SUCCESS;
  582. Irp->IoStatus.Information = sizeof(DFS_GET_VERSION_ARG);
  583. } else {
  584. Status = STATUS_INVALID_PARAMETER;
  585. }
  586. DfsCompleteRequest(IrpContext, Irp, Status);
  587. break;
  588. case FSCTL_DFS_STOP_DFS:
  589. DfsStopDfs();
  590. Status = STATUS_SUCCESS;
  591. DfsCompleteRequest(IrpContext, Irp, Status);
  592. break;
  593. case FSCTL_DFS_IS_ROOT:
  594. Status = STATUS_INVALID_DOMAIN_ROLE;
  595. DfsCompleteRequest(IrpContext, Irp, Status);
  596. break;
  597. case FSCTL_DFS_IS_VALID_PREFIX: {
  598. PDFS_IS_VALID_PREFIX_ARG PrefixArg;
  599. UNICODE_STRING fileName, pathName;
  600. PrefixArg = (PDFS_IS_VALID_PREFIX_ARG)InputBuffer;
  601. if (cbInput < sizeof(DFS_IS_VALID_PREFIX_ARG)
  602. ||
  603. (ULONG)(FIELD_OFFSET(DFS_IS_VALID_PREFIX_ARG,RemoteName) +
  604. PrefixArg->RemoteNameLen) > cbInput
  605. ) {
  606. Status = STATUS_INVALID_PARAMETER;
  607. DfsCompleteRequest(IrpContext, Irp, Status);
  608. break;
  609. }
  610. //
  611. // Reject negative and odd RemoteNameLen's
  612. //
  613. if (PrefixArg->RemoteNameLen < 0
  614. ||
  615. (PrefixArg->RemoteNameLen & 0x1) != 0
  616. ) {
  617. Status = STATUS_INVALID_PARAMETER;
  618. DfsCompleteRequest(IrpContext, Irp, Status);
  619. break;
  620. }
  621. fileName.Length = PrefixArg->RemoteNameLen;
  622. fileName.MaximumLength = (USHORT) PrefixArg->RemoteNameLen;
  623. fileName.Buffer = (PWCHAR) PrefixArg->RemoteName;
  624. try {
  625. Status = DfsFsctrlIsThisADfsPath(
  626. &fileName,
  627. PrefixArg->CSCAgentCreate,
  628. &pathName );
  629. } except (EXCEPTION_EXECUTE_HANDLER) {
  630. Status = STATUS_INVALID_PARAMETER;
  631. }
  632. DfsCompleteRequest(IrpContext, Irp, Status);
  633. }
  634. break;
  635. case FSCTL_DFS_IS_VALID_LOGICAL_ROOT:
  636. if (cbInput == sizeof(WCHAR)) {
  637. UNICODE_STRING logRootName, Remaining;
  638. WCHAR buffer[3];
  639. PDFS_VCB Vcb;
  640. LUID LogonID;
  641. buffer[0] = *((PWCHAR) InputBuffer);
  642. buffer[1] = UNICODE_DRIVE_SEP;
  643. buffer[2] = UNICODE_PATH_SEP;
  644. logRootName.Length = sizeof(buffer);
  645. logRootName.MaximumLength = sizeof(buffer);
  646. logRootName.Buffer = buffer;
  647. DfsGetLogonId(&LogonID);
  648. #ifdef TERMSRV
  649. Status = IoGetRequestorSessionId(Irp, &SessionID);
  650. if (NT_SUCCESS(Status)) {
  651. Status = DfsFindLogicalRoot(&logRootName, SessionID, &LogonID, &Vcb, &Remaining);
  652. }
  653. #else
  654. Status = DfsFindLogicalRoot(&logRootName, &LogonID, &Vcb, &Remaining);
  655. #endif
  656. if (!NT_SUCCESS(Status)) {
  657. DfsDbgTrace(0, Dbg, "Logical root not found!\n", 0);
  658. Status = STATUS_NO_SUCH_DEVICE;
  659. }
  660. } else {
  661. Status = STATUS_INVALID_PARAMETER;
  662. }
  663. DfsCompleteRequest(IrpContext, Irp, Status);
  664. break;
  665. case FSCTL_DFS_PKT_SET_DC_NAME:
  666. Status = DfsFsctrlSetDCName(IrpContext,
  667. Irp,
  668. InputBuffer,
  669. cbInput);
  670. break;
  671. case FSCTL_DFS_PKT_SET_DOMAINNAMEFLAT:
  672. Status = DfsFsctrlSetDomainNameFlat(IrpContext,
  673. Irp,
  674. InputBuffer,
  675. cbInput);
  676. break;
  677. case FSCTL_DFS_PKT_SET_DOMAINNAMEDNS:
  678. Status = DfsFsctrlSetDomainNameDns(IrpContext,
  679. Irp,
  680. InputBuffer,
  681. cbInput);
  682. break;
  683. case FSCTL_DFS_DEFINE_LOGICAL_ROOT:
  684. Status = DfsFsctrlDefineLogicalRoot( IrpContext, Irp,
  685. (PFILE_DFS_DEF_ROOT_BUFFER)InputBuffer, cbInput);
  686. break;
  687. case FSCTL_DFS_DELETE_LOGICAL_ROOT:
  688. Status = DfsFsctrlUndefineLogicalRoot( IrpContext, Irp,
  689. (PFILE_DFS_DEF_ROOT_BUFFER)InputBuffer, cbInput);
  690. break;
  691. case FSCTL_DFS_GET_LOGICAL_ROOT_PREFIX:
  692. Status = DfsFsctrlGetLogicalRootPrefix( IrpContext, Irp,
  693. (PFILE_DFS_DEF_ROOT_BUFFER)InputBuffer, cbInput,
  694. (PUCHAR)OutputBuffer, cbOutput);
  695. break;
  696. case FSCTL_DFS_GET_CONNECTED_RESOURCES:
  697. Status = DfsFsctrlGetConnectedResources(IrpContext,
  698. Irp,
  699. InputBuffer,
  700. cbInput,
  701. OutputBuffer,
  702. cbOutput);
  703. break;
  704. case FSCTL_DFS_DEFINE_ROOT_CREDENTIALS:
  705. Status = DfsFsctrlDefineRootCredentials(
  706. IrpContext,
  707. Irp,
  708. InputBuffer,
  709. cbInput);
  710. break;
  711. case FSCTL_DFS_GET_SERVER_NAME:
  712. Status = DfsFsctrlGetServerName(IrpContext,
  713. Irp,
  714. InputBuffer,
  715. cbInput,
  716. OutputBuffer,
  717. cbOutput);
  718. break;
  719. case FSCTL_DFS_SET_PKT_ENTRY_TIMEOUT:
  720. if (cbInput == sizeof(ULONG)) {
  721. DfsData.Pkt.EntryTimeToLive = *(PULONG) InputBuffer;
  722. Status = STATUS_SUCCESS;
  723. } else {
  724. Status = STATUS_INVALID_PARAMETER;
  725. }
  726. DfsCompleteRequest(IrpContext, Irp, Status);
  727. break;
  728. case FSCTL_DFS_PKT_FLUSH_CACHE:
  729. Status = PktFsctrlFlushCache(IrpContext, Irp,
  730. InputBuffer, cbInput
  731. );
  732. break;
  733. case FSCTL_DFS_PKT_FLUSH_SPC_CACHE:
  734. Status = PktFsctrlFlushSpcCache(IrpContext, Irp,
  735. InputBuffer, cbInput
  736. );
  737. break;
  738. case FSCTL_DFS_GET_PKT_ENTRY_STATE:
  739. Status = DfsFsctrlGetPktEntryState(IrpContext,
  740. Irp,
  741. InputBuffer,
  742. cbInput,
  743. OutputBuffer,
  744. cbOutput);
  745. break;
  746. case FSCTL_DFS_SET_PKT_ENTRY_STATE:
  747. Status = DfsFsctrlSetPktEntryState(IrpContext,
  748. Irp,
  749. InputBuffer,
  750. cbInput);
  751. break;
  752. case FSCTL_DFS_GET_PKT:
  753. Status = DfsFsctrlGetPkt(IrpContext,
  754. Irp,
  755. OutputBuffer,
  756. cbOutput);
  757. break;
  758. case FSCTL_DFS_GET_SPC_TABLE:
  759. Status = DfsFsctrlGetSpcTable(IrpContext,
  760. Irp,
  761. InputBuffer,
  762. cbInput,
  763. OutputBuffer,
  764. cbOutput);
  765. break;
  766. case FSCTL_DFS_SPECIAL_SET_DC:
  767. Status = DfsFsctrlSpcSetDc(IrpContext,
  768. Irp,
  769. InputBuffer,
  770. cbInput);
  771. break;
  772. case FSCTL_DFS_REREAD_REGISTRY:
  773. DfsGetEventLogValue();
  774. #if DBG
  775. MupGetDebugFlags();
  776. DbgPrint("DfsDebugTraceLevel=0x%x\n", DfsDebugTraceLevel);
  777. DbgPrint("MupVerbose=0x%x\n", MupVerbose);
  778. DbgPrint("DfsEventLog=0x%x\n", DfsEventLog);
  779. #endif // DBG
  780. Status = STATUS_SUCCESS;
  781. DfsCompleteRequest(IrpContext, Irp, Status);
  782. break;
  783. #if DBG
  784. case FSCTL_DFS_INTERNAL_READ_MEM:
  785. Status = DfsFsctrlReadMem( IrpContext, Irp,
  786. (PFILE_DFS_READ_MEM)InputBuffer, cbInput,
  787. OutputBuffer, cbOutput );
  788. break;
  789. case FSCTL_DFS_DBG_BREAK:
  790. DbgBreakPoint();
  791. Status = STATUS_SUCCESS;
  792. DfsCompleteRequest(IrpContext, Irp, Status);
  793. break;
  794. case FSCTL_DFS_DBG_FLAGS:
  795. if (cbInput >= sizeof(ULONG))
  796. DfsDebugTraceLevel = * ((PULONG) InputBuffer);
  797. DbgPrint("DfsDebugTraceLevel=0x%x\n", DfsDebugTraceLevel);
  798. DbgPrint("MupVerbose=0x%x\n", MupVerbose);
  799. DbgPrint("DfsEventLog=0x%x\n", DfsEventLog);
  800. Status = STATUS_SUCCESS;
  801. DfsCompleteRequest(IrpContext, Irp, Status);
  802. break;
  803. case FSCTL_DFS_VERBOSE_FLAGS:
  804. if (cbInput >= sizeof(ULONG))
  805. MupVerbose = * ((PULONG) InputBuffer);
  806. DbgPrint("DfsDebugTraceLevel=0x%x\n", DfsDebugTraceLevel);
  807. DbgPrint("MupVerbose=0x%x\n", MupVerbose);
  808. DbgPrint("DfsEventLog=0x%x\n", DfsEventLog);
  809. Status = STATUS_SUCCESS;
  810. DfsCompleteRequest(IrpContext, Irp, Status);
  811. break;
  812. case FSCTL_DFS_EVENTLOG_FLAGS:
  813. if (cbInput >= sizeof(ULONG))
  814. DfsEventLog = * ((PULONG) InputBuffer);
  815. DbgPrint("DfsDebugTraceLevel=0x%x\n", DfsDebugTraceLevel);
  816. DbgPrint("MupVerbose=0x%x\n", MupVerbose);
  817. DbgPrint("DfsEventLog=0x%x\n", DfsEventLog);
  818. Status = STATUS_SUCCESS;
  819. DfsCompleteRequest(IrpContext, Irp, Status);
  820. break;
  821. #endif // DBG
  822. case FSCTL_DFS_GET_CONNECTION_PERF_INFO:
  823. Status = DfsFsctrlGetConnectionPerfInfo(IrpContext,
  824. Irp,
  825. InputBuffer,
  826. cbInput,
  827. OutputBuffer,
  828. cbOutput);
  829. break;
  830. case FSCTL_DFS_CSC_SERVER_OFFLINE:
  831. Status = DfsFsctrlCscServerOffline(IrpContext,
  832. Irp,
  833. InputBuffer,
  834. cbInput,
  835. OutputBuffer,
  836. cbOutput);
  837. break;
  838. case FSCTL_DFS_CSC_SERVER_ONLINE:
  839. Status = DfsFsctrlCscServerOnline(IrpContext,
  840. Irp,
  841. InputBuffer,
  842. cbInput,
  843. OutputBuffer,
  844. cbOutput);
  845. break;
  846. case FSCTL_DFS_SPC_REFRESH:
  847. Status = DfsFsctrlSpcRefresh(IrpContext,
  848. Irp,
  849. InputBuffer,
  850. cbInput);
  851. break;
  852. default:
  853. //
  854. // It is not a recognized DFS fsctrl. If it is for a redirected
  855. // file, just pass it along to the underlying file system.
  856. //
  857. if (
  858. (IS_DFS_CTL_CODE(FsControlCode))
  859. ||
  860. (DfsDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb) != RedirectedFileOpen)
  861. ) {
  862. DfsDbgTrace(0, Dbg, "Dfs: Invalid FS control code -> %08lx\n", ULongToPtr(FsControlCode) );
  863. DfsCompleteRequest( IrpContext, Irp, STATUS_NOT_SUPPORTED);
  864. Status = STATUS_NOT_SUPPORTED;
  865. break;
  866. }
  867. //
  868. // Copy the stack from one to the next...
  869. //
  870. NextIrpSp = IoGetNextIrpStackLocation(Irp);
  871. (*NextIrpSp) = (*IrpSp);
  872. IoSetCompletionRoutine( Irp,
  873. NULL,
  874. NULL,
  875. FALSE,
  876. FALSE,
  877. FALSE);
  878. //
  879. // Call to the real device for the file object.
  880. //
  881. Status = IoCallDriver( Fcb->TargetDevice, Irp );
  882. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsUserFsctl_Error_IoCallDriver,
  883. LOGSTATUS(Status)
  884. LOGPTR(Irp)
  885. LOGPTR(FileObject));
  886. //
  887. // The IRP will be completed by the called driver. We have
  888. // no need for the IrpContext in the completion routine.
  889. //
  890. DfsDeleteIrpContext(IrpContext);
  891. IrpContext = NULL;
  892. Irp = NULL;
  893. break;
  894. }
  895. DfsDbgTrace(-1, Dbg, "DfsUserFsctl: Exit -> %08lx\n", ULongToPtr(Status) );
  896. return Status;
  897. }
  898. //+-------------------------------------------------------------------------
  899. //
  900. // Function: DfsOplockRequest, local
  901. //
  902. // Synopsis: DfsOplockRequest will process an oplock request.
  903. //
  904. // Arguments: [IrpContext] -
  905. // [Irp] -
  906. //
  907. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  908. // STATUS_OPLOCK_NOT_GRANTED if the oplock is refuesed
  909. //
  910. //
  911. //--------------------------------------------------------------------------
  912. NTSTATUS
  913. DfsOplockRequest (
  914. IN PIRP_CONTEXT IrpContext,
  915. IN PIRP Irp
  916. ) {
  917. NTSTATUS Status;
  918. ULONG FsControlCode;
  919. PDFS_FCB Fcb;
  920. PDFS_VCB Vcb;
  921. TYPE_OF_OPEN TypeOfOpen;
  922. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  923. PFILE_OBJECT FileObject = IrpSp->FileObject;
  924. PIO_STACK_LOCATION NextIrpSp;
  925. BOOLEAN AcquiredVcb = FALSE;
  926. //
  927. // Save some references to make our life a little easier
  928. //
  929. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  930. DfsDbgTrace(+1, Dbg, "DfsOplockRequest...\n", 0);
  931. DfsDbgTrace( 0, Dbg, "FsControlCode = %08lx\n", ULongToPtr(FsControlCode) );
  932. //
  933. // We only permit oplock requests on files.
  934. //
  935. if ((TypeOfOpen = DfsDecodeFileObject(IrpSp->FileObject, &Vcb, &Fcb))
  936. != RedirectedFileOpen) {
  937. //
  938. // A bit bizarre that someone wants to oplock a device object, but
  939. // hey, if it makes them happy...
  940. //
  941. DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  942. DfsDbgTrace(-1, Dbg, "DfsOplockRequest -> STATUS_INVALID_PARAMETER\n", 0);
  943. return STATUS_INVALID_PARAMETER;
  944. } else {
  945. //
  946. // RedirectedFileOpen - we pass the buck to the underlying FS.
  947. //
  948. NextIrpSp = IoGetNextIrpStackLocation(Irp);
  949. (*NextIrpSp) = (*IrpSp);
  950. IoSetCompletionRoutine(Irp, NULL, NULL, FALSE, FALSE, FALSE);
  951. //
  952. // ...and call the next device
  953. //
  954. Status = IoCallDriver( Fcb->TargetDevice, Irp );
  955. MUP_TRACE_ERROR_HIGH(Status, ALL_ERROR, DfsOplockRequest_Error_IoCallDriver,
  956. LOGSTATUS(Status)
  957. LOGPTR(Irp)
  958. LOGPTR(FileObject));
  959. DfsDeleteIrpContext( IrpContext );
  960. return(Status);
  961. }
  962. }
  963. //+----------------------------------------------------------------------------
  964. //
  965. // Function: DfsStopDfs, local
  966. //
  967. // Synopsis: "Stops" the Dfs client - causes Dfs to release all references
  968. // to provider device objects.
  969. //
  970. // Arguments: None
  971. //
  972. // Returns: Nothing
  973. //
  974. //-----------------------------------------------------------------------------
  975. VOID
  976. DfsStopDfs()
  977. {
  978. ULONG i;
  979. PDFS_PKT_ENTRY pktEntry;
  980. PDFS_VCB Vcb;
  981. ExAcquireResourceExclusiveLite( &DfsData.Pkt.Resource, TRUE );
  982. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  983. //
  984. // Lets go through and release any opens to server IPC$ shares and
  985. // provider device objects.
  986. //
  987. for (pktEntry = PktFirstEntry(&DfsData.Pkt);
  988. pktEntry != NULL;
  989. pktEntry = PktNextEntry(&DfsData.Pkt, pktEntry)) {
  990. for (i = 0; i < pktEntry->Info.ServiceCount; i++) {
  991. if (pktEntry->Info.ServiceList[i].ConnFile != NULL) {
  992. ObDereferenceObject(
  993. pktEntry->Info.ServiceList[i].ConnFile);
  994. pktEntry->Info.ServiceList[i].ConnFile = NULL;
  995. }
  996. if (pktEntry->Info.ServiceList[i].pMachEntry->AuthConn != NULL) {
  997. ObDereferenceObject(
  998. pktEntry->Info.ServiceList[i].pMachEntry->AuthConn);
  999. pktEntry->Info.ServiceList[i].pMachEntry->AuthConn = NULL;
  1000. pktEntry->Info.ServiceList[i].pMachEntry->Credentials->RefCount--;
  1001. pktEntry->Info.ServiceList[i].pMachEntry->Credentials = NULL;
  1002. }
  1003. //
  1004. // We are going to be closing all references to provider device
  1005. // objects. So, clear the service's pointer to its provider.
  1006. //
  1007. pktEntry->Info.ServiceList[i].pProvider = NULL;
  1008. }
  1009. }
  1010. for (i = 0; i < (ULONG) DfsData.cProvider; i++) {
  1011. if (DfsData.pProvider[i].FileObject != NULL) {
  1012. ObDereferenceObject( DfsData.pProvider[i].FileObject );
  1013. DfsData.pProvider[i].FileObject = NULL;
  1014. ASSERT( DfsData.pProvider[i].DeviceObject != NULL );
  1015. ObDereferenceObject( DfsData.pProvider[i].DeviceObject );
  1016. DfsData.pProvider[i].DeviceObject = NULL;
  1017. }
  1018. }
  1019. ExReleaseResourceLite( &DfsData.Resource );
  1020. ExReleaseResourceLite( &DfsData.Pkt.Resource );
  1021. }
  1022. //+----------------------------------------------------------------------------
  1023. //
  1024. // Function: DfsFsctrlIsThisADfsPath, local
  1025. //
  1026. // Synopsis: Determines whether a given path is a Dfs path or not.
  1027. // The general algorithm is:
  1028. //
  1029. // - Do a prefix lookup in the Pkt. If an entry is found, it's
  1030. // a Dfs path.
  1031. // - Ask the Dfs service whether this is a domain based Dfs
  1032. // path. If so, it's a Dfs path.
  1033. // - Finally, do an ZwCreateFile on the path name (assuming
  1034. // it's a Dfs path). If it succeeds, it's a Dfs path.
  1035. //
  1036. // Arguments: [filePath] - Name of entire file
  1037. // [pathName] - If this is a Dfs path, this will return the
  1038. // component of filePath that was a Dfs path name (ie, the
  1039. // entry path of the Dfs volume that holds the file). The
  1040. // buffer will point to the same buffer as filePath, so
  1041. // nothing is allocated.
  1042. //
  1043. // Returns: [STATUS_SUCCESS] -- filePath is a Dfs path.
  1044. //
  1045. // [STATUS_BAD_NETWORK_PATH] -- filePath is not a Dfs path.
  1046. //
  1047. //-----------------------------------------------------------------------------
  1048. NTSTATUS
  1049. DfsFsctrlIsThisADfsPath(
  1050. IN PUNICODE_STRING filePath,
  1051. IN BOOLEAN CSCAgentCreate,
  1052. OUT PUNICODE_STRING pathName)
  1053. {
  1054. NTSTATUS status;
  1055. PDFS_PKT pkt;
  1056. PDFS_PKT_ENTRY pktEntry;
  1057. UNICODE_STRING dfsRootName, shareName, remPath;
  1058. UNICODE_STRING RootShareName;
  1059. USHORT i, j;
  1060. BOOLEAN pktLocked;
  1061. PDFS_SPECIAL_ENTRY pSpecialEntry;
  1062. LARGE_INTEGER StartTime;
  1063. LARGE_INTEGER EndTime;
  1064. KeQuerySystemTime(&StartTime);
  1065. DfsDbgTrace(+1, Dbg, "DfsFsctrlIsThisADfsPath: Entered %wZ\n", filePath);
  1066. #if DBG
  1067. if (MupVerbose) {
  1068. KeQuerySystemTime(&EndTime);
  1069. DbgPrint("[%d] DfsFsctrlIsThisADfsPath: Entered %wZ\n",
  1070. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  1071. filePath);
  1072. }
  1073. #endif
  1074. //
  1075. // Only proceed if the first character is a backslash.
  1076. //
  1077. if (filePath->Buffer[0] != UNICODE_PATH_SEP) {
  1078. status = STATUS_BAD_NETWORK_PATH;
  1079. DfsDbgTrace(-1, Dbg, "filePath does not begin with backslash\n", 0);
  1080. MUP_TRACE_HIGH(ERROR, DfsFsctrlIsThisADfsPath_Error_PathDoesNotBeginWithBackSlash,
  1081. LOGSTATUS(status));
  1082. return( status );
  1083. }
  1084. //
  1085. // Find the second component in the name.
  1086. //
  1087. for (i = 1;
  1088. i < filePath->Length/sizeof(WCHAR) &&
  1089. filePath->Buffer[i] != UNICODE_PATH_SEP;
  1090. i++) {
  1091. NOTHING;
  1092. }
  1093. if (i >= filePath->Length/sizeof(WCHAR)) {
  1094. status = STATUS_BAD_NETWORK_PATH;
  1095. DfsDbgTrace(-1, Dbg, "Did not find second backslash\n", 0);
  1096. MUP_TRACE_HIGH(ERROR, DfsFsctrlIsThisADfsPath_Error_DidNotFindSecondBackSlash,
  1097. LOGSTATUS(status));
  1098. return( status );
  1099. }
  1100. status = DfspIsRootOnline(filePath, CSCAgentCreate);
  1101. if (!NT_SUCCESS(status)) {
  1102. return STATUS_BAD_NETWORK_PATH;
  1103. }
  1104. dfsRootName.Length = (i-1) * sizeof(WCHAR);
  1105. dfsRootName.MaximumLength = dfsRootName.Length;
  1106. dfsRootName.Buffer = &filePath->Buffer[1];
  1107. if (dfsRootName.Length == 0) {
  1108. status = STATUS_BAD_NETWORK_PATH;
  1109. MUP_TRACE_HIGH(ERROR, DfsFsctrlIsThisADfsPath_Error_DfsRootNameHasZeroLength,
  1110. LOGSTATUS(status));
  1111. return( status );
  1112. }
  1113. //
  1114. // Figure out the share name
  1115. //
  1116. for (j = i+1;
  1117. j < filePath->Length/sizeof(WCHAR) &&
  1118. filePath->Buffer[j] != UNICODE_PATH_SEP;
  1119. j++) {
  1120. NOTHING;
  1121. }
  1122. shareName.Length = (j - i - 1) * sizeof(WCHAR);
  1123. shareName.MaximumLength = shareName.Length;
  1124. shareName.Buffer = &filePath->Buffer[i+1];
  1125. if (shareName.Length == 0) {
  1126. status = STATUS_BAD_NETWORK_PATH;
  1127. MUP_TRACE_HIGH(ERROR, DfsFsctrlIsThisADfsPath_Error_ShareNameHasZeroLength,
  1128. LOGSTATUS(status));
  1129. return( status );
  1130. }
  1131. if (DfspIsSpecialShare(&shareName)) {
  1132. status = STATUS_BAD_NETWORK_PATH;
  1133. MUP_TRACE_HIGH(ERROR, DfsFsctrlIsThisADfsPath_Error_DfspIsSpecialShare_FALSE,
  1134. LOGUSTR(shareName)
  1135. LOGSTATUS(status));
  1136. return( status );
  1137. }
  1138. //
  1139. // For our purposes we only need to check the \\server\share part of the
  1140. // filePath presented. Any longer matches will be handled in the dnr loop -
  1141. // we don't care about junction points below the root at this stage.
  1142. //
  1143. RootShareName.Buffer = filePath->Buffer;
  1144. RootShareName.Length = j * sizeof(WCHAR);
  1145. RootShareName.MaximumLength = filePath->MaximumLength;
  1146. #if DBG
  1147. if (MupVerbose)
  1148. DbgPrint(" RootShareName=[%wZ]\n", &RootShareName);
  1149. #endif
  1150. //
  1151. // First, do a prefix lookup. If we find an entry, it's a Dfs path
  1152. //
  1153. pkt = _GetPkt();
  1154. PktAcquireShared( TRUE, &pktLocked );
  1155. pktEntry = PktLookupEntryByPrefix( pkt, &RootShareName, &remPath );
  1156. if (pktEntry != NULL && pktEntry->ExpireTime > 0) {
  1157. DfsDbgTrace(-1, Dbg, "Found pkt entry %08lx\n", pktEntry);
  1158. pathName->Length = RootShareName.Length - remPath.Length;
  1159. pathName->MaximumLength = pathName->Length;
  1160. pathName->Buffer = RootShareName.Buffer;
  1161. PktRelease();
  1162. #if DBG
  1163. if (MupVerbose) {
  1164. KeQuerySystemTime(&EndTime);
  1165. DbgPrint("[%d] DfsFsctrlIsThisADfsPath(1): exit STATUS_SUCCESS\n",
  1166. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)));
  1167. }
  1168. #endif
  1169. return( STATUS_SUCCESS );
  1170. }
  1171. #if DBG
  1172. if (MupVerbose) {
  1173. if (pktEntry == NULL)
  1174. DbgPrint(" No pkt entry found.\n");
  1175. else
  1176. DbgPrint(" Stale pkt entry 0x%x ExpireTime=%d\n", pktEntry, pktEntry->ExpireTime);
  1177. }
  1178. #endif
  1179. PktRelease();
  1180. //
  1181. // Nothing in the Pkt, check (by getting a referral) is this is a dfs
  1182. //
  1183. status = PktCreateDomainEntry( &dfsRootName, &shareName, CSCAgentCreate );
  1184. if (NT_SUCCESS(status)) {
  1185. pathName->Length = sizeof(UNICODE_PATH_SEP) + dfsRootName.Length;
  1186. pathName->MaximumLength = pathName->Length;
  1187. pathName->Buffer = RootShareName.Buffer;
  1188. DfsDbgTrace(-1, Dbg, "Domain/Machine Dfs name %wZ\n", pathName );
  1189. #if DBG
  1190. if (MupVerbose) {
  1191. KeQuerySystemTime(&EndTime);
  1192. DbgPrint("[%d] DfsFsctrlIsThisADfsPath(2): exit STATUS_SUCCESS\n",
  1193. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)));
  1194. }
  1195. #endif
  1196. return( STATUS_SUCCESS );
  1197. }
  1198. #if DBG
  1199. if (MupVerbose) {
  1200. KeQuerySystemTime(&EndTime);
  1201. DbgPrint(" [%d] PktCreateDomainEntry() returned 0x%x\n",
  1202. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)),
  1203. status);
  1204. }
  1205. #endif
  1206. //
  1207. // Failed getting referral - see if we have a stale one.
  1208. //
  1209. PktAcquireShared( TRUE, &pktLocked );
  1210. pktEntry = PktLookupEntryByPrefix( pkt, &RootShareName, &remPath );
  1211. if (pktEntry != NULL) {
  1212. #if DBG
  1213. if (MupVerbose)
  1214. DbgPrint(" Found stale pkt entry %08lx - adding 15 sec to it\n", pktEntry);
  1215. #endif
  1216. DfsDbgTrace(-1, Dbg, "Found pkt entry %08lx\n", pktEntry);
  1217. pathName->Length = RootShareName.Length - remPath.Length;
  1218. pathName->MaximumLength = pathName->Length;
  1219. pathName->Buffer = RootShareName.Buffer;
  1220. if (pktEntry->ExpireTime <= 0) {
  1221. pktEntry->ExpireTime = 15;
  1222. pktEntry->TimeToLive = 15;
  1223. }
  1224. PktRelease();
  1225. #if DBG
  1226. if (MupVerbose) {
  1227. KeQuerySystemTime(&EndTime);
  1228. DbgPrint("[%d] DfsFsctrlIsThisADfsPath(3): exit STATUS_SUCCESS\n",
  1229. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)));
  1230. }
  1231. #endif
  1232. return( STATUS_SUCCESS );
  1233. }
  1234. PktRelease();
  1235. if (DfspIsSysVolShare(&shareName)) {
  1236. #if DBG
  1237. if (MupVerbose)
  1238. DbgPrint(" Trying as sysvol\n");
  1239. #endif
  1240. status = PktExpandSpecialName(&dfsRootName, &pSpecialEntry);
  1241. if (NT_SUCCESS(status)) {
  1242. InterlockedDecrement(&pSpecialEntry->UseCount);
  1243. #if DBG
  1244. if (MupVerbose) {
  1245. KeQuerySystemTime(&EndTime);
  1246. DbgPrint("[%d] DfsFsctrlIsThisADfsPath(SYSVOL): exit STATUS_SUCCESS\n",
  1247. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)));
  1248. }
  1249. #endif
  1250. return STATUS_SUCCESS;
  1251. }
  1252. }
  1253. if (DfsIsSpecialName(&dfsRootName)) {
  1254. status = STATUS_SUCCESS;
  1255. return status;
  1256. }
  1257. DfsDbgTrace(-1, Dbg, "Not A Dfs path\n", 0);
  1258. #if DBG
  1259. if (MupVerbose) {
  1260. KeQuerySystemTime(&EndTime);
  1261. DbgPrint("[%d] DfsFsctrlIsThisADfsPath: exit STATUS_BAD_NETWORK_PATH\n",
  1262. (ULONG)((EndTime.QuadPart - StartTime.QuadPart)/(10 * 1000)));
  1263. }
  1264. #endif
  1265. status = STATUS_BAD_NETWORK_PATH;
  1266. MUP_TRACE_HIGH(ERROR, DfsFsctrlIsThisADfsPath_Exit_NotADfsPath,
  1267. LOGSTATUS(status));
  1268. return( STATUS_BAD_NETWORK_PATH );
  1269. }
  1270. //+----------------------------------------------------------------------------
  1271. //
  1272. // Function: DfspIsSpecialShare, local
  1273. //
  1274. // Synopsis: Sees if a share name is a special share.
  1275. //
  1276. // Arguments: [ShareName] -- Name of share to test.
  1277. //
  1278. // Returns: TRUE if special, FALSE otherwise.
  1279. //
  1280. //-----------------------------------------------------------------------------
  1281. BOOLEAN
  1282. DfspIsSpecialShare(
  1283. PUNICODE_STRING ShareName)
  1284. {
  1285. ULONG i;
  1286. BOOLEAN fSpecial = FALSE;
  1287. for (i = 0;
  1288. (i < (sizeof(SpecialShares) / sizeof(SpecialShares[0]))) &&
  1289. !fSpecial;
  1290. i++) {
  1291. if (SpecialShares[i].Length == ShareName->Length) {
  1292. if (_wcsnicmp(
  1293. SpecialShares[i].Buffer,
  1294. ShareName->Buffer,
  1295. ShareName->Length/sizeof(WCHAR)) == 0) {
  1296. fSpecial = TRUE;
  1297. }
  1298. }
  1299. }
  1300. return( fSpecial );
  1301. }
  1302. //+----------------------------------------------------------------------------
  1303. //
  1304. // Function: DfspIsSysVolShare, local
  1305. //
  1306. // Synopsis: Sees if a share name is a sysvol share.
  1307. //
  1308. // Arguments: [ShareName] -- Name of share to test.
  1309. //
  1310. // Returns: TRUE if special, FALSE otherwise.
  1311. //
  1312. //-----------------------------------------------------------------------------
  1313. BOOLEAN
  1314. DfspIsSysVolShare(
  1315. PUNICODE_STRING ShareName)
  1316. {
  1317. ULONG i;
  1318. BOOLEAN fSpecial = FALSE;
  1319. for (i = 0;
  1320. (i < (sizeof(SysVolShares) / sizeof(SysVolShares[0]))) &&
  1321. !fSpecial;
  1322. i++) {
  1323. if (SysVolShares[i].Length == ShareName->Length) {
  1324. if (_wcsnicmp(
  1325. SysVolShares[i].Buffer,
  1326. ShareName->Buffer,
  1327. ShareName->Length/sizeof(WCHAR)) == 0) {
  1328. fSpecial = TRUE;
  1329. }
  1330. }
  1331. }
  1332. return( fSpecial );
  1333. }
  1334. //+-------------------------------------------------------------------------
  1335. //
  1336. // Function: DfsFsctrlDefineLogicalRoot, local
  1337. //
  1338. // Synopsis: DfsFsctrlDefineLogicalRoot will create a new logical root structure.
  1339. //
  1340. // Arguments: [IrpContext] -
  1341. // [Irp] -
  1342. // [pDlrParam] -- Pointer to a FILE_DFS_DEF_ROOT_BUFFER,
  1343. // giving the name of the logical root to be created.
  1344. // [InputBufferLength] -- Size of InputBuffer
  1345. //
  1346. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  1347. //
  1348. // Notes: This routine needs to be called from the FSP thread,
  1349. // since IoCreateDevice (called from DfsInitializeLogicalRoot)
  1350. // will fail if PreviousMode != KernelMode.
  1351. //
  1352. //--------------------------------------------------------------------------
  1353. NTSTATUS
  1354. DfsFsctrlDefineLogicalRoot (
  1355. IN PIRP_CONTEXT IrpContext,
  1356. IN PIRP Irp,
  1357. IN PFILE_DFS_DEF_ROOT_BUFFER pDlrParam,
  1358. IN ULONG InputBufferLength
  1359. ) {
  1360. NTSTATUS Status;
  1361. UNICODE_STRING ustrPrefix;
  1362. BOOLEAN pktLocked;
  1363. PWCHAR wCp;
  1364. PCHAR InputBufferEnd = (PCHAR)pDlrParam + InputBufferLength;
  1365. ULONG i;
  1366. LUID LogonID;
  1367. #ifdef TERMSRV
  1368. ULONG SessionID;
  1369. #endif
  1370. DfsDbgTrace(+1, Dbg, "DfsFsctrlDefineLogicalRoot...\n", 0);
  1371. //
  1372. // Reference the input buffer and make sure it's large enough
  1373. //
  1374. if (InputBufferLength < sizeof (FILE_DFS_DEF_ROOT_BUFFER)) {
  1375. DfsDbgTrace(0, Dbg, "Input buffer is too small\n", 0);
  1376. DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1377. Status = STATUS_INVALID_PARAMETER;
  1378. DfsDbgTrace(-1, Dbg, "DfsFsctrlDefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1379. return Status;
  1380. }
  1381. //
  1382. // Verify there's a null someplace in the LogicalRoot buffer
  1383. //
  1384. for (i = 0; i < MAX_LOGICAL_ROOT_NAME && pDlrParam->LogicalRoot[i]; i++)
  1385. NOTHING;
  1386. if (i >= MAX_LOGICAL_ROOT_NAME) {
  1387. Status = STATUS_INVALID_PARAMETER;
  1388. DfsCompleteRequest( IrpContext, Irp, Status );
  1389. DfsDbgTrace(-1, Dbg, "DfsFsctrlDefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1390. return Status;
  1391. }
  1392. //
  1393. // Verify there's a null someplace in the RootPrefix buffer
  1394. //
  1395. for (wCp = &pDlrParam->RootPrefix[0]; wCp < (PWCHAR)InputBufferEnd && *wCp; wCp++) {
  1396. NOTHING;
  1397. }
  1398. if (wCp >= (PWCHAR)InputBufferEnd) {
  1399. Status = STATUS_INVALID_PARAMETER;
  1400. DfsCompleteRequest( IrpContext, Irp, Status );
  1401. DfsDbgTrace(-1, Dbg, "DfsFsctrlDefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1402. return Status;
  1403. }
  1404. //
  1405. // We can insert logical roots only from the FSP, because IoCreateDevice
  1406. // will fail if previous mode != Kernel mode.
  1407. //
  1408. if ((IrpContext->Flags & IRP_CONTEXT_FLAG_IN_FSD) != 0) {
  1409. DfsDbgTrace(0, Dbg, "DfsFsctrlDefineLogicalRoot: Posting to FSP\n", 0);
  1410. Status = DfsFsdPostRequest( IrpContext, Irp );
  1411. DfsDbgTrace(-1, Dbg, "DfsFsctrlDefineLogicalRoot: Exit -> %08lx\n", ULongToPtr(Status) );
  1412. return(Status);
  1413. }
  1414. //
  1415. // Since we are going to muck with DfsData's VcbQueue, we acquire it
  1416. // exclusively.
  1417. //
  1418. RtlInitUnicodeString(&ustrPrefix, pDlrParam->RootPrefix);
  1419. PktAcquireExclusive( TRUE, &pktLocked );
  1420. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  1421. Status = DfsGetLogonId(&LogonID);
  1422. #ifdef TERMSRV
  1423. Status = IoGetRequestorSessionId(Irp, &SessionID);
  1424. if( NT_SUCCESS( Status ) ) {
  1425. Status =
  1426. DfsInitializeLogicalRoot(
  1427. (PWSTR) pDlrParam->LogicalRoot,
  1428. &ustrPrefix,
  1429. NULL,
  1430. 0,
  1431. SessionID,
  1432. &LogonID );
  1433. }
  1434. #else // TERMSRV
  1435. Status = DfsInitializeLogicalRoot(
  1436. (PWSTR) pDlrParam->LogicalRoot,
  1437. &ustrPrefix,
  1438. NULL,
  1439. 0,
  1440. &LogonID );
  1441. #endif // TERMSRV
  1442. ExReleaseResourceLite(&DfsData.Resource);
  1443. PktRelease();
  1444. DfsCompleteRequest(IrpContext, Irp, Status);
  1445. DfsDbgTrace(-1, Dbg, "DfsFsctrlDefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1446. return Status;
  1447. }
  1448. //+----------------------------------------------------------------------------
  1449. //
  1450. // Function: DfsFsctrlUndefineLogicalRoot
  1451. //
  1452. // Synopsis: Deletes an existing logical root structure.
  1453. //
  1454. // Arguments: [IrpContext] --
  1455. // [Irp] --
  1456. // [pDlrParam] -- The LogicalRoot field of this structure will
  1457. // contain the name of the logical root to be deleted.
  1458. // [InputBufferLength] -- Length of pDlrParam
  1459. //
  1460. // Returns: Yes ;-)
  1461. //
  1462. //-----------------------------------------------------------------------------
  1463. NTSTATUS
  1464. DfsFsctrlUndefineLogicalRoot (
  1465. IN PIRP_CONTEXT IrpContext,
  1466. IN PIRP Irp,
  1467. IN PFILE_DFS_DEF_ROOT_BUFFER pDlrParam,
  1468. IN ULONG InputBufferLength)
  1469. {
  1470. NTSTATUS Status;
  1471. BOOLEAN pktLocked;
  1472. ULONG i;
  1473. PWCHAR wCp;
  1474. PCHAR InputBufferEnd = (PCHAR)pDlrParam + InputBufferLength;
  1475. LUID LogonID ;
  1476. #ifdef TERMSRV
  1477. ULONG SessionID;
  1478. #endif
  1479. DfsDbgTrace(+1, Dbg, "DfsFsctrlUndefineLogicalRoot...\n", 0);
  1480. //
  1481. // Reference the input buffer and make sure it's large enough
  1482. //
  1483. if (InputBufferLength < sizeof (FILE_DFS_DEF_ROOT_BUFFER)) {
  1484. DfsDbgTrace(0, Dbg, "Input buffer is too small\n", 0);
  1485. DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  1486. Status = STATUS_INVALID_PARAMETER;
  1487. DfsDbgTrace(-1, Dbg, "DfsFsctrlUndefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1488. return Status;
  1489. }
  1490. DfsGetLogonId( &LogonID );
  1491. //
  1492. // Verify there's a null someplace in the LogicalRoot buffer
  1493. //
  1494. for (i = 0; i < MAX_LOGICAL_ROOT_NAME && pDlrParam->LogicalRoot[i]; i++)
  1495. NOTHING;
  1496. if (i >= MAX_LOGICAL_ROOT_NAME) {
  1497. Status = STATUS_INVALID_PARAMETER;
  1498. DfsCompleteRequest( IrpContext, Irp, Status );
  1499. DfsDbgTrace(-1, Dbg, "DfsFsctrlUndefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1500. return Status;
  1501. }
  1502. if (pDlrParam->LogicalRoot[0] == UNICODE_NULL) {
  1503. //
  1504. // Verify there's a null someplace in the RootPrefix buffer
  1505. //
  1506. for (wCp = &pDlrParam->RootPrefix[0]; wCp < (PWCHAR)InputBufferEnd && *wCp; wCp++) {
  1507. NOTHING;
  1508. }
  1509. if (wCp >= (PWCHAR)InputBufferEnd) {
  1510. Status = STATUS_INVALID_PARAMETER;
  1511. DfsCompleteRequest( IrpContext, Irp, Status );
  1512. DfsDbgTrace(-1, Dbg, "DfsFsctrlUnDefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1513. return Status;
  1514. }
  1515. }
  1516. #ifdef TERMSRV
  1517. if ( !NT_SUCCESS(IoGetRequestorSessionId(Irp, &SessionID)) ) {
  1518. Status = STATUS_INVALID_PARAMETER;
  1519. DfsCompleteRequest( IrpContext, Irp, Status );
  1520. DfsDbgTrace(-1, Dbg, "DfsFsctrlUndefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1521. return Status;
  1522. }
  1523. #endif
  1524. //
  1525. // We can remove logical roots only from the FSP
  1526. //
  1527. if (pDlrParam->LogicalRoot[0] != UNICODE_NULL) {
  1528. DfsDbgTrace(0, Dbg, "Deleting root [%ws]\n", pDlrParam->LogicalRoot);
  1529. #ifdef TERMSRV
  1530. Status =
  1531. DfsDeleteLogicalRoot(
  1532. (PWSTR) pDlrParam->LogicalRoot,
  1533. pDlrParam->fForce,
  1534. SessionID,
  1535. &LogonID );
  1536. #else // TERMSRV
  1537. Status = DfsDeleteLogicalRoot(
  1538. (PWSTR) pDlrParam->LogicalRoot,
  1539. pDlrParam->fForce,
  1540. &LogonID);
  1541. #endif // TERMSRV
  1542. DfsDbgTrace(0, Dbg, "DfsDeleteLogicalRoot returned %08lx\n", ULongToPtr(Status) );
  1543. } else {
  1544. UNICODE_STRING name;
  1545. RtlInitUnicodeString(&name, pDlrParam->RootPrefix);
  1546. DfsDbgTrace(0, Dbg, "Deleting connection to [%wZ]\n", &name);
  1547. #ifdef TERMSRV
  1548. Status = DfsDeleteDevlessRoot(
  1549. &name,
  1550. SessionID,
  1551. &LogonID );
  1552. #else // TERMSRV
  1553. Status = DfsDeleteDevlessRoot(
  1554. &name,
  1555. &LogonID);
  1556. #endif // TERMSRV
  1557. }
  1558. DfsCompleteRequest(IrpContext, Irp, Status);
  1559. DfsDbgTrace(-1, Dbg, "DfsFsctrlUndefineLogicalRoot -> %08lx\n", ULongToPtr(Status) );
  1560. return Status;
  1561. }
  1562. //+----------------------------------------------------------------------------
  1563. //
  1564. // Function: DfsFsctrlGetLogicalRootPrefix
  1565. //
  1566. // Synopsis:
  1567. //
  1568. // Arguments:
  1569. //
  1570. // Returns:
  1571. //
  1572. //-----------------------------------------------------------------------------
  1573. NTSTATUS
  1574. DfsFsctrlGetLogicalRootPrefix (
  1575. IN PIRP_CONTEXT IrpContext,
  1576. IN PIRP Irp,
  1577. IN PFILE_DFS_DEF_ROOT_BUFFER pDlrParam,
  1578. IN ULONG InputBufferLength,
  1579. IN OUT PUCHAR OutputBuffer,
  1580. IN ULONG OutputBufferLength)
  1581. {
  1582. NTSTATUS Status;
  1583. UNICODE_STRING RootPath, Remaining;
  1584. PDFS_VCB Vcb;
  1585. WCHAR RootBuffer[MAX_LOGICAL_ROOT_NAME + 2];
  1586. BOOLEAN bAcquired = FALSE;
  1587. ULONG i;
  1588. USHORT PrefixLength;
  1589. LUID LogonID;
  1590. #ifdef TERMSRV
  1591. ULONG SessionID;
  1592. #endif
  1593. DfsDbgTrace(+1, Dbg, "DfsFsctrlGetLogicalRootPrefix...\n", 0);
  1594. //
  1595. // Reference the input buffer and make sure it's large enough
  1596. //
  1597. if (InputBufferLength < sizeof (FILE_DFS_DEF_ROOT_BUFFER)) {
  1598. DfsDbgTrace(0, Dbg, "Input buffer is too small\n", 0);
  1599. Status = STATUS_INVALID_PARAMETER;
  1600. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetLogicalRootPrefix -> %08lx\n", ULongToPtr(Status) );
  1601. goto Cleanup;
  1602. }
  1603. //
  1604. // Verify there's a null someplace in the buffer
  1605. //
  1606. for (i = 0; i < MAX_LOGICAL_ROOT_NAME && pDlrParam->LogicalRoot[i]; i++)
  1607. NOTHING;
  1608. if (i >= MAX_LOGICAL_ROOT_NAME) {
  1609. Status = STATUS_INVALID_PARAMETER;
  1610. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetLogicalRootPrefix -> %08lx\n", ULongToPtr(Status) );
  1611. goto Cleanup;
  1612. }
  1613. RootPath.Buffer = RootBuffer;
  1614. RootPath.Length = 0;
  1615. RootPath.MaximumLength = sizeof RootBuffer;
  1616. Status = DfspLogRootNameToPath(pDlrParam->LogicalRoot, &RootPath);
  1617. if (!NT_SUCCESS(Status)) {
  1618. DfsDbgTrace(0, Dbg, "Input name is too big\n", 0);
  1619. Status = STATUS_INVALID_PARAMETER;
  1620. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetLogicalRootPrefix -> %08lx\n", ULongToPtr(Status) );
  1621. goto Cleanup;
  1622. }
  1623. bAcquired = ExAcquireResourceSharedLite(&DfsData.Resource, TRUE);
  1624. DfsGetLogonId(&LogonID);
  1625. #ifdef TERMSRV
  1626. Status = IoGetRequestorSessionId(Irp, &SessionID);
  1627. if( NT_SUCCESS( Status ) ) {
  1628. Status = DfsFindLogicalRoot( &RootPath, SessionID, &LogonID, &Vcb, &Remaining);
  1629. }
  1630. #else // TERMSRV
  1631. Status = DfsFindLogicalRoot(&RootPath, &LogonID, &Vcb, &Remaining);
  1632. #endif // TERMSRV
  1633. if (!NT_SUCCESS(Status)) {
  1634. DfsDbgTrace(0, Dbg, "Logical root not found!\n", 0);
  1635. Status = STATUS_NO_SUCH_DEVICE;
  1636. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetLogicalRootPrefix -> %08lx\n", ULongToPtr(Status) );
  1637. goto Cleanup;
  1638. }
  1639. PrefixLength = Vcb->LogRootPrefix.Length;
  1640. if ((PrefixLength + sizeof(UNICODE_NULL)) > OutputBufferLength) {
  1641. //
  1642. // Return required length in IoStatus.Information.
  1643. //
  1644. RETURN_BUFFER_SIZE( PrefixLength + sizeof(UNICODE_NULL), Status );
  1645. DfsDbgTrace(0, Dbg, "Output buffer too small\n", 0);
  1646. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetLogicalRootPrefix -> %08lx\n", ULongToPtr(Status) );
  1647. goto Cleanup;
  1648. }
  1649. //
  1650. // All ok, copy prefix and get out.
  1651. //
  1652. if (PrefixLength > 0) {
  1653. RtlMoveMemory(
  1654. OutputBuffer,
  1655. Vcb->LogRootPrefix.Buffer,
  1656. PrefixLength);
  1657. }
  1658. ((PWCHAR) OutputBuffer)[PrefixLength/sizeof(WCHAR)] = UNICODE_NULL;
  1659. Irp->IoStatus.Information = Vcb->LogRootPrefix.Length + sizeof(UNICODE_NULL);
  1660. Status = STATUS_SUCCESS;
  1661. Cleanup:
  1662. if (bAcquired) {
  1663. ExReleaseResourceLite(&DfsData.Resource);
  1664. }
  1665. DfsCompleteRequest(IrpContext, Irp, Status);
  1666. return(Status);
  1667. }
  1668. //+----------------------------------------------------------------------------
  1669. //
  1670. // Function: DfsFsctrlGetConnectedResources
  1671. //
  1672. // Synopsis: Returns LPNETRESOURCE structures for each Logical Root,
  1673. // starting from the logical root indicated in the InputBuffer
  1674. // and including as many as will fit in OutputBuffer.
  1675. //
  1676. // Arguments:
  1677. //
  1678. // Returns:
  1679. //
  1680. //-----------------------------------------------------------------------------
  1681. NTSTATUS
  1682. DfsFsctrlGetConnectedResources(
  1683. IN PIRP_CONTEXT IrpContext,
  1684. IN PIRP Irp,
  1685. IN PUCHAR InputBuffer,
  1686. IN ULONG InputBufferLength,
  1687. IN PUCHAR OutputBuffer,
  1688. IN ULONG OutputBufferLength)
  1689. {
  1690. NTSTATUS Status = STATUS_SUCCESS;
  1691. PLIST_ENTRY Link;
  1692. PDFS_DEVLESS_ROOT pDrt;
  1693. PDFS_VCB pVcb;
  1694. ULONG count = 0;
  1695. ULONG remLen;
  1696. ULONG skipNum;
  1697. ULONG DFS_UNALIGNED *retCnt;
  1698. UNICODE_STRING providerName;
  1699. PUCHAR buf = OutputBuffer;
  1700. BOOLEAN providerNameAllocated;
  1701. LUID LogonID;
  1702. ULONG ResourceSize;
  1703. #ifdef TERMSRV
  1704. ULONG SessionID;
  1705. #endif
  1706. STD_FSCTRL_PROLOGUE(DfsFsctrlGetConnectedResources, TRUE, TRUE, FALSE);
  1707. #ifdef TERMSRV
  1708. //
  1709. // Get SessionID of this request first.
  1710. //
  1711. Status = IoGetRequestorSessionId(Irp, &SessionID);
  1712. if( !NT_SUCCESS(Status) ) {
  1713. Status = STATUS_INVALID_PARAMETER;
  1714. DfsCompleteRequest( IrpContext, Irp, Status );
  1715. DfsDbgTrace(-1,Dbg,
  1716. "DfsFsctrlGetConnectedResources: Exit->%08lx\n", ULongToPtr(Status) );
  1717. return Status;
  1718. }
  1719. #endif
  1720. if (OutputBufferLength < sizeof(ULONG)) {
  1721. Status = STATUS_BUFFER_TOO_SMALL;
  1722. DfsCompleteRequest( IrpContext, Irp, Status );
  1723. DfsDbgTrace(-1,Dbg,
  1724. "DfsFsctrlGetConnectedResources: Exit->%08lx\n", ULongToPtr(Status) );
  1725. return( Status );
  1726. }
  1727. if (InputBufferLength < sizeof(DWORD)) {
  1728. Status = STATUS_INVALID_PARAMETER;
  1729. DfsCompleteRequest( IrpContext, Irp, Status );
  1730. DfsDbgTrace(-1,Dbg,
  1731. "DfsFsctrlGetConnectedResources: Exit->%08lx\n", ULongToPtr(Status) );
  1732. return Status;
  1733. }
  1734. if (InputBufferLength == sizeof(DWORD)) {
  1735. skipNum = *((ULONG *) InputBuffer);
  1736. providerName.Length = sizeof(DFS_PROVIDER_NAME) - sizeof(UNICODE_NULL);
  1737. providerName.MaximumLength = sizeof(DFS_PROVIDER_NAME);
  1738. providerName.Buffer = DFS_PROVIDER_NAME;
  1739. providerNameAllocated = FALSE;
  1740. } else {
  1741. skipNum = 0;
  1742. providerName.Length =
  1743. (USHORT) (InputBufferLength - sizeof(UNICODE_NULL));
  1744. providerName.MaximumLength = (USHORT) InputBufferLength;
  1745. providerName.Buffer = ExAllocatePoolWithTag(PagedPool, InputBufferLength, ' puM');
  1746. if (providerName.Buffer != NULL) {
  1747. providerNameAllocated = TRUE;
  1748. RtlCopyMemory(
  1749. providerName.Buffer,
  1750. InputBuffer,
  1751. InputBufferLength);
  1752. } else {
  1753. Status = STATUS_INSUFFICIENT_RESOURCES;
  1754. DfsCompleteRequest( IrpContext, Irp, Status );
  1755. DfsDbgTrace(-1,Dbg,
  1756. "DfsFsctrlGetConnectedResources: Exit->%08lx\n", ULongToPtr(Status) );
  1757. return Status;
  1758. }
  1759. }
  1760. RtlZeroMemory(OutputBuffer, OutputBufferLength);
  1761. remLen = OutputBufferLength-sizeof(ULONG);
  1762. retCnt = (ULONG *) (OutputBuffer + remLen);
  1763. DfsGetLogonId(&LogonID);
  1764. ExAcquireResourceSharedLite(&DfsData.Resource, TRUE);
  1765. //
  1766. // First get the device-less connections
  1767. //
  1768. for (Link = DfsData.DrtQueue.Flink;
  1769. Link != &DfsData.DrtQueue;
  1770. Link = Link->Flink ) {
  1771. pDrt = CONTAINING_RECORD( Link, DFS_DEVLESS_ROOT, DrtLinks );
  1772. #ifdef TERMSRV
  1773. if( (SessionID != INVALID_SESSIONID) &&
  1774. (SessionID == pDrt->SessionID) &&
  1775. RtlEqualLuid(&pDrt->LogonID, &LogonID) ) {
  1776. #else // TERMSRV
  1777. if ( RtlEqualLuid(&pDrt->LogonID, &LogonID) ) {
  1778. #endif
  1779. if (skipNum > 0) {
  1780. skipNum--;
  1781. } else {
  1782. //
  1783. // Report devices for this session only
  1784. //
  1785. Status = DfsGetResourceFromDevlessRoot(
  1786. Irp,
  1787. pDrt,
  1788. &providerName,
  1789. OutputBuffer,
  1790. buf,
  1791. &remLen,
  1792. &ResourceSize);
  1793. if (!NT_SUCCESS(Status))
  1794. break;
  1795. buf = buf + ResourceSize;
  1796. count++;
  1797. }
  1798. }
  1799. }
  1800. //
  1801. // Next, get the Device connections
  1802. //
  1803. if (NT_SUCCESS(Status)) {
  1804. for (Link = DfsData.VcbQueue.Flink;
  1805. Link != &DfsData.VcbQueue;
  1806. Link = Link->Flink ) {
  1807. pVcb = CONTAINING_RECORD( Link, DFS_VCB, VcbLinks );
  1808. #ifdef TERMSRV
  1809. if( (pVcb->LogicalRoot.Length == sizeof(WCHAR)) &&
  1810. (SessionID != INVALID_SESSIONID) &&
  1811. (SessionID == pVcb->SessionID) &&
  1812. RtlEqualLuid(&pVcb->LogonID, &LogonID) ) {
  1813. #else // TERMSRV
  1814. if ((pVcb->LogicalRoot.Length == sizeof(WCHAR)) &&
  1815. RtlEqualLuid(&pVcb->LogonID, &LogonID) ) {
  1816. #endif
  1817. if (skipNum > 0) {
  1818. skipNum--;
  1819. } else {
  1820. Status = DfsGetResourceFromVcb(
  1821. Irp,
  1822. pVcb,
  1823. &providerName,
  1824. OutputBuffer,
  1825. buf,
  1826. &remLen,
  1827. &ResourceSize);
  1828. if (!NT_SUCCESS(Status))
  1829. break;
  1830. buf = buf + ResourceSize;
  1831. count++;
  1832. }
  1833. }
  1834. }
  1835. }
  1836. if (!NT_SUCCESS(Status)) {
  1837. //
  1838. // Now if we did not get atleast one in, then we need to return
  1839. // required size which is in remLen.
  1840. //
  1841. if (count == 0) {
  1842. // the + sizeof(ULONG) is for cnt size
  1843. RETURN_BUFFER_SIZE( remLen + sizeof(ULONG), Status );
  1844. DfsDbgTrace(0, Dbg, "Output buffer too small\n", 0);
  1845. } else if (Status == STATUS_BUFFER_OVERFLOW) {
  1846. *retCnt = count;
  1847. Irp->IoStatus.Information = OutputBufferLength;
  1848. DfsDbgTrace(0, Dbg, "Could not fill in all RESOURCE structs \n", 0);
  1849. } else {
  1850. //
  1851. // Dont know why we should get any other error code.
  1852. //
  1853. ASSERT(Status == STATUS_BUFFER_OVERFLOW);
  1854. }
  1855. } else {
  1856. //
  1857. // Everything went smoothly.
  1858. //
  1859. DfsDbgTrace(0, Dbg, "Succeeded in getting all Resources \n", 0);
  1860. *retCnt = count;
  1861. Irp->IoStatus.Information = OutputBufferLength;
  1862. }
  1863. if (providerNameAllocated == TRUE) {
  1864. ExFreePool(providerName.Buffer);
  1865. }
  1866. ExReleaseResourceLite(&DfsData.Resource);
  1867. DfsCompleteRequest( IrpContext, Irp, Status );
  1868. DfsDbgTrace(-1,Dbg,"DfsFsctrlGetConnectedResources: Exit->%08lx\n", ULongToPtr(Status) );
  1869. return Status;
  1870. }
  1871. //+----------------------------------------------------------------------------
  1872. //
  1873. // Function: DfsFsctrlDefineRootCredentials
  1874. //
  1875. // Synopsis: Creates a new logical root, a new user credential record, or
  1876. // both.
  1877. //
  1878. // Arguments:
  1879. //
  1880. // Returns:
  1881. //
  1882. //-----------------------------------------------------------------------------
  1883. NTSTATUS
  1884. DfsFsctrlDefineRootCredentials(
  1885. IN PIRP_CONTEXT IrpContext,
  1886. IN PIRP Irp,
  1887. IN PUCHAR InputBuffer,
  1888. IN ULONG InputBufferLength)
  1889. {
  1890. NTSTATUS status = STATUS_SUCCESS;
  1891. PFILE_DFS_DEF_ROOT_CREDENTIALS def;
  1892. PDFS_CREDENTIALS creds = NULL;
  1893. ULONG prefixIndex;
  1894. UNICODE_STRING prefix;
  1895. BOOLEAN deviceless = FALSE;
  1896. LUID LogonID;
  1897. #ifdef TERMSRV
  1898. ULONG SessionID;
  1899. #endif
  1900. //
  1901. // We must do this from the FSP because IoCreateDevice will fail if
  1902. // PreviousMode != KernelMode
  1903. //
  1904. STD_FSCTRL_PROLOGUE(DfsFsctrlDefineRootCredentials, TRUE, FALSE, FALSE);
  1905. //
  1906. // Validate our parameters, best we can.
  1907. //
  1908. if (InputBufferLength < sizeof(FILE_DFS_DEF_ROOT_CREDENTIALS)) {
  1909. status = STATUS_INVALID_PARAMETER;
  1910. DfsCompleteRequest( IrpContext, Irp, status );
  1911. DfsDbgTrace(-1,Dbg,"DfsFsctrlDefineRootCredentials: Exit->%08lx\n", ULongToPtr(status) );
  1912. return status;
  1913. }
  1914. def = (PFILE_DFS_DEF_ROOT_CREDENTIALS) InputBuffer;
  1915. prefixIndex = (def->DomainNameLen +
  1916. def->UserNameLen +
  1917. def->PasswordLen +
  1918. def->ServerNameLen +
  1919. def->ShareNameLen) / sizeof(WCHAR);
  1920. prefix.MaximumLength = prefix.Length = def->RootPrefixLen;
  1921. prefix.Buffer = &def->Buffer[ prefixIndex ];
  1922. if (
  1923. !UNICODESTRING_IS_VALID(prefix, InputBuffer, InputBufferLength)
  1924. ||
  1925. (prefix.Length < (4 * sizeof(WCHAR)))
  1926. ||
  1927. (prefix.Buffer[0] != UNICODE_PATH_SEP)
  1928. ) {
  1929. status = STATUS_INVALID_PARAMETER;
  1930. DfsCompleteRequest( IrpContext, Irp, status );
  1931. DfsDbgTrace(-1,Dbg,"DfsFsctrlDefineRootCredentials: Exit->%08lx\n", ULongToPtr(status) );
  1932. return status;
  1933. }
  1934. deviceless = (BOOLEAN) (def->LogicalRoot[0] == UNICODE_NULL);
  1935. #ifdef TERMSRV
  1936. if (NT_SUCCESS(status)) {
  1937. status = IoGetRequestorSessionId(Irp, &SessionID);
  1938. if (!NT_SUCCESS(status) ) {
  1939. status = STATUS_INVALID_PARAMETER;
  1940. }
  1941. }
  1942. #endif
  1943. //
  1944. // Now get the LogonID.
  1945. //
  1946. if (NT_SUCCESS(status)) {
  1947. status = DfsGetLogonId(&LogonID);
  1948. }
  1949. //
  1950. // First, create the credentials.
  1951. //
  1952. if (NT_SUCCESS(status)) {
  1953. #ifdef TERMSRV
  1954. status = DfsCreateCredentials(def,
  1955. InputBufferLength,
  1956. SessionID,
  1957. &LogonID,
  1958. &creds );
  1959. #else // TERMSRV
  1960. status = DfsCreateCredentials(def,
  1961. InputBufferLength,
  1962. &LogonID,
  1963. &creds );
  1964. #endif // TERMSRV
  1965. if (NT_SUCCESS(status)) {
  1966. //
  1967. // Verify the credentials if the username, domainname, or
  1968. // password are not null
  1969. //
  1970. if ((def->DomainNameLen > 0) ||
  1971. (def->UserNameLen > 0) ||
  1972. (def->PasswordLen > 0)) {
  1973. status = DfsVerifyCredentials( &prefix, creds );
  1974. }
  1975. if (NT_SUCCESS(status)) {
  1976. PDFS_CREDENTIALS existingCreds;
  1977. status = DfsInsertCredentials( &creds, deviceless );
  1978. if (status == STATUS_OBJECT_NAME_COLLISION) {
  1979. status = STATUS_SUCCESS;
  1980. }
  1981. }
  1982. if (!NT_SUCCESS(status))
  1983. DfsFreeCredentials( creds );
  1984. }
  1985. }
  1986. //
  1987. // Next, try and create the logical root, if specified
  1988. //
  1989. if (NT_SUCCESS(status)) {
  1990. BOOLEAN pktLocked;
  1991. PktAcquireExclusive( TRUE, &pktLocked );
  1992. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  1993. if (!deviceless) {
  1994. USHORT VcbStateFlags = 0;
  1995. if (def->CSCAgentCreate) {
  1996. VcbStateFlags |= VCB_STATE_CSCAGENT_VOLUME;
  1997. }
  1998. #ifdef TERMSRV
  1999. status = DfsInitializeLogicalRoot(
  2000. (PWSTR) def->LogicalRoot,
  2001. &prefix,
  2002. creds,
  2003. VcbStateFlags,
  2004. SessionID,
  2005. &LogonID );
  2006. #else // TERMSRV
  2007. status = DfsInitializeLogicalRoot(
  2008. (PWSTR) def->LogicalRoot,
  2009. &prefix,
  2010. creds,
  2011. VcbStateFlags,
  2012. &LogonID );
  2013. #endif // TERMSRV
  2014. }
  2015. else {
  2016. #ifdef TERMSRV
  2017. status = DfsInitializeDevlessRoot(
  2018. &prefix,
  2019. creds,
  2020. SessionID,
  2021. &LogonID );
  2022. #else // TERMSRV
  2023. status = DfsInitializeDevlessRoot(
  2024. &prefix,
  2025. creds,
  2026. &LogonID );
  2027. #endif // TERMSRV
  2028. }
  2029. if (status != STATUS_SUCCESS) {
  2030. DfsDeleteCredentials( creds );
  2031. }
  2032. ExReleaseResourceLite(&DfsData.Resource);
  2033. PktRelease();
  2034. }
  2035. DfsCompleteRequest( IrpContext, Irp, status );
  2036. DfsDbgTrace(-1,Dbg,"DfsFsctrlDefineRootCredentials: Exit->%08lx\n", ULongToPtr(status) );
  2037. return status;
  2038. }
  2039. //+----------------------------------------------------------------------------
  2040. //
  2041. // Function: DfsFsctrlGetServerName
  2042. //
  2043. // Synopsis: Given a Prefix in Dfs namespace it gets a server name for
  2044. // it.
  2045. //
  2046. // Arguments:
  2047. //
  2048. // Returns:
  2049. //
  2050. //-----------------------------------------------------------------------------
  2051. NTSTATUS
  2052. DfsFsctrlGetServerName(
  2053. IN PIRP_CONTEXT IrpContext,
  2054. IN PIRP Irp,
  2055. IN PUCHAR InputBuffer,
  2056. IN ULONG InputBufferLength,
  2057. IN PUCHAR OutputBuffer,
  2058. IN ULONG OutputBufferLength)
  2059. {
  2060. NTSTATUS status = STATUS_SUCCESS;
  2061. PDFS_PKT pkt;
  2062. PDFS_PKT_ENTRY pEntry;
  2063. UNICODE_STRING ustrPrefix, RemainingPath;
  2064. PWCHAR pwch;
  2065. PDFS_SERVICE pService;
  2066. ULONG cbSizeRequired = 0;
  2067. BOOLEAN pktLocked;
  2068. PWCHAR wCp = (PWCHAR) InputBuffer;
  2069. ULONG i;
  2070. STD_FSCTRL_PROLOGUE(DfsFsctrlGetServerName, TRUE, TRUE, FALSE);
  2071. if (InputBufferLength < 2 * sizeof(WCHAR)
  2072. ||
  2073. wCp[0] != UNICODE_PATH_SEP
  2074. ) {
  2075. status = STATUS_INVALID_PARAMETER;
  2076. DfsCompleteRequest( IrpContext, Irp, status );
  2077. return status;
  2078. }
  2079. ustrPrefix.Length = (USHORT) InputBufferLength;
  2080. ustrPrefix.MaximumLength = (USHORT) InputBufferLength;
  2081. ustrPrefix.Buffer = (PWCHAR) InputBuffer;
  2082. if (ustrPrefix.Buffer[0] == UNICODE_PATH_SEP &&
  2083. ustrPrefix.Buffer[1] == UNICODE_PATH_SEP) {
  2084. ustrPrefix.Buffer++;
  2085. ustrPrefix.Length -= sizeof(WCHAR);
  2086. }
  2087. if (ustrPrefix.Buffer[ ustrPrefix.Length/sizeof(WCHAR) - 1]
  2088. == UNICODE_NULL) {
  2089. ustrPrefix.Length -= sizeof(WCHAR);
  2090. }
  2091. pkt = _GetPkt();
  2092. PktAcquireExclusive(TRUE, &pktLocked);
  2093. pEntry = PktLookupEntryByPrefix(pkt,
  2094. &ustrPrefix,
  2095. &RemainingPath);
  2096. if (pEntry == NULL) {
  2097. status = STATUS_OBJECT_NAME_NOT_FOUND;
  2098. } else {
  2099. if (pEntry->ActiveService != NULL) {
  2100. pService = pEntry->ActiveService;
  2101. } else if (pEntry->Info.ServiceCount == 0) {
  2102. pService = NULL;
  2103. } else {
  2104. pService = pEntry->Info.ServiceList;
  2105. }
  2106. if (pService != NULL) {
  2107. cbSizeRequired = sizeof(UNICODE_PATH_SEP) +
  2108. pService->Address.Length +
  2109. sizeof(UNICODE_PATH_SEP) +
  2110. RemainingPath.Length +
  2111. sizeof(UNICODE_NULL);
  2112. if (OutputBufferLength < cbSizeRequired) {
  2113. RETURN_BUFFER_SIZE(cbSizeRequired, status);
  2114. } else {
  2115. PWCHAR pwszPath, pwszAddr, pwszRemainingPath;
  2116. ULONG cwAddr;
  2117. //
  2118. // The code below is simply constructing a string of the form
  2119. // \<pService->Address>\RemainingPath. However, due to the
  2120. // fact that InputBuffer and OutputBuffer actually point to
  2121. // the same piece of memory, RemainingPath.Buffer points into
  2122. // a spot in the *OUTPUT* buffer. Hence, we first have to
  2123. // move the RemainingPath to its proper place in the
  2124. // OutputBuffer, and then stuff in the pService->Address,
  2125. // instead of the much more natural method of constructing the
  2126. // string left to right.
  2127. //
  2128. pwszPath = (PWCHAR) OutputBuffer;
  2129. pwszAddr = pService->Address.Buffer;
  2130. cwAddr = pService->Address.Length / sizeof(WCHAR);
  2131. if (cwAddr > 0 && pwszAddr[cwAddr-1] == UNICODE_PATH_SEP)
  2132. cwAddr--;
  2133. pwszRemainingPath = &pwszPath[ 1 + cwAddr ];
  2134. if (RemainingPath.Length > 0) {
  2135. if (RemainingPath.Buffer[0] != UNICODE_PATH_SEP) {
  2136. pwszRemainingPath++;
  2137. }
  2138. RtlMoveMemory(
  2139. pwszRemainingPath,
  2140. RemainingPath.Buffer,
  2141. RemainingPath.Length);
  2142. pwszRemainingPath[-1] = UNICODE_PATH_SEP;
  2143. }
  2144. pwszRemainingPath[RemainingPath.Length/sizeof(WCHAR)] = UNICODE_NULL;
  2145. RtlCopyMemory(
  2146. &pwszPath[1],
  2147. pwszAddr,
  2148. cwAddr * sizeof(WCHAR));
  2149. pwszPath[0] = UNICODE_PATH_SEP;
  2150. Irp->IoStatus.Information = cbSizeRequired;
  2151. }
  2152. } else {
  2153. status = STATUS_OBJECT_NAME_NOT_FOUND;
  2154. }
  2155. }
  2156. PktRelease();
  2157. DfsCompleteRequest( IrpContext, Irp, status );
  2158. DfsDbgTrace(-1,Dbg,"DfsFsctrlGetServerName: Exit->%08lx\n", ULongToPtr(status) );
  2159. return status;
  2160. }
  2161. //+----------------------------------------------------------------------------
  2162. //
  2163. // Function: DfsFsctrlGetPktEntryState
  2164. //
  2165. // Synopsis: Given a Prefix in Dfs namespace it gets a list of servers
  2166. // for it. (DFS_INFO_X calls).
  2167. //
  2168. // Arguments:
  2169. //
  2170. // Returns:
  2171. //
  2172. //-----------------------------------------------------------------------------
  2173. NTSTATUS
  2174. DfsFsctrlGetPktEntryState(
  2175. IN PIRP_CONTEXT IrpContext,
  2176. IN PIRP Irp,
  2177. IN PUCHAR InputBuffer,
  2178. IN ULONG InputBufferLength,
  2179. IN PUCHAR OutputBuffer,
  2180. IN ULONG OutputBufferLength)
  2181. {
  2182. NTSTATUS NtStatus = STATUS_SUCCESS;
  2183. PDFS_GET_PKT_ENTRY_STATE_ARG arg;
  2184. PDFS_SERVICE pService;
  2185. UNICODE_STRING DfsEntryPath;
  2186. UNICODE_STRING ServerName;
  2187. UNICODE_STRING ShareName;
  2188. UNICODE_STRING remPath;
  2189. PDFS_PKT pkt;
  2190. PDFS_PKT_ENTRY pktEntry;
  2191. BOOLEAN pktLocked = FALSE;
  2192. ULONG cbOutBuffer;
  2193. ULONG Level;
  2194. PCHAR cp;
  2195. PUCHAR InBuffer = NULL;
  2196. DfsDbgTrace(+1, Dbg, "DfsFsctrlGetPktEntryState\n", 0);
  2197. STD_FSCTRL_PROLOGUE(DfsFsctrlGetPktEntryState, TRUE, TRUE, FALSE);
  2198. if (InputBufferLength < sizeof(DFS_GET_PKT_ENTRY_STATE_ARG)) {
  2199. DfsDbgTrace( 0, Dbg, "Input buffer too small\n", 0);
  2200. NtStatus = STATUS_INVALID_PARAMETER;
  2201. Irp->IoStatus.Information = 0;
  2202. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  2203. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetPktEntryState -> %08lx\n", ULongToPtr(NtStatus) );
  2204. return( NtStatus );
  2205. }
  2206. //
  2207. // Dup the buffer - we're going to construct UNICODE strings that point into
  2208. // the buffer, and the buffer is also the output buffer, so we don't want to
  2209. // overwrite those strings as we build the output buffer.
  2210. //
  2211. InBuffer = ExAllocatePoolWithTag(PagedPool, InputBufferLength, ' puM');
  2212. if (InBuffer) {
  2213. try {
  2214. RtlCopyMemory(InBuffer, InputBuffer, InputBufferLength);
  2215. } except (EXCEPTION_EXECUTE_HANDLER) {
  2216. NtStatus = GetExceptionCode();
  2217. }
  2218. } else {
  2219. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2220. }
  2221. //
  2222. // Check args that don't need to be unmarshalled.
  2223. //
  2224. if (NT_SUCCESS(NtStatus)) {
  2225. arg = (PDFS_GET_PKT_ENTRY_STATE_ARG) InBuffer;
  2226. if (!(arg->Level >= 1 && arg->Level <= 4) ||
  2227. (arg->ServerNameLen == 0 && arg->ShareNameLen != 0)) {
  2228. NtStatus = STATUS_INVALID_PARAMETER;
  2229. }
  2230. }
  2231. //
  2232. // Unmarshall the strings
  2233. //
  2234. if (NT_SUCCESS(NtStatus)) {
  2235. try {
  2236. Level = arg->Level;
  2237. DfsEntryPath.Length = DfsEntryPath.MaximumLength = arg->DfsEntryPathLen;
  2238. DfsEntryPath.Buffer = arg->Buffer;
  2239. DfsDbgTrace( 0, Dbg, "\tDfsName=%wZ\n", &DfsEntryPath);
  2240. RtlInitUnicodeString(&ServerName, NULL);
  2241. RtlInitUnicodeString(&ShareName, NULL);
  2242. if (arg->ServerNameLen) {
  2243. cp = (PCHAR)arg->Buffer + arg->DfsEntryPathLen;
  2244. ServerName.Buffer = (WCHAR *)cp;
  2245. ServerName.Length = ServerName.MaximumLength = arg->ServerNameLen;
  2246. cp += arg->ServerNameLen;
  2247. }
  2248. if (arg->ShareNameLen) {
  2249. ShareName.Buffer = (WCHAR *)cp;
  2250. ShareName.Length = ShareName.MaximumLength = arg->ShareNameLen;
  2251. DfsDbgTrace( 0, Dbg, "\tServerName=%wZ\n", &ServerName);
  2252. DfsDbgTrace( 0, Dbg, "\tShareName=%wZ\n", &ShareName);
  2253. }
  2254. DfsDbgTrace( 0, Dbg, "\tLevel=%d\n", ULongToPtr(arg->Level) );
  2255. DfsDbgTrace( 0, Dbg, "\tOutputBufferLength=0x%x\n", ULongToPtr(OutputBufferLength) );
  2256. } except (EXCEPTION_EXECUTE_HANDLER) {
  2257. NtStatus = GetExceptionCode();
  2258. }
  2259. }
  2260. if (NT_SUCCESS(NtStatus)) {
  2261. //
  2262. // Do a prefix lookup. If we find an entry, it's a Dfs path
  2263. //
  2264. pkt = _GetPkt();
  2265. PktAcquireShared( TRUE, &pktLocked );
  2266. pktEntry = PktLookupEntryByPrefix( pkt, &DfsEntryPath, &remPath );
  2267. if (pktEntry != NULL) {
  2268. DfsDbgTrace( 0, Dbg, "\tFound pkt entry %08lx\n", pktEntry);
  2269. //
  2270. // Calculate the needed output buffer size
  2271. //
  2272. NtStatus = DfsGetEntryStateSize(Level,
  2273. &ServerName,
  2274. &ShareName,
  2275. pktEntry,
  2276. &cbOutBuffer);
  2277. //
  2278. // Let user know if it's too small
  2279. //
  2280. if (OutputBufferLength < cbOutBuffer) {
  2281. RETURN_BUFFER_SIZE(cbOutBuffer, NtStatus);
  2282. }
  2283. } else {
  2284. NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  2285. }
  2286. }
  2287. if (NtStatus == STATUS_SUCCESS) {
  2288. //
  2289. // Args are ok, and it fits - marshall the data
  2290. //
  2291. NtStatus = DfsGetEntryStateMarshall(Level,
  2292. &ServerName,
  2293. &ShareName,
  2294. pktEntry,
  2295. OutputBuffer,
  2296. cbOutBuffer);
  2297. Irp->IoStatus.Information = cbOutBuffer;
  2298. }
  2299. //
  2300. // Release any locks taken, and free any memory allocated.
  2301. //
  2302. if (pktLocked) {
  2303. PktRelease();
  2304. }
  2305. if (InBuffer) {
  2306. ExFreePool(InBuffer);
  2307. }
  2308. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  2309. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetPktEntryState -> %08lx\n", ULongToPtr(NtStatus) );
  2310. return( NtStatus );
  2311. }
  2312. //+----------------------------------------------------------------------------
  2313. //
  2314. // Function: DfsGetEntryStateSize
  2315. //
  2316. // Synopsis: Helper routine for DfsFsctrlGetPktEntryState
  2317. // Calculates output buffer size.
  2318. //
  2319. // Arguments:
  2320. //
  2321. // Returns:
  2322. //
  2323. //-----------------------------------------------------------------------------
  2324. NTSTATUS
  2325. DfsGetEntryStateSize(
  2326. ULONG Level,
  2327. PUNICODE_STRING ServerName,
  2328. PUNICODE_STRING ShareName,
  2329. PDFS_PKT_ENTRY pktEntry,
  2330. PULONG pcbOutBuffer)
  2331. {
  2332. UNICODE_STRING Server;
  2333. UNICODE_STRING Share;
  2334. PDFS_SERVICE pService;
  2335. ULONG Size;
  2336. ULONG NumServices;
  2337. ULONG i;
  2338. DfsDbgTrace(+1, Dbg, "DfsGetEntryStateSize\n", 0);
  2339. //
  2340. // Calculate the needed output buffer size
  2341. //
  2342. Size = pktEntry->Id.Prefix.Length + // Len of EntryPath
  2343. sizeof(WCHAR); // ... with null
  2344. switch (Level) {
  2345. case 4:
  2346. Size += sizeof(DFS_INFO_4);
  2347. break;
  2348. case 3:
  2349. Size += sizeof(DFS_INFO_3);
  2350. break;
  2351. case 2:
  2352. Size += sizeof(DFS_INFO_2);
  2353. break;
  2354. case 1:
  2355. Size += sizeof(DFS_INFO_1);
  2356. break;
  2357. }
  2358. //
  2359. // For Level 3 & 4, add the size of any storages that
  2360. // match the ServerName/ShareName passed in.
  2361. //
  2362. NumServices = pktEntry->Info.ServiceCount;
  2363. if (Level == 3 || Level == 4) {
  2364. for (i = 0; i < NumServices; i++) {
  2365. pService = &pktEntry->Info.ServiceList[i];
  2366. DfsDbgTrace( 0, Dbg, "Examining %wZ\n", &pService->Address);
  2367. //
  2368. // Tease apart the address (of form \Server\Share into Server and Share
  2369. //
  2370. RemoveLastComponent(&pService->Address, &Server);
  2371. //
  2372. // Remove leading & trailing '\'
  2373. //
  2374. Server.Length -= 2* sizeof(WCHAR);
  2375. Server.MaximumLength -= 2* sizeof(WCHAR);
  2376. Server.Buffer++;
  2377. //
  2378. // And figure out Share
  2379. //
  2380. Share.Buffer = Server.Buffer + (Server.Length / sizeof(WCHAR)) + 1;
  2381. Share.Length = pService->Address.Length - (Server.Length + 2 * sizeof(WCHAR));
  2382. Share.MaximumLength = Share.Length;
  2383. DfsDbgTrace( 0, Dbg, "DfsGetEntryStateSize: Server=%wZ\n", &Server);
  2384. DfsDbgTrace( 0, Dbg, " Share=%wZ\n", &Share);
  2385. if ((ServerName->Length && RtlCompareUnicodeString(ServerName, &Server, TRUE))
  2386. ||
  2387. (ShareName->Length && RtlCompareUnicodeString(ShareName, &Share, TRUE))) {
  2388. continue;
  2389. }
  2390. Size += sizeof(DFS_STORAGE_INFO) +
  2391. pService->Address.Length +
  2392. sizeof(WCHAR);
  2393. }
  2394. }
  2395. DfsDbgTrace( 0, Dbg, "Size=0x%x\n", ULongToPtr(Size) );
  2396. *pcbOutBuffer = Size;
  2397. DfsDbgTrace(-1, Dbg, "DfsGetEntryStateSize -> %08lx\n", STATUS_SUCCESS );
  2398. return (STATUS_SUCCESS);
  2399. }
  2400. //+----------------------------------------------------------------------------
  2401. //
  2402. // Function: DfsGetEntryStateMarshall
  2403. //
  2404. // Synopsis: Helper routine for DfsFsctrlGetPktEntryState
  2405. // Marshalls the output buffer
  2406. //
  2407. // Arguments:
  2408. //
  2409. // Returns:
  2410. //
  2411. //-----------------------------------------------------------------------------
  2412. NTSTATUS
  2413. DfsGetEntryStateMarshall(
  2414. ULONG Level,
  2415. PUNICODE_STRING ServerName,
  2416. PUNICODE_STRING ShareName,
  2417. PDFS_PKT_ENTRY pktEntry,
  2418. PBYTE OutputBuffer,
  2419. ULONG cbOutBuffer)
  2420. {
  2421. NTSTATUS NtStatus = STATUS_SUCCESS;
  2422. ULONG iStr;
  2423. ULONG i;
  2424. PDFS_INFO_4 pDfsInfo4;
  2425. PDFS_INFO_3 pDfsInfo3;
  2426. PDFS_STORAGE_INFO pDfsStorageInfo;
  2427. PDFS_SERVICE pService;
  2428. ULONG NumStorageInfo;
  2429. UNICODE_STRING Server;
  2430. UNICODE_STRING Share;
  2431. DfsDbgTrace(+1, Dbg, "DfsGetEntryStateMarshall\n", 0);
  2432. try {
  2433. RtlZeroMemory(OutputBuffer, cbOutBuffer);
  2434. pDfsInfo4 = (PDFS_INFO_4) OutputBuffer;
  2435. pDfsInfo3 = (PDFS_INFO_3) OutputBuffer;
  2436. //
  2437. // iStr will be used to place unicode strings into the buffer
  2438. // starting at the end, working backwards
  2439. //
  2440. iStr = cbOutBuffer;
  2441. //
  2442. // LPWSTR's are stored as offsets into the buffer - the NetDfsXXX calls
  2443. // fix them up.
  2444. //
  2445. iStr -= pktEntry->Id.Prefix.Length + sizeof(WCHAR);
  2446. RtlCopyMemory(&OutputBuffer[iStr],
  2447. pktEntry->Id.Prefix.Buffer,
  2448. pktEntry->Id.Prefix.Length);
  2449. //
  2450. // This could could be much more clever, as the DFS_INFO_X structs
  2451. // are similar, but I've gone for clarity over cleverness. (jharper)
  2452. //
  2453. switch (Level) {
  2454. case 4:
  2455. pDfsInfo4->EntryPath = (WCHAR*) ULongToPtr(iStr);
  2456. pDfsInfo4->Comment = NULL;
  2457. pDfsInfo4->State = DFS_VOLUME_STATE_OK;
  2458. pDfsInfo4->Timeout = pktEntry->TimeToLive;
  2459. pDfsInfo4->Guid = pktEntry->Id.Uid;
  2460. pDfsInfo4->NumberOfStorages = pktEntry->Info.ServiceCount;
  2461. pDfsStorageInfo = (PDFS_STORAGE_INFO)(pDfsInfo4 + 1);
  2462. pDfsInfo4->Storage = (PDFS_STORAGE_INFO)((PCHAR)pDfsStorageInfo - OutputBuffer);
  2463. break;
  2464. case 3:
  2465. pDfsInfo3->EntryPath = (WCHAR*) ULongToPtr(iStr);
  2466. pDfsInfo3->Comment = NULL;
  2467. pDfsInfo3->State = DFS_VOLUME_STATE_OK;
  2468. pDfsInfo3->NumberOfStorages = pktEntry->Info.ServiceCount;
  2469. pDfsStorageInfo = (PDFS_STORAGE_INFO)(pDfsInfo3 + 1);
  2470. pDfsInfo3->Storage = (PDFS_STORAGE_INFO)((PCHAR)pDfsStorageInfo - OutputBuffer);
  2471. break;
  2472. case 2:
  2473. pDfsInfo3->EntryPath = (WCHAR*) ULongToPtr(iStr);
  2474. pDfsInfo3->Comment = NULL;
  2475. pDfsInfo3->State = DFS_VOLUME_STATE_OK;
  2476. pDfsInfo3->NumberOfStorages = pktEntry->Info.ServiceCount;
  2477. break;
  2478. case 1:
  2479. pDfsInfo3->EntryPath = (WCHAR*) ULongToPtr(iStr);
  2480. break;
  2481. }
  2482. //
  2483. // For Level 3 & 4 we now walk the services and load State,
  2484. // ServerName and ShareName. With the complication that if the user
  2485. // specified ServerName and/or ShareName, we must match on those, too.
  2486. //
  2487. if (Level == 3 || Level == 4) {
  2488. NumStorageInfo = 0;
  2489. for (i = 0; i < pktEntry->Info.ServiceCount; i++) {
  2490. LPWSTR wp;
  2491. UNICODE_STRING uStr;
  2492. USHORT m, n;
  2493. pService = &pktEntry->Info.ServiceList[i];
  2494. DfsDbgTrace( 0, Dbg, "Examining %wZ\n", &pService->Address);
  2495. //
  2496. // We want to work with the \Server\Share part of the address only,
  2497. // so count up to 3 backslashes, then stop.
  2498. //
  2499. uStr = pService->Address;
  2500. for (m = n = 0; m < uStr.Length/sizeof(WCHAR) && n < 3; m++) {
  2501. if (uStr.Buffer[m] == UNICODE_PATH_SEP) {
  2502. n++;
  2503. }
  2504. }
  2505. uStr.Length = (n >= 3) ? (m-1) * sizeof(WCHAR) : m * sizeof(WCHAR);
  2506. //
  2507. // Tease apart the address (of form \Server\Share) into Server
  2508. // (Handles a dfs-link like \server\share\dir1\dir2)
  2509. //
  2510. RemoveLastComponent(&uStr, &Server);
  2511. //
  2512. // Remove leading & trailing '\'s
  2513. //
  2514. Server.Length -= 2* sizeof(WCHAR);
  2515. Server.MaximumLength = Server.Length;
  2516. Server.Buffer++;
  2517. //
  2518. // And figure out Share (which will be everything after the server)
  2519. //
  2520. Share.Buffer = Server.Buffer + (Server.Length / sizeof(WCHAR)) + 1;
  2521. Share.Length = pService->Address.Length - (Server.Length + 2 * sizeof(WCHAR));
  2522. Share.MaximumLength = Share.Length;
  2523. DfsDbgTrace( 0, Dbg, "DfsGetEntryStateSize: Server=%wZ\n", &Server);
  2524. DfsDbgTrace( 0, Dbg, " Share=%wZ\n", &Share);
  2525. //
  2526. // If ServerName or ShareName are specified, then they must match
  2527. //
  2528. if (
  2529. (ServerName->Length && RtlCompareUnicodeString(ServerName, &Server, TRUE))
  2530. ||
  2531. (ShareName->Length && RtlCompareUnicodeString(ShareName, &Share, TRUE))
  2532. ) {
  2533. continue;
  2534. }
  2535. //
  2536. // Online or Offline?
  2537. //
  2538. if (pService->Type & DFS_SERVICE_TYPE_OFFLINE) {
  2539. pDfsStorageInfo->State = DFS_STORAGE_STATE_OFFLINE;
  2540. } else {
  2541. pDfsStorageInfo->State = DFS_STORAGE_STATE_ONLINE;
  2542. }
  2543. //
  2544. // Active?
  2545. //
  2546. if (pService == pktEntry->ActiveService) {
  2547. pDfsStorageInfo->State |= DFS_STORAGE_STATE_ACTIVE;
  2548. }
  2549. //
  2550. // Sever name
  2551. //
  2552. iStr -= Server.Length + sizeof(WCHAR);
  2553. RtlCopyMemory(&OutputBuffer[iStr],
  2554. Server.Buffer,
  2555. Server.Length);
  2556. pDfsStorageInfo->ServerName = (WCHAR*) ULongToPtr(iStr);
  2557. //
  2558. // Share name
  2559. //
  2560. iStr -= Share.Length + sizeof(WCHAR);
  2561. RtlCopyMemory(&OutputBuffer[iStr],
  2562. Share.Buffer,
  2563. Share.Length);
  2564. pDfsStorageInfo->ShareName = (WCHAR*) ULongToPtr(iStr);
  2565. pDfsStorageInfo++;
  2566. NumStorageInfo++;
  2567. }
  2568. //
  2569. // Finally, adjust the # entries we loaded into the buffer
  2570. //
  2571. switch (Level) {
  2572. case 4:
  2573. pDfsInfo4->NumberOfStorages = NumStorageInfo;
  2574. break;
  2575. case 3:
  2576. pDfsInfo3->NumberOfStorages = NumStorageInfo;
  2577. break;
  2578. }
  2579. }
  2580. } except (EXCEPTION_EXECUTE_HANDLER) {
  2581. NtStatus = STATUS_SUCCESS; // Per Arg Validation Spec
  2582. }
  2583. DfsDbgTrace(-1, Dbg, "DfsGetEntryStateMarshall -> %08lx\n", ULongToPtr(NtStatus) );
  2584. return (NtStatus);
  2585. }
  2586. //+----------------------------------------------------------------------------
  2587. //
  2588. // Function: DfsFsctrlSetPktEntryState
  2589. //
  2590. // Synopsis: Given a Prefix in Dfs namespace it sets the Timeout or the State
  2591. // of an alternate. (DFS_INFO_X calls).
  2592. //
  2593. // Arguments:
  2594. //
  2595. // Returns:
  2596. //
  2597. //-----------------------------------------------------------------------------
  2598. NTSTATUS
  2599. DfsFsctrlSetPktEntryState(
  2600. IN PIRP_CONTEXT IrpContext,
  2601. IN PIRP Irp,
  2602. IN PUCHAR InputBuffer,
  2603. IN ULONG InputBufferLength)
  2604. {
  2605. NTSTATUS NtStatus = STATUS_SUCCESS;
  2606. PDFS_SET_PKT_ENTRY_STATE_ARG arg;
  2607. PDFS_SERVICE pService;
  2608. UNICODE_STRING DfsEntryPath;
  2609. UNICODE_STRING ServerName;
  2610. UNICODE_STRING ShareName;
  2611. UNICODE_STRING remPath;
  2612. PDFS_PKT pkt;
  2613. PDFS_PKT_ENTRY pktEntry;
  2614. BOOLEAN pktLocked = FALSE;
  2615. ULONG cbOutBuffer;
  2616. ULONG Level;
  2617. ULONG State;
  2618. ULONG Timeout;
  2619. PCHAR cp;
  2620. DfsDbgTrace(+1, Dbg, "DfsFsctrlSetPktEntryState\n", 0);
  2621. STD_FSCTRL_PROLOGUE(DfsFsctrlSetPktEntryState, TRUE, FALSE, FALSE);
  2622. if (InputBufferLength < sizeof(DFS_SET_PKT_ENTRY_STATE_ARG)) {
  2623. DfsDbgTrace( 0, Dbg, "Input buffer too small\n", 0);
  2624. NtStatus = STATUS_INVALID_PARAMETER;
  2625. Irp->IoStatus.Information = 0;
  2626. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  2627. DfsDbgTrace(-1, Dbg, "DfsFsctrlSetPktEntryState exit 0x%x\n", ULongToPtr(NtStatus) );
  2628. return( NtStatus );
  2629. }
  2630. //
  2631. // Check args that don't need to be unmarshalled.
  2632. //
  2633. if (NT_SUCCESS(NtStatus)) {
  2634. arg = (PDFS_SET_PKT_ENTRY_STATE_ARG) InputBuffer;
  2635. Level = arg->Level;
  2636. //
  2637. // Check for valid Level
  2638. //
  2639. // Level 101 requires that both be present
  2640. // Level 102 ignores ServerName and ShareName
  2641. //
  2642. switch (Level) {
  2643. case 101:
  2644. State = arg->State;
  2645. if (State != DFS_STORAGE_STATE_ACTIVE ||
  2646. arg->ServerNameLen == 0 ||
  2647. arg->ShareNameLen == 0) {
  2648. NtStatus = STATUS_INVALID_PARAMETER;
  2649. }
  2650. break;
  2651. case 102:
  2652. Timeout = arg->Timeout;
  2653. break;
  2654. default:
  2655. NtStatus = STATUS_INVALID_PARAMETER;
  2656. }
  2657. }
  2658. //
  2659. // Unmarshall the strings
  2660. //
  2661. if (NT_SUCCESS(NtStatus)) {
  2662. try {
  2663. DfsEntryPath.Length = DfsEntryPath.MaximumLength = arg->DfsEntryPathLen;
  2664. DfsEntryPath.Buffer = arg->Buffer;
  2665. DfsDbgTrace( 0, Dbg, "\tDfsName=%wZ\n", &DfsEntryPath);
  2666. RtlInitUnicodeString(&ServerName, NULL);
  2667. RtlInitUnicodeString(&ShareName, NULL);
  2668. if (arg->ServerNameLen) {
  2669. cp = (PCHAR)arg->Buffer + arg->DfsEntryPathLen;
  2670. ServerName.Buffer = (WCHAR *)cp;
  2671. ServerName.Length = ServerName.MaximumLength = arg->ServerNameLen;
  2672. DfsDbgTrace( 0, Dbg, "\tServerName=%wZ\n", &ServerName);
  2673. }
  2674. if (arg->ShareNameLen) {
  2675. cp = (PCHAR)arg->Buffer + arg->DfsEntryPathLen + arg->ServerNameLen;
  2676. ShareName.Buffer = (WCHAR *)cp;
  2677. ShareName.Length = ShareName.MaximumLength = arg->ShareNameLen;
  2678. DfsDbgTrace( 0, Dbg, "\tShareName=%wZ\n", &ShareName);
  2679. }
  2680. DfsDbgTrace( 0, Dbg, "\tLevel=%d\n", ULongToPtr(arg->Level) );
  2681. } except (EXCEPTION_EXECUTE_HANDLER) {
  2682. NtStatus = GetExceptionCode();
  2683. }
  2684. }
  2685. //
  2686. // Do a prefix lookup. If we find an entry, it's a Dfs path
  2687. //
  2688. if (NT_SUCCESS(NtStatus)) {
  2689. pkt = _GetPkt();
  2690. PktAcquireExclusive( TRUE, &pktLocked );
  2691. pktEntry = PktLookupEntryByPrefix( pkt, &DfsEntryPath, &remPath );
  2692. if (pktEntry != NULL) {
  2693. DfsDbgTrace( 0, Dbg, "\tFound pkt entry %08lx\n", pktEntry);
  2694. } else {
  2695. NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  2696. }
  2697. }
  2698. if (NT_SUCCESS(NtStatus)) {
  2699. //
  2700. // Args are ok - do the work
  2701. //
  2702. switch (Level) {
  2703. case 101:
  2704. NtStatus = DfsSetPktEntryActive(
  2705. &ServerName,
  2706. &ShareName,
  2707. pktEntry,
  2708. State);
  2709. break;
  2710. case 102:
  2711. NtStatus = DfsSetPktEntryTimeout(pktEntry,
  2712. Timeout);
  2713. break;
  2714. }
  2715. Irp->IoStatus.Information = 0;
  2716. }
  2717. //
  2718. // Release any locks taken, and free any memory allocated.
  2719. //
  2720. if (pktLocked) {
  2721. PktRelease();
  2722. }
  2723. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  2724. DfsDbgTrace(-1, Dbg, "DfsFsctrlSetPktEntryState exit 0x%x\n", ULongToPtr(NtStatus) );
  2725. return( NtStatus );
  2726. }
  2727. //+-------------------------------------------------------------------------
  2728. //
  2729. // Function: RemoveFirstComponent, public
  2730. //
  2731. // Synopsis: Removes the first component of the string passed.
  2732. //
  2733. // Arguments: [Prefix] -- The prefix whose first component is to be returned.
  2734. // [newPrefix] -- The first component.
  2735. //
  2736. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  2737. //
  2738. // Notes: On return, the newPrefix points to the same memory buffer
  2739. // as Prefix.
  2740. //
  2741. //--------------------------------------------------------------------------
  2742. void
  2743. RemoveFirstComponent(
  2744. PUNICODE_STRING Prefix,
  2745. PUNICODE_STRING newPrefix
  2746. )
  2747. {
  2748. PWCHAR pwch;
  2749. USHORT i=sizeof(WCHAR);
  2750. *newPrefix = *Prefix;
  2751. pwch = newPrefix->Buffer;
  2752. pwch ++; //skip the first slash
  2753. while ((*pwch != UNICODE_PATH_SEP) && ((pwch - newPrefix->Buffer) != Prefix->Length)) {
  2754. i += sizeof(WCHAR);
  2755. pwch++;
  2756. }
  2757. newPrefix->Length = i + sizeof(WCHAR);
  2758. }
  2759. //+----------------------------------------------------------------------------
  2760. //
  2761. // Function: DfsSetPktEntryActive
  2762. //
  2763. // Synopsis: Helper for DfsFsctrlSetPktEntryState
  2764. //
  2765. // Arguments:
  2766. //
  2767. // Returns:
  2768. //
  2769. //-----------------------------------------------------------------------------
  2770. NTSTATUS
  2771. DfsSetPktEntryActive(
  2772. PUNICODE_STRING ServerName,
  2773. PUNICODE_STRING ShareName,
  2774. PDFS_PKT_ENTRY pktEntry,
  2775. DWORD State)
  2776. {
  2777. UNICODE_STRING Server;
  2778. UNICODE_STRING Share;
  2779. PDFS_SERVICE pService;
  2780. NTSTATUS NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  2781. ULONG i;
  2782. DfsDbgTrace(+1, Dbg, "DfsSetPktEntryActive\n", 0);
  2783. for (i = 0; i < pktEntry->Info.ServiceCount && NtStatus != STATUS_SUCCESS; i++) {
  2784. LPWSTR wp;
  2785. pService = &pktEntry->Info.ServiceList[i];
  2786. DfsDbgTrace( 0, Dbg, "Examining %wZ\n", &pService->Address);
  2787. //
  2788. // Tease apart the address (of form \Server\Share) into Server and Share
  2789. //
  2790. RemoveFirstComponent(&pService->Address, &Server);
  2791. //
  2792. // Remove leading & trailing '\'s
  2793. //
  2794. Server.Length -= 2* sizeof(WCHAR);
  2795. Server.MaximumLength = Server.Length;
  2796. Server.Buffer++;
  2797. //
  2798. // And figure out Share
  2799. //
  2800. Share.Buffer = Server.Buffer + (Server.Length / sizeof(WCHAR)) + 1;
  2801. Share.Length = pService->Address.Length - (Server.Length + 2 * sizeof(WCHAR));
  2802. Share.MaximumLength = Share.Length;
  2803. //
  2804. // If ServerName or ShareName don't match, then move on to the next service
  2805. //
  2806. if (
  2807. RtlCompareUnicodeString(ServerName, &Server, TRUE)
  2808. ||
  2809. RtlCompareUnicodeString(ShareName, &Share, TRUE)
  2810. ) {
  2811. continue;
  2812. }
  2813. DfsDbgTrace( 0, Dbg, "DfsSetPktEntryActive: Server=%wZ\n", &Server);
  2814. DfsDbgTrace( 0, Dbg, " Share=%wZ\n", &Share);
  2815. //
  2816. // Make this the active share
  2817. //
  2818. pktEntry->ActiveService = pService;
  2819. NtStatus = STATUS_SUCCESS;
  2820. }
  2821. DfsDbgTrace(-1, Dbg, "DfsSetPktEntryActive -> %08lx\n", ULongToPtr(NtStatus) );
  2822. return NtStatus;
  2823. }
  2824. //+----------------------------------------------------------------------------
  2825. //
  2826. // Function: DfsSetPktEntryTimeout
  2827. //
  2828. // Synopsis: Helper for DfsFsctrlSetPktEntryState
  2829. //
  2830. // Arguments:
  2831. //
  2832. // Returns:
  2833. //
  2834. //-----------------------------------------------------------------------------
  2835. NTSTATUS
  2836. DfsSetPktEntryTimeout(
  2837. PDFS_PKT_ENTRY pktEntry,
  2838. ULONG Timeout)
  2839. {
  2840. DfsDbgTrace(+1, Dbg, "DfsSetPktEntryTimeout\n", 0);
  2841. pktEntry->ExpireTime = pktEntry->TimeToLive = Timeout;
  2842. DfsDbgTrace(-1, Dbg, "DfsSetPktEntryTimeout -> %08lx\n", STATUS_SUCCESS );
  2843. return STATUS_SUCCESS;
  2844. }
  2845. //+----------------------------------------------------------------------------
  2846. //
  2847. // Function: DfsFsctrlGetPkt
  2848. //
  2849. // Synopsis: Returns the current (cached Pkt)
  2850. //
  2851. // Arguments:
  2852. //
  2853. // Returns:
  2854. //
  2855. //-----------------------------------------------------------------------------
  2856. NTSTATUS
  2857. DfsFsctrlGetPkt(
  2858. IN PIRP_CONTEXT IrpContext,
  2859. IN PIRP Irp,
  2860. IN PUCHAR OutputBuffer,
  2861. IN ULONG OutputBufferLength)
  2862. {
  2863. NTSTATUS NtStatus = STATUS_SUCCESS;
  2864. PDFS_PKT pkt;
  2865. BOOLEAN pktLocked = FALSE;
  2866. ULONG cbOutBuffer;
  2867. DfsDbgTrace(+1, Dbg, "DfsFsctrlGetPktEntryState\n", 0);
  2868. STD_FSCTRL_PROLOGUE(DfsFsctrlGetPkt, FALSE, TRUE, FALSE);
  2869. pkt = _GetPkt();
  2870. PktAcquireShared( TRUE, &pktLocked );
  2871. //
  2872. // Calculate the needed output buffer size
  2873. //
  2874. NtStatus = DfsGetPktSize(&cbOutBuffer);
  2875. //
  2876. // Let user know if it's too small
  2877. //
  2878. if (OutputBufferLength < cbOutBuffer) {
  2879. RETURN_BUFFER_SIZE(cbOutBuffer, NtStatus);
  2880. }
  2881. if (NtStatus == STATUS_SUCCESS) {
  2882. //
  2883. // Args are ok, and it fits - marshall the data
  2884. //
  2885. NtStatus = DfsGetPktMarshall(OutputBuffer, cbOutBuffer);
  2886. Irp->IoStatus.Information = cbOutBuffer;
  2887. }
  2888. //
  2889. // Release any locks taken, and free any memory allocated.
  2890. //
  2891. if (pktLocked) {
  2892. PktRelease();
  2893. }
  2894. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  2895. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetPkt -> %08lx\n", ULongToPtr(NtStatus) );
  2896. return( NtStatus );
  2897. }
  2898. //+----------------------------------------------------------------------------
  2899. //
  2900. // Function: DfsGetPktSize, private
  2901. //
  2902. // Synopsis: Calculates the size needed to return the Pkt. Helper for
  2903. // DfsFsctrlGetPkt().
  2904. //
  2905. //-----------------------------------------------------------------------------
  2906. NTSTATUS
  2907. DfsGetPktSize(
  2908. PULONG pSize)
  2909. {
  2910. ULONG EntryCount = 0;
  2911. ULONG i;
  2912. ULONG Size = 0;
  2913. PDFS_PKT_ENTRY pPktEntry;
  2914. PDFS_PKT pkt = _GetPkt();
  2915. //
  2916. // Walk the linked list of Pkt entries
  2917. //
  2918. for ( pPktEntry = PktFirstEntry(pkt);
  2919. pPktEntry != NULL;
  2920. pPktEntry = PktNextEntry(pkt, pPktEntry)) {
  2921. //
  2922. // Space for the Prefix and ShortPrefix, including a UNICODE_NULL
  2923. //
  2924. Size += pPktEntry->Id.Prefix.Length + sizeof(WCHAR);
  2925. Size += pPktEntry->Id.ShortPrefix.Length + sizeof(WCHAR);
  2926. //
  2927. // Space for an array of pointers to DFS_PKT_ADDRESS_OBJECTS
  2928. //
  2929. Size += sizeof(PDFS_PKT_ADDRESS_OBJECT) * pPktEntry->Info.ServiceCount;
  2930. //
  2931. // Space for the ServerShare address, plus a UNICODE_NULL, plus the state
  2932. //
  2933. for (i = 0; i < pPktEntry->Info.ServiceCount; i++) {
  2934. Size += sizeof(USHORT) + pPktEntry->Info.ServiceList[i].Address.Length + sizeof(WCHAR);
  2935. }
  2936. EntryCount++;
  2937. }
  2938. //
  2939. // Space for the DFS_PKT_ARG, which will have EntryCount objects on the end
  2940. //
  2941. Size += FIELD_OFFSET(DFS_GET_PKT_ARG, EntryObject[EntryCount]);
  2942. //
  2943. // Make sure the size is a multiple of the size of a PDFS_PKT_ADDRESS_OBJECT, as that is what
  2944. // will be at the end of the buffer
  2945. //
  2946. while ((Size & (sizeof(PDFS_PKT_ADDRESS_OBJECT)-1)) != 0) {
  2947. Size++;
  2948. }
  2949. *pSize = Size;
  2950. return STATUS_SUCCESS;
  2951. }
  2952. //+----------------------------------------------------------------------------
  2953. //
  2954. // Function: DfsGetPktMarshall, private
  2955. //
  2956. // Synopsis: Marshalls the Pkt. Helper for DfsFsctrlGetPkt().
  2957. //
  2958. //-----------------------------------------------------------------------------
  2959. NTSTATUS
  2960. DfsGetPktMarshall(
  2961. PBYTE Buffer,
  2962. ULONG Size)
  2963. {
  2964. ULONG EntryCount = 0;
  2965. ULONG i;
  2966. ULONG j;
  2967. ULONG Type;
  2968. PCHAR pCh;
  2969. PDFS_PKT_ENTRY pPktEntry;
  2970. PDFS_GET_PKT_ARG pPktArg;
  2971. PDFS_PKT pkt = _GetPkt();
  2972. //
  2973. // This will be a two-pass operation, the first pass will calculate how
  2974. // much room for the LPWSTR arrays at the end of the buffer, then the
  2975. // second pass will put the strings into place, too.
  2976. //
  2977. RtlZeroMemory(Buffer,Size);
  2978. //
  2979. // Point to the end of the buffer
  2980. //
  2981. pCh = (PCHAR)(Buffer + Size);
  2982. pPktArg = (PDFS_GET_PKT_ARG)Buffer;
  2983. for ( pPktEntry = PktFirstEntry(pkt);
  2984. pPktEntry != NULL;
  2985. pPktEntry = PktNextEntry(pkt, pPktEntry)) {
  2986. //
  2987. // Space for an array of pointers to DFS_PKT_ADDRESS_OBJECTS
  2988. //
  2989. pCh -= sizeof(PDFS_PKT_ADDRESS_OBJECT) * pPktEntry->Info.ServiceCount;
  2990. pPktArg->EntryObject[EntryCount].Address = (PDFS_PKT_ADDRESS_OBJECT *)pCh;
  2991. EntryCount++;
  2992. }
  2993. //
  2994. // Now marshall
  2995. //
  2996. EntryCount = 0;
  2997. for ( pPktEntry = PktFirstEntry(pkt);
  2998. pPktEntry != NULL;
  2999. pPktEntry = PktNextEntry(pkt, pPktEntry)) {
  3000. pCh -= pPktEntry->Id.Prefix.Length + sizeof(WCHAR);
  3001. pPktArg->EntryObject[EntryCount].Prefix = (LPWSTR)pCh;
  3002. RtlCopyMemory(
  3003. pPktArg->EntryObject[EntryCount].Prefix,
  3004. pPktEntry->Id.Prefix.Buffer,
  3005. pPktEntry->Id.Prefix.Length);
  3006. pCh -= pPktEntry->Id.ShortPrefix.Length + sizeof(WCHAR);
  3007. pPktArg->EntryObject[EntryCount].ShortPrefix = (LPWSTR)pCh;
  3008. RtlCopyMemory(
  3009. pPktArg->EntryObject[EntryCount].ShortPrefix,
  3010. pPktEntry->Id.ShortPrefix.Buffer,
  3011. pPktEntry->Id.ShortPrefix.Length);
  3012. pPktArg->EntryObject[EntryCount].Type = pPktEntry->Type;
  3013. pPktArg->EntryObject[EntryCount].USN = pPktEntry->USN;
  3014. pPktArg->EntryObject[EntryCount].ExpireTime = pPktEntry->ExpireTime;
  3015. pPktArg->EntryObject[EntryCount].UseCount = pPktEntry->UseCount;
  3016. pPktArg->EntryObject[EntryCount].Uid = pPktEntry->Id.Uid;
  3017. pPktArg->EntryObject[EntryCount].ServiceCount = pPktEntry->Info.ServiceCount;
  3018. for (i = 0; i < pPktEntry->Info.ServiceCount; i++) {
  3019. Type = pPktEntry->Info.ServiceList[i].Type;
  3020. pCh -= sizeof(USHORT) + pPktEntry->Info.ServiceList[i].Address.Length + sizeof(WCHAR);
  3021. pPktArg->EntryObject[EntryCount].Address[i] = (PDFS_PKT_ADDRESS_OBJECT)pCh;
  3022. pPktArg->EntryObject[EntryCount].Address[i]->State = (USHORT)Type;
  3023. if (pPktEntry->ActiveService == &pPktEntry->Info.ServiceList[i]) {
  3024. pPktArg->EntryObject[EntryCount].Address[i]->State |= DFS_SERVICE_TYPE_ACTIVE;
  3025. }
  3026. RtlCopyMemory(
  3027. &pPktArg->EntryObject[EntryCount].Address[i]->ServerShare[0],
  3028. pPktEntry->Info.ServiceList[i].Address.Buffer,
  3029. pPktEntry->Info.ServiceList[i].Address.Length);
  3030. }
  3031. EntryCount++;
  3032. }
  3033. pPktArg->EntryCount = EntryCount;
  3034. //
  3035. // Convert all the pointers to relative offsets
  3036. //
  3037. for (i = 0; i < pPktArg->EntryCount; i++) {
  3038. for (j = 0; j < pPktArg->EntryObject[i].ServiceCount; j++) {
  3039. POINTER_TO_OFFSET(pPktArg->EntryObject[i].Address[j], Buffer);
  3040. }
  3041. POINTER_TO_OFFSET(pPktArg->EntryObject[i].Prefix, Buffer);
  3042. POINTER_TO_OFFSET(pPktArg->EntryObject[i].ShortPrefix, Buffer);
  3043. POINTER_TO_OFFSET(pPktArg->EntryObject[i].Address, Buffer);
  3044. }
  3045. return STATUS_SUCCESS;
  3046. }
  3047. //+----------------------------------------------------------------------------
  3048. //
  3049. // Function: DfsFsctrlGetSpcTable
  3050. //
  3051. // Synopsis: Given a NULL string, it returns a list of all the domains
  3052. // Given a non-NULL string, it returns a list of DC's in that domain
  3053. // (if the name is a domain name). Similar to a special referral request.
  3054. //
  3055. // Arguments:
  3056. //
  3057. // Returns:
  3058. //
  3059. //-----------------------------------------------------------------------------
  3060. NTSTATUS
  3061. DfsFsctrlGetSpcTable(
  3062. IN PIRP_CONTEXT IrpContext,
  3063. IN PIRP Irp,
  3064. IN PUCHAR InputBuffer,
  3065. IN ULONG InputBufferLength,
  3066. IN PUCHAR OutputBuffer,
  3067. IN ULONG OutputBufferLength)
  3068. {
  3069. NTSTATUS NtStatus = STATUS_SUCCESS;
  3070. LPWSTR SpcName;
  3071. ULONG i;
  3072. DfsDbgTrace(+1, Dbg, "DfsFsctrlGetSpcTable\n", 0);
  3073. STD_FSCTRL_PROLOGUE(DfsFsctrlGetSpcTable, TRUE, TRUE, FALSE);
  3074. SpcName = (WCHAR *)InputBuffer;
  3075. //
  3076. // Verify there's a null someplace in the buffer
  3077. //
  3078. for (i = 0; i < InputBufferLength/sizeof(WCHAR) && SpcName[i]; i++)
  3079. NOTHING;
  3080. if (i >= InputBufferLength/sizeof(WCHAR)) {
  3081. NtStatus = STATUS_INVALID_PARAMETER;
  3082. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  3083. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetSpcTable -> %08lx\n", ULongToPtr(NtStatus) );
  3084. return NtStatus;
  3085. }
  3086. DfsDbgTrace(0, Dbg, "SpcName=[%ws]\n", SpcName);
  3087. if (wcslen(SpcName) == 0) {
  3088. //
  3089. // return all the domain names
  3090. //
  3091. NtStatus = DfsGetSpcTableNames(
  3092. Irp,
  3093. OutputBuffer,
  3094. OutputBufferLength);
  3095. } else if (wcslen(SpcName) == 1 && *SpcName == L'*') {
  3096. //
  3097. // Return DC Info
  3098. //
  3099. NtStatus = DfsGetSpcDcInfo(
  3100. Irp,
  3101. OutputBuffer,
  3102. OutputBufferLength);
  3103. } else {
  3104. //
  3105. // Expand the one name
  3106. //
  3107. NtStatus = DfsExpSpcTableName(
  3108. SpcName,
  3109. Irp,
  3110. OutputBuffer,
  3111. OutputBufferLength);
  3112. }
  3113. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  3114. DfsDbgTrace(-1, Dbg, "DfsFsctrlGetSpcTable -> %08lx\n", ULongToPtr(NtStatus) );
  3115. return( NtStatus );
  3116. }
  3117. //+----------------------------------------------------------------------------
  3118. //
  3119. // Function: DfsGetspcTableNames, private
  3120. //
  3121. // Synopsis: Marshalls the spc table (Names). Helper for DfsFsctrlGetSpcTable().
  3122. //
  3123. //-----------------------------------------------------------------------------
  3124. NTSTATUS
  3125. DfsGetSpcTableNames(
  3126. PIRP Irp,
  3127. PUCHAR OutputBuffer,
  3128. ULONG OutputBufferLength)
  3129. {
  3130. PDFS_SPECIAL_ENTRY pSpecialEntry;
  3131. PDFS_SPECIAL_TABLE pSpecialTable;
  3132. PDFS_PKT Pkt;
  3133. WCHAR *wCp;
  3134. ULONG Size;
  3135. ULONG i;
  3136. BOOLEAN pktLocked;
  3137. NTSTATUS Status;
  3138. RtlZeroMemory(OutputBuffer, OutputBufferLength);
  3139. Pkt = _GetPkt();
  3140. pSpecialTable = &Pkt->SpecialTable;
  3141. PktAcquireShared(TRUE, &pktLocked);
  3142. Size = sizeof(UNICODE_NULL);
  3143. pSpecialEntry = CONTAINING_RECORD(
  3144. pSpecialTable->SpecialEntryList.Flink,
  3145. DFS_SPECIAL_ENTRY,
  3146. Link);
  3147. for (i = 0; i < pSpecialTable->SpecialEntryCount; i++) {
  3148. Size += pSpecialEntry->SpecialName.Length +
  3149. sizeof(UNICODE_NULL) +
  3150. sizeof(WCHAR);
  3151. pSpecialEntry = CONTAINING_RECORD(
  3152. pSpecialEntry->Link.Flink,
  3153. DFS_SPECIAL_ENTRY,
  3154. Link);
  3155. }
  3156. if (Size > OutputBufferLength) {
  3157. RETURN_BUFFER_SIZE(Size, Status)
  3158. PktRelease();
  3159. return Status;
  3160. }
  3161. wCp = (WCHAR *)OutputBuffer;
  3162. pSpecialEntry = CONTAINING_RECORD(
  3163. pSpecialTable->SpecialEntryList.Flink,
  3164. DFS_SPECIAL_ENTRY,
  3165. Link);
  3166. for (i = 0; i < pSpecialTable->SpecialEntryCount; i++) {
  3167. *wCp++ = pSpecialEntry->NeedsExpansion == TRUE ? L'-' : '+';
  3168. RtlCopyMemory(
  3169. wCp,
  3170. pSpecialEntry->SpecialName.Buffer,
  3171. pSpecialEntry->SpecialName.Length);
  3172. wCp += pSpecialEntry->SpecialName.Length/sizeof(WCHAR);
  3173. *wCp++ = UNICODE_NULL;
  3174. pSpecialEntry = CONTAINING_RECORD(
  3175. pSpecialEntry->Link.Flink,
  3176. DFS_SPECIAL_ENTRY,
  3177. Link);
  3178. }
  3179. *wCp++ = UNICODE_NULL;
  3180. PktRelease();
  3181. Irp->IoStatus.Information = Size;
  3182. return STATUS_SUCCESS;
  3183. }
  3184. //+----------------------------------------------------------------------------
  3185. //
  3186. // Function: DfsGetSpcDcInfo, private
  3187. //
  3188. // Synopsis: Marshalls DC Info w.r.t. the special name table
  3189. //
  3190. //-----------------------------------------------------------------------------
  3191. NTSTATUS
  3192. DfsGetSpcDcInfo(
  3193. PIRP Irp,
  3194. PUCHAR OutputBuffer,
  3195. ULONG OutputBufferLength)
  3196. {
  3197. NTSTATUS Status = STATUS_SUCCESS;
  3198. BOOLEAN pktLocked;
  3199. PDFS_PKT Pkt;
  3200. WCHAR *wCp;
  3201. ULONG Size;
  3202. Pkt = _GetPkt();
  3203. PktAcquireShared(TRUE, &pktLocked);
  3204. RtlZeroMemory(OutputBuffer, OutputBufferLength);
  3205. Size = sizeof(UNICODE_NULL);
  3206. Size += Pkt->DCName.Length +
  3207. sizeof(UNICODE_NULL) +
  3208. sizeof(WCHAR);
  3209. Size += Pkt->DomainNameFlat.Length +
  3210. sizeof(UNICODE_NULL) +
  3211. sizeof(WCHAR);
  3212. Size += Pkt->DomainNameDns.Length +
  3213. sizeof(UNICODE_NULL) +
  3214. sizeof(WCHAR);
  3215. if (Size > OutputBufferLength) {
  3216. RETURN_BUFFER_SIZE(Size, Status)
  3217. PktRelease();
  3218. return Status;
  3219. }
  3220. wCp = (WCHAR *)OutputBuffer;
  3221. *wCp++ = L'*';
  3222. RtlCopyMemory(
  3223. wCp,
  3224. Pkt->DCName.Buffer,
  3225. Pkt->DCName.Length);
  3226. wCp += Pkt->DCName.Length/sizeof(WCHAR);
  3227. *wCp++ = UNICODE_NULL;
  3228. *wCp++ = L'*';
  3229. RtlCopyMemory(
  3230. wCp,
  3231. Pkt->DomainNameFlat.Buffer,
  3232. Pkt->DomainNameFlat.Length);
  3233. wCp += Pkt->DomainNameFlat.Length/sizeof(WCHAR);
  3234. *wCp++ = UNICODE_NULL;
  3235. *wCp++ = L'*';
  3236. RtlCopyMemory(
  3237. wCp,
  3238. Pkt->DomainNameDns.Buffer,
  3239. Pkt->DomainNameDns.Length);
  3240. wCp += Pkt->DomainNameDns.Length/sizeof(WCHAR);
  3241. *wCp++ = UNICODE_NULL;
  3242. *wCp++ = UNICODE_NULL;
  3243. PktRelease();
  3244. Irp->IoStatus.Information = Size;
  3245. return STATUS_SUCCESS;
  3246. }
  3247. //+----------------------------------------------------------------------------
  3248. //
  3249. // Function: DfsExpSpcTableName, private
  3250. //
  3251. // Synopsis: Marshalls the spc table (1 expansion). Helper for DfsFsctrlGetSpcTable().
  3252. //
  3253. //-----------------------------------------------------------------------------
  3254. NTSTATUS
  3255. DfsExpSpcTableName(
  3256. LPWSTR SpcName,
  3257. PIRP Irp,
  3258. PUCHAR OutputBuffer,
  3259. ULONG OutputBufferLength)
  3260. {
  3261. PDFS_SPECIAL_ENTRY pSpcEntry = NULL;
  3262. UNICODE_STRING Name;
  3263. NTSTATUS Status = STATUS_SUCCESS;
  3264. WCHAR *wCp;
  3265. ULONG Size;
  3266. ULONG i;
  3267. RtlInitUnicodeString(&Name, SpcName);
  3268. Status = PktExpandSpecialName(&Name, &pSpcEntry);
  3269. if (!NT_SUCCESS(Status)) {
  3270. return Status;
  3271. }
  3272. RtlZeroMemory(OutputBuffer, OutputBufferLength);
  3273. Size = sizeof(UNICODE_NULL);
  3274. for (i = 0; i < pSpcEntry->ExpandedCount; i++) {
  3275. Size += pSpcEntry->ExpandedNames[i].ExpandedName.Length +
  3276. sizeof(UNICODE_NULL) +
  3277. sizeof(WCHAR);
  3278. }
  3279. if (Size > OutputBufferLength) {
  3280. RETURN_BUFFER_SIZE(Size, Status)
  3281. InterlockedDecrement(&pSpcEntry->UseCount);
  3282. return Status;
  3283. }
  3284. wCp = (WCHAR *)OutputBuffer;
  3285. for (i = 0; i < pSpcEntry->ExpandedCount; i++) {
  3286. *wCp++ = i == pSpcEntry->Active ? L'+' : L'-';
  3287. RtlCopyMemory(
  3288. wCp,
  3289. pSpcEntry->ExpandedNames[i].ExpandedName.Buffer,
  3290. pSpcEntry->ExpandedNames[i].ExpandedName.Length);
  3291. wCp += pSpcEntry->ExpandedNames[i].ExpandedName.Length/sizeof(WCHAR);
  3292. *wCp++ = UNICODE_NULL;
  3293. }
  3294. *wCp++ = UNICODE_NULL;
  3295. InterlockedDecrement(&pSpcEntry->UseCount);
  3296. Irp->IoStatus.Information = Size;
  3297. return STATUS_SUCCESS;
  3298. }
  3299. //+----------------------------------------------------------------------------
  3300. //
  3301. // Function: DfsFsctrlSpcSetDc
  3302. //
  3303. // Synopsis: Given a special name and a dc name, it makes the DC in that special
  3304. // list the 'active' DC.
  3305. //
  3306. // Arguments:
  3307. //
  3308. // Returns:
  3309. //
  3310. //-----------------------------------------------------------------------------
  3311. NTSTATUS
  3312. DfsFsctrlSpcSetDc(
  3313. IN PIRP_CONTEXT IrpContext,
  3314. IN PIRP Irp,
  3315. IN PUCHAR InputBuffer,
  3316. IN ULONG InputBufferLength)
  3317. {
  3318. NTSTATUS NtStatus = STATUS_SUCCESS;
  3319. PDFS_SPECIAL_SET_DC_INPUT_ARG arg = (PDFS_SPECIAL_SET_DC_INPUT_ARG) InputBuffer;
  3320. DfsDbgTrace(+1, Dbg, "DfsFsctrlSpcSetDc\n", 0);
  3321. STD_FSCTRL_PROLOGUE(DfsFsctrlSpcSetDc, TRUE, FALSE, FALSE);
  3322. //
  3323. // Check the input args
  3324. //
  3325. if (InputBufferLength < sizeof(DFS_SPECIAL_SET_DC_INPUT_ARG)) {
  3326. NtStatus = STATUS_INVALID_PARAMETER;
  3327. goto exit_with_status;
  3328. }
  3329. OFFSET_TO_POINTER(arg->SpecialName.Buffer, arg);
  3330. if (!UNICODESTRING_IS_VALID(arg->SpecialName, InputBuffer, InputBufferLength)) {
  3331. NtStatus = STATUS_INVALID_PARAMETER;
  3332. goto exit_with_status;
  3333. }
  3334. OFFSET_TO_POINTER(arg->DcName.Buffer, arg);
  3335. if (!UNICODESTRING_IS_VALID(arg->DcName, InputBuffer, InputBufferLength)) {
  3336. NtStatus = STATUS_INVALID_PARAMETER;
  3337. goto exit_with_status;
  3338. }
  3339. NtStatus = PktpSetActiveSpcService(
  3340. &arg->SpecialName,
  3341. &arg->DcName,
  3342. TRUE);
  3343. exit_with_status:
  3344. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  3345. DfsDbgTrace(-1, Dbg, "DfsFsctrlSpcSetDc -> %08lx\n", ULongToPtr(NtStatus) );
  3346. return( NtStatus );
  3347. }
  3348. #if DBG
  3349. //+-------------------------------------------------------------------------
  3350. //
  3351. // Function: DfsFsctrlReadMem, local
  3352. //
  3353. // Synopsis: DfsFsctrlReadMem is a debugging function which will return
  3354. // the contents of a chunk of kernel space memory
  3355. //
  3356. // Arguments: [IrpContext] -
  3357. // [Irp] -
  3358. // [Request] -- Pointer to a FILE_DFS_READ_MEM struct,
  3359. // giving the description of the data to be returned.
  3360. // [InputBufferLength] -- Size of InputBuffer
  3361. // [OutputBuffer] -- User's output buffer, in which the
  3362. // data structure will be returned.
  3363. // [OutputBufferLength] -- Size of OutputBuffer
  3364. //
  3365. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  3366. //
  3367. // Notes: Available in DBG builds only.
  3368. //
  3369. //--------------------------------------------------------------------------
  3370. NTSTATUS
  3371. DfsFsctrlReadMem (
  3372. IN PIRP_CONTEXT IrpContext,
  3373. IN PIRP Irp,
  3374. IN PFILE_DFS_READ_MEM Request,
  3375. IN ULONG InputBufferLength,
  3376. IN OUT PUCHAR OutputBuffer,
  3377. IN ULONG OutputBufferLength
  3378. ) {
  3379. NTSTATUS Status;
  3380. PUCHAR ReadBuffer;
  3381. ULONG ReadLength;
  3382. DfsDbgTrace(+1, Dbg, "DfsFsctrlReadMem...\n", 0);
  3383. if (InputBufferLength != sizeof (FILE_DFS_READ_MEM)) {
  3384. DfsDbgTrace(0, Dbg, "Input buffer is wrong size\n", 0);
  3385. DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3386. Status = STATUS_INVALID_PARAMETER;
  3387. DfsDbgTrace(-1, Dbg, "DfsFsctrlReadMem -> %08lx\n", ULongToPtr(Status) );
  3388. return Status;
  3389. }
  3390. ReadBuffer = (PUCHAR) Request->Address;
  3391. ReadLength = (ULONG) Request->Length;
  3392. //
  3393. // Special case ReadBuffer == 0 and ReadLength == 0 - means return the
  3394. // address of DfsData
  3395. //
  3396. if (ReadLength == 0 && ReadBuffer == 0) {
  3397. if (OutputBufferLength < sizeof(ULONG_PTR)) {
  3398. DfsDbgTrace(0, Dbg, "Output buffer is too small\n", 0);
  3399. DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3400. Status = STATUS_INVALID_PARAMETER;
  3401. DfsDbgTrace(-1, Dbg, "DfsFsctrlReadMem -> %08lx\n", ULongToPtr(Status) );
  3402. return Status;
  3403. } else {
  3404. *(PULONG_PTR) OutputBuffer = (ULONG_PTR) &DfsData;
  3405. Irp->IoStatus.Information = sizeof(ULONG);
  3406. Irp->IoStatus.Status = Status = STATUS_SUCCESS;
  3407. DfsCompleteRequest( IrpContext, Irp, Status );
  3408. return Status;
  3409. }
  3410. }
  3411. //
  3412. // Normal case, read data from the address specified in input buffer
  3413. //
  3414. if (ReadLength > OutputBufferLength) {
  3415. DfsDbgTrace(0, Dbg, "Output buffer is smaller than requested size\n", 0);
  3416. DfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  3417. Status = STATUS_INVALID_PARAMETER;
  3418. DfsDbgTrace(-1, Dbg, "DfsFsctrlReadMem -> %08lx\n", ULongToPtr(Status) );
  3419. return Status;
  3420. }
  3421. try {
  3422. RtlMoveMemory( OutputBuffer, ReadBuffer, ReadLength );
  3423. Irp->IoStatus.Information = ReadLength;
  3424. Irp->IoStatus.Status = Status = STATUS_SUCCESS;
  3425. } except(EXCEPTION_EXECUTE_HANDLER) {
  3426. Status = STATUS_INVALID_USER_BUFFER;
  3427. }
  3428. DfsCompleteRequest(IrpContext, Irp, Status);
  3429. DfsDbgTrace(-1, Dbg, "DfsFsctrlReadMem -> %08lx\n", ULongToPtr(Status) );
  3430. return Status;
  3431. }
  3432. void
  3433. DfsDumpBuf(PCHAR cp, ULONG len)
  3434. {
  3435. ULONG i, j, c;
  3436. for (i = 0; i < len; i += 16) {
  3437. DbgPrint("%08x ", i);
  3438. for (j = 0; j < 16; j++) {
  3439. c = i+j < len ? cp[i+j] & 0xff : ' ';
  3440. DbgPrint("%02x ", c);
  3441. if (j == 7)
  3442. DbgPrint(" ");
  3443. }
  3444. DbgPrint(" ");
  3445. for (j = 0; j < 16; j++) {
  3446. c = i+j < len ? cp[i+j] & 0xff : ' ';
  3447. if (c < ' ' || c > '~')
  3448. c = '.';
  3449. DbgPrint("%c", c);
  3450. if (j == 7)
  3451. DbgPrint("|");
  3452. }
  3453. DbgPrint("\n");
  3454. }
  3455. }
  3456. #endif // DBG
  3457. //+----------------------------------------------------------------------------
  3458. //
  3459. // Function: DfsCaptureCredentials
  3460. //
  3461. // Synopsis: Captures the credentials to use... similar to DnrCaptureCred..
  3462. //
  3463. // Arguments: Irp and Filename.
  3464. //
  3465. // Returns: Credentials
  3466. //
  3467. //-----------------------------------------------------------------------------
  3468. PDFS_CREDENTIALS
  3469. DfsCaptureCredentials(
  3470. IN PIRP Irp,
  3471. IN PUNICODE_STRING FileName)
  3472. {
  3473. #ifdef TERMSRV
  3474. NTSTATUS Status;
  3475. ULONG SessionID;
  3476. #endif // TERMSRV
  3477. LUID LogonID;
  3478. PDFS_CREDENTIALS creds;
  3479. DfsDbgTrace(+1, Dbg, "DfsCaptureCredentials: Enter [%wZ] \n", FileName);
  3480. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  3481. DfsGetLogonId( &LogonID );
  3482. #ifdef TERMSRV
  3483. Status = IoGetRequestorSessionId( Irp, & SessionID );
  3484. if( NT_SUCCESS( Status ) ) {
  3485. creds = DfsLookupCredentials( FileName, SessionID, &LogonID );
  3486. }
  3487. else {
  3488. creds = NULL;
  3489. }
  3490. #else // TERMSRV
  3491. creds = DfsLookupCredentials( FileName, &LogonID );
  3492. #endif // TERMSRV
  3493. if (creds != NULL)
  3494. creds->RefCount++;
  3495. ExReleaseResourceLite( &DfsData.Resource );
  3496. DfsDbgTrace(-1, Dbg, "DfsCaptureCredentials: Exit. Creds %x\n", creds);
  3497. return creds;
  3498. }
  3499. //+----------------------------------------------------------------------------
  3500. //
  3501. // Function: DfsReleaseCredentials
  3502. //
  3503. // Synopsis: Releases the credentials supplied.
  3504. //
  3505. // Arguments: Credentials
  3506. //
  3507. // Returns: Nothing
  3508. //
  3509. //-----------------------------------------------------------------------------
  3510. VOID
  3511. DfsReleaseCredentials(
  3512. IN PDFS_CREDENTIALS Creds )
  3513. {
  3514. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  3515. if (Creds != NULL)
  3516. Creds->RefCount--;
  3517. ExReleaseResourceLite( &DfsData.Resource );
  3518. }
  3519. //+-------------------------------------------------------------------
  3520. //
  3521. // Function: DfsFsctrlGetConnectionPerfInfo, public
  3522. //
  3523. // Synopsis: This routine implements the functionality to get the
  3524. // performance information of an opened connection.
  3525. //
  3526. // Returns: [NTSTATUS] -- The completion status.
  3527. //
  3528. //--------------------------------------------------------------------
  3529. NTSTATUS
  3530. DfsFsctrlGetConnectionPerfInfo(
  3531. IN PIRP_CONTEXT IrpContext,
  3532. IN PIRP Irp,
  3533. IN PUCHAR InputBuffer,
  3534. IN ULONG InputBufferLength,
  3535. IN OUT PUCHAR OutputBuffer,
  3536. IN ULONG OutputBufferLength)
  3537. {
  3538. UNICODE_STRING Prefix;
  3539. NTSTATUS status = STATUS_SUCCESS;
  3540. UNICODE_STRING remPath, shareName;
  3541. PDFS_PKT pkt;
  3542. PDFS_PKT_ENTRY pktEntry;
  3543. PDFS_SERVICE service;
  3544. ULONG i, USN;
  3545. BOOLEAN pktLocked, fRetry;
  3546. PDFS_CREDENTIALS Creds;
  3547. ULONG InfoLen;
  3548. PUCHAR BufToUse;
  3549. UNICODE_STRING UsePrefix;
  3550. BufToUse = Irp->UserBuffer;
  3551. //
  3552. // try to use the User's buffer here. The underlying call sets up
  3553. // pointers to unicode strings within the output buffer, and passing
  3554. // a kernel buffer and copying it out to the user would not produce
  3555. // the intended results.
  3556. //
  3557. if (BufToUse!= NULL) {
  3558. try {
  3559. ProbeForWrite(BufToUse,OutputBufferLength,sizeof(UCHAR));
  3560. } except(EXCEPTION_EXECUTE_HANDLER) {
  3561. status = STATUS_INVALID_PARAMETER;
  3562. }
  3563. }
  3564. else {
  3565. status = STATUS_INVALID_PARAMETER;
  3566. }
  3567. if (NT_SUCCESS(status)) {
  3568. if ( (InputBufferLength > 0) &&
  3569. (InputBufferLength < MAXUSHORT) &&
  3570. ((InputBufferLength & 0x1) == 0) ) {
  3571. Prefix.MaximumLength = (USHORT)(InputBufferLength);
  3572. Prefix.Buffer = (PWCHAR) InputBuffer;
  3573. Prefix.Length = Prefix.MaximumLength;
  3574. }
  3575. else {
  3576. status = STATUS_INVALID_PARAMETER;
  3577. }
  3578. }
  3579. if (NT_SUCCESS(status)) {
  3580. Creds = DfsCaptureCredentials (Irp, &Prefix);
  3581. DfsDbgTrace(+1, Dbg, "GetConnPerfInfo entered %wZ\n", &Prefix);
  3582. DfsDbgTrace(0, Dbg, "GetConnPerfInfo creds=0x%x\n", Creds);
  3583. DfsGetServerShare( &UsePrefix, &Prefix);
  3584. pkt = _GetPkt();
  3585. PktAcquireShared( TRUE, &pktLocked );
  3586. do {
  3587. fRetry = FALSE;
  3588. pktEntry = PktLookupEntryByPrefix( pkt, &UsePrefix, &remPath );
  3589. if (pktEntry != NULL) {
  3590. InterlockedIncrement(&pktEntry->UseCount);
  3591. USN = pktEntry->USN;
  3592. status = STATUS_BAD_NETWORK_PATH;
  3593. for (i = 0; i < pktEntry->Info.ServiceCount; i++) {
  3594. service = &pktEntry->Info.ServiceList[i];
  3595. try {
  3596. status = DfsTreeConnectGetConnectionInfo(
  3597. service,
  3598. Creds,
  3599. BufToUse,
  3600. OutputBufferLength,
  3601. &InfoLen);
  3602. }
  3603. except(EXCEPTION_EXECUTE_HANDLER) {
  3604. status = STATUS_INVALID_PARAMETER;
  3605. }
  3606. //
  3607. // If tree connect succeeded, we are done.
  3608. //
  3609. if (NT_SUCCESS(status))
  3610. break;
  3611. //
  3612. // If tree connect failed with an "interesting error" like
  3613. // STATUS_ACCESS_DENIED, we are done.
  3614. //
  3615. if (!ReplIsRecoverableError(status))
  3616. break;
  3617. //
  3618. // Tree connect failed because of an error like host not
  3619. // reachable. In that case, we want to go on to the next
  3620. // server in the list. But before we do that, we have to see
  3621. // if the pkt changed on us while we were off doing the tree
  3622. // connect.
  3623. //
  3624. if (USN != pktEntry->USN) {
  3625. fRetry = TRUE;
  3626. break;
  3627. }
  3628. }
  3629. InterlockedDecrement(&pktEntry->UseCount);
  3630. } else {
  3631. status = STATUS_BAD_NETWORK_PATH;
  3632. }
  3633. } while ( fRetry );
  3634. PktRelease();
  3635. DfsReleaseCredentials(Creds);
  3636. //
  3637. // Dont put the InfoLen here... we already have the information in the
  3638. // the user buffer, and dont want a copyout of kernel to user.
  3639. //
  3640. }
  3641. Irp->IoStatus.Information = 0;
  3642. DfsCompleteRequest(IrpContext, Irp, status);
  3643. DfsDbgTrace(-1, Dbg, "GetConnPerfInfo Done, Status %x\n", ULongToPtr(status) );
  3644. return( status );
  3645. }
  3646. //+-------------------------------------------------------------------
  3647. //
  3648. // Function: DfsTreeConnecGetConnectionInfo, private
  3649. //
  3650. // Synopsis: This routine calls into the provider with FSCTL_LMR
  3651. // fsctl. Only lanman supports this fsctl, and if the provider
  3652. // is lanman, we get our information buffer filled in.
  3653. //
  3654. // Returns: [NTSTATUS] -- The completion status.
  3655. //
  3656. //--------------------------------------------------------------------
  3657. NTSTATUS
  3658. DfsTreeConnectGetConnectionInfo(
  3659. IN PDFS_SERVICE Service,
  3660. IN PDFS_CREDENTIALS Creds,
  3661. IN OUT PUCHAR OutputBuffer,
  3662. IN ULONG OutputBufferLength,
  3663. OUT PULONG InfoLen)
  3664. {
  3665. NTSTATUS status;
  3666. NTSTATUS ObjectRefStatus;
  3667. UNICODE_STRING shareName;
  3668. HANDLE treeHandle;
  3669. OBJECT_ATTRIBUTES objectAttributes;
  3670. IO_STATUS_BLOCK ioStatusBlock;
  3671. BOOLEAN pktLocked;
  3672. USHORT i, k;
  3673. *InfoLen = 0;
  3674. DfsDbgTrace(+1, Dbg, "DfsTreeConnectGetInfo entered creds %x\n", Creds);
  3675. ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
  3676. //
  3677. // Compute the share name...
  3678. //
  3679. if (Service->pProvider != NULL &&
  3680. Service->pProvider->DeviceName.Buffer != NULL &&
  3681. Service->pProvider->DeviceName.Length > 0) {
  3682. //
  3683. // We have a provider already - use it
  3684. //
  3685. shareName.MaximumLength =
  3686. Service->pProvider->DeviceName.Length +
  3687. Service->Address.Length;
  3688. } else {
  3689. //
  3690. // We don't have a provider yet - give it to the mup to find one
  3691. //
  3692. shareName.MaximumLength =
  3693. sizeof(DD_NFS_DEVICE_NAME_U) +
  3694. Service->Address.Length;
  3695. }
  3696. shareName.Buffer = ExAllocatePoolWithTag(PagedPool, shareName.MaximumLength, ' puM');
  3697. if (shareName.Buffer != NULL) {
  3698. //
  3699. // If we have a cached connection to the IPC$ share of this server,
  3700. // close it or it might conflict with the credentials supplied here.
  3701. //
  3702. if (Service->ConnFile != NULL) {
  3703. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  3704. if (Service->ConnFile != NULL)
  3705. DfsCloseConnection(Service);
  3706. ExReleaseResourceLite(&DfsData.Resource);
  3707. }
  3708. //
  3709. // Now, build the share name to tree connect to.
  3710. //
  3711. shareName.Length = 0;
  3712. if (Service->pProvider != NULL &&
  3713. Service->pProvider->DeviceName.Buffer != NULL &&
  3714. Service->pProvider->DeviceName.Length > 0) {
  3715. //
  3716. // We have a provider already - use it
  3717. //
  3718. RtlAppendUnicodeToString(
  3719. &shareName,
  3720. Service->pProvider->DeviceName.Buffer);
  3721. } else {
  3722. //
  3723. // We don't have a provider yet - give it to the mup to find one
  3724. //
  3725. RtlAppendUnicodeToString(
  3726. &shareName,
  3727. DD_NFS_DEVICE_NAME_U);
  3728. }
  3729. RtlAppendUnicodeStringToString(&shareName, &Service->Address);
  3730. //
  3731. // One can only do tree connects to server\share. So, in case
  3732. // pService->Address refers to something deeper than the share,
  3733. // make sure we setup a tree-conn only to server\share. Note that
  3734. // by now, shareName is of the form
  3735. // \Device\LanmanRedirector\server\share<\path>. So, count up to
  3736. // 4 slashes and terminate the share name there.
  3737. //
  3738. for (i = 0, k = 0;
  3739. i < shareName.Length/sizeof(WCHAR) && k < 5;
  3740. i++) {
  3741. if (shareName.Buffer[i] == UNICODE_PATH_SEP)
  3742. k++;
  3743. }
  3744. shareName.Length = i * sizeof(WCHAR);
  3745. if (k == 5)
  3746. shareName.Length -= sizeof(WCHAR);
  3747. InitializeObjectAttributes(
  3748. &objectAttributes,
  3749. &shareName,
  3750. OBJ_CASE_INSENSITIVE,
  3751. NULL,
  3752. NULL);
  3753. //
  3754. // Release the Pkt before going over the net...
  3755. //
  3756. PktRelease();
  3757. status = ZwCreateFile(
  3758. &treeHandle,
  3759. SYNCHRONIZE,
  3760. &objectAttributes,
  3761. &ioStatusBlock,
  3762. NULL,
  3763. FILE_ATTRIBUTE_NORMAL,
  3764. FILE_SHARE_READ |
  3765. FILE_SHARE_WRITE |
  3766. FILE_SHARE_DELETE,
  3767. FILE_OPEN_IF,
  3768. FILE_CREATE_TREE_CONNECTION |
  3769. FILE_SYNCHRONOUS_IO_NONALERT,
  3770. (PVOID) (Creds) ? Creds->EaBuffer : NULL,
  3771. (Creds) ? Creds->EaLength : 0);
  3772. if (NT_SUCCESS(status)) {
  3773. PFILE_OBJECT fileObject;
  3774. LMR_REQUEST_PACKET request;
  3775. DfsGetLogonId(&request.LogonId);
  3776. request.Type = GetConnectionInfo;
  3777. request.Version = REQUEST_PACKET_VERSION;
  3778. request.Level = 3;
  3779. status = ZwFsControlFile(
  3780. treeHandle,
  3781. NULL,
  3782. NULL,
  3783. NULL,
  3784. &ioStatusBlock,
  3785. FSCTL_LMR_GET_CONNECTION_INFO,
  3786. (LPVOID)&request,
  3787. sizeof(request),
  3788. OutputBuffer,
  3789. OutputBufferLength);
  3790. if (NT_SUCCESS(status)) {
  3791. *InfoLen = (ULONG)ioStatusBlock.Information;
  3792. }
  3793. //
  3794. // 426184, need to check return code for errors.
  3795. //
  3796. ObjectRefStatus = ObReferenceObjectByHandle(
  3797. treeHandle,
  3798. 0,
  3799. NULL,
  3800. KernelMode,
  3801. &fileObject,
  3802. NULL);
  3803. ZwClose( treeHandle );
  3804. if (NT_SUCCESS(ObjectRefStatus)) {
  3805. DfsDeleteTreeConnection( fileObject, USE_FORCE );
  3806. }
  3807. }
  3808. ExFreePool( shareName.Buffer );
  3809. PktAcquireShared( TRUE, &pktLocked );
  3810. } else {
  3811. status = STATUS_INSUFFICIENT_RESOURCES;
  3812. }
  3813. DfsDbgTrace(-1, Dbg, "DfsTreeConnectGetInfo exit: Status %x\n", ULongToPtr(status) );
  3814. return( status );
  3815. }
  3816. //+-------------------------------------------------------------------
  3817. //
  3818. // Function: DfsFsctrlCscServerOffline, public
  3819. //
  3820. // Synopsis: This routine implements the functionality to mark a server
  3821. // as offline.
  3822. //
  3823. // Returns: [NTSTATUS] -- The completion status.
  3824. //
  3825. //--------------------------------------------------------------------
  3826. NTSTATUS
  3827. DfsFsctrlCscServerOffline(
  3828. IN PIRP_CONTEXT IrpContext,
  3829. IN PIRP Irp,
  3830. IN PUCHAR InputBuffer,
  3831. IN ULONG InputBufferLength,
  3832. IN OUT PUCHAR OutputBuffer,
  3833. IN ULONG OutputBufferLength)
  3834. {
  3835. UNICODE_STRING ServerName;
  3836. LPWSTR Name;
  3837. ULONG i, j;
  3838. NTSTATUS NtStatus;
  3839. DfsDbgTrace(+1, Dbg, "DfsFsctrlCscServerOffline -> %ws\n", (WCHAR *)InputBuffer);
  3840. if(InputBuffer == NULL) {
  3841. NtStatus = STATUS_INVALID_PARAMETER;
  3842. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  3843. return NtStatus;
  3844. }
  3845. Name = (WCHAR *)InputBuffer;
  3846. for (i = 0; i < InputBufferLength/sizeof(WCHAR) && (Name[i] == UNICODE_PATH_SEP); i++)
  3847. NOTHING;
  3848. for (j = i; j < InputBufferLength/sizeof(WCHAR) && (Name[j] != UNICODE_PATH_SEP); j++)
  3849. NOTHING;
  3850. ServerName.Buffer = &Name[i];
  3851. ServerName.MaximumLength = ServerName.Length = (USHORT)(j - i) * sizeof(WCHAR);
  3852. NtStatus = DfspMarkServerOffline(&ServerName);
  3853. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  3854. DfsDbgTrace(-1, Dbg, "DfsFsctrlCscServerOffline -> %08lx\n", ULongToPtr(NtStatus) );
  3855. return NtStatus;
  3856. }
  3857. //+-------------------------------------------------------------------
  3858. //
  3859. // Function: DfsFsctrlCscServerOnline, public
  3860. //
  3861. // Synopsis: This routine implements the functionality to mark a server
  3862. // as online.
  3863. //
  3864. // Returns: [NTSTATUS] -- The completion status.
  3865. //
  3866. //--------------------------------------------------------------------
  3867. NTSTATUS
  3868. DfsFsctrlCscServerOnline(
  3869. IN PIRP_CONTEXT IrpContext,
  3870. IN PIRP Irp,
  3871. IN PUCHAR InputBuffer,
  3872. IN ULONG InputBufferLength,
  3873. IN OUT PUCHAR OutputBuffer,
  3874. IN ULONG OutputBufferLength)
  3875. {
  3876. UNICODE_STRING ServerName;
  3877. LPWSTR Name;
  3878. ULONG i, j;
  3879. NTSTATUS NtStatus;
  3880. DfsDbgTrace(+1, Dbg, "DfsFsctrlCscServerOnline -> %ws\n", (WCHAR *)InputBuffer);
  3881. if(InputBuffer == NULL) {
  3882. NtStatus = STATUS_INVALID_PARAMETER;
  3883. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  3884. return NtStatus;
  3885. }
  3886. Name = (WCHAR *)InputBuffer;
  3887. for (i = 0; i < InputBufferLength/sizeof(WCHAR) && (Name[i] == UNICODE_PATH_SEP); i++)
  3888. NOTHING;
  3889. for (j = i; j < InputBufferLength/sizeof(WCHAR) && (Name[j] != UNICODE_PATH_SEP); j++)
  3890. NOTHING;
  3891. ServerName.Buffer = &Name[i];
  3892. ServerName.MaximumLength = ServerName.Length = (USHORT)(j - i) * sizeof(WCHAR);
  3893. NtStatus = DfspMarkServerOnline(&ServerName);
  3894. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  3895. DfsDbgTrace(-1, Dbg, "DfsFsctrlCscServerOnline -> %08lx\n", ULongToPtr(NtStatus) );
  3896. return NtStatus;
  3897. }
  3898. //+-------------------------------------------------------------------
  3899. //
  3900. // Function: DfsFsctrlSpcRefresh, public
  3901. //
  3902. // Synopsis: This routine implements the functionality to update the
  3903. // special table with a list of trusted domains, based on
  3904. // the passed in domainname and dcname.
  3905. //
  3906. // Returns: [NTSTATUS] -- The completion status.
  3907. //
  3908. //--------------------------------------------------------------------
  3909. #if defined (_WIN64)
  3910. // 32 bit structure for handling spcrefresh from 32 bit client
  3911. typedef struct _DFS_SPC_REFRESH_INFO32 {
  3912. ULONG EventType;
  3913. WORD * POINTER_32 DomainName; // Name of domain
  3914. WORD * POINTER_32 DCName; // Path of the share
  3915. } DFS_SPC_REFRESH_INFO32, *PDFS_SPC_REFRESH_INFO32;
  3916. #endif /* _WIN64 */
  3917. NTSTATUS
  3918. DfsFsctrlSpcRefresh (
  3919. IN PIRP_CONTEXT IrpContext,
  3920. IN PIRP Irp,
  3921. IN PUCHAR InputBuffer,
  3922. IN ULONG InputBufferLength
  3923. ) {
  3924. NTSTATUS NtStatus = STATUS_SUCCESS;
  3925. UNICODE_STRING DomainName;
  3926. UNICODE_STRING DCName;
  3927. ULONG NameLen, i;
  3928. LPWSTR Name, BufferEnd;
  3929. DFS_SPC_REFRESH_INFO Param;
  3930. PDFS_SPC_REFRESH_INFO pParam;
  3931. DfsDbgTrace(+1, Dbg, "DfsFsctrlSpcRefresh\n", 0);
  3932. STD_FSCTRL_PROLOGUE(DfsFsctrlSpcRefresh, TRUE, FALSE, FALSE);
  3933. pParam = (PDFS_SPC_REFRESH_INFO) InputBuffer;
  3934. #if defined (_WIN64)
  3935. if (IoIs32bitProcess(Irp)) {
  3936. PDFS_SPC_REFRESH_INFO32 pParam32;
  3937. pParam32 = (PDFS_SPC_REFRESH_INFO32) InputBuffer;
  3938. if (InputBufferLength < sizeof(DFS_SPC_REFRESH_INFO32)) {
  3939. NtStatus = STATUS_INVALID_PARAMETER;
  3940. goto exit_with_status;
  3941. }
  3942. Param.EventType = pParam32->EventType;
  3943. Param.DomainName = (WCHAR *)(((ULONG_PTR)pParam32) + (ULONG)pParam32->DomainName);
  3944. Param.DCName = (WCHAR *)(((ULONG_PTR)pParam32) + (ULONG)pParam32->DCName);
  3945. pParam = &Param;
  3946. }
  3947. else {
  3948. #endif
  3949. if (InputBufferLength < sizeof(DFS_SPC_REFRESH_INFO)) {
  3950. NtStatus = STATUS_INVALID_PARAMETER;
  3951. goto exit_with_status;
  3952. }
  3953. OFFSET_TO_POINTER(pParam->DomainName, pParam);
  3954. OFFSET_TO_POINTER(pParam->DCName, pParam);
  3955. #if defined (_WIN64)
  3956. }
  3957. #endif
  3958. if (pParam->EventType != 0) {
  3959. NtStatus = STATUS_INVALID_PARAMETER;
  3960. goto exit_with_status;
  3961. }
  3962. //
  3963. // If either string is not within the input buffer, error.
  3964. //
  3965. if ((POINTER_IN_BUFFER(pParam->DomainName, sizeof(WCHAR),
  3966. InputBuffer, InputBufferLength) == 0) ||
  3967. (POINTER_IN_BUFFER(pParam->DomainName, sizeof(WCHAR),
  3968. InputBuffer, InputBufferLength) == 0)) {
  3969. NtStatus = STATUS_INVALID_PARAMETER;
  3970. goto exit_with_status;
  3971. }
  3972. //
  3973. // make sure the strings are valid.
  3974. //
  3975. BufferEnd = (LPWSTR)(InputBuffer + InputBufferLength);
  3976. NameLen = (ULONG)(BufferEnd - pParam->DomainName);
  3977. Name = pParam->DomainName;
  3978. // Strip off leading slashes.
  3979. for (i = 0; i < NameLen; i++) {
  3980. if (*Name != UNICODE_PATH_SEP) {
  3981. break;
  3982. }
  3983. Name++;
  3984. }
  3985. NameLen -= (ULONG)(Name - pParam->DomainName);
  3986. for (i = 0; i < NameLen && Name[i]; i++)
  3987. NOTHING;
  3988. if ((i >= NameLen) || (i >= MAXUSHORT)) {
  3989. NtStatus = STATUS_INVALID_PARAMETER;
  3990. goto exit_with_status;
  3991. }
  3992. RtlInitUnicodeString(&DomainName, Name);
  3993. NameLen = (ULONG)(BufferEnd - pParam->DCName);
  3994. Name = pParam->DCName;
  3995. // Strip off leading slashes.
  3996. for (i = 0; i < NameLen; i++) {
  3997. if (*Name != UNICODE_PATH_SEP) {
  3998. break;
  3999. }
  4000. Name++;
  4001. }
  4002. NameLen -= (ULONG)(Name - pParam->DCName);
  4003. for (i = 0; i < NameLen && Name[i]; i++)
  4004. NOTHING;
  4005. if ((i >= NameLen) || (i >= MAXUSHORT)) {
  4006. NtStatus = STATUS_INVALID_PARAMETER;
  4007. goto exit_with_status;
  4008. }
  4009. RtlInitUnicodeString(&DCName, Name);
  4010. NtStatus = PktpUpdateSpecialTable(
  4011. &DomainName,
  4012. &DCName);
  4013. exit_with_status:
  4014. DfsCompleteRequest( IrpContext, Irp, NtStatus );
  4015. DfsDbgTrace(-1, Dbg, "DfsFsctrlSpcRefresh -> %08lx\n", ULongToPtr(NtStatus) );
  4016. return( NtStatus );
  4017. }