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.

564 lines
19 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. RdrFsCtl.c
  5. Abstract:
  6. NetpRdrFsControlTree performs an FSCTL (file system control) operation
  7. on a given tree connection name.
  8. Author:
  9. John Rogers (JohnRo) 26-Mar-1991
  10. Environment:
  11. Only runs under NT; has an NT-specific interface (with Win32 types).
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. 26-Mar-91 JohnRo
  15. Created.
  16. 02-Apr-1991 JohnRo
  17. Moved NetpRdrFsControlTree to <netlibnt.h>. Use IF_DEBUG and
  18. NetpNtStatusToApiStatus().
  19. 10-Apr-1991 JohnRo
  20. Various changes suggested by LINT.
  21. 16-Apr-1991 JohnRo
  22. Added a little more debug output.
  23. 07-May-1991 JohnRo
  24. Implement UNICODE. Avoid NET_API_FUNCTION.
  25. 14-Nov-1991 JohnRo
  26. RAID 4407: "NET VIEW" to an NT server gives 2140.
  27. Made changes suggested by PC-LINT. Use more FORMAT_ equates.
  28. Display unexpected create file error even if trace off.
  29. 21-Nov-1991 JohnRo
  30. Removed NT dependencies to reduce recompiles.
  31. 22-Sep-1992 JohnRo
  32. RAID 6739: Browser too slow when not logged into browsed domain.
  33. 21-Jun-1993 JohnRo
  34. RAID 14180: NetServerEnum never returns (alignment bug in
  35. RxpConvertDataStructures).
  36. Also quiet some debug output if other machine just isn't there.
  37. Added tree name to unexpected error debug messages.
  38. Made changes suggested by PC-LINT 5.0
  39. Use NetpKdPrint() where possible.
  40. Use PREFIX_ equates.
  41. --*/
  42. // These must be included first:
  43. #include <nt.h> // IN, etc. (Needed by ntddnfs.h and others.)
  44. #include <windef.h> // LPVOID, etc.
  45. #include <lmcons.h> // NET_API_STATUS, etc.
  46. // These may be included in any order:
  47. #include <debuglib.h> // IF_DEBUG().
  48. #include <lmerr.h> // NERR_Success, etc.
  49. #include <names.h> // NetpIsRemoteNameValid().
  50. #include <netdebug.h> // FORMAT_NTSTATUS, NetpKdPrint(), etc.
  51. #include <netlib.h> // NetpMemoryAllocate().
  52. #include <netlibnt.h> // My prototype.
  53. #include <ntddnfs.h> // DD_NFS_DEVICE_NAME, EA_NAME_ equates, etc.
  54. #include <ntioapi.h> // NtFsControlFile().
  55. #include <ntrtl.h> // Rtl APIs.
  56. #include <ntstatus.h> // NT_SUCCESS(), STATUS_PENDING, etc.
  57. #include <prefix.h> // PREFIX_ equates.
  58. #include <tstr.h> // STRCAT(), STRCPY(), STRLEN().
  59. #include <lmuse.h> // USE_IPC...
  60. #include <align.h> // ALIGN_xxx
  61. NET_API_STATUS
  62. NetpRdrFsControlTree(
  63. IN LPTSTR TreeName,
  64. IN LPTSTR TransportName OPTIONAL,
  65. IN DWORD ConnectionType,
  66. IN DWORD FsControlCode,
  67. IN LPVOID SecurityDescriptor OPTIONAL,
  68. IN LPVOID InputBuffer OPTIONAL,
  69. IN DWORD InputBufferSize,
  70. OUT LPVOID OutputBuffer OPTIONAL,
  71. IN DWORD OutputBufferSize,
  72. IN BOOL NoPermissionRequired
  73. )
  74. /*++
  75. Routine Description:
  76. NetpRdrFsControlTree performs a given FSCTL (file system control)
  77. on a given tree connection name.
  78. Arguments:
  79. TreeName - Remote name to do fsctl to (in \\server\share format).
  80. FsControlCode - function code to pass to the redirector. These are
  81. defined in <ntddnfs.h>.
  82. SecurityDescriptor - optionally points to a security descriptor to be
  83. used when creating the tree connection.
  84. InputBuffer - optionally points to a structure to be passed to the
  85. redirector.
  86. InputBufferSize - size of InputBuffer in bytes; must be zero if
  87. InputBuffer is a NULL pointer.
  88. OutputBuffer - optionally points to a structure to be filled in by the
  89. redirector.
  90. OutputBufferSize - size of OutputBuffer in bytes; must be zero if
  91. OutputBuffer is a NULL pointer.
  92. NoPermissionRequired - TRUE if this is a no permission required API. (I.e.
  93. TRUE if the null session may be used.)
  94. Return Value:
  95. NET_API_STATUS
  96. --*/
  97. {
  98. NET_API_STATUS ApiStatus;
  99. IO_STATUS_BLOCK iosb;
  100. NTSTATUS ntstatus; // Status from NT operations.
  101. OBJECT_ATTRIBUTES objattrTreeConn; // Attrs for tree conn.
  102. LPTSTR pszTreeConn = NULL; // See strTreeConn below.
  103. UNICODE_STRING ucTreeConn;
  104. HANDLE TreeConnHandle = NULL;
  105. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  106. PFILE_FULL_EA_INFORMATION Ea;
  107. USHORT TransportNameSize = 0;
  108. ULONG EaBufferSize = 0;
  109. PWSTR UnicodeTransportName = NULL;
  110. BOOLEAN ImpersonatingAnonymous = FALSE;
  111. HANDLE CurrentToken = NULL;
  112. UCHAR EaNameDomainNameSize = (UCHAR) (ROUND_UP_COUNT(
  113. strlen(EA_NAME_DOMAIN) + sizeof(CHAR),
  114. ALIGN_WCHAR
  115. ) - sizeof(CHAR));
  116. UCHAR EaNamePasswordSize = (UCHAR) (ROUND_UP_COUNT(
  117. strlen(EA_NAME_PASSWORD) + sizeof(CHAR),
  118. ALIGN_WCHAR
  119. ) - sizeof(CHAR));
  120. UCHAR EaNameTransportNameSize = (UCHAR) (ROUND_UP_COUNT(
  121. strlen(EA_NAME_TRANSPORT) + sizeof(CHAR),
  122. ALIGN_WCHAR
  123. ) - sizeof(CHAR));
  124. UCHAR EaNameTypeSize = (UCHAR) (ROUND_UP_COUNT(
  125. strlen(EA_NAME_TYPE) + sizeof(CHAR),
  126. ALIGN_DWORD
  127. ) - sizeof(CHAR));
  128. UCHAR EaNameUserNameSize = (UCHAR) (ROUND_UP_COUNT(
  129. strlen(EA_NAME_USERNAME) + sizeof(CHAR),
  130. ALIGN_WCHAR
  131. ) - sizeof(CHAR));
  132. USHORT TypeSize = sizeof(ULONG);
  133. IF_DEBUG(RDRFSCTL) {
  134. NetpKdPrint(( PREFIX_NETLIB
  135. "NetpRdrFsControlTree: entered, TreeName='"
  136. FORMAT_LPTSTR "', " FORMAT_LPTSTR " session.\n",
  137. TreeName,
  138. NoPermissionRequired ? TEXT("null") : TEXT("non-null") ));
  139. }
  140. if ((TreeName == NULL) || (TreeName[0] == 0)) {
  141. ApiStatus = ERROR_INVALID_PARAMETER;
  142. goto Cleanup;
  143. }
  144. if (! NetpIsRemoteNameValid(TreeName)) {
  145. ApiStatus = ERROR_INVALID_PARAMETER;
  146. goto Cleanup;
  147. }
  148. //
  149. // Build NT-style name for what we're connecting to. Note that there is
  150. // NOT a pair of backslashes anywhere in this name.
  151. //
  152. {
  153. DWORD NameSize =
  154. // /Device/LanManRedirector / server/share \0
  155. ( ( STRLEN((LPTSTR)DD_NFS_DEVICE_NAME_U) + 1 + STRLEN(TreeName) + 1 ) )
  156. * sizeof(TCHAR);
  157. pszTreeConn = (LPTSTR)NetpMemoryAllocate( NameSize );
  158. }
  159. if (pszTreeConn == NULL) {
  160. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  161. goto Cleanup;
  162. }
  163. //
  164. // Build the tree connect name.
  165. //
  166. (void) STRCPY(pszTreeConn, (LPTSTR) DD_NFS_DEVICE_NAME_U);
  167. //
  168. // NOTE: We add 1, (not sizeof(TCHAR)) because pointer arithmetic is done
  169. // in terms of multiples of sizeof(*pointer), not bytes
  170. //
  171. (void) STRCAT(pszTreeConn, TreeName+1); // \server\share
  172. RtlInitUnicodeString(&ucTreeConn, pszTreeConn);
  173. IF_DEBUG(RDRFSCTL) {
  174. NetpKdPrint(( PREFIX_NETLIB
  175. "NetpRdrFsControlTree: UNICODE name is " FORMAT_LPWSTR
  176. ".\n", ucTreeConn.Buffer ));
  177. }
  178. //
  179. // Calculate the number of bytes needed for the EA buffer.
  180. // This may have the transport name. For regular sessions, the user
  181. // name, password, and domain name are implicit. For null sessions, we
  182. // must give 0-len user name, 0-len password, and 0-len domain name.
  183. //
  184. if (ARGUMENT_PRESENT(TransportName)) {
  185. ASSERT(ConnectionType == USE_IPC);
  186. UnicodeTransportName = TransportName;
  187. TransportNameSize = (USHORT) (wcslen(UnicodeTransportName) * sizeof(WCHAR));
  188. EaBufferSize += ROUND_UP_COUNT(
  189. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  190. EaNameTransportNameSize + sizeof(CHAR) +
  191. TransportNameSize,
  192. ALIGN_DWORD
  193. );
  194. }
  195. EaBufferSize += ((ULONG)FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]))+
  196. EaNameTypeSize + sizeof(CHAR) +
  197. TypeSize;
  198. //
  199. // Allocate the EA buffer
  200. //
  201. if ((EaBuffer = NetpMemoryAllocate( EaBufferSize )) == NULL) {
  202. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  203. goto Cleanup;
  204. }
  205. //
  206. // Fill-in the EA buffer.
  207. //
  208. RtlZeroMemory(EaBuffer, EaBufferSize);
  209. Ea = EaBuffer;
  210. if (ARGUMENT_PRESENT(TransportName)) {
  211. //
  212. // Copy the EA name into EA buffer. EA name length does not
  213. // include the zero terminator.
  214. //
  215. strcpy(Ea->EaName, EA_NAME_TRANSPORT);
  216. Ea->EaNameLength = EaNameTransportNameSize;
  217. //
  218. // Copy the EA value into EA buffer. EA value length does not
  219. // include the zero terminator.
  220. //
  221. (VOID) wcscpy(
  222. (LPWSTR) &(Ea->EaName[EaNameTransportNameSize + sizeof(CHAR)]),
  223. UnicodeTransportName
  224. );
  225. Ea->EaValueLength = TransportNameSize;
  226. Ea->NextEntryOffset = ROUND_UP_COUNT(
  227. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
  228. EaNameTransportNameSize + sizeof(CHAR) +
  229. TransportNameSize,
  230. ALIGN_DWORD
  231. );
  232. Ea->Flags = 0;
  233. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  234. }
  235. //
  236. // Copy the EA for the connection type name into EA buffer. EA name length
  237. // does not include the zero terminator.
  238. //
  239. strcpy(Ea->EaName, EA_NAME_TYPE);
  240. Ea->EaNameLength = EaNameTypeSize;
  241. *((PULONG) &(Ea->EaName[EaNameTypeSize + sizeof(CHAR)])) = ConnectionType;
  242. Ea->EaValueLength = TypeSize;
  243. Ea->NextEntryOffset = 0;
  244. Ea->Flags = 0;
  245. // Set object attributes for the tree conn.
  246. InitializeObjectAttributes(
  247. & objattrTreeConn, // obj attr to init
  248. (LPVOID) & ucTreeConn, // string to use
  249. OBJ_CASE_INSENSITIVE, // Attributes
  250. NULL, // Root directory
  251. SecurityDescriptor); // Security Descriptor
  252. //
  253. // If the caller doesn't want to call as himself,
  254. // impersonate the anonymous token.
  255. //
  256. if (NoPermissionRequired) {
  257. //
  258. // Check to see if we're already impsonating
  259. //
  260. ntstatus = NtOpenThreadToken(
  261. NtCurrentThread(),
  262. TOKEN_IMPERSONATE,
  263. TRUE, // as self to ensure we never fail
  264. &CurrentToken
  265. );
  266. if ( ntstatus == STATUS_NO_TOKEN ) {
  267. //
  268. // We're not already impersonating
  269. CurrentToken = NULL;
  270. } else if ( !NT_SUCCESS(ntstatus) ) {
  271. ApiStatus = NetpNtStatusToApiStatus(ntstatus);
  272. NetpKdPrint(( PREFIX_NETLIB
  273. "NetpRdrFsControlTree: cannot NtOpenThreadToken: 0x%lx\n",
  274. ntstatus ));
  275. goto Cleanup;
  276. }
  277. //
  278. // Impersonate the anonymous token
  279. //
  280. ntstatus = NtImpersonateAnonymousToken( NtCurrentThread() );
  281. if ( !NT_SUCCESS(ntstatus)) {
  282. ApiStatus = NetpNtStatusToApiStatus(ntstatus);
  283. NetpKdPrint(( PREFIX_NETLIB
  284. "NetpRdrFsControlTree: cannot NtImpersonatedAnonymousToken: 0x%lx\n",
  285. ntstatus ));
  286. goto Cleanup;
  287. }
  288. ImpersonatingAnonymous = TRUE;
  289. }
  290. //
  291. // Open a tree connection to the remote server.
  292. //
  293. IF_DEBUG(RDRFSCTL) {
  294. NetpKdPrint(( PREFIX_NETLIB
  295. "NetpRdrFsControlTree: opening " FORMAT_LPTSTR ".\n",
  296. pszTreeConn ));
  297. }
  298. ntstatus = NtCreateFile(
  299. &TreeConnHandle, // ptr to handle
  300. SYNCHRONIZE // desired...
  301. | GENERIC_READ | GENERIC_WRITE, // ...access
  302. & objattrTreeConn, // name & attributes
  303. & iosb, // I/O status block.
  304. NULL, // alloc size.
  305. FILE_ATTRIBUTE_NORMAL, // (ignored)
  306. FILE_SHARE_READ | FILE_SHARE_WRITE, // ...access
  307. FILE_OPEN_IF, // create disposition
  308. FILE_CREATE_TREE_CONNECTION // create...
  309. | FILE_SYNCHRONOUS_IO_NONALERT, // ...options
  310. EaBuffer, // EA buffer
  311. EaBufferSize ); // Ea buffer size
  312. if (! NT_SUCCESS(ntstatus)) {
  313. ApiStatus = NetpNtStatusToApiStatus(ntstatus);
  314. if (ApiStatus == ERROR_BAD_NET_NAME) {
  315. ApiStatus = NERR_BadTransactConfig; // Special meaning if no IPC$
  316. }
  317. if (ApiStatus != ERROR_BAD_NETPATH) {
  318. NetpKdPrint(( PREFIX_NETLIB
  319. "NetpRdrFsControlTree: unexpected create error,\n"
  320. " tree name='" FORMAT_LPTSTR "', "
  321. "ntstatus=" FORMAT_NTSTATUS ",\n"
  322. " iosb.Status=" FORMAT_NTSTATUS ", "
  323. "iosb.Info=" FORMAT_HEX_ULONG ", "
  324. " returning " FORMAT_API_STATUS ".\n",
  325. TreeName, ntstatus,
  326. iosb.Status, iosb.Information, ApiStatus ));
  327. }
  328. goto Cleanup;
  329. }
  330. // Do the FSCTL.
  331. IF_DEBUG(RDRFSCTL) {
  332. NetpKdPrint(( PREFIX_NETLIB
  333. "NetpRdrFsControlTree: doing fsctl...\n" ));
  334. }
  335. ntstatus = NtFsControlFile(
  336. TreeConnHandle, // handle
  337. NULL, // no event
  338. NULL, // no APC routine
  339. NULL, // no APC context
  340. & iosb, // I/O stat blk (set)
  341. FsControlCode, // func code
  342. InputBuffer,
  343. InputBufferSize,
  344. OutputBuffer,
  345. OutputBufferSize);
  346. {
  347. // The additional scope is to localize all the changes for deleting the
  348. // connection. When a connection is opened with the FILE_CREATE_TREE_CONNECTION
  349. // flag set, the rdr takes an additional reference on the connection. In order
  350. // to delete the connection this additional reference needs to be taken off
  351. // by issuing a FSCTL_LMR_DELETE_CONNECTION.
  352. LMR_REQUEST_PACKET Rrp; // Redirector request packet
  353. NTSTATUS Status;
  354. RtlZeroMemory(&Rrp,sizeof(LMR_REQUEST_PACKET));
  355. Rrp.Level = USE_FORCE; // this tells rdr2 to take away the extra reference
  356. // to connection strucutre even when files are open.
  357. // BUG #381842
  358. Rrp.Version = REQUEST_PACKET_VERSION;
  359. Status = NtFsControlFile(
  360. TreeConnHandle, // handle
  361. NULL, // no event
  362. NULL, // no APC routine
  363. NULL, // no APC context
  364. &iosb, // I/O stat blk (set)
  365. FSCTL_LMR_DELETE_CONNECTION, // func code
  366. &Rrp,
  367. sizeof(LMR_REQUEST_PACKET),
  368. NULL,
  369. 0);
  370. /*
  371. NetpKdPrint(( PREFIX_NETLIB
  372. "NetpRdrFsControlTree: "
  373. "Deleting tree connection: "
  374. FORMAT_NTSTATUS "\n",
  375. Status ));
  376. */
  377. IF_DEBUG(RDRFSCTL) {
  378. if (!NT_SUCCESS(Status)) {
  379. NetpKdPrint(( PREFIX_NETLIB
  380. "NetpRdrFsControlTree: "
  381. "Unexpected error Deleting tree connection: "
  382. FORMAT_NTSTATUS "\n",
  383. Status ));
  384. }
  385. }
  386. }
  387. if (! NT_SUCCESS(ntstatus)) {
  388. ApiStatus = NetpNtStatusToApiStatus(ntstatus);
  389. NetpKdPrint(( PREFIX_NETLIB
  390. "NetpRdrFsControlTree: unexpected FSCTL error,\n"
  391. " tree name='" FORMAT_LPTSTR "', "
  392. "ntstatus=" FORMAT_NTSTATUS ".\n"
  393. " ApiStatus=" FORMAT_API_STATUS ", "
  394. "iosb.Status=" FORMAT_NTSTATUS ", "
  395. "iosb.Info=" FORMAT_HEX_ULONG ".\n",
  396. TreeName, ntstatus, ApiStatus, iosb.Status, iosb.Information ));
  397. goto Cleanup;
  398. }
  399. ApiStatus = NERR_Success;
  400. Cleanup:
  401. // Clean up.
  402. if ( TreeConnHandle != NULL ) {
  403. ntstatus = NtClose(TreeConnHandle);
  404. IF_DEBUG(RDRFSCTL) {
  405. if (!NT_SUCCESS(ntstatus)) {
  406. NetpKdPrint(( PREFIX_NETLIB
  407. "NetpRdrFsControlTree: "
  408. "Unexpected error closing tree connect handle: "
  409. FORMAT_NTSTATUS "\n", ntstatus ));
  410. }
  411. }
  412. }
  413. if ( pszTreeConn != NULL ) {
  414. NetpMemoryFree(pszTreeConn);
  415. }
  416. if (EaBuffer != NULL) {
  417. NetpMemoryFree(EaBuffer);
  418. }
  419. if ( ImpersonatingAnonymous ) {
  420. ntstatus = NtSetInformationThread(
  421. NtCurrentThread(),
  422. ThreadImpersonationToken,
  423. &CurrentToken,
  424. sizeof(HANDLE)
  425. );
  426. if (!NT_SUCCESS(ntstatus)) {
  427. NetpKdPrint(( PREFIX_NETLIB
  428. "NetpRdrFsControlTree: "
  429. "Unexpected error reverting to self: "
  430. FORMAT_NTSTATUS "\n", ntstatus ));
  431. }
  432. }
  433. if ( CurrentToken != NULL ) {
  434. NtClose( CurrentToken );
  435. }
  436. return ApiStatus;
  437. } // NetpRdrFsControlTree