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

676 lines
18 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)ALIGN_SMB_WSTR( request->RequestFileName );
  187. dfsName.Length = MIN( (USHORT)( END_OF_TRANSACTION_PARAMETERS( transaction ) - (PCHAR)dfsName.Buffer + 1) & ~0x1, 0xFFEE );
  188. dfsName.MaximumLength = dfsName.Length;
  189. dfsName.Length -= sizeof(UNICODE_NULL);
  190. dataCount = transaction->MaxDataCount;
  191. status = DfsGetReferrals( WorkContext->Connection->ClientIPAddress,
  192. &dfsName, request->MaxReferralLevel,
  193. transaction->OutData,
  194. &dataCount );
  195. if( !NT_SUCCESS( status ) ) {
  196. SrvSetSmbError( WorkContext, status );
  197. SmbStatus = SmbTransStatusErrorWithoutData;
  198. goto Cleanup;
  199. }
  200. transaction->SetupCount = 0;
  201. transaction->ParameterCount = 0;
  202. transaction->DataCount = dataCount;
  203. SmbStatus = SmbTransStatusSuccess;
  204. Cleanup:
  205. SrvWmiEndContext(WorkContext);
  206. return SmbStatus;
  207. }
  208. NTSTATUS
  209. DfsGetReferrals(
  210. ULONG IPAddress,
  211. PUNICODE_STRING DfsName,
  212. USHORT MaxReferralLevel,
  213. PVOID ReferralListBuffer,
  214. PULONG SizeReferralListBuffer
  215. )
  216. {
  217. DFS_GET_REFERRALS_INPUT_ARG dfsArgs;
  218. IO_STATUS_BLOCK ioStatus;
  219. PRESP_GET_DFS_REFERRAL pResp;
  220. PUCHAR eBuffer;
  221. ULONG i;
  222. PAGED_CODE();
  223. if( SrvDfsFastIoDeviceControl == NULL ) {
  224. return STATUS_FS_DRIVER_REQUIRED;
  225. }
  226. IF_DEBUG( DFS ) {
  227. KdPrint(( "SRV: Referral sought for: <%wZ>\n", DfsName ));
  228. }
  229. //
  230. // Call DFS, getting back the vector of referrals
  231. //
  232. RtlZeroMemory( &dfsArgs, sizeof(dfsArgs) );
  233. dfsArgs.DfsPathName = *DfsName;
  234. dfsArgs.MaxReferralLevel = MaxReferralLevel;
  235. if( IPAddress != 0 ) {
  236. dfsArgs.IpAddress.IpFamily = TDI_ADDRESS_TYPE_IP;
  237. dfsArgs.IpAddress.IpLen = sizeof( IPAddress );
  238. RtlCopyMemory( dfsArgs.IpAddress.IpData, &IPAddress, sizeof( IPAddress ) );
  239. }
  240. SrvDfsFastIoDeviceControl(
  241. SrvDfsFileObject,
  242. TRUE,
  243. &dfsArgs,
  244. sizeof( dfsArgs ),
  245. ReferralListBuffer,
  246. *SizeReferralListBuffer,
  247. FSCTL_DFS_GET_REFERRALS,
  248. &ioStatus,
  249. SrvDfsDeviceObject
  250. );
  251. if( NT_SUCCESS( ioStatus.Status ) ||
  252. ioStatus.Status == STATUS_BUFFER_OVERFLOW ) {
  253. *SizeReferralListBuffer = (ULONG)ioStatus.Information;
  254. } else {
  255. IF_DEBUG( DFS ) {
  256. KdPrint(("\tSrvDfsFastIoDeviceControl returned %X, 0x%p\n",
  257. ioStatus.Status, (PVOID)ioStatus.Information ));
  258. }
  259. }
  260. return ioStatus.Status;
  261. }
  262. SMB_TRANS_STATUS
  263. SrvSmbReportDfsInconsistency (
  264. IN OUT PWORK_CONTEXT WorkContext
  265. )
  266. {
  267. //
  268. // We no longer support middle triangles in DFS
  269. //
  270. SrvSetSmbError( WorkContext, STATUS_NOT_SUPPORTED );
  271. return SmbTransStatusErrorWithoutData;
  272. #if XXX
  273. PTRANSACTION transaction;
  274. UNICODE_STRING dfsName;
  275. PREQ_REPORT_DFS_INCONSISTENCY request;
  276. PDFS_REFERRAL_V1 ref;
  277. PTREE_CONNECT treeConnect;
  278. PSHARE share;
  279. DFS_REPORT_INCONSISTENCY_ARG dfsArgs;
  280. IO_STATUS_BLOCK ioStatus;
  281. PAGED_CODE();
  282. transaction = WorkContext->Parameters.Transaction;
  283. request = (PREQ_REPORT_DFS_INCONSISTENCY)transaction->InParameters;
  284. ref = (PDFS_REFERRAL_V1)transaction->InData;
  285. //
  286. // Verify that enough parameter bytes were sent and the SMB is unicode
  287. //
  288. if( transaction->ParameterCount < sizeof( *request ) ||
  289. !SMB_IS_UNICODE( WorkContext ) ) {
  290. //
  291. // Not enough parameter bytes were sent.
  292. //
  293. IF_DEBUG( DFS ) {
  294. KdPrint(( "SrvSmbReportDfsInconsistency: bad parameter byte counts: "
  295. "%ld %ld\n",
  296. transaction->ParameterCount, sizeof( *request ) ));
  297. if( !SMB_IS_UNICODE( WorkContext ) ) {
  298. KdPrint(( "SrvSmbReportDfsInconsistency: NOT UNICODE!\n" ));
  299. }
  300. }
  301. SrvLogInvalidSmb( WorkContext );
  302. SrvSetSmbError( WorkContext, STATUS_INVALID_SMB );
  303. return SmbTransStatusErrorWithoutData;
  304. }
  305. //
  306. // This SMB can only be sent over IPC$, by a logged-in user
  307. //
  308. treeConnect = transaction->TreeConnect;
  309. share = treeConnect->Share;
  310. if( share->ShareType != ShareTypePipe ||
  311. transaction->Session->IsNullSession ) {
  312. IF_DEBUG( DFS ) {
  313. if( share->ShareType != ShareTypePipe ) {
  314. KdPrint(( "SrvSmbReportDfsInconsistency: Wrong share type %d\n", share->ShareType ));
  315. }
  316. if( transaction->Session->IsNullSession ) {
  317. KdPrint(( "SrvSmbReportDfsInconsistency: NULL session!\n" ));
  318. }
  319. }
  320. SrvSetSmbError( WorkContext, STATUS_ACCESS_DENIED );
  321. return SmbTransStatusErrorWithoutData;
  322. }
  323. dfsName.Buffer = ALIGN_SMB_WSTR( request->RequestFileName );
  324. dfsName.Length = (USHORT)transaction->TotalParameterCount -
  325. sizeof(UNICODE_NULL);
  326. dfsName.MaximumLength = dfsName.Length;
  327. IF_DEBUG( DFS ) {
  328. KdPrint(( "SrvSmbReportDfsInconsistency: %wZ\n", &dfsName ));
  329. }
  330. dfsArgs.DfsPathName = dfsName;
  331. dfsArgs.Ref = (PBYTE) ref;
  332. if (SrvDfsFastIoDeviceControl != NULL) {
  333. SrvDfsFastIoDeviceControl(
  334. SrvDfsFileObject,
  335. TRUE,
  336. &dfsArgs,
  337. sizeof( dfsArgs ),
  338. NULL,
  339. 0,
  340. FSCTL_DFS_REPORT_INCONSISTENCY,
  341. &ioStatus,
  342. SrvDfsDeviceObject
  343. );
  344. }
  345. transaction->ParameterCount = 0;
  346. transaction->DataCount = 0;
  347. return SmbTransStatusSuccess;
  348. #endif
  349. }
  350. NTSTATUS SRVFASTCALL
  351. DfsNormalizeName(
  352. IN PSHARE Share,
  353. IN PUNICODE_STRING RelatedPath OPTIONAL,
  354. IN BOOLEAN StripLastComponent,
  355. IN PUNICODE_STRING String
  356. )
  357. {
  358. DFS_TRANSLATE_PATH_ARG dfsArgs;
  359. IO_STATUS_BLOCK ioStatus;
  360. #if DBG
  361. UNICODE_STRING save = *String;
  362. #endif
  363. PAGED_CODE();
  364. //
  365. // If Share->NtPathName covers String, then the remaining pathname in String->Buffer should
  366. // be moved to String->Buffer and String->Length should be adjusted. In other words, on return
  367. // the value of String->Buffer must not be changed, but the contents of String->Buffer needs to
  368. // be adjusted.
  369. //
  370. ASSERT( String->Buffer != NULL );
  371. IF_DEBUG( DFS ) {
  372. KdPrint(( "DfsNormalizeName: %p, Share: %wZ\n", String, &Share->NtPathName ));
  373. }
  374. if( Share->ShareType == ShareTypeDisk &&
  375. SrvDfsFastIoDeviceControl != NULL ) {
  376. //
  377. // Make an FSCTL to the DFS driver to normalize the name
  378. //
  379. dfsArgs.Flags = 0;
  380. if (StripLastComponent)
  381. dfsArgs.Flags |= DFS_TRANSLATE_STRIP_LAST_COMPONENT;
  382. dfsArgs.SubDirectory = Share->NtPathName;
  383. if (ARGUMENT_PRESENT(RelatedPath)) {
  384. UNICODE_STRING Parent;
  385. //ASSERT(RelatedPath->Length >= Share->DosPathName.Length);
  386. if (RelatedPath->Length <= Share->DosPathName.Length) {
  387. Parent.MaximumLength = Parent.Length = sizeof(WCHAR);
  388. Parent.Buffer = L"\\";
  389. } else {
  390. Parent.MaximumLength = Parent.Length =
  391. RelatedPath->Length - Share->DosPathName.Length;
  392. Parent.Buffer =
  393. &RelatedPath->Buffer[ Share->DosPathName.Length/sizeof(WCHAR) ];
  394. }
  395. dfsArgs.ParentPathName = Parent;
  396. } else {
  397. dfsArgs.ParentPathName.Length = 0;
  398. dfsArgs.ParentPathName.MaximumLength = 0;
  399. dfsArgs.ParentPathName.Buffer = NULL;
  400. }
  401. dfsArgs.DfsPathName = *String;
  402. SrvDfsFastIoDeviceControl(
  403. SrvDfsFileObject,
  404. TRUE,
  405. &dfsArgs,
  406. sizeof( dfsArgs ),
  407. NULL,
  408. 0,
  409. FSCTL_DFS_TRANSLATE_PATH,
  410. &ioStatus,
  411. SrvDfsDeviceObject
  412. );
  413. if (NT_SUCCESS(ioStatus.Status)) {
  414. ASSERT( dfsArgs.DfsPathName.Buffer == String->Buffer );
  415. ASSERT( dfsArgs.DfsPathName.Length <= String->Length );
  416. ASSERT( dfsArgs.DfsPathName.MaximumLength >= dfsArgs.DfsPathName.Length );
  417. *String = dfsArgs.DfsPathName;
  418. IF_DEBUG( DFS ) {
  419. KdPrint(( "\t%wZ\n", String ));
  420. }
  421. }
  422. } else {
  423. ioStatus.Status = STATUS_FS_DRIVER_REQUIRED;
  424. }
  425. ASSERT( save.Buffer == String->Buffer );
  426. ASSERT( save.Length >= String->Length );
  427. if( !NT_SUCCESS( ioStatus.Status ) ) {
  428. IF_DEBUG( DFS ) {
  429. KdPrint(( "\tStatus %X\n", ioStatus.Status ));
  430. }
  431. }
  432. return ioStatus.Status;
  433. }
  434. NTSTATUS SRVFASTCALL
  435. DfsFindShareName(
  436. IN PUNICODE_STRING ShareName
  437. )
  438. {
  439. NTSTATUS status = STATUS_BAD_NETWORK_NAME;
  440. DFS_FIND_SHARE_ARG dfsArgs;
  441. IO_STATUS_BLOCK ioStatus;
  442. KAPC_STATE ApcState;
  443. PEPROCESS process;
  444. //
  445. // Ensure we are in the system process
  446. //
  447. process = IoGetCurrentProcess();
  448. if ( process != SrvServerProcess ) {
  449. KeStackAttachProcess( SrvServerProcess, &ApcState );
  450. }
  451. //
  452. // If 'shareName' is known to the DFS driver, then we must return
  453. // STATUS_PATH_NOT_COVERED. Otherwise we must return STATUS_BAD_NETWORK_NAME.
  454. // This will cause the DFS client to come back and ask for a referral through
  455. // the normal mechanism.
  456. //
  457. IF_DEBUG( DFS ) {
  458. KdPrint(( "SRV: DfsFindShareName: %wZ\n", ShareName ));
  459. }
  460. if( SrvDfsFastIoDeviceControl != NULL ) {
  461. dfsArgs.ShareName = *ShareName;
  462. SrvDfsFastIoDeviceControl(
  463. SrvDfsFileObject,
  464. TRUE,
  465. &dfsArgs,
  466. sizeof( dfsArgs ),
  467. NULL,
  468. 0,
  469. FSCTL_DFS_FIND_SHARE,
  470. &ioStatus,
  471. SrvDfsDeviceObject
  472. );
  473. if( ioStatus.Status == STATUS_PATH_NOT_COVERED ) {
  474. status = ioStatus.Status;
  475. }
  476. }
  477. IF_DEBUG( DFS ) {
  478. KdPrint(( "SRV: DfsFindShareName: status %X\n", status ));
  479. }
  480. //
  481. // Get back to where we were
  482. //
  483. if( process != SrvServerProcess ) {
  484. KeUnstackDetachProcess( &ApcState );
  485. }
  486. return status;
  487. }
  488. VOID SRVFASTCALL
  489. SrvIsShareInDfs(
  490. IN PSHARE Share,
  491. OUT BOOLEAN *IsDfs,
  492. OUT BOOLEAN *IsDfsRoot
  493. )
  494. {
  495. DFS_IS_SHARE_IN_DFS_ARG dfsArgs;
  496. IO_STATUS_BLOCK ioStatus;
  497. KAPC_STATE ApcState;
  498. PEPROCESS process;
  499. PAGED_CODE();
  500. *IsDfs = FALSE;
  501. *IsDfsRoot = FALSE;
  502. if( Share->ShareType != ShareTypeDisk ||
  503. SrvDfsFastIoDeviceControl == NULL ) {
  504. return;
  505. }
  506. dfsArgs.ServerType = 1; // SMB server
  507. dfsArgs.ShareName = Share->ShareName;
  508. dfsArgs.SharePath = Share->NtPathName;
  509. //
  510. // Ensure we are in the system process
  511. //
  512. process = IoGetCurrentProcess();
  513. if ( process != SrvServerProcess ) {
  514. KeStackAttachProcess( SrvServerProcess, &ApcState );
  515. }
  516. SrvDfsFastIoDeviceControl(
  517. SrvDfsFileObject,
  518. TRUE,
  519. &dfsArgs,
  520. sizeof( dfsArgs ),
  521. NULL,
  522. 0,
  523. FSCTL_DFS_IS_SHARE_IN_DFS,
  524. &ioStatus,
  525. SrvDfsDeviceObject
  526. );
  527. //
  528. // Get back to where we were
  529. //
  530. if( process != SrvServerProcess ) {
  531. KeUnstackDetachProcess( &ApcState );
  532. }
  533. if (NT_SUCCESS(ioStatus.Status)) {
  534. if (dfsArgs.ShareType & DFS_SHARE_TYPE_DFS_VOLUME)
  535. *IsDfs = TRUE;
  536. if (dfsArgs.ShareType & DFS_SHARE_TYPE_ROOT)
  537. *IsDfsRoot = TRUE;
  538. }
  539. }