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.

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