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.

328 lines
8.9 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. MountSup.c
  5. Abstract:
  6. This module implements the support routines in Ntfs for reparse points.
  7. Author:
  8. Felipe Cabrera [cabrera] 30-Jun-1997
  9. Revision History:
  10. --*/
  11. #include "NtfsProc.h"
  12. #define Dbg DEBUG_TRACE_FSCTRL
  13. //
  14. // Define a tag for general pool allocations from this module
  15. //
  16. #undef MODULE_POOL_TAG
  17. #define MODULE_POOL_TAG ('PFtN')
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, NtfsInitializeReparsePointIndex)
  20. #pragma alloc_text(PAGE, NtfsValidateReparsePointBuffer)
  21. #endif
  22. VOID
  23. NtfsInitializeReparsePointIndex (
  24. IN PIRP_CONTEXT IrpContext,
  25. IN PFCB Fcb,
  26. IN PVCB Vcb
  27. )
  28. /*++
  29. Routine Description:
  30. This routine opens the mount points index for the volume. If the index does not
  31. exist it is created and initialized.
  32. Arguments:
  33. Fcb - Pointer to Fcb for the object id file.
  34. Vcb - Volume control block for volume being mounted.
  35. Return Value:
  36. None
  37. --*/
  38. {
  39. UNICODE_STRING IndexName = CONSTANT_UNICODE_STRING( L"$R" );
  40. PAGED_CODE();
  41. NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, 0 );
  42. try {
  43. NtOfsCreateIndex( IrpContext,
  44. Fcb,
  45. IndexName,
  46. CREATE_OR_OPEN,
  47. 0,
  48. COLLATION_NTOFS_ULONGS,
  49. NtOfsCollateUlongs,
  50. NULL,
  51. &Vcb->ReparsePointTableScb );
  52. } finally {
  53. NtfsReleaseFcb( IrpContext, Fcb );
  54. }
  55. }
  56. NTSTATUS
  57. NtfsValidateReparsePointBuffer (
  58. IN ULONG BufferLength,
  59. IN PREPARSE_DATA_BUFFER ReparseBuffer
  60. )
  61. /*++
  62. Routine Description:
  63. This routine verifies that the reparse point buffer is valid.
  64. Arguments:
  65. BufferLength - Length of the reparse point buffer.
  66. ReparseBuffer - The reparse point buffer to be validated.
  67. Return Value:
  68. NTSTATUS - The return status for the operation.
  69. If successful, STATUS_SUCCESS will be returned.
  70. --*/
  71. {
  72. NTSTATUS Status = STATUS_SUCCESS;
  73. ULONG ReparseTag;
  74. USHORT ReparseDataLength;
  75. PREPARSE_GUID_DATA_BUFFER ReparseGuidBuffer;
  76. PAGED_CODE();
  77. //
  78. // Be defensive about the length of the buffer before re-referencing it.
  79. //
  80. ASSERT( REPARSE_DATA_BUFFER_HEADER_SIZE < REPARSE_GUID_DATA_BUFFER_HEADER_SIZE );
  81. if (BufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE) {
  82. //
  83. // Return invalid buffer parameter error.
  84. //
  85. Status = STATUS_IO_REPARSE_DATA_INVALID;
  86. DebugTrace( 0, Dbg, ("Data in buffer is too short.\n") );
  87. return Status;
  88. }
  89. //
  90. // Return if the buffer is too long.
  91. //
  92. if (BufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) {
  93. //
  94. // Return invalid buffer parameter error.
  95. //
  96. Status = STATUS_IO_REPARSE_DATA_INVALID;
  97. DebugTrace( 0, Dbg, ("Data in buffer is too long.\n") );
  98. return Status;
  99. }
  100. //
  101. // Get the header information brought in the buffer.
  102. // While all the headers coincide in the layout of the first three fields we are home free.
  103. //
  104. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseTag) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseTag) );
  105. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, ReparseDataLength) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, ReparseDataLength) );
  106. ASSERT( FIELD_OFFSET(REPARSE_DATA_BUFFER, Reserved) == FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, Reserved) );
  107. ReparseTag = ReparseBuffer->ReparseTag;
  108. ReparseDataLength = ReparseBuffer->ReparseDataLength;
  109. ReparseGuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer;
  110. DebugTrace( 0, Dbg, ("ReparseTag = %08lx, ReparseDataLength = [x]%08lx [d]%08ld\n", ReparseTag, ReparseDataLength, ReparseDataLength) );
  111. //
  112. // Verify that the buffer and the data length in its header are
  113. // internally consistent. We need to have a REPARSE_DATA_BUFFER or a
  114. // REPARSE_GUID_DATA_BUFFER.
  115. //
  116. if (((ULONG)(ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE) != BufferLength) &&
  117. ((ULONG)(ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE) != BufferLength)) {
  118. //
  119. // Return invalid buffer parameter error.
  120. //
  121. Status = STATUS_IO_REPARSE_DATA_INVALID;
  122. DebugTrace( 0, Dbg, ("Buffer is not self-consistent.\n") );
  123. return Status;
  124. }
  125. //
  126. // Sanity check the buffer size combination reserved for Microsoft tags.
  127. //
  128. if ((ULONG)(ReparseDataLength + REPARSE_DATA_BUFFER_HEADER_SIZE) == BufferLength) {
  129. //
  130. // This buffer length can only be used with Microsoft tags.
  131. //
  132. if (!IsReparseTagMicrosoft( ReparseTag )) {
  133. //
  134. // Return buffer parameter error.
  135. //
  136. Status = STATUS_IO_REPARSE_DATA_INVALID;
  137. DebugTrace( 0, Dbg, ("Wrong reparse tag in Microsoft buffer.\n") );
  138. return Status;
  139. }
  140. }
  141. //
  142. // Sanity check the buffer size combination that has a GUID.
  143. //
  144. if ((ULONG)(ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE) == BufferLength) {
  145. //
  146. // If the tag is a non-Microsoft tag, then the GUID cannot be NULL
  147. //
  148. if (!IsReparseTagMicrosoft( ReparseTag )) {
  149. if ((ReparseGuidBuffer->ReparseGuid.Data1 == 0) &&
  150. (ReparseGuidBuffer->ReparseGuid.Data2 == 0) &&
  151. (ReparseGuidBuffer->ReparseGuid.Data3 == 0) &&
  152. (ReparseGuidBuffer->ReparseGuid.Data4[0] == 0) &&
  153. (ReparseGuidBuffer->ReparseGuid.Data4[1] == 0) &&
  154. (ReparseGuidBuffer->ReparseGuid.Data4[2] == 0) &&
  155. (ReparseGuidBuffer->ReparseGuid.Data4[3] == 0) &&
  156. (ReparseGuidBuffer->ReparseGuid.Data4[4] == 0) &&
  157. (ReparseGuidBuffer->ReparseGuid.Data4[5] == 0) &&
  158. (ReparseGuidBuffer->ReparseGuid.Data4[6] == 0) &&
  159. (ReparseGuidBuffer->ReparseGuid.Data4[7] == 0)) {
  160. //
  161. // Return invalid buffer parameter error.
  162. //
  163. Status = STATUS_IO_REPARSE_DATA_INVALID;
  164. DebugTrace( 0, Dbg, ("The GUID is null for a non-Microsoft reparse tag.\n") );
  165. return Status;
  166. }
  167. }
  168. //
  169. // This kind of buffer cannot be used for name grafting operations.
  170. //
  171. if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  172. //
  173. // Return invalid buffer parameter error.
  174. //
  175. Status = STATUS_IO_REPARSE_DATA_INVALID;
  176. DebugTrace( 0, Dbg, ("Attempt to use the GUID buffer for name grafting.\n") );
  177. return Status;
  178. }
  179. }
  180. //
  181. // We verify that the caller has zeroes in all the reserved bits and that she
  182. // sets one of the non-reserved tags. Also fail if the tag is the retired NSS
  183. // flag.
  184. //
  185. if ((ReparseTag & ~IO_REPARSE_TAG_VALID_VALUES) ||
  186. (ReparseTag == IO_REPARSE_TAG_RESERVED_ZERO) ||
  187. (ReparseTag == IO_REPARSE_TAG_RESERVED_ONE)) {
  188. Status = STATUS_IO_REPARSE_TAG_INVALID;
  189. DebugTrace( 0, Dbg, ("Reparse tag is an reserved one.\n") );
  190. return Status;
  191. }
  192. //
  193. // NTFS directory junctions are only to be set at directories and have a valid buffer.
  194. //
  195. if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
  196. //
  197. // Valid ReparseBuffer must have
  198. //
  199. // 1) Enough space for the length fields
  200. // 2) A correct substitute name offset
  201. // 3) A print name offset following the substitute name
  202. // 4) enough space for the path name and substitute name
  203. //
  204. if ((ReparseBuffer->ReparseDataLength <
  205. (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE)) ||
  206. (ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset != 0) ||
  207. (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset !=
  208. (ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof( UNICODE_NULL ))) ||
  209. (ReparseBuffer->ReparseDataLength !=
  210. (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]) - REPARSE_DATA_BUFFER_HEADER_SIZE) +
  211. ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength +
  212. ReparseBuffer->MountPointReparseBuffer.PrintNameLength +
  213. 2 * sizeof( UNICODE_NULL ))) {
  214. Status = STATUS_IO_REPARSE_DATA_INVALID;
  215. DebugTrace( 0, Dbg, ("Invalid mount point reparse buffer.\n") );
  216. return Status;
  217. }
  218. }
  219. return Status;
  220. }