NTSTATUS PvfsQuerySecurityFile( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_NOT_SUPPORTED; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; PSECURITY_DESCRIPTOR_RELATIVE pReturnSecDesc = NULL; ULONG SecDescLength = 0; SECURITY_INFORMATION SecInfo = 0; IRP_ARGS_QUERY_SET_SECURITY Args = pIrpContext->pIrp->Args.QuerySetSecurity; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); if (!IsSetFlag(pCcb->Flags, PVFS_CCB_FLAG_CREATE_COMPLETE)) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } BAIL_ON_INVALID_PTR(Args.SecurityDescriptor, ntError); ntError = PvfsAccessCheckFileHandle(pCcb, READ_CONTROL); BAIL_ON_NT_STATUS(ntError); pReturnSecDesc = Args.SecurityDescriptor; SecDescLength = Args.Length; SecInfo = Args.SecurityInformation; /* Real work starts here */ ntError = PvfsGetSecurityDescriptorFile(pCcb, SecInfo, pReturnSecDesc, &SecDescLength); BAIL_ON_NT_STATUS(ntError); pIrp->IoStatusBlock.BytesTransferred = SecDescLength; ntError = STATUS_SUCCESS; cleanup: if (pCcb) { PvfsReleaseCCB(pCcb); } return ntError; error: goto cleanup; }
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; }