/*++ Copyright (c) 1989 Microsoft Corporation Module Name: createms.c Abstract: This module implements the file create mailslot routine for MSFS called by the dispatch driver. Author: Manny Weiser (mannyw) 17-Jan-1991 Revision History: --*/ #include "mailslot.h" // // The debug trace level // #define Dbg (DEBUG_TRACE_CREATE_MAILSLOT) // // local procedure prototypes // NTSTATUS MsCommonCreateMailslot ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp ); IO_STATUS_BLOCK MsCreateMailslot ( IN PROOT_DCB RootDcb, IN PFILE_OBJECT FileObject, IN UNICODE_STRING FileName, IN ACCESS_MASK DesiredAccess, IN ULONG CreateDisposition, IN USHORT ShareAccess, IN ULONG MailslotQuota, IN ULONG MaximumMessageSize, IN LARGE_INTEGER ReadTimeout, IN PEPROCESS CreatorProcess, IN PACCESS_STATE AccessState ); BOOLEAN MsIsNameValid ( PUNICODE_STRING Name ); #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, MsCommonCreateMailslot ) #pragma alloc_text( PAGE, MsCreateMailslot ) #pragma alloc_text( PAGE, MsFsdCreateMailslot ) #pragma alloc_text( PAGE, MsIsNameValid ) #endif NTSTATUS MsFsdCreateMailslot ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of the NtCreateMailslotFile API call. Arguments: MsfsDeviceObject - Supplies the device object to use. Irp - Supplies the Irp being processed Return Value: NTSTATUS - The Fsd status for the Irp --*/ { NTSTATUS status; PAGED_CODE(); DebugTrace(+1, Dbg, "MsFsdCreateMailslot\n", 0); // // Call the common create routine. // try { status = MsCommonCreateMailslot( MsfsDeviceObject, Irp ); } except(MsExceptionFilter( GetExceptionCode() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code. // status = MsProcessException( MsfsDeviceObject, Irp, GetExceptionCode() ); } // // Return to the caller. // DebugTrace(-1, Dbg, "MsFsdCreateMailslot -> %08lx\n", status ); return status; } NTSTATUS MsCommonCreateMailslot ( IN PMSFS_DEVICE_OBJECT MsfsDeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the common routine for creating a mailslot. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - the return status for the operation --*/ { NTSTATUS status; PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; PFILE_OBJECT relatedFileObject; UNICODE_STRING fileName; ACCESS_MASK desiredAccess; ULONG options; USHORT shareAccess; PMAILSLOT_CREATE_PARAMETERS parameters; ULONG mailslotQuota; ULONG maximumMessageSize; PEPROCESS creatorProcess; LARGE_INTEGER readTimeout; BOOLEAN caseInsensitive = TRUE; //**** Make all searches case insensitive PVCB vcb; PFCB fcb; ULONG createDisposition; UNICODE_STRING remainingPart; PAGED_CODE(); // // Make local copies of the input parameters to make things easier. // irpSp = IoGetCurrentIrpStackLocation( Irp ); fileObject = irpSp->FileObject; relatedFileObject = irpSp->FileObject->RelatedFileObject; fileName = *(PUNICODE_STRING)&irpSp->FileObject->FileName; desiredAccess = irpSp->Parameters.CreateMailslot.SecurityContext->DesiredAccess; options = irpSp->Parameters.CreateMailslot.Options; shareAccess = irpSp->Parameters.CreateMailslot.ShareAccess; parameters = irpSp->Parameters.CreateMailslot.Parameters; mailslotQuota = parameters->MailslotQuota; maximumMessageSize = parameters->MaximumMessageSize; if (parameters->TimeoutSpecified) { readTimeout = parameters->ReadTimeout; } else { readTimeout.QuadPart = -1; } creatorProcess = IoGetRequestorProcess( Irp ); DebugTrace(+1, Dbg, "MsCommonCreateMailslot\n", 0 ); DebugTrace( 0, Dbg, "MsfsDeviceObject = %08lx\n", (ULONG)MsfsDeviceObject ); DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp ); DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)fileObject ); DebugTrace( 0, Dbg, "RelatedFileObject = %08lx\n", (ULONG)relatedFileObject ); DebugTrace( 0, Dbg, "FileName = %wZ\n", (ULONG)&fileName ); DebugTrace( 0, Dbg, "DesiredAccess = %08lx\n", desiredAccess ); DebugTrace( 0, Dbg, "Options = %08lx\n", options ); DebugTrace( 0, Dbg, "ShareAccess = %08lx\n", shareAccess ); DebugTrace( 0, Dbg, "Parameters = %08lx\n", (ULONG)parameters ); DebugTrace( 0, Dbg, "MailslotQuota = %08lx\n", mailslotQuota ); DebugTrace( 0, Dbg, "MaximumMesssageSize = %08lx\n", maximumMessageSize ); DebugTrace( 0, Dbg, "CreatorProcess = %08lx\n", (ULONG)creatorProcess ); // // Get the VCB we are trying to access and extract the // create disposition. // vcb = &MsfsDeviceObject->Vcb; createDisposition = (options >> 24) & 0x000000ff; // // Acquire exclusive access to the VCB. // MsAcquireExclusiveVcb( vcb ); try { // // If there is a related file object then this is a relative open // and it better be the root DCB. Both the then and the else clause // return an FCB. // if (relatedFileObject != NULL) { PDCB dcb; dcb = relatedFileObject->FsContext; if (NodeType(dcb) != MSFS_NTC_ROOT_DCB) { DebugTrace(0, Dbg, "Bad file name\n", 0); MsCompleteRequest( Irp, STATUS_OBJECT_NAME_INVALID ); try_return( status = STATUS_OBJECT_NAME_INVALID ); } fcb = MsFindRelativePrefix( dcb, &fileName, caseInsensitive, &remainingPart ); } else { // // The only nonrelative name we allow are of the form // "\mailslot-name". // if ((fileName.Length <= sizeof( WCHAR )) || (fileName.Buffer[0] != L'\\')) { DebugTrace(0, Dbg, "Bad file name\n", 0); MsCompleteRequest( Irp, STATUS_OBJECT_NAME_INVALID ); try_return( status = STATUS_OBJECT_NAME_INVALID ); } fcb = MsFindPrefix( vcb, &fileName, caseInsensitive, &remainingPart ); } // // If the remaining name is empty then we better have an FCB // otherwise we were given a illegal object name. // if (remainingPart.Length == 0) { if (fcb->Header.NodeTypeCode == MSFS_NTC_FCB) { DebugTrace(0, Dbg, "Attempt to create an existing mailslot, " "Fcb = %08lx\n", (ULONG)fcb ); status = STATUS_OBJECT_NAME_COLLISION; } else { DebugTrace(0, Dbg, "Illegal object name\n", 0); status = STATUS_OBJECT_NAME_INVALID; } } else { // // The remaining name is not empty so we better have the root DCB // and then have a valid object path. // if ( fcb->Header.NodeTypeCode == MSFS_NTC_ROOT_DCB && MsIsNameValid( &remainingPart ) ) { DebugTrace(0, Dbg, "Create new mailslot, Fcb = %08lx\n", (ULONG)fcb ); Irp->IoStatus = MsCreateMailslot( fcb, fileObject, fileName, desiredAccess, createDisposition, shareAccess, mailslotQuota, maximumMessageSize, readTimeout, creatorProcess, irpSp->Parameters.CreateMailslot.SecurityContext->AccessState ); status = Irp->IoStatus.Status; } else { DebugTrace(0, Dbg, "Illegal object name\n", 0); status = STATUS_OBJECT_NAME_INVALID; } } // // Complete the IRP and return to the caller. // MsCompleteRequest( Irp, status ); try_return( NOTHING ); try_exit: NOTHING; } finally { MsReleaseVcb( vcb ); } DebugTrace(-1, Dbg, "MsCommonCreateMailslot -> %08lx\n", status); return status; } IO_STATUS_BLOCK MsCreateMailslot ( IN PROOT_DCB RootDcb, IN PFILE_OBJECT FileObject, IN UNICODE_STRING FileName, IN ACCESS_MASK DesiredAccess, IN ULONG CreateDisposition, IN USHORT ShareAccess, IN ULONG MailslotQuota, IN ULONG MaximumMessageSize, IN LARGE_INTEGER ReadTimeout, IN PEPROCESS CreatorProcess, IN PACCESS_STATE AccessState ) /*++ Routine Description: This routine performs the operation for creating a new mailslot Fcb. This routine does not complete any IRP, it preforms its function and then returns an iosb. Arguments: RootDcb - Supplies the root dcb where this is going to be added. FileObject - Supplies the file object associated with the mailslot. FileName - Supplies the name of the mailslot (not qualified i.e., simply "mailslot-name" and not "\mailslot-name". DesiredAccess - Supplies the caller's desired access. CreateDisposition - Supplies the caller's create disposition flags. ShareAccess - Supplies the caller specified share access. MailslotQuota - Supplies the mailslot quota amount. MaximumMessageSize - Supplies the size of the largest message that can be written to this mailslot. CreatorProcess - Supplies the process creating the mailslot. Return Value: IO_STATUS_BLOCK - Returns the status of the operation. --*/ { // FIX, FIX - TEMPORARY ONLY. UCHAR SDBody[SECURITY_DESCRIPTOR_MIN_LENGTH]; PSECURITY_DESCRIPTOR TmpSecurityDescriptor = (PSECURITY_DESCRIPTOR)(&SDBody[0]); // FIX, FIX - TEMPORARY ONLY. IO_STATUS_BLOCK iosb; PFCB fcb; PAGED_CODE(); DebugTrace(+1, Dbg, "MsCreateMailslot\n", 0 ); fcb = NULL; iosb.Status = STATUS_UNSUCCESSFUL; try { // // Check the parameters that must be supplied for a mailslot // if (CreateDisposition == FILE_OPEN) { try_return( iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND ); } // // Create a new FCB for the mailslot. // fcb = MsCreateFcb( RootDcb->Vcb, RootDcb, &FileName, CreatorProcess, MailslotQuota, MaximumMessageSize ); fcb->Specific.Fcb.ReadTimeout = ReadTimeout; // // Set the security descriptor in the Fcb // SeLockSubjectContext( &AccessState->SubjectSecurityContext ); iosb.Status = SeAssignSecurity( NULL, AccessState->SecurityDescriptor, &fcb->SecurityDescriptor, FALSE, &AccessState->SubjectSecurityContext, IoGetFileObjectGenericMapping(), PagedPool ); SeUnlockSubjectContext( &AccessState->SubjectSecurityContext ); if (!NT_SUCCESS(iosb.Status)) { DebugTrace(0, Dbg, "Error calling SeAssignSecurity\n", 0 ); try_return( iosb.Status ); } // // Set the new share access. // IoSetShareAccess( DesiredAccess, ShareAccess, FileObject, &fcb->ShareAccess ); // // Set the file object back pointers and our pointer to the // server file object. // MsSetFileObject( FileObject, fcb, NULL ); fcb->FileObject = FileObject; // // Update the FCB timestamps. // KeQuerySystemTime( &fcb->Specific.Fcb.CreationTime ); fcb->Specific.Fcb.LastModificationTime = fcb->Specific.Fcb.CreationTime; fcb->Specific.Fcb.LastAccessTime = fcb->Specific.Fcb.CreationTime; fcb->Specific.Fcb.LastChangeTime = fcb->Specific.Fcb.CreationTime; // // Set the return status. // iosb.Status = STATUS_SUCCESS; iosb.Information = FILE_CREATED; // // The root directory has changed. Complete any notify change // directory requests. // MsCheckForNotify( fcb->ParentDcb, TRUE ); try_exit: NOTHING; } finally { // // Now if we ever terminate the preceding try-statement with // a status that is not successful and the FCB pointer // is non-null then we need to deallocate the structure. // if (!NT_SUCCESS(iosb.Status) && fcb != NULL) { // // Remove the Fcb from the prefix table. // MsAcquirePrefixTableLock(); RtlRemoveUnicodePrefix( &fcb->Vcb->PrefixTable, &fcb->PrefixTableEntry ); MsReleasePrefixTableLock(); // // Remove the Fcb from our parent DCB's queue. // RemoveEntryList( &fcb->ParentDcbLinks ); MsDeleteFcb( fcb ); } } // // Return to the caller. // DebugTrace(-1, Dbg, "MsCreateMailslot -> %08lx\n", iosb.Status); return iosb; } BOOLEAN MsIsNameValid ( PUNICODE_STRING Name ) /*++ Routine Description: This routine tests for illegal characters in a name. The same character set as Npfs/Ntfs is used. Also preceding backslashes, wildcards, and path names are not allowed. Arguments: Name - The name to search for illegal characters Return Value: BOOLEAN - TRUE if the name is valid, FALSE otherwise. --*/ { ULONG i; PAGED_CODE(); for (i=0; i < Name->Length / sizeof(WCHAR); i += 1) { WCHAR Char = Name->Buffer[i]; if ( (Char <= 0xff) && (Char != L'\\') && !FsRtlIsAnsiCharacterLegalNtfs(Char, FALSE) ) { return FALSE; } } return TRUE; }