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.

677 lines
17 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. dfs.c
  5. Abstract:
  6. This module contains various support routines for processing Dfs related operations.
  7. --*/
  8. #include "precomp.h"
  9. #include "dfs.tmh"
  10. #pragma hdrstop
  11. #include <dfsfsctl.h>
  12. #define BugCheckFileId SRV_FILE_DFS
  13. NTSTATUS
  14. DfsGetReferrals(
  15. ULONG ClientIPAddress,
  16. PUNICODE_STRING DfsName,
  17. USHORT MaxReferralLevel,
  18. PVOID ReferralListBuffer,
  19. PULONG SizeReferralListBuffer
  20. );
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text( PAGE, SrvInitializeDfs )
  23. #pragma alloc_text( PAGE, SrvTerminateDfs )
  24. #pragma alloc_text( PAGE, SrvSmbGetDfsReferral )
  25. #pragma alloc_text( PAGE, SrvSmbReportDfsInconsistency )
  26. #pragma alloc_text( PAGE, DfsGetReferrals )
  27. #pragma alloc_text( PAGE, DfsNormalizeName )
  28. #pragma alloc_text( PAGE, DfsFindShareName )
  29. #pragma alloc_text( PAGE, SrvIsShareInDfs )
  30. #endif
  31. //
  32. // Initialize with the Dfs driver. Called at startup
  33. //
  34. VOID
  35. SrvInitializeDfs()
  36. {
  37. NTSTATUS status;
  38. HANDLE dfsHandle;
  39. UNICODE_STRING dfsDriverName;
  40. OBJECT_ATTRIBUTES objectAttributes;
  41. IO_STATUS_BLOCK ioStatusBlock;
  42. PAGED_CODE();
  43. //
  44. // Get the DFS dispatch entry for file control operations
  45. //
  46. RtlInitUnicodeString( &dfsDriverName, DFS_SERVER_NAME );
  47. SrvInitializeObjectAttributes_U(
  48. &objectAttributes,
  49. &dfsDriverName,
  50. 0,
  51. NULL,
  52. NULL
  53. );
  54. status = IoCreateFile(
  55. &dfsHandle,
  56. GENERIC_READ | GENERIC_WRITE,
  57. &objectAttributes,
  58. &ioStatusBlock,
  59. NULL,
  60. FILE_ATTRIBUTE_NORMAL,
  61. FILE_SHARE_READ | FILE_SHARE_WRITE,
  62. FILE_OPEN,
  63. 0, // Create Options
  64. NULL, // EA Buffer
  65. 0, // EA Length
  66. CreateFileTypeNone, // File type
  67. NULL, // ExtraCreateParameters
  68. IO_FORCE_ACCESS_CHECK // Options
  69. );
  70. if( NT_SUCCESS( status ) ) {
  71. //
  72. // Get a pointer to the fast Device Control entry point of the Dfs driver so
  73. // we can quickly perform Dfs operations
  74. //
  75. status = ObReferenceObjectByHandle(
  76. dfsHandle,
  77. 0,
  78. NULL,
  79. KernelMode,
  80. (PVOID *)&SrvDfsFileObject,
  81. NULL
  82. );
  83. if( NT_SUCCESS( status ) ) {
  84. PFAST_IO_DISPATCH fastIoDispatch;
  85. SrvDfsDeviceObject = IoGetRelatedDeviceObject( SrvDfsFileObject );
  86. fastIoDispatch = SrvDfsDeviceObject->DriverObject->FastIoDispatch;
  87. if( fastIoDispatch != NULL &&
  88. fastIoDispatch->SizeOfFastIoDispatch > FIELD_OFFSET( FAST_IO_DISPATCH, FastIoDeviceControl ) ) {
  89. SrvDfsFastIoDeviceControl = fastIoDispatch->FastIoDeviceControl;
  90. }
  91. if( SrvDfsFastIoDeviceControl == NULL ) {
  92. ObDereferenceObject( SrvDfsFileObject );
  93. SrvDfsFileObject = NULL;
  94. SrvDfsDeviceObject = NULL;
  95. }
  96. }
  97. SrvNtClose( dfsHandle, FALSE );
  98. }
  99. IF_DEBUG( DFS ) {
  100. if( SrvDfsFastIoDeviceControl == NULL ) {
  101. KdPrint(( "SRV: Dfs operations unavailable, status %X\n", status ));
  102. }
  103. }
  104. }
  105. //
  106. // De-initialize with the Dfs driver. Called at server shutdown
  107. //
  108. VOID
  109. SrvTerminateDfs()
  110. {
  111. PAGED_CODE();
  112. //
  113. // Disconnect from the Dfs driver
  114. //
  115. if( SrvDfsFileObject != NULL ) {
  116. SrvDfsFastIoDeviceControl = NULL;
  117. SrvDfsDeviceObject = NULL;
  118. ObDereferenceObject( SrvDfsFileObject );
  119. SrvDfsFileObject = NULL;
  120. }
  121. }
  122. SMB_TRANS_STATUS
  123. SrvSmbGetDfsReferral (
  124. IN OUT PWORK_CONTEXT WorkContext
  125. )
  126. {
  127. PTRANSACTION transaction;
  128. UNICODE_STRING dfsName;
  129. PREQ_GET_DFS_REFERRAL request;
  130. NTSTATUS status = STATUS_SUCCESS;
  131. PTREE_CONNECT treeConnect;
  132. PSHARE share;
  133. PVOID referrals;
  134. ULONG size;
  135. ULONG dataCount;
  136. SMB_TRANS_STATUS SmbStatus = SmbTransStatusInProgress;
  137. PAGED_CODE();
  138. if (WorkContext->PreviousSMB == EVENT_TYPE_SMB_LAST_EVENT)
  139. WorkContext->PreviousSMB = EVENT_TYPE_SMB_GET_DFS_REFERRALS;
  140. SrvWmiStartContext(WorkContext);
  141. transaction = WorkContext->Parameters.Transaction;
  142. request = (PREQ_GET_DFS_REFERRAL)transaction->InParameters;
  143. //
  144. // Verify that enough parameter bytes were sent and that we're allowed
  145. // to return enough parameter bytes.
  146. // The +1 is to ensure that there is at least room for a single unicode
  147. // character in the supplied buffer, since this assumption is implicitly
  148. // made below.
  149. //
  150. if( (transaction->ParameterCount <
  151. sizeof( REQ_GET_DFS_REFERRAL ) + 1) ||
  152. !SMB_IS_UNICODE( WorkContext ) ) {
  153. //
  154. // Not enough parameter bytes were sent.
  155. //
  156. IF_DEBUG( DFS ) {
  157. KdPrint(( "SrvSmbGetDfsReferral: bad parameter byte counts: "
  158. "%ld\n",
  159. transaction->ParameterCount ));
  160. if( !SMB_IS_UNICODE( WorkContext ) ) {
  161. KdPrint(( "SrvSmbGetDfsReferral: NOT UNICODE!\n" ));
  162. }
  163. }
  164. SrvLogInvalidSmb( WorkContext );
  165. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  166. SmbStatus = SmbTransStatusErrorWithoutData;
  167. status = STATUS_INVALID_SMB;
  168. goto Cleanup;
  169. }
  170. //
  171. // This SMB can only be sent over IPC$, by a logged-in user
  172. //
  173. treeConnect = transaction->TreeConnect;
  174. share = treeConnect->Share;
  175. if( share->ShareType != ShareTypePipe ) {
  176. IF_DEBUG( DFS ) {
  177. if( share->ShareType != ShareTypePipe ) {
  178. KdPrint(( "SrvSmbGetDfsReferral: Wrong share type %d\n", share->ShareType ));
  179. }
  180. }
  181. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  182. SmbStatus = SmbTransStatusErrorWithoutData;
  183. status = STATUS_ACCESS_DENIED;
  184. goto Cleanup;
  185. }
  186. dfsName.Buffer = (PWCHAR)( request->RequestFileName );
  187. dfsName.Length = (USHORT)(transaction->TotalParameterCount -
  188. FIELD_OFFSET(REQ_GET_DFS_REFERRAL, RequestFileName));
  189. dfsName.MaximumLength = dfsName.Length;
  190. dfsName.Length -= sizeof(UNICODE_NULL);
  191. dataCount = transaction->MaxDataCount;
  192. status = DfsGetReferrals( WorkContext->Connection->ClientIPAddress,
  193. &dfsName, request->MaxReferralLevel,
  194. transaction->OutData,
  195. &dataCount );
  196. if( !NT_SUCCESS( status ) ) {
  197. SrvSetSmbError( WorkContext, status );
  198. SmbStatus = SmbTransStatusErrorWithoutData;
  199. goto Cleanup;
  200. }
  201. transaction->SetupCount = 0;
  202. transaction->ParameterCount = 0;
  203. transaction->DataCount = dataCount;
  204. SmbStatus = SmbTransStatusSuccess;
  205. Cleanup:
  206. SrvWmiEndContext(WorkContext);
  207. return SmbStatus;
  208. }
  209. NTSTATUS
  210. DfsGetReferrals(
  211. ULONG IPAddress,
  212. PUNICODE_STRING DfsName,
  213. USHORT MaxReferralLevel,
  214. PVOID ReferralListBuffer,
  215. PULONG SizeReferralListBuffer
  216. )
  217. {
  218. DFS_GET_REFERRALS_INPUT_ARG dfsArgs;
  219. IO_STATUS_BLOCK ioStatus;
  220. PRESP_GET_DFS_REFERRAL pResp;
  221. PUCHAR eBuffer;
  222. ULONG i;
  223. PAGED_CODE();
  224. if( SrvDfsFastIoDeviceControl == NULL ) {
  225. return STATUS_FS_DRIVER_REQUIRED;
  226. }
  227. IF_DEBUG( DFS ) {
  228. KdPrint(( "SRV: Referral sought for: <%wZ>\n", DfsName ));
  229. }
  230. //
  231. // Call DFS, getting back the vector of referrals
  232. //
  233. RtlZeroMemory( &dfsArgs, sizeof(dfsArgs) );
  234. dfsArgs.DfsPathName = *DfsName;
  235. dfsArgs.MaxReferralLevel = MaxReferralLevel;
  236. if( IPAddress != 0 ) {
  237. dfsArgs.IpAddress.IpFamily = TDI_ADDRESS_TYPE_IP;
  238. dfsArgs.IpAddress.IpLen = sizeof( IPAddress );
  239. RtlCopyMemory( dfsArgs.IpAddress.IpData, &IPAddress, sizeof( IPAddress ) );
  240. }
  241. SrvDfsFastIoDeviceControl(
  242. SrvDfsFileObject,
  243. TRUE,
  244. &dfsArgs,
  245. sizeof( dfsArgs ),
  246. ReferralListBuffer,
  247. *SizeReferralListBuffer,
  248. FSCTL_DFS_GET_REFERRALS,
  249. &ioStatus,
  250. SrvDfsDeviceObject
  251. );
  252. if( NT_SUCCESS( ioStatus.Status ) ||
  253. ioStatus.Status == STATUS_BUFFER_OVERFLOW ) {
  254. *SizeReferralListBuffer = (ULONG)ioStatus.Information;
  255. } else {
  256. IF_DEBUG( DFS ) {
  257. KdPrint(("\tSrvDfsFastIoDeviceControl returned %X, 0x%p\n",
  258. ioStatus.Status, (PVOID)ioStatus.Information ));
  259. }
  260. }
  261. return ioStatus.Status;
  262. }
  263. SMB_TRANS_STATUS
  264. SrvSmbReportDfsInconsistency (
  265. IN OUT PWORK_CONTEXT WorkContext
  266. )
  267. {
  268. //
  269. // We no longer support middle triangles in DFS
  270. //
  271. SrvSetSmbError( WorkContext, STATUS_NOT_SUPPORTED );
  272. return SmbTransStatusErrorWithoutData;
  273. #if XXX
  274. PTRANSACTION transaction;
  275. UNICODE_STRING dfsName;
  276. PREQ_REPORT_DFS_INCONSISTENCY request;
  277. PDFS_REFERRAL_V1 ref;
  278. PTREE_CONNECT treeConnect;
  279. PSHARE share;
  280. DFS_REPORT_INCONSISTENCY_ARG dfsArgs;
  281. IO_STATUS_BLOCK ioStatus;
  282. PAGED_CODE();
  283. transaction = WorkContext->Parameters.Transaction;
  284. request = (PREQ_REPORT_DFS_INCONSISTENCY)transaction->InParameters;
  285. ref = (PDFS_REFERRAL_V1)transaction->InData;
  286. //
  287. // Verify that enough parameter bytes were sent and the SMB is unicode
  288. //
  289. if( transaction->ParameterCount < sizeof( *request ) ||
  290. !SMB_IS_UNICODE( WorkContext ) ) {
  291. //
  292. // Not enough parameter bytes were sent.
  293. //
  294. IF_DEBUG( DFS ) {
  295. KdPrint(( "SrvSmbReportDfsInconsistency: bad parameter byte counts: "
  296. "%ld %ld\n",
  297. transaction->ParameterCount, sizeof( *request ) ));
  298. if( !SMB_IS_UNICODE( WorkContext ) ) {
  299. KdPrint(( "SrvSmbReportDfsInconsistency: NOT UNICODE!\n" ));
  300. }
  301. }
  302. SrvLogInvalidSmb( WorkContext );
  303. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  304. return SmbTransStatusErrorWithoutData;
  305. }
  306. //
  307. // This SMB can only be sent over IPC$, by a logged-in user
  308. //
  309. treeConnect = transaction->TreeConnect;
  310. share = treeConnect->Share;
  311. if( share->ShareType != ShareTypePipe ||
  312. transaction->Session->IsNullSession ) {
  313. IF_DEBUG( DFS ) {
  314. if( share->ShareType != ShareTypePipe ) {
  315. KdPrint(( "SrvSmbReportDfsInconsistency: Wrong share type %d\n", share->ShareType ));
  316. }
  317. if( transaction->Session->IsNullSession ) {
  318. KdPrint(( "SrvSmbReportDfsInconsistency: NULL session!\n" ));
  319. }
  320. }
  321. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  322. return SmbTransStatusErrorWithoutData;
  323. }
  324. dfsName.Buffer = ALIGN_SMB_WSTR( request->RequestFileName );
  325. dfsName.Length = (USHORT)transaction->TotalParameterCount -
  326. sizeof(UNICODE_NULL);
  327. dfsName.MaximumLength = dfsName.Length;
  328. IF_DEBUG( DFS ) {
  329. KdPrint(( "SrvSmbReportDfsInconsistency: %wZ\n", &dfsName ));
  330. }
  331. dfsArgs.DfsPathName = dfsName;
  332. dfsArgs.Ref = (PBYTE) ref;
  333. if (SrvDfsFastIoDeviceControl != NULL) {
  334. SrvDfsFastIoDeviceControl(
  335. SrvDfsFileObject,
  336. TRUE,
  337. &dfsArgs,
  338. sizeof( dfsArgs ),
  339. NULL,
  340. 0,
  341. FSCTL_DFS_REPORT_INCONSISTENCY,
  342. &ioStatus,
  343. SrvDfsDeviceObject
  344. );
  345. }
  346. transaction->ParameterCount = 0;
  347. transaction->DataCount = 0;
  348. return SmbTransStatusSuccess;
  349. #endif
  350. }
  351. NTSTATUS SRVFASTCALL
  352. DfsNormalizeName(
  353. IN PSHARE Share,
  354. IN PUNICODE_STRING RelatedPath OPTIONAL,
  355. IN BOOLEAN StripLastComponent,
  356. IN PUNICODE_STRING String
  357. )
  358. {
  359. DFS_TRANSLATE_PATH_ARG dfsArgs;
  360. IO_STATUS_BLOCK ioStatus;
  361. #if DBG
  362. UNICODE_STRING save = *String;
  363. #endif
  364. PAGED_CODE();
  365. //
  366. // If Share->NtPathName covers String, then the remaining pathname in String->Buffer should
  367. // be moved to String->Buffer and String->Length should be adjusted. In other words, on return
  368. // the value of String->Buffer must not be changed, but the contents of String->Buffer needs to
  369. // be adjusted.
  370. //
  371. ASSERT( String->Buffer != NULL );
  372. IF_DEBUG( DFS ) {
  373. KdPrint(( "DfsNormalizeName: %p, Share: %wZ\n", String, &Share->NtPathName ));
  374. }
  375. if( Share->ShareType == ShareTypeDisk &&
  376. SrvDfsFastIoDeviceControl != NULL ) {
  377. //
  378. // Make an FSCTL to the DFS driver to normalize the name
  379. //
  380. dfsArgs.Flags = 0;
  381. if (StripLastComponent)
  382. dfsArgs.Flags |= DFS_TRANSLATE_STRIP_LAST_COMPONENT;
  383. dfsArgs.SubDirectory = Share->NtPathName;
  384. if (ARGUMENT_PRESENT(RelatedPath)) {
  385. UNICODE_STRING Parent;
  386. //ASSERT(RelatedPath->Length >= Share->DosPathName.Length);
  387. if (RelatedPath->Length <= Share->DosPathName.Length) {
  388. Parent.MaximumLength = Parent.Length = sizeof(WCHAR);
  389. Parent.Buffer = L"\\";
  390. } else {
  391. Parent.MaximumLength = Parent.Length =
  392. RelatedPath->Length - Share->DosPathName.Length;
  393. Parent.Buffer =
  394. &RelatedPath->Buffer[ Share->DosPathName.Length/sizeof(WCHAR) ];
  395. }
  396. dfsArgs.ParentPathName = Parent;
  397. } else {
  398. dfsArgs.ParentPathName.Length = 0;
  399. dfsArgs.ParentPathName.MaximumLength = 0;
  400. dfsArgs.ParentPathName.Buffer = NULL;
  401. }
  402. dfsArgs.DfsPathName = *String;
  403. SrvDfsFastIoDeviceControl(
  404. SrvDfsFileObject,
  405. TRUE,
  406. &dfsArgs,
  407. sizeof( dfsArgs ),
  408. NULL,
  409. 0,
  410. FSCTL_DFS_TRANSLATE_PATH,
  411. &ioStatus,
  412. SrvDfsDeviceObject
  413. );
  414. if (NT_SUCCESS(ioStatus.Status)) {
  415. ASSERT( dfsArgs.DfsPathName.Buffer == String->Buffer );
  416. ASSERT( dfsArgs.DfsPathName.Length <= String->Length );
  417. ASSERT( dfsArgs.DfsPathName.MaximumLength >= dfsArgs.DfsPathName.Length );
  418. *String = dfsArgs.DfsPathName;
  419. IF_DEBUG( DFS ) {
  420. KdPrint(( "\t%wZ\n", String ));
  421. }
  422. }
  423. } else {
  424. ioStatus.Status = STATUS_FS_DRIVER_REQUIRED;
  425. }
  426. ASSERT( save.Buffer == String->Buffer );
  427. ASSERT( save.Length >= String->Length );
  428. if( !NT_SUCCESS( ioStatus.Status ) ) {
  429. IF_DEBUG( DFS ) {
  430. KdPrint(( "\tStatus %X\n", ioStatus.Status ));
  431. }
  432. }
  433. return ioStatus.Status;
  434. }
  435. NTSTATUS SRVFASTCALL
  436. DfsFindShareName(
  437. IN PUNICODE_STRING ShareName
  438. )
  439. {
  440. NTSTATUS status = STATUS_BAD_NETWORK_NAME;
  441. DFS_FIND_SHARE_ARG dfsArgs;
  442. IO_STATUS_BLOCK ioStatus;
  443. KAPC_STATE ApcState;
  444. PEPROCESS process;
  445. //
  446. // Ensure we are in the system process
  447. //
  448. process = IoGetCurrentProcess();
  449. if ( process != SrvServerProcess ) {
  450. KeStackAttachProcess( SrvServerProcess, &ApcState );
  451. }
  452. //
  453. // If 'shareName' is known to the DFS driver, then we must return
  454. // STATUS_PATH_NOT_COVERED. Otherwise we must return STATUS_BAD_NETWORK_NAME.
  455. // This will cause the DFS client to come back and ask for a referral through
  456. // the normal mechanism.
  457. //
  458. IF_DEBUG( DFS ) {
  459. KdPrint(( "SRV: DfsFindShareName: %wZ\n", ShareName ));
  460. }
  461. if( SrvDfsFastIoDeviceControl != NULL ) {
  462. dfsArgs.ShareName = *ShareName;
  463. SrvDfsFastIoDeviceControl(
  464. SrvDfsFileObject,
  465. TRUE,
  466. &dfsArgs,
  467. sizeof( dfsArgs ),
  468. NULL,
  469. 0,
  470. FSCTL_DFS_FIND_SHARE,
  471. &ioStatus,
  472. SrvDfsDeviceObject
  473. );
  474. if( ioStatus.Status == STATUS_PATH_NOT_COVERED ) {
  475. status = ioStatus.Status;
  476. }
  477. }
  478. IF_DEBUG( DFS ) {
  479. KdPrint(( "SRV: DfsFindShareName: status %X\n", status ));
  480. }
  481. //
  482. // Get back to where we were
  483. //
  484. if( process != SrvServerProcess ) {
  485. KeUnstackDetachProcess( &ApcState );
  486. }
  487. return status;
  488. }
  489. VOID SRVFASTCALL
  490. SrvIsShareInDfs(
  491. IN PSHARE Share,
  492. OUT BOOLEAN *IsDfs,
  493. OUT BOOLEAN *IsDfsRoot
  494. )
  495. {
  496. DFS_IS_SHARE_IN_DFS_ARG dfsArgs;
  497. IO_STATUS_BLOCK ioStatus;
  498. KAPC_STATE ApcState;
  499. PEPROCESS process;
  500. PAGED_CODE();
  501. *IsDfs = FALSE;
  502. *IsDfsRoot = FALSE;
  503. if( Share->ShareType != ShareTypeDisk ||
  504. SrvDfsFastIoDeviceControl == NULL ) {
  505. return;
  506. }
  507. dfsArgs.ServerType = 1; // SMB server
  508. dfsArgs.ShareName = Share->ShareName;
  509. dfsArgs.SharePath = Share->NtPathName;
  510. //
  511. // Ensure we are in the system process
  512. //
  513. process = IoGetCurrentProcess();
  514. if ( process != SrvServerProcess ) {
  515. KeStackAttachProcess( SrvServerProcess, &ApcState );
  516. }
  517. SrvDfsFastIoDeviceControl(
  518. SrvDfsFileObject,
  519. TRUE,
  520. &dfsArgs,
  521. sizeof( dfsArgs ),
  522. NULL,
  523. 0,
  524. FSCTL_DFS_IS_SHARE_IN_DFS,
  525. &ioStatus,
  526. SrvDfsDeviceObject
  527. );
  528. //
  529. // Get back to where we were
  530. //
  531. if( process != SrvServerProcess ) {
  532. KeUnstackDetachProcess( &ApcState );
  533. }
  534. if (NT_SUCCESS(ioStatus.Status)) {
  535. if (dfsArgs.ShareType & DFS_SHARE_TYPE_DFS_VOLUME)
  536. *IsDfs = TRUE;
  537. if (dfsArgs.ShareType & DFS_SHARE_TYPE_ROOT)
  538. *IsDfsRoot = TRUE;
  539. }
  540. }