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.

612 lines
16 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Create.c
  5. Abstract:
  6. This module implements the File Create routine for NPFS called by the
  7. dispatch driver.
  8. Author:
  9. Gary Kimura [GaryKi] 21-Aug-1990
  10. Revision History:
  11. --*/
  12. #include "NpProcs.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_CREATE)
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, NpFsdCreate)
  19. #pragma alloc_text(PAGE, NpOpenNamedPipeFileSystem)
  20. #pragma alloc_text(PAGE, NpOpenNamedPipeRootDirectory)
  21. #pragma alloc_text(PAGE, NpCreateClientEnd)
  22. #endif
  23. NTSTATUS
  24. NpFsdCreate (
  25. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  26. IN PIRP Irp
  27. )
  28. /*++
  29. Routine Description:
  30. This routine implements the FSD part of the NtCreateFile and NtOpenFile
  31. API calls.
  32. Arguments:
  33. NpfsDeviceObject - Supplies the device object to use.
  34. Irp - Supplies the Irp being processed
  35. Return Value:
  36. NTSTATUS - The Fsd status for the Irp
  37. --*/
  38. {
  39. NTSTATUS Status;
  40. PIO_STACK_LOCATION IrpSp;
  41. PFILE_OBJECT FileObject;
  42. PFILE_OBJECT RelatedFileObject;
  43. UNICODE_STRING FileName;
  44. ACCESS_MASK DesiredAccess;
  45. BOOLEAN CaseInsensitive = TRUE; //**** Make all searches case insensitive
  46. PFCB Fcb;
  47. PCCB Ccb;
  48. UNICODE_STRING RemainingPart;
  49. LIST_ENTRY DeferredList;
  50. NODE_TYPE_CODE RelatedType;
  51. PAGED_CODE();
  52. InitializeListHead (&DeferredList);
  53. //
  54. // Reference our input parameters to make things easier
  55. //
  56. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  57. FileObject = IrpSp->FileObject;
  58. RelatedFileObject = IrpSp->FileObject->RelatedFileObject;
  59. FileName = *(PUNICODE_STRING)&IrpSp->FileObject->FileName;
  60. DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
  61. RelatedType = NTC_UNDEFINED;
  62. //
  63. // Acquire exclusive access to the Vcb
  64. //
  65. FsRtlEnterFileSystem();
  66. NpAcquireExclusiveVcb();
  67. if (RelatedFileObject != NULL) {
  68. RelatedType = NpDecodeFileObject (RelatedFileObject,
  69. &Fcb,
  70. &Ccb,
  71. NULL);
  72. }
  73. //
  74. // Check if we are trying to open the named pipe file system
  75. // (i.e., the Vcb).
  76. //
  77. if ((FileName.Length == 0) &&
  78. ((RelatedFileObject == NULL) || (RelatedType == NPFS_NTC_VCB))) {
  79. DebugTrace(0, Dbg, "Open name pipe file system\n", 0);
  80. Irp->IoStatus = NpOpenNamedPipeFileSystem (FileObject,
  81. DesiredAccess);
  82. Status = Irp->IoStatus.Status;
  83. goto exit_and_cleanup;
  84. }
  85. //
  86. // Check if we are trying to open the root directory
  87. //
  88. if (((FileName.Length == 2) && (FileName.Buffer[0] == L'\\') && (RelatedFileObject == NULL))
  89. ||
  90. ((FileName.Length == 0) && (RelatedType == NPFS_NTC_ROOT_DCB))) {
  91. DebugTrace(0, Dbg, "Open root directory system\n", 0);
  92. Irp->IoStatus = NpOpenNamedPipeRootDirectory (NpVcb->RootDcb,
  93. FileObject,
  94. DesiredAccess,
  95. &DeferredList);
  96. Status = Irp->IoStatus.Status;
  97. goto exit_and_cleanup;
  98. }
  99. //
  100. // If the name is an alias, translate it.
  101. //
  102. Status = NpTranslateAlias (&FileName);
  103. if (!NT_SUCCESS (Status)) {
  104. goto exit_and_cleanup;
  105. }
  106. //
  107. // If there is a related file object then this is a relative open
  108. // and it better be the root dcb. Both the then and the else clause
  109. // return an Fcb.
  110. //
  111. if (RelatedFileObject != NULL) {
  112. if (RelatedType == NPFS_NTC_ROOT_DCB) {
  113. PDCB Dcb;
  114. Dcb = (PDCB) Fcb;
  115. Status = NpFindRelativePrefix (Dcb, &FileName, CaseInsensitive, &RemainingPart, &Fcb);
  116. if (!NT_SUCCESS (Status)) {
  117. goto exit_and_cleanup;
  118. }
  119. } else if (RelatedType == NPFS_NTC_CCB && FileName.Length == 0) {
  120. RemainingPart.Length = 0;
  121. } else {
  122. DebugTrace(0, Dbg, "Bad file name\n", 0);
  123. Status = STATUS_OBJECT_NAME_INVALID;
  124. goto exit_and_cleanup;
  125. }
  126. } else {
  127. //
  128. // The only nonrelative name we allow are of the form "\pipe-name"
  129. //
  130. if ((FileName.Length <= 2) || (FileName.Buffer[0] != L'\\')) {
  131. DebugTrace(0, Dbg, "Bad file name\n", 0);
  132. Status = STATUS_OBJECT_NAME_INVALID;
  133. goto exit_and_cleanup;
  134. }
  135. Fcb = NpFindPrefix (&FileName, CaseInsensitive, &RemainingPart);
  136. }
  137. //
  138. // If the remaining name is not empty then we have an error, either
  139. // we have an illegal name or a non-existent name.
  140. //
  141. if (RemainingPart.Length != 0) {
  142. if (Fcb->NodeTypeCode == NPFS_NTC_FCB) {
  143. //
  144. // We were given a name such as "\pipe-name\another-name"
  145. //
  146. DebugTrace(0, Dbg, "Illegal object name\n", 0);
  147. Status = STATUS_OBJECT_NAME_INVALID;
  148. } else {
  149. //
  150. // We were given a non-existent name
  151. //
  152. DebugTrace(0, Dbg, "non-existent name\n", 0);
  153. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  154. }
  155. } else {
  156. //
  157. // The remaining name is empty so we better have an Fcb otherwise
  158. // we have an invalid object name.
  159. //
  160. if (Fcb->NodeTypeCode == NPFS_NTC_FCB) {
  161. DebugTrace(0, Dbg, "Create client end named pipe, Fcb = %08lx\n", Fcb );
  162. //
  163. // If the server has no handles open, then pretend that
  164. // the pipe name doesn't exist.
  165. //
  166. if (Fcb->ServerOpenCount == 0) {
  167. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  168. } else {
  169. Irp->IoStatus = NpCreateClientEnd (Fcb,
  170. FileObject,
  171. DesiredAccess,
  172. IrpSp->Parameters.Create.SecurityContext->SecurityQos,
  173. IrpSp->Parameters.Create.SecurityContext->AccessState,
  174. (KPROCESSOR_MODE)(FlagOn(IrpSp->Flags, SL_FORCE_ACCESS_CHECK) ?
  175. UserMode : Irp->RequestorMode),
  176. Irp->Tail.Overlay.Thread,
  177. &DeferredList);
  178. Status = Irp->IoStatus.Status;
  179. }
  180. } else {
  181. DebugTrace(0, Dbg, "Illegal object name\n", 0);
  182. Status = STATUS_OBJECT_NAME_INVALID;
  183. }
  184. }
  185. exit_and_cleanup:
  186. NpReleaseVcb ();
  187. //
  188. // Complete any deferred IRPs
  189. //
  190. NpCompleteDeferredIrps (&DeferredList);
  191. FsRtlExitFileSystem();
  192. NpCompleteRequest (Irp, Status);
  193. return Status;
  194. }
  195. //
  196. // Internal support routine
  197. //
  198. IO_STATUS_BLOCK
  199. NpCreateClientEnd (
  200. IN PFCB Fcb,
  201. IN PFILE_OBJECT FileObject,
  202. IN ACCESS_MASK DesiredAccess,
  203. IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
  204. IN PACCESS_STATE AccessState,
  205. IN KPROCESSOR_MODE RequestorMode,
  206. IN PETHREAD UserThread,
  207. IN PLIST_ENTRY DeferredList
  208. )
  209. /*++
  210. Routine Description:
  211. This routine performs the operation for opening the client end of a named
  212. pipe. This routine does not complete the IRP, it performs the function
  213. and then returns a status
  214. Arguments:
  215. Fcb - Supplies the Fcb for the named pipe being accessed
  216. FileObject - Supplies the file object associated with the client end
  217. DesiredAccess - Supplies the callers desired access
  218. SecurityQos - Supplies the security qos parameter from the create irp
  219. AccessState - Supplies the access state parameter from the create irp
  220. RequestorMode - Supplies the mode of the originating irp
  221. UserTherad - Supplies the client end user thread
  222. DeferredList - List of IRP's to complete later
  223. Return Value:
  224. IO_STATUS_BLOCK - Returns the appropriate status for the operation
  225. --*/
  226. {
  227. IO_STATUS_BLOCK Iosb={0};
  228. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  229. BOOLEAN AccessGranted;
  230. ACCESS_MASK GrantedAccess;
  231. UNICODE_STRING Name;
  232. PCCB Ccb;
  233. PLIST_ENTRY Links;
  234. PPRIVILEGE_SET Privileges = NULL;
  235. DebugTrace(+1, Dbg, "NpCreateClientEnd\n", 0 );
  236. NamedPipeConfiguration = Fcb->Specific.Fcb.NamedPipeConfiguration;
  237. //
  238. // "Create Pipe Instance" access is part of generic write and so
  239. // we need to mask out the bit. Even if the client has explicitly
  240. // asked for "create pipe instance" access we will mask it out.
  241. // This will allow the default ACL to be strengthened to protect
  242. // against spurious threads from creating new pipe instances.
  243. //
  244. DesiredAccess &= ~FILE_CREATE_PIPE_INSTANCE;
  245. //
  246. // First do an access check for the user against the Fcb
  247. //
  248. SeLockSubjectContext (&AccessState->SubjectSecurityContext);
  249. AccessGranted = SeAccessCheck (Fcb->SecurityDescriptor,
  250. &AccessState->SubjectSecurityContext,
  251. TRUE, // Tokens are locked
  252. DesiredAccess,
  253. 0,
  254. &Privileges,
  255. IoGetFileObjectGenericMapping(),
  256. RequestorMode,
  257. &GrantedAccess,
  258. &Iosb.Status);
  259. if (Privileges != NULL) {
  260. SeAppendPrivileges (AccessState,
  261. Privileges);
  262. SeFreePrivileges (Privileges);
  263. }
  264. //
  265. // Transfer over the access masks from what is desired to
  266. // what we just granted. Also patch up the maximum allowed
  267. // case because we just did the mapping for it. Note that if
  268. // the user didn't ask for maximum allowed then the following
  269. // code is still okay because we'll just zero a zero bit.
  270. //
  271. if (AccessGranted) {
  272. AccessState->PreviouslyGrantedAccess |= GrantedAccess;
  273. AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
  274. }
  275. Name.Buffer = L"NamedPipe";
  276. Name.Length = sizeof (L"NamedPipe") - sizeof (WCHAR);
  277. SeOpenObjectAuditAlarm (&Name,
  278. NULL,
  279. &FileObject->FileName,
  280. Fcb->SecurityDescriptor,
  281. AccessState,
  282. FALSE,
  283. AccessGranted,
  284. RequestorMode,
  285. &AccessState->GenerateOnClose);
  286. SeUnlockSubjectContext (&AccessState->SubjectSecurityContext);
  287. if (!AccessGranted) {
  288. DebugTrace(0, Dbg, "Access Denied\n", 0 );
  289. return Iosb;
  290. }
  291. //
  292. // Check if the user wants to write to an outbound pipe or read from
  293. // and inbound pipe. And if so then tell the user the error
  294. //
  295. if ((FlagOn (GrantedAccess, FILE_READ_DATA) && (NamedPipeConfiguration == FILE_PIPE_INBOUND)) ||
  296. (FlagOn (GrantedAccess, FILE_WRITE_DATA) && (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))) {
  297. Iosb.Status = STATUS_ACCESS_DENIED;
  298. return Iosb;
  299. }
  300. //
  301. // If the caller specifies neither read nor write access then don't capture the security context.
  302. //
  303. if ((GrantedAccess&(FILE_READ_DATA|FILE_WRITE_DATA)) == 0) {
  304. SecurityQos = NULL;
  305. }
  306. //
  307. // First try and find a ccb that is in the listening state. If we
  308. // exit the loop with Ccb not equal to null then we've found one.
  309. //
  310. Links = Fcb->Specific.Fcb.CcbQueue.Flink;
  311. while (1) {
  312. if (Links == &Fcb->Specific.Fcb.CcbQueue) {
  313. Iosb.Status = STATUS_PIPE_NOT_AVAILABLE;
  314. return Iosb;
  315. }
  316. Ccb = CONTAINING_RECORD (Links, CCB, CcbLinks);
  317. if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) {
  318. break;
  319. }
  320. Links = Links->Flink;
  321. }
  322. if (!NT_SUCCESS(Iosb.Status = NpInitializeSecurity (Ccb,
  323. SecurityQos,
  324. UserThread))) {
  325. DebugTrace(0, Dbg, "Security QOS error\n", 0);
  326. return Iosb;
  327. }
  328. //
  329. // Set the pipe into the connect state, the read mode to byte stream,
  330. // and the completion mode to queued operation. This also
  331. // sets the client file object's back pointer to the ccb
  332. //
  333. if (!NT_SUCCESS(Iosb.Status = NpSetConnectedPipeState (Ccb,
  334. FileObject,
  335. DeferredList))) {
  336. NpUninitializeSecurity (Ccb);
  337. return Iosb;
  338. }
  339. //
  340. // Set up the client session and info. NULL for the
  341. // client info indicates a local session.
  342. //
  343. Ccb->ClientInfo = NULL;
  344. Ccb->ClientProcess = IoThreadToProcess (UserThread);
  345. //
  346. // And set our return status
  347. //
  348. Iosb.Status = STATUS_SUCCESS;
  349. Iosb.Information = FILE_OPENED;
  350. DebugTrace(-1, Dbg, "NpCreateClientEnd -> %08lx\n", Iosb.Status);
  351. return Iosb;
  352. }
  353. //
  354. // Internal support routine
  355. //
  356. IO_STATUS_BLOCK
  357. NpOpenNamedPipeFileSystem (
  358. IN PFILE_OBJECT FileObject,
  359. IN ACCESS_MASK DesiredAccess
  360. )
  361. {
  362. IO_STATUS_BLOCK Iosb = {0};
  363. PAGED_CODE();
  364. DebugTrace(+1, Dbg, "NpOpenNamedPipeFileSystem, Vcb = %08lx\n", NpVcb);
  365. //
  366. // Have the file object point back to the Vcb, and increment the
  367. // open count. The pipe end on the call to set file object really
  368. // doesn't matter.
  369. //
  370. NpSetFileObject( FileObject, NpVcb, NULL, FILE_PIPE_CLIENT_END );
  371. NpVcb->OpenCount += 1;
  372. //
  373. // Set our return status
  374. //
  375. Iosb.Status = STATUS_SUCCESS;
  376. Iosb.Information = FILE_OPENED;
  377. //
  378. // And return to our caller
  379. //
  380. return Iosb;
  381. }
  382. //
  383. // Internal support routine
  384. //
  385. IO_STATUS_BLOCK
  386. NpOpenNamedPipeRootDirectory(
  387. IN PROOT_DCB RootDcb,
  388. IN PFILE_OBJECT FileObject,
  389. IN ACCESS_MASK DesiredAccess,
  390. IN PLIST_ENTRY DeferredList
  391. )
  392. {
  393. IO_STATUS_BLOCK Iosb={0};
  394. PROOT_DCB_CCB Ccb;
  395. PAGED_CODE();
  396. DebugTrace(+1, Dbg, "NpOpenNamedPipeRootDirectory, RootDcb = %08lx\n", RootDcb);
  397. Iosb.Status = NpCreateRootDcbCcb (&Ccb);
  398. if (!NT_SUCCESS(Iosb.Status)) {
  399. return Iosb;
  400. }
  401. //
  402. // Have the file object point back to the Dcb, and reference the root
  403. // dcb, ccb, and increment our open count. The pipe end on the
  404. // call to set file object really doesn't matter.
  405. //
  406. NpSetFileObject (FileObject,
  407. RootDcb,
  408. Ccb,
  409. FILE_PIPE_CLIENT_END);
  410. RootDcb->OpenCount += 1;
  411. //
  412. // Set our return status
  413. //
  414. Iosb.Status = STATUS_SUCCESS;
  415. Iosb.Information = FILE_OPENED;
  416. DebugTrace(-1, Dbg, "NpOpenNamedPipeRootDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
  417. //
  418. // And return to our caller
  419. //
  420. return Iosb;
  421. }