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.

548 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: testsup.c
  6. //
  7. // Contents: This file contains functions which are purportedly
  8. // useful for testing the DsFs driver.
  9. //
  10. // Functions: DsfsCleanup -- Cleanup opened files, etc.
  11. // DsfsDefineLogicalRoot -- Define a logical root to the FSD
  12. // DsfsDefineProvider -- Define a DFS provider
  13. // DsfsAddPrefix - Add an entry path to the FSD's prefix table
  14. // DsfsDelPrefix - Delete a prefix table entry in the FSD
  15. // DsfsUpdReferralList - update the referral list of a prefix entry
  16. // DsfsReadStruct - Return dsfs data structures.
  17. // DfsCreateSymbolicLink - create a symbolic link for logical root
  18. //
  19. // History: 04 Feb 1992 alanw Created.
  20. // 30 May 1992 alanw Added DfsCreateSymbolicLink
  21. //
  22. // Notes: These functions are not necessarily multi-thread safe.
  23. //
  24. //--------------------------------------------------------------------------
  25. #include "nt.h"
  26. #include "ntrtl.h"
  27. #include "nturtl.h"
  28. #include "wchar.h"
  29. #include "dsfsctl.h"
  30. #include "testsup.h"
  31. #include "dfsstr.h"
  32. #define MAX_ENTRY_PATH 80 // max. length of an entry path
  33. #define LOG_ROOT_LENGTH 16 // max. length of a logical root name
  34. #define LMRDR L"\\Device\\LanmanRedirector\\"
  35. extern PWSTR gpwszServer;
  36. HANDLE DsfsFile = NULL;
  37. PWSTR DsfsDeviceName = L"\\Dfs";
  38. PWSTR DsfsLogicalRootName = L"\\Device\\WinDFS";
  39. //
  40. // from PKT.H
  41. //
  42. #define DFS_SERVICE_TYPE_LOCAL (0x0004)
  43. //+-------------------------------------------------------------------------
  44. //
  45. // Function: DsfsOpenDevice, local
  46. //
  47. // Synopsis: Conditionally open the Dsfs file system device object.
  48. //
  49. // Arguments: -none-
  50. //
  51. // Returns: NTSTATUS - STATUS_SUCCESS if the device was opened
  52. // successfully.
  53. //
  54. //--------------------------------------------------------------------------
  55. NTSTATUS
  56. DsfsOpenDevice(
  57. void
  58. ) {
  59. NTSTATUS Stat;
  60. OBJECT_ATTRIBUTES ObjAttrs;
  61. UNICODE_STRING DsfsName;
  62. IO_STATUS_BLOCK IoStatus;
  63. if (DsfsFile == NULL) {
  64. WCHAR wszServer[sizeof(LMRDR) / sizeof(WCHAR) +
  65. 16 + // max NetBIOS machine name length
  66. sizeof(ROOT_SHARE_NAME) / sizeof(WCHAR) +
  67. 1];
  68. if(gpwszServer != NULL) {
  69. swprintf(wszServer,
  70. L"%ws%ws%ws",
  71. LMRDR,
  72. gpwszServer,
  73. ROOT_SHARE_NAME);
  74. RtlInitUnicodeString( &DsfsName, wszServer );
  75. }
  76. else {
  77. RtlInitUnicodeString( &DsfsName, DsfsDeviceName );
  78. }
  79. InitializeObjectAttributes( &ObjAttrs, &DsfsName,
  80. OBJ_CASE_INSENSITIVE, NULL, NULL);
  81. Stat = NtCreateFile(
  82. &DsfsFile,
  83. FILE_READ_DATA | SYNCHRONIZE,
  84. &ObjAttrs,
  85. &IoStatus,
  86. NULL,
  87. FILE_ATTRIBUTE_NORMAL,
  88. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  89. FILE_OPEN_IF,
  90. FILE_CREATE_TREE_CONNECTION |
  91. FILE_SYNCHRONOUS_IO_NONALERT,
  92. NULL,
  93. 0);
  94. if ( NT_SUCCESS(Stat) )
  95. Stat = IoStatus.Status;
  96. return Stat;
  97. }
  98. return STATUS_SUCCESS;
  99. }
  100. //+-------------------------------------------------------------------------
  101. //
  102. // Function: DsfsDoFsctl, local
  103. //
  104. // Synopsis: Issues an NtFsControlFile call to the Dsfs file system
  105. // driver. This is a helper routine that just assures that
  106. // the device is opened, and supplies some conventional
  107. // parameters.
  108. //
  109. // Arguments: [FsControlCode] -- The file system control code to be used
  110. // [InputBuffer] -- The fsctl input buffer
  111. // [InputBufferLength]
  112. // [OutputBuffer] -- The fsctl output buffer
  113. // [OutputBufferLength]
  114. //
  115. // Returns: NTSTATUS - the status of the open or fsctl operation.
  116. //
  117. //--------------------------------------------------------------------------
  118. NTSTATUS
  119. DsfsDoFsctl(
  120. IN ULONG FsControlCode,
  121. IN PVOID InputBuffer OPTIONAL,
  122. IN ULONG InputBufferLength,
  123. OUT PVOID OutputBuffer OPTIONAL,
  124. IN ULONG OutputBufferLength
  125. ) {
  126. NTSTATUS Stat;
  127. IO_STATUS_BLOCK IoStatus;
  128. Stat = DsfsOpenDevice();
  129. if (! NT_SUCCESS(Stat))
  130. return Stat;
  131. Stat = NtFsControlFile(
  132. DsfsFile,
  133. NULL, // Event,
  134. NULL, // ApcRoutine,
  135. NULL, // ApcContext,
  136. &IoStatus,
  137. FsControlCode,
  138. InputBuffer,
  139. InputBufferLength,
  140. OutputBuffer,
  141. OutputBufferLength );
  142. if ( NT_SUCCESS(Stat) ) {
  143. Stat = IoStatus.Status;
  144. }
  145. return Stat;
  146. }
  147. //+-------------------------------------------------------------------------
  148. //
  149. // Function: DsfsCleanup, public
  150. //
  151. // Synopsis: DsfsCleanup will release any resources held by the
  152. // module (the open file handle to the Dsfs device).
  153. //
  154. // Arguments: -none-
  155. //
  156. // Returns: -none-
  157. //
  158. //--------------------------------------------------------------------------
  159. VOID
  160. DsfsCleanup(
  161. void
  162. ) {
  163. if (DsfsFile == NULL) {
  164. (VOID) NtClose(DsfsFile);
  165. DsfsFile = NULL;
  166. }
  167. return;
  168. }
  169. //+-------------------------------------------------------------------------
  170. //
  171. // Function: DsfsDefineLogicalRoot, public
  172. //
  173. // Synopsis: This routine will issue the Define Logical Root fsctl
  174. // to the Dsfs file system driver. If successful, this
  175. // will create a new DS logical root.
  176. //
  177. // Effects: A new DS logical root is created in the DSFS driver.
  178. // It may also be necessary to create a symbolic link to
  179. // \DosDevices and inform the Cairo OSM to complete the
  180. // operation.
  181. //
  182. // Arguments: [LogicalRoot] -- the name of the logical root to be
  183. // created
  184. //
  185. // Returns: NTSTATUS - the status of the operation.
  186. //
  187. // Notes: Generally, only one DS logical root will exist (org).
  188. // Others, such as domain and udomain will be symbolic links
  189. // to somewhere within org.
  190. //
  191. //--------------------------------------------------------------------------
  192. NTSTATUS
  193. DsfsDefineLogicalRoot(
  194. IN PWSTR LogicalRoot
  195. ) {
  196. NTSTATUS Stat;
  197. WCHAR Buffer[ LOG_ROOT_LENGTH + MAX_ENTRY_PATH ];
  198. PFILE_DFS_DEF_ROOT_BUFFER pDlrBuf =
  199. (PFILE_DFS_DEF_ROOT_BUFFER) &Buffer[0];
  200. int i;
  201. for (i=0; i<15; i++) {
  202. pDlrBuf->LogicalRoot[i] = *LogicalRoot++;
  203. if (pDlrBuf->LogicalRoot[i] == (WCHAR) ':')
  204. break;
  205. if (pDlrBuf->LogicalRoot[i] == UNICODE_NULL)
  206. break;
  207. }
  208. pDlrBuf->LogicalRoot[i] = UNICODE_NULL;
  209. // if (ARGUMENT_PRESENT(EntryPath)) {
  210. // for (i=0; i<MAX_ENTRY_PATH; i++) {
  211. // pDlrBuf->PrefixName[i] = *LogicalRoot++;
  212. // if (pDlrBuf->PrefixName[i] == (WCHAR) '/')
  213. // pDlrBuf->PrefixName[i] = (WCHAR) '\\';
  214. // if (pDlrBuf->PrefixName[i] == UNICODE_NULL)
  215. // break;
  216. // }
  217. // if (i >= MAX_ENTRY_PATH) {
  218. // return STATUS_BUFFER_TOO_SMALL;
  219. // }
  220. // }
  221. Stat = DsfsDoFsctl(
  222. FSCTL_DFS_DEFINE_LOGICAL_ROOT,
  223. (PVOID)pDlrBuf,
  224. sizeof *pDlrBuf,
  225. NULL,
  226. 0);
  227. return Stat;
  228. }
  229. //+-------------------------------------------------------------------------
  230. //
  231. // Function: DsfsReadStruct, public
  232. //
  233. // Synopsis: A dsfs data structure is returned
  234. //
  235. // Arguments: [pRsParam] -- The Fsctl buffer which describes the
  236. // data structure to be returned.
  237. // [pucData] -- Pointer to a buffer where the data will
  238. // be returned.
  239. //
  240. // Returns: NTSTATUS - the status of the operation.
  241. //
  242. // Notes: This call will be effective on a debug build of the
  243. // dsfs driver only.
  244. //
  245. //--------------------------------------------------------------------------
  246. NTSTATUS
  247. DsfsReadStruct(
  248. PFILE_DFS_READ_STRUCT_PARAM pRsParam,
  249. PUCHAR pucData
  250. )
  251. {
  252. NTSTATUS Stat;
  253. Stat = DsfsDoFsctl(
  254. FSCTL_DFS_INTERNAL_READSTRUCT,
  255. (PVOID)pRsParam,
  256. sizeof *pRsParam,
  257. (PVOID)pucData,
  258. (ULONG)pRsParam->ByteCount);
  259. return Stat;
  260. }
  261. //+-------------------------------------------------------------------
  262. //
  263. // Function: DfsCreateSymbolicLink, public
  264. //
  265. // Synopsis: This function creates a symbolic link object for the specified
  266. // local device name which is linked to the logical root device
  267. // name that has a form of \Device\WinDFS\logicalrootname
  268. //
  269. // Arguments:
  270. // [Local] -- Supplies the local device name.
  271. // [DestStr] -- Supplies the string which is the link target of
  272. // the symbolic link object, if other than the local
  273. // name itself.
  274. //
  275. // Returns: NTSTATUS - STATUS_Success or reason for failure.
  276. //
  277. //--------------------------------------------------------------------
  278. NTSTATUS
  279. DfsCreateSymbolicLink(
  280. IN PWSTR Local,
  281. IN PWSTR DestStr OPTIONAL
  282. )
  283. {
  284. NTSTATUS status;
  285. HANDLE SymbolicLink;
  286. UNICODE_STRING LinkStringU;
  287. UNICODE_STRING DestStringU;
  288. OBJECT_ATTRIBUTES LinkAttributes;
  289. WCHAR LocalName[LOG_ROOT_LENGTH + 1];
  290. WCHAR ExistLinkBuffer[MAXIMUM_FILENAME_LENGTH];
  291. UNICODE_STRING ExistLink;
  292. ExistLink.MaximumLength = sizeof( ExistLinkBuffer );
  293. ExistLink.Buffer = ExistLinkBuffer;
  294. ExistLink.Length = 0;
  295. LinkStringU.Buffer = NULL;
  296. DestStringU.Buffer = NULL;
  297. wcscpy(LocalName, Local);
  298. _wcsupr(LocalName);
  299. //
  300. // Since the logical root name is like a disk device, we want to
  301. // make its name refer to the root directory before calling
  302. // RtlDosNameToNtPathName to convert to NT-style path name.
  303. //
  304. wcscat(LocalName, L"\\");
  305. //
  306. // We expect this routine to generate an NT-style path name that is unique
  307. // per logon user using the Logon Id, so we have to be impersonating the
  308. // user at this point.
  309. //
  310. if (! RtlDosPathNameToNtPathName_U(LocalName, &LinkStringU, NULL, NULL)) {
  311. return STATUS_INVALID_PARAMETER;
  312. }
  313. //
  314. // Remove the trailing slash character in order to create a symbolic
  315. // link of X: rather than X:/
  316. //
  317. LinkStringU.Length -= sizeof(WCHAR);
  318. if (ARGUMENT_PRESENT(DestStr)) {
  319. if (! RtlDosPathNameToNtPathName_U(DestStr, &DestStringU, NULL, NULL)) {
  320. status = STATUS_INVALID_PARAMETER;
  321. goto FreeStrings;
  322. }
  323. RtlFreeUnicodeString(&DestStringU);
  324. if (! DfsCreateLogicalRootName (DestStr, &DestStringU)) {
  325. status = STATUS_INVALID_PARAMETER;
  326. goto FreeStrings;
  327. }
  328. } else {
  329. if (! DfsCreateLogicalRootName (Local, &DestStringU)) {
  330. status = STATUS_INVALID_PARAMETER;
  331. goto FreeStrings;
  332. }
  333. }
  334. //
  335. // About to create a new symbolic link object.
  336. //
  337. InitializeObjectAttributes(
  338. &LinkAttributes,
  339. &LinkStringU,
  340. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  341. NULL,
  342. NULL
  343. );
  344. //
  345. // Check to see if there's already an existing symbolic link.
  346. //
  347. if ((status = NtOpenSymbolicLinkObject(
  348. &SymbolicLink,
  349. DELETE | GENERIC_READ,
  350. &LinkAttributes
  351. )) == STATUS_OBJECT_NAME_NOT_FOUND) {
  352. //
  353. // Logical root name has no link target. Go ahead and
  354. // create the new one.
  355. //
  356. goto CreateLink;
  357. }
  358. else if (! NT_SUCCESS(status)) {
  359. goto FreeStrings;
  360. }
  361. //
  362. // Find out if the device specified is already
  363. // redirected
  364. //
  365. if (! NT_SUCCESS(NtQuerySymbolicLinkObject(
  366. SymbolicLink,
  367. &ExistLink,
  368. NULL
  369. ))) {
  370. goto CloseSymbolicHandle;
  371. }
  372. if (RtlPrefixString( (PSTRING) &DsfsLogicalRootName,
  373. (PSTRING) &ExistLink,
  374. TRUE) == FALSE) {
  375. //
  376. // Device is already redirected to something else
  377. //
  378. status = STATUS_DEVICE_ALREADY_ATTACHED;
  379. goto CloseSymbolicHandle;
  380. }
  381. //
  382. // Device is a DFS symbolic link, let's delete it so that we can create
  383. // a new symbolic link to the DFS logical root.
  384. //
  385. if (! NT_SUCCESS(NtMakeTemporaryObject(
  386. SymbolicLink
  387. ))) {
  388. status = STATUS_INVALID_PARAMETER;
  389. }
  390. CloseSymbolicHandle:
  391. NtClose(SymbolicLink);
  392. if (! NT_SUCCESS(status)) {
  393. goto FreeStrings;
  394. }
  395. CreateLink:
  396. //
  397. // Create a symbolic link object to the device we are redirecting only
  398. // if one does not already exist; or if one existed, it was deleted
  399. // successfully.
  400. //
  401. status = NtCreateSymbolicLinkObject(
  402. &SymbolicLink,
  403. GENERIC_READ | GENERIC_WRITE,
  404. &LinkAttributes,
  405. &DestStringU
  406. );
  407. if (NT_SUCCESS(status)) {
  408. NtClose(SymbolicLink);
  409. }
  410. FreeStrings:
  411. if (DestStringU.Buffer != NULL)
  412. RtlFreeUnicodeString(&DestStringU);
  413. //
  414. // Free memory allocated by RtlDosPathNameToNtPathName
  415. //
  416. if (LinkStringU.Buffer != NULL)
  417. RtlFreeUnicodeString(&LinkStringU);
  418. return status;
  419. }
  420. //+-------------------------------------------------------------------------
  421. //
  422. // Function: DfsCreateLogicalRootName, private
  423. //
  424. // Synopsis: An input logical root style name is converted to be
  425. // an absolute name referring to the NT DFS logical
  426. // root device directory.
  427. //
  428. // Arguments: [Name] -- The input logical root based path name.
  429. // [Dest] -- Pointer to a string in which the translated
  430. // name will be returned.
  431. //
  432. // Returns: BOOLEAN - FALSE if the operation failed.
  433. //
  434. // Notes: The buffer for the string is allocated and should be
  435. // freed by the caller.
  436. //
  437. //--------------------------------------------------------------------------
  438. BOOLEAN
  439. DfsCreateLogicalRootName (
  440. PWSTR Name,
  441. PUNICODE_STRING Dest
  442. )
  443. {
  444. PWSTR Buf = NULL;
  445. PWSTR Src;
  446. int FoundColon = 0;
  447. Dest->MaximumLength = (wcslen(Name) + wcslen(DsfsLogicalRootName) + 2 ) * sizeof (WCHAR);
  448. Buf = RtlAllocateHeap( RtlProcessHeap(), 0, Dest->MaximumLength);
  449. if (Buf == NULL) {
  450. return FALSE;
  451. }
  452. Dest->Buffer = Buf;
  453. for (Src = DsfsLogicalRootName; *Buf++ = *Src++; )
  454. ;
  455. Buf[-1] = (WCHAR) '\\';
  456. for (Src = Name; *Buf = *Src++; Buf++)
  457. if (*Buf == (WCHAR) ':' && !FoundColon) {
  458. Buf--;
  459. FoundColon++;
  460. }
  461. if (Buf[-1] == (WCHAR) '\\')
  462. Buf--;
  463. Dest->Length = (PCHAR)Buf - (PCHAR)Dest->Buffer;
  464. return TRUE;
  465. }