static NTSTATUS PvfsSetEndOfFileWithContext( PVOID pContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PPVFS_PENDING_SET_END_OF_FILE pSetEoFCtx = (PPVFS_PENDING_SET_END_OF_FILE)pContext; PIRP pIrp = pSetEoFCtx->pIrpContext->pIrp; PPVFS_CCB pCcb = pSetEoFCtx->pCcb; IRP_ARGS_QUERY_SET_INFORMATION Args = {0}; PFILE_END_OF_FILE_INFORMATION pFileInfo = NULL; Args = pSetEoFCtx->pIrpContext->pIrp->Args.QuerySetInformation; pFileInfo = (PFILE_END_OF_FILE_INFORMATION)Args.FileInformation; ntError = PvfsSysFtruncate(pCcb->fd, (off_t)pFileInfo->EndOfFile); BAIL_ON_NT_STATUS(ntError); pIrp->IoStatusBlock.BytesTransferred = sizeof(*pFileInfo); ntError = STATUS_SUCCESS; PvfsNotifyScheduleFullReport( pCcb->pScb->pOwnerFcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED, pCcb->pScb->pOwnerFcb->pszFilename); cleanup: return ntError; error: goto cleanup; }
NTSTATUS PvfsSetFileAttributes( IN PPVFS_CCB pCcb, IN FILE_ATTRIBUTES Attributes ) { NTSTATUS ntError = STATUS_ACCESS_DENIED; FILE_ATTRIBUTES AttribNotSettable = FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_SPARSE_FILE; /* Use PvfsSetFileAttributesEx() for IoControl */ if (Attributes & AttribNotSettable) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } /* Clear some bits that should not be stored */ Attributes &= ~(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_NORMAL); if (Attributes & FILE_ATTRIBUTE_SYSTEM) { Attributes |= FILE_ATTRIBUTE_ARCHIVE; } #ifdef HAVE_EA_SUPPORT ntError = PvfsSetFileAttributesXattr(pCcb, Attributes); #else ntError = STATUS_SUCCESS; #endif BAIL_ON_NT_STATUS(ntError); PvfsNotifyScheduleFullReport( pCcb->pFcb, FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, pCcb->pszFilename); cleanup: return ntError; error: goto cleanup; }
NTSTATUS PvfsCreateDirDoSysOpen( IN PVOID pContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PPVFS_PENDING_CREATE pCreateContext = (PPVFS_PENDING_CREATE)pContext; PIRP pIrp = pCreateContext->pIrpContext->pIrp; IRP_ARGS_CREATE Args = pIrp->Args.Create; int fd = -1; int unixFlags = 0; PIO_CREATE_SECURITY_CONTEXT pSecCtx = Args.SecurityContext; FILE_CREATE_RESULT CreateResult = 0; IO_MATCH_FILE_SPEC FileSpec = {0}; WCHAR wszPattern[2] = {L'*', 0x0 }; PIO_SECURITY_CONTEXT_PROCESS_INFORMATION pProcess = NULL; PBOOLEAN pbEnableAbe = NULL; ULONG ulEcpSize = 0; pProcess = IoSecurityGetProcessInfo(pSecCtx); /* Fail any create that requires setting the security but doesn't have the Unix uid/gid information */ if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_SECURITY) && (pProcess == NULL)) { ntError = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(ntError); } /* Do the open() */ ntError = MapPosixOpenFlags( &unixFlags, pCreateContext->GrantedAccess, Args); BAIL_ON_NT_STATUS(ntError); if (!pCreateContext->bFileExisted) { ntError = PvfsSysMkDir( pCreateContext->pszDiskFilename, (mode_t)gPvfsDriverConfig.CreateDirectoryMode); BAIL_ON_NT_STATUS(ntError); } /* Open the DIR* and then open a fd based on that */ ntError = PvfsAllocateMemory( (PVOID)&pCreateContext->pCcb->pDirContext, sizeof(PVFS_DIRECTORY_CONTEXT)); BAIL_ON_NT_STATUS(ntError); pCreateContext->pCcb->pszFilename = pCreateContext->pszDiskFilename; pCreateContext->pszDiskFilename = NULL; ntError = IoRtlEcpListFind( pIrp->Args.Create.EcpList, SRV_ECP_TYPE_ABE, OUT_PPVOID(&pbEnableAbe), &ulEcpSize); if (ntError != STATUS_NOT_FOUND) { BAIL_ON_NT_STATUS(ntError); if (ulEcpSize != sizeof(BOOLEAN)) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } if (*pbEnableAbe) { pCreateContext->pCcb->EcpFlags |= PVFS_ECP_ENABLE_ABE; } } do { ntError = PvfsSysOpen( &fd, pCreateContext->pCcb->pszFilename, 0, 0); } while (ntError == STATUS_MORE_PROCESSING_REQUIRED); BAIL_ON_NT_STATUS(ntError); /* Save our state */ pCreateContext->pCcb->fd = fd; pCreateContext->pCcb->ShareFlags = Args.ShareAccess; pCreateContext->pCcb->AccessGranted = pCreateContext->GrantedAccess; pCreateContext->pCcb->CreateOptions = Args.CreateOptions; ntError = PvfsAddCCBToFCB(pCreateContext->pFcb, pCreateContext->pCcb); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSaveFileDeviceInfo(pCreateContext->pCcb); BAIL_ON_NT_STATUS(ntError); if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_SECURITY) && pSecCtx) { /* Unix Security */ ntError = PvfsSysChown( pCreateContext->pCcb, pProcess->Uid, pProcess->Gid); BAIL_ON_NT_STATUS(ntError); /* Security Descriptor */ ntError = PvfsCreateFileSecurity( pCreateContext->pCcb->pUserToken, pCreateContext->pCcb, Args.SecurityDescriptor, TRUE); BAIL_ON_NT_STATUS(ntError); } if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_ATTRIB) && (Args.FileAttributes != 0)) { ntError = PvfsSetFileAttributes( pCreateContext->pCcb, Args.FileAttributes); BAIL_ON_NT_STATUS(ntError); } /* Save the delete-on-close flag to the FCB */ if (Args.CreateOptions & FILE_DELETE_ON_CLOSE) { LwRtlUnicodeStringInit(&FileSpec.Pattern, wszPattern); ntError = PvfsEnumerateDirectory(pCreateContext->pCcb, &FileSpec, 1, FALSE); if (ntError == STATUS_SUCCESS) { ntError = STATUS_DIRECTORY_NOT_EMPTY; BAIL_ON_NT_STATUS(ntError); } pCreateContext->pCcb->bPendingDeleteHandle = TRUE; } ntError = PvfsStoreCCB(pIrp->FileHandle, pCreateContext->pCcb); BAIL_ON_NT_STATUS(ntError); PvfsInitializeZctSupport(pCreateContext->pCcb, pIrp->FileHandle); CreateResult = PvfsSetCreateResult( Args.CreateDisposition, pCreateContext->bFileExisted, STATUS_SUCCESS); if (CreateResult == FILE_CREATED) { PvfsNotifyScheduleFullReport( pCreateContext->pCcb->pFcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, pCreateContext->pCcb->pszFilename); } /* The CCB has been handled off to the FileHandle so make sure we don't think we still own it */ pCreateContext->pCcb = NULL; cleanup: pIrp->IoStatusBlock.CreateResult = CreateResult; return ntError; error: CreateResult = PvfsSetCreateResult( Args.CreateDisposition, pCreateContext->bFileExisted, ntError); if (fd != -1) { PSTR pszRemovePath = NULL; /* Pick up where we started the pathname */ pszRemovePath = pCreateContext->pszDiskFilename ? pCreateContext->pszDiskFilename : pCreateContext->pCcb->pszFilename; PvfsCleanupFailedCreate( fd, pszRemovePath, !pCreateContext->bFileExisted); } goto cleanup; }
NTSTATUS PvfsCreateFileDoSysOpen( IN PVOID pContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PPVFS_PENDING_CREATE pCreateContext = (PPVFS_PENDING_CREATE)pContext; PIRP pIrp = pCreateContext->pIrpContext->pIrp; IRP_ARGS_CREATE Args = pIrp->Args.Create; int fd = -1; int unixFlags = 0; PIO_CREATE_SECURITY_CONTEXT pSecCtx = Args.SecurityContext; FILE_CREATE_RESULT CreateResult = 0; PIO_SECURITY_CONTEXT_PROCESS_INFORMATION pProcess = NULL; pProcess = IoSecurityGetProcessInfo(pSecCtx); /* Fail any create that requires setting the security but doesn't have the Unix uid/gid information */ if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_SECURITY) && (pProcess == NULL)) { ntError = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(ntError); } ntError = PvfsEnforceShareMode( pCreateContext->pFcb, Args.ShareAccess, pCreateContext->GrantedAccess); BAIL_ON_NT_STATUS(ntError); /* Do the open() */ ntError = MapPosixOpenFlags(&unixFlags, pCreateContext->GrantedAccess, Args); BAIL_ON_NT_STATUS(ntError); do { ntError = PvfsSysOpen( &fd, pCreateContext->pszDiskFilename, unixFlags, (mode_t)gPvfsDriverConfig.CreateFileMode); } while (ntError == STATUS_MORE_PROCESSING_REQUIRED); BAIL_ON_NT_STATUS(ntError); /* Perform preallocation is requested */ if (Args.AllocationSize > 0) { BOOLEAN bAllocate = FALSE; switch (Args.CreateDisposition) { case FILE_SUPERSEDE: case FILE_CREATE: case FILE_OVERWRITE: case FILE_OVERWRITE_IF: bAllocate = TRUE; break; case FILE_OPEN_IF: if (!pCreateContext->bFileExisted) { bAllocate = TRUE; } break; } if (bAllocate) { ntError = PvfsSysFtruncate(fd, (off_t)Args.AllocationSize); BAIL_ON_NT_STATUS(ntError); } } /* Save our state */ pCreateContext->pCcb->fd = fd; pCreateContext->pCcb->ShareFlags = Args.ShareAccess; pCreateContext->pCcb->AccessGranted = pCreateContext->GrantedAccess; pCreateContext->pCcb->CreateOptions = Args.CreateOptions; pCreateContext->pCcb->pszFilename = pCreateContext->pszDiskFilename; pCreateContext->pszDiskFilename = NULL; ntError = PvfsAddCCBToFCB(pCreateContext->pFcb, pCreateContext->pCcb); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSaveFileDeviceInfo(pCreateContext->pCcb); BAIL_ON_NT_STATUS(ntError); /* CCB is now complete */ if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_SECURITY) && pSecCtx) { /* Unix Security */ ntError = PvfsSysChown( pCreateContext->pCcb, pProcess->Uid, pProcess->Gid); BAIL_ON_NT_STATUS(ntError); /* Security Descriptor */ ntError = PvfsCreateFileSecurity( pCreateContext->pCcb->pUserToken, pCreateContext->pCcb, Args.SecurityDescriptor, FALSE); BAIL_ON_NT_STATUS(ntError); } if ((pCreateContext->SetPropertyFlags & PVFS_SET_PROP_ATTRIB) && (Args.FileAttributes != 0)) { ntError = PvfsSetFileAttributes( pCreateContext->pCcb, Args.FileAttributes); BAIL_ON_NT_STATUS(ntError); } /* Save the delete-on-close flag to the FCB */ if (Args.CreateOptions & FILE_DELETE_ON_CLOSE) { pCreateContext->pCcb->bPendingDeleteHandle = TRUE; } ntError = PvfsStoreCCB(pIrp->FileHandle, pCreateContext->pCcb); BAIL_ON_NT_STATUS(ntError); PvfsInitializeZctSupport(pCreateContext->pCcb, pIrp->FileHandle); CreateResult = PvfsSetCreateResult( Args.CreateDisposition, pCreateContext->bFileExisted, STATUS_SUCCESS); if (CreateResult == FILE_CREATED) { PvfsNotifyScheduleFullReport( pCreateContext->pCcb->pFcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, pCreateContext->pCcb->pszFilename); } /* The CCB has been handled off to the FileHandle so make sure we don't think we still own it */ pCreateContext->pCcb = NULL; cleanup: pIrp->IoStatusBlock.CreateResult = CreateResult; return ntError; error: CreateResult = PvfsSetCreateResult( Args.CreateDisposition, pCreateContext->bFileExisted, ntError); if (fd != -1) { PSTR pszRemovePath = NULL; /* Pick up where we started the pathname */ pszRemovePath = pCreateContext->pszDiskFilename ? pCreateContext->pszDiskFilename : pCreateContext->pCcb->pszFilename; PvfsCleanupFailedCreate( fd, pszRemovePath, !pCreateContext->bFileExisted); } goto cleanup; }
NTSTATUS PvfsCcbSetFileBasicInformation( PPVFS_CCB pCcb, PFILE_BASIC_INFORMATION pFileInfo ) { NTSTATUS ntError = STATUS_SUCCESS; LONG64 WriteTime = 0; LONG64 AccessTime = 0; FILE_NOTIFY_CHANGE NotifyFilter = FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS; PVFS_STAT Stat = {0}; BOOLEAN fcbControlLocked = FALSE; PPVFS_FCB pFcb = PvfsReferenceFCB(pCcb->pScb->pOwnerFcb); if (PvfsIsDefaultStream(pCcb->pScb)) { ntError = PvfsValidatePathSCB(pCcb->pScb, &pCcb->FileId); } else { // Have to grab the base file object LWIO_LOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex); ntError = PvfsValidatePathFCB(pFcb, &pFcb->FileId); BAIL_ON_NT_STATUS(ntError); LWIO_UNLOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex); } /* We cant's set the Change Time so ignore it */ WriteTime = pFileInfo->LastWriteTime; AccessTime = pFileInfo->LastAccessTime; /* Ignore 0xffffffff */ if (WriteTime == (LONG64)-1) { WriteTime = 0; } if (AccessTime == (LONG64)-1) { AccessTime = 0; } /* Save for "sticky" WriteTime sematics */ if (WriteTime != 0) { PvfsSetLastWriteTimeFCB(pFcb, WriteTime); } /* Check if we need to preserve any original timestamps */ if (WriteTime == 0 || AccessTime == 0) { if (PvfsIsDefaultStream(pCcb->pScb)) { ntError = PvfsSysFstat(pCcb->fd, &Stat); } else { // Have to grab the stat() on the base file object ntError = PvfsSysStatByFcb(pFcb, &Stat); } BAIL_ON_NT_STATUS(ntError); if (WriteTime == 0) { NotifyFilter &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; ntError = PvfsUnixToWinTime(&WriteTime, Stat.s_mtime); BAIL_ON_NT_STATUS(ntError); } if (AccessTime == 0) { NotifyFilter &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS; ntError = PvfsUnixToWinTime(&AccessTime, Stat.s_atime); BAIL_ON_NT_STATUS(ntError); } } ntError = PvfsSysUtimeByFcb(pFcb, WriteTime, AccessTime); BAIL_ON_NT_STATUS(ntError); if (pFileInfo->FileAttributes != 0) { ntError = PvfsSetFileAttributes(pCcb, pFileInfo->FileAttributes); BAIL_ON_NT_STATUS(ntError); } if (NotifyFilter != 0) { PvfsNotifyScheduleFullReport( pFcb, NotifyFilter, FILE_ACTION_MODIFIED, pFcb->pszFilename); } error: LWIO_UNLOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex); if (pFcb) { PvfsReleaseFCB(&pFcb); } return ntError; }
NTSTATUS PvfsSetSecurityDescriptorFile( IN PPVFS_CCB pCcb, IN SECURITY_INFORMATION SecInfo, IN PSECURITY_DESCRIPTOR_RELATIVE pSecDesc, IN ULONG SecDescLength ) { NTSTATUS ntError = STATUS_ACCESS_DENIED; PSECURITY_DESCRIPTOR_RELATIVE pFinalSecDesc = NULL; ULONG ulFinalSecDescLength = 0; SECURITY_INFORMATION SecInfoAll = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION); BYTE pCurrentSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE]; ULONG ulCurrentSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE; BYTE pNewSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE]; ULONG ulNewSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE; PSECURITY_DESCRIPTOR_ABSOLUTE pIncAbsSecDesc = NULL; union { TOKEN_OWNER TokenOwnerInfo; BYTE Buffer[SID_MAX_SIZE]; } TokenOwnerBuffer; PTOKEN_OWNER pTokenOwnerInformation = (PTOKEN_OWNER)&TokenOwnerBuffer; ULONG ulTokenOwnerLength = 0; union { SID Sid; BYTE Buffer[SID_MAX_SIZE]; } LocalSystemSidBuffer; PSID pLocalSystemSid = (PSID)&LocalSystemSidBuffer; ULONG ulLocalSystemSidLength = sizeof(LocalSystemSidBuffer); memset(pCurrentSecDescBuffer, 0, SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE); memset(pNewSecDescBuffer, 0, SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE); memset(TokenOwnerBuffer.Buffer, 0, SID_MAX_SIZE); /* Sanity checks */ if (SecInfo == 0) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } /* If the new Security Descriptor contains owner or group SID information, berify that the user's ACCESS_TOKEN contains the SID as a member */ if (SecInfo & (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION)) { PSID pOwner = NULL; PSID pGroup = NULL; BOOLEAN bDefaulted = FALSE; ntError = PvfsSecurityAclSelfRelativeToAbsoluteSD( &pIncAbsSecDesc, pSecDesc); BAIL_ON_NT_STATUS(ntError); ntError = RtlQueryAccessTokenInformation( pCcb->pUserToken, TokenOwner, (PVOID)pTokenOwnerInformation, sizeof(TokenOwnerBuffer), &ulTokenOwnerLength); BAIL_ON_NT_STATUS(ntError); ntError = RtlCreateWellKnownSid( WinLocalSystemSid, NULL, pLocalSystemSid, &ulLocalSystemSidLength); BAIL_ON_NT_STATUS(ntError); if (SecInfo & OWNER_SECURITY_INFORMATION) { ntError = RtlGetOwnerSecurityDescriptor( pIncAbsSecDesc, &pOwner, &bDefaulted); BAIL_ON_NT_STATUS(ntError); if (!RtlIsSidMemberOfToken(pCcb->pUserToken, pOwner) && !RtlEqualSid(pLocalSystemSid, pTokenOwnerInformation->Owner)) { ntError = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(ntError); } } if (SecInfo & GROUP_SECURITY_INFORMATION) { ntError = RtlGetGroupSecurityDescriptor( pIncAbsSecDesc, &pGroup, &bDefaulted); BAIL_ON_NT_STATUS(ntError); if (!RtlIsSidMemberOfToken(pCcb->pUserToken, pGroup) && !RtlEqualSid(pLocalSystemSid, pTokenOwnerInformation->Owner)) { ntError = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(ntError); } } } if (SecInfo == SecInfoAll) { /* We already have a fully formed Security Descriptor */ pFinalSecDesc = pSecDesc; ulFinalSecDescLength = SecDescLength; } else { /* Retrieve the existing SD and merge with the incoming one */ ntError = PvfsGetSecurityDescriptorFile( pCcb, SecInfoAll, (PSECURITY_DESCRIPTOR_RELATIVE)pCurrentSecDescBuffer, &ulCurrentSecDescLength); BAIL_ON_NT_STATUS(ntError); /* Assume that the new SD is <= the combined size of the current SD and the incoming one */ ntError = RtlSetSecurityDescriptorInfo( SecInfo, pSecDesc, (PSECURITY_DESCRIPTOR_RELATIVE)pCurrentSecDescBuffer, (PSECURITY_DESCRIPTOR_RELATIVE)pNewSecDescBuffer, &ulNewSecDescLength, &gPvfsFileGenericMapping); BAIL_ON_NT_STATUS(ntError); pFinalSecDesc = (PSECURITY_DESCRIPTOR_RELATIVE)pNewSecDescBuffer; ulFinalSecDescLength = ulNewSecDescLength; } /* Save the combined SD */ #ifdef HAVE_EA_SUPPORT ntError = PvfsSetSecurityDescriptorFileXattr( pCcb, pFinalSecDesc, ulFinalSecDescLength); #else ntError = PvfsSetSecurityDescriptorPosix( pCcb, pFinalSecDesc, ulFinalSecDescLength); #endif BAIL_ON_NT_STATUS(ntError); PvfsNotifyScheduleFullReport( pCcb->pFcb, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, pCcb->pszFilename); cleanup: if (pIncAbsSecDesc) { PvfsFreeAbsoluteSecurityDescriptor(&pIncAbsSecDesc); } return ntError; error: goto cleanup; }