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.

425 lines
12 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Function: main
  4. //
  5. // Arguments:
  6. // argc, argv: the passed in argument list.
  7. //
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <windef.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <stddef.h>
  18. #include <shellapi.h>
  19. #include "rpc.h"
  20. #include "rpcdce.h"
  21. #include <lm.h>
  22. #include <winsock2.h>
  23. #include <tchar.h>
  24. #define IO_REPARSE_TAG_DFS 0x8000000A
  25. #define UNICODE_PATH_SEP L'\\'
  26. VOID
  27. CloseDirectory(
  28. HANDLE DirHandle )
  29. {
  30. NtClose( DirHandle );
  31. }
  32. NTSTATUS
  33. ClearDfsReparsePoint(
  34. IN HANDLE DirHandle )
  35. {
  36. NTSTATUS NtStatus = STATUS_SUCCESS;
  37. REPARSE_DATA_BUFFER ReparseDataBuffer;
  38. IO_STATUS_BLOCK IoStatusBlock;
  39. //
  40. // Attempt to set a reparse point on the directory
  41. //
  42. RtlZeroMemory( &ReparseDataBuffer, sizeof(ReparseDataBuffer) );
  43. ReparseDataBuffer.ReparseTag = IO_REPARSE_TAG_DFS;
  44. ReparseDataBuffer.ReparseDataLength = 0;
  45. NtStatus = NtFsControlFile( DirHandle,
  46. NULL,
  47. NULL,
  48. NULL,
  49. &IoStatusBlock,
  50. FSCTL_DELETE_REPARSE_POINT,
  51. &ReparseDataBuffer,
  52. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataBuffer.ReparseDataLength,
  53. NULL,
  54. 0 );
  55. return NtStatus;
  56. }
  57. NTSTATUS
  58. OpenDirectory(
  59. PUNICODE_STRING pDirectoryName,
  60. ULONG ShareMode,
  61. HANDLE RelativeHandle,
  62. PHANDLE pOpenedHandle,
  63. PBOOLEAN pIsNewlyCreated )
  64. {
  65. NTSTATUS NtStatus;
  66. OBJECT_ATTRIBUTES ObjectAttributes;
  67. ACCESS_MASK DesiredAccess;
  68. PLARGE_INTEGER AllocationSize;
  69. ULONG FileAttributes;
  70. ULONG CreateDisposition;
  71. ULONG CreateOptions;
  72. IO_STATUS_BLOCK IoStatusBlock;
  73. AllocationSize = NULL;
  74. FileAttributes = FILE_ATTRIBUTE_NORMAL;
  75. CreateDisposition = FILE_OPEN_IF;
  76. CreateOptions = FILE_DIRECTORY_FILE |
  77. FILE_OPEN_REPARSE_POINT |
  78. FILE_SYNCHRONOUS_IO_NONALERT;
  79. DesiredAccess = FILE_READ_DATA |
  80. FILE_WRITE_DATA |
  81. FILE_READ_ATTRIBUTES |
  82. FILE_WRITE_ATTRIBUTES |
  83. SYNCHRONIZE;
  84. InitializeObjectAttributes (
  85. &ObjectAttributes,
  86. pDirectoryName, //Object Name
  87. 0, //Attributes
  88. RelativeHandle, //Root handle
  89. NULL); //Security descriptor.
  90. NtStatus = NtCreateFile(pOpenedHandle,
  91. DesiredAccess,
  92. &ObjectAttributes,
  93. &IoStatusBlock,
  94. AllocationSize,
  95. FileAttributes,
  96. ShareMode,
  97. CreateDisposition,
  98. CreateOptions,
  99. NULL, // EaBuffer
  100. 0 ); // EaLength
  101. if ( (NtStatus == STATUS_SUCCESS) && (pIsNewlyCreated != NULL) )
  102. {
  103. *pIsNewlyCreated = (IoStatusBlock.Information == FILE_CREATED)? TRUE : FALSE;
  104. }
  105. return NtStatus;
  106. }
  107. NTSTATUS
  108. IsDirectoryReparsePoint(
  109. IN HANDLE DirHandle,
  110. OUT PBOOLEAN pReparsePoint,
  111. OUT PBOOLEAN pDfsReparsePoint )
  112. {
  113. NTSTATUS NtStatus;
  114. FILE_BASIC_INFORMATION BasicInfo;
  115. IO_STATUS_BLOCK IoStatusBlock;
  116. //
  117. //we assume these are not reparse points.
  118. //
  119. *pReparsePoint = FALSE;
  120. *pDfsReparsePoint = FALSE;
  121. //
  122. // Query for the basic information, which has the attributes.
  123. //
  124. NtStatus = NtQueryInformationFile( DirHandle,
  125. &IoStatusBlock,
  126. (PVOID)&BasicInfo,
  127. sizeof(BasicInfo),
  128. FileBasicInformation );
  129. if (NtStatus == STATUS_SUCCESS)
  130. {
  131. //
  132. // If the attributes indicate reparse point, we have a reparse
  133. // point directory on our hands.
  134. //
  135. if ( BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  136. {
  137. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  138. *pReparsePoint = TRUE;
  139. NtStatus = NtQueryInformationFile( DirHandle,
  140. &IoStatusBlock,
  141. (PVOID)&FileTagInformation,
  142. sizeof(FileTagInformation),
  143. FileAttributeTagInformation );
  144. if (NtStatus == STATUS_SUCCESS)
  145. {
  146. //
  147. // Checkif the tag indicates its a DFS reparse point,
  148. // and setup the return accordingly.
  149. //
  150. if (FileTagInformation.ReparseTag == IO_REPARSE_TAG_DFS)
  151. {
  152. *pDfsReparsePoint = TRUE;
  153. }
  154. }
  155. }
  156. }
  157. return NtStatus;
  158. }
  159. BOOLEAN
  160. IsEmptyDirectory(
  161. HANDLE DirectoryHandle,
  162. PVOID pDirectoryBuffer,
  163. ULONG DirectoryBufferSize )
  164. {
  165. NTSTATUS NtStatus;
  166. FILE_NAMES_INFORMATION *pFileInfo;
  167. ULONG NumberOfFiles = 1;
  168. BOOLEAN ReturnValue = FALSE;
  169. IO_STATUS_BLOCK IoStatus;
  170. NtStatus = NtQueryDirectoryFile ( DirectoryHandle,
  171. NULL, // no event
  172. NULL, // no apc routine
  173. NULL, // no apc context
  174. &IoStatus,
  175. pDirectoryBuffer,
  176. DirectoryBufferSize,
  177. FileNamesInformation,
  178. FALSE, // return single entry = false
  179. NULL, // filename
  180. FALSE ); // restart scan = false
  181. if (NtStatus == ERROR_SUCCESS)
  182. {
  183. pFileInfo = (FILE_NAMES_INFORMATION *)pDirectoryBuffer;
  184. while (pFileInfo->NextEntryOffset) {
  185. NumberOfFiles++;
  186. if (NumberOfFiles > 3)
  187. {
  188. break;
  189. }
  190. pFileInfo = (FILE_NAMES_INFORMATION *)((ULONG_PTR)(pFileInfo) +
  191. pFileInfo->NextEntryOffset);
  192. }
  193. if (NumberOfFiles <= 2)
  194. {
  195. ReturnValue = TRUE;
  196. }
  197. }
  198. return ReturnValue;
  199. }
  200. NTSTATUS
  201. StripLastPathComponent(
  202. PUNICODE_STRING pPath )
  203. {
  204. USHORT i = 0, j;
  205. NTSTATUS Status = STATUS_SUCCESS;
  206. if (pPath->Length == 0)
  207. {
  208. return Status;
  209. }
  210. for( i = (pPath->Length - 1)/ sizeof(WCHAR); i != 0; i--) {
  211. if (pPath->Buffer[i] != UNICODE_PATH_SEP) {
  212. break;
  213. }
  214. }
  215. for (j = i; j != 0; j--){
  216. if (pPath->Buffer[j] == UNICODE_PATH_SEP) {
  217. break;
  218. }
  219. }
  220. pPath->Length = (j) * sizeof(WCHAR);
  221. return Status;
  222. }
  223. NTSTATUS
  224. DeleteLinkDirectories(
  225. PUNICODE_STRING pLinkName,
  226. HANDLE RelativeHandle )
  227. {
  228. UNICODE_STRING DirectoryToDelete = *pLinkName;
  229. NTSTATUS NtStatus = STATUS_SUCCESS;
  230. OBJECT_ATTRIBUTES ObjectAttributes;
  231. HANDLE CurrentDirectory = NULL;
  232. ULONG ShareMode = 0;
  233. ShareMode = FILE_SHARE_READ;
  234. //
  235. // dfsdev: fix this fixed size limit. it will hurt us in the future.
  236. //
  237. ULONG DirectoryBufferSize = 4096;
  238. PBYTE pDirectoryBuffer = new BYTE [DirectoryBufferSize];
  239. if (pDirectoryBuffer == NULL)
  240. {
  241. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  242. }
  243. while ( (NtStatus == STATUS_SUCCESS) && (DirectoryToDelete.Length != 0) )
  244. {
  245. NtStatus = OpenDirectory( &DirectoryToDelete,
  246. ShareMode,
  247. RelativeHandle,
  248. &CurrentDirectory,
  249. NULL );
  250. if (NtStatus == ERROR_SUCCESS)
  251. {
  252. if (IsEmptyDirectory(CurrentDirectory,
  253. pDirectoryBuffer,
  254. DirectoryBufferSize) == FALSE)
  255. {
  256. CloseDirectory( CurrentDirectory );
  257. break;
  258. }
  259. CloseDirectory( CurrentDirectory );
  260. InitializeObjectAttributes (
  261. &ObjectAttributes,
  262. &DirectoryToDelete,
  263. 0,
  264. RelativeHandle,
  265. NULL);
  266. NtStatus = NtDeleteFile( &ObjectAttributes );
  267. StripLastPathComponent( &DirectoryToDelete );
  268. }
  269. }
  270. if (pDirectoryBuffer != NULL)
  271. {
  272. delete [] pDirectoryBuffer;
  273. }
  274. return NtStatus;
  275. }
  276. NTSTATUS
  277. DeleteLinkReparsePoint(
  278. PUNICODE_STRING pDirectoryName,
  279. HANDLE ParentHandle )
  280. {
  281. NTSTATUS NtStatus;
  282. HANDLE LinkDirectoryHandle;
  283. BOOLEAN IsReparsePoint, IsDfsReparsePoint;
  284. NtStatus = OpenDirectory( pDirectoryName,
  285. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  286. ParentHandle,
  287. &LinkDirectoryHandle,
  288. NULL );
  289. if (NtStatus == STATUS_SUCCESS)
  290. {
  291. NtStatus = IsDirectoryReparsePoint( LinkDirectoryHandle,
  292. &IsReparsePoint,
  293. &IsDfsReparsePoint );
  294. if ((NtStatus == STATUS_SUCCESS) &&
  295. (IsDfsReparsePoint == TRUE) )
  296. {
  297. NtStatus = ClearDfsReparsePoint( LinkDirectoryHandle );
  298. wprintf(L"ClearDfsReparsePoint for %s returned %x\n", pDirectoryName->Buffer, NtStatus);
  299. }
  300. else if(NtStatus != STATUS_SUCCESS)
  301. {
  302. NtStatus = RtlNtStatusToDosError(NtStatus);
  303. wprintf(L"Clearing DFS reparse point for %s failed %x\n", pDirectoryName->Buffer);
  304. }
  305. else if(IsDfsReparsePoint == FALSE)
  306. {
  307. wprintf(L"%s does not have a DFS reparse point %x\n", pDirectoryName->Buffer);
  308. }
  309. NtClose( LinkDirectoryHandle );
  310. }
  311. else
  312. {
  313. NtStatus = RtlNtStatusToDosError(NtStatus);
  314. wprintf(L"Open for %s returned %x\n", pDirectoryName->Buffer, NtStatus);
  315. }
  316. if (NtStatus == STATUS_SUCCESS)
  317. {
  318. NtStatus = DeleteLinkDirectories( pDirectoryName,
  319. NULL);
  320. }
  321. return NtStatus;
  322. }
  323. void
  324. _cdecl
  325. _tmain(int argc, LPWSTR *argv[])
  326. {
  327. DWORD Status = 0;
  328. DWORD BuffLen = 0;
  329. LPWSTR lpExistingFileName = NULL;
  330. UNICODE_STRING UnicodeFileName;
  331. if(argc == 1)
  332. {
  333. wprintf(L"Usage: DfsRemoverp [Dir]\n");
  334. ExitProcess (0);
  335. }
  336. BuffLen = (wcslen(L"\\??\\") + 1) * sizeof(WCHAR);
  337. BuffLen += ((wcslen((const wchar_t *)argv[1]) + 1)* sizeof(WCHAR));
  338. lpExistingFileName = (LPWSTR)HeapAlloc (GetProcessHeap(), 0, BuffLen);
  339. if(lpExistingFileName == NULL)
  340. {
  341. wprintf(L"Out of memory\n");
  342. ExitProcess (0);
  343. }
  344. wcscpy(lpExistingFileName, L"\\??\\");
  345. wcscat(lpExistingFileName, (const wchar_t *) argv[1]);
  346. UnicodeFileName.Buffer = lpExistingFileName ;
  347. UnicodeFileName.Length = wcslen(lpExistingFileName) * sizeof(WCHAR);
  348. UnicodeFileName.MaximumLength = UnicodeFileName.Length;
  349. wprintf(L"getting rid of reparse point for %s\n", UnicodeFileName.Buffer);
  350. Status = DeleteLinkReparsePoint( &UnicodeFileName,
  351. NULL);
  352. HeapFree(GetProcessHeap(), 0, lpExistingFileName);
  353. }