mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
vfs: Add inheritance emulation to vfs_nfs4acl_xattr.
Recursively inherit ACL from parent directory if no acl xattr is found on the current file. Use a default ACL if a non-inheriting ACL is encountered. With this the nfs4acl_xattr.dynamic test passes. But the nfs4acl_xattr.inheritance test results in an error because of warnings that cause the test to pass a failed result. Reviewed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
parent
fe8a1fcda7
commit
97eb8f73e5
@ -46,7 +46,6 @@
|
||||
^samba3.raw.samba3hide.samba3hide\((s3dc|plugin_s4_dc)\) # This test fails against an smbd environment with NT ACLs enabled
|
||||
^samba3.raw.samba3closeerr.samba3closeerr\(s3dc\) # This test fails against an smbd environment with NT ACLs enabled
|
||||
^samba3.raw.acls nfs4acl_xattr.INHERITFLAGS\(s3dc\) # This (and the follow nfs4acl_xattr tests fail because our NFSv4 backend isn't a complete mapping yet.
|
||||
^samba3.raw.acls nfs4acl_xattr.dynamic\(s3dc\)
|
||||
^samba3.raw.acls nfs4acl_xattr.sd\(s3dc\)
|
||||
^samba3.raw.acls nfs4acl_xattr.create_file\(s3dc\)
|
||||
^samba3.raw.acls nfs4acl_xattr.create_dir\(s3dc\)
|
||||
|
@ -176,30 +176,29 @@ static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx
|
||||
return status;
|
||||
}
|
||||
|
||||
/* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
|
||||
static bool nfs4_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SMB4ACL_T *smbacl)
|
||||
static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
|
||||
SMB4ACL_T *smbacl,
|
||||
struct nfs4acl **pnfs4acl,
|
||||
bool denymissingspecial)
|
||||
{
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
int i;
|
||||
struct nfs4acl *nfs4acl;
|
||||
SMB4ACE_T *smbace;
|
||||
bool have_special_id = false;
|
||||
int ret;
|
||||
DATA_BLOB blob;
|
||||
int i;
|
||||
|
||||
/* allocate the field of NFS4 aces */
|
||||
nfs4acl = talloc_zero(frame, struct nfs4acl);
|
||||
nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
|
||||
if(nfs4acl == NULL) {
|
||||
TALLOC_FREE(frame);
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
|
||||
nfs4acl->a_count = smb_get_naces(smbacl);
|
||||
|
||||
nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace, nfs4acl->a_count);
|
||||
nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
|
||||
nfs4acl->a_count);
|
||||
if(nfs4acl->ace == NULL) {
|
||||
TALLOC_FREE(frame);
|
||||
TALLOC_FREE(nfs4acl);
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
@ -239,26 +238,93 @@ static bool nfs4_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SM
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_special_id
|
||||
&& lp_parm_bool(fsp->conn->params->service, "nfs4acl_xattr",
|
||||
"denymissingspecial", false)) {
|
||||
TALLOC_FREE(frame);
|
||||
if (!have_special_id && denymissingspecial) {
|
||||
TALLOC_FREE(nfs4acl);
|
||||
errno = EACCES;
|
||||
return false;
|
||||
}
|
||||
|
||||
SMB_ASSERT(i == nfs4acl->a_count);
|
||||
|
||||
*pnfs4acl = nfs4acl;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nfs4acl_xattr_set_smb4acl(vfs_handle_struct *handle,
|
||||
const char *path,
|
||||
SMB4ACL_T *smbacl)
|
||||
{
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
struct nfs4acl *nfs4acl;
|
||||
int ret;
|
||||
bool denymissingspecial;
|
||||
DATA_BLOB blob;
|
||||
|
||||
denymissingspecial = lp_parm_bool(handle->conn->params->service,
|
||||
"nfs4acl_xattr",
|
||||
"denymissingspecial", false);
|
||||
|
||||
if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
|
||||
denymissingspecial)) {
|
||||
DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
|
||||
TALLOC_FREE(frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
blob = nfs4acl_acl2blob(frame, nfs4acl);
|
||||
if (!blob.data) {
|
||||
DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
|
||||
DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
|
||||
TALLOC_FREE(frame);
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_XATTR_NAME, blob.data, blob.length, 0);
|
||||
ret = SMB_VFS_NEXT_SETXATTR(handle, path, NFS4ACL_XATTR_NAME,
|
||||
blob.data, blob.length, 0);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
|
||||
}
|
||||
TALLOC_FREE(frame);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
/* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
|
||||
static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
|
||||
files_struct *fsp,
|
||||
SMB4ACL_T *smbacl)
|
||||
{
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
struct nfs4acl *nfs4acl;
|
||||
int ret;
|
||||
bool denymissingspecial;
|
||||
DATA_BLOB blob;
|
||||
|
||||
denymissingspecial = lp_parm_bool(fsp->conn->params->service,
|
||||
"nfs4acl_xattr",
|
||||
"denymissingspecial", false);
|
||||
|
||||
if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
|
||||
denymissingspecial)) {
|
||||
DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
|
||||
TALLOC_FREE(frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
blob = nfs4acl_acl2blob(frame, nfs4acl);
|
||||
if (!blob.data) {
|
||||
DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
|
||||
TALLOC_FREE(frame);
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
if (fsp->fh->fd == -1) {
|
||||
DEBUG(0, ("Error: fsp->fh->fd == -1\n"));
|
||||
}
|
||||
ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_XATTR_NAME,
|
||||
blob.data, blob.length, 0);
|
||||
if (ret != 0) {
|
||||
DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
|
||||
}
|
||||
TALLOC_FREE(frame);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
@ -271,7 +337,180 @@ static NTSTATUS nfs4_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
|
||||
const struct security_descriptor *psd)
|
||||
{
|
||||
return smb_set_nt_acl_nfs4(handle, fsp, security_info_sent, psd,
|
||||
nfs4_process_smbacl);
|
||||
nfs4acl_xattr_fset_smb4acl);
|
||||
}
|
||||
|
||||
static SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
SMB4ACL_T *pacl = NULL;
|
||||
SMB4ACE_T *pace;
|
||||
SMB_ACE4PROP_T ace = { SMB_ACE4_ID_SPECIAL,
|
||||
SMB_ACE4_WHO_EVERYONE,
|
||||
SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE,
|
||||
0,
|
||||
SMB_ACE4_ALL_MASKS };
|
||||
|
||||
DEBUG(10, ("Building default full access acl\n"));
|
||||
|
||||
pacl = smb_create_smb4acl(mem_ctx);
|
||||
if (pacl == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pace = smb_add_ace4(pacl, &ace);
|
||||
if (pace == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
TALLOC_FREE(pacl);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pacl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Because there is no good way to guarantee that a new xattr will be
|
||||
* created on file creation there might be no acl xattr on a file when
|
||||
* trying to read the acl. In this case the acl xattr will get
|
||||
* constructed at that time from the parent acl.
|
||||
* If the parent ACL doesn't have an xattr either the call will
|
||||
* recurse to the next parent directory until the share root is
|
||||
* reached. If the share root doesn't contain an ACL xattr either a
|
||||
* default ACL will be used.
|
||||
* Also a default ACL will be set if a non inheriting ACL is encountered.
|
||||
*
|
||||
* Basic algorithm:
|
||||
* read acl xattr blob
|
||||
* if acl xattr blob doesn't exist
|
||||
* stat current directory to know if it's a file or directory
|
||||
* read acl xattr blob from parent dir
|
||||
* acl xattr blob to smb nfs4 acl
|
||||
* calculate inherited smb nfs4 acl
|
||||
* without inheritance use default smb nfs4 acl
|
||||
* smb nfs4 acl to acl xattr blob
|
||||
* set acl xattr blob
|
||||
* return smb nfs4 acl
|
||||
* else
|
||||
* acl xattr blob to smb nfs4 acl
|
||||
*
|
||||
* Todo: Really use mem_ctx after fixing interface of nfs4_acls
|
||||
*/
|
||||
static SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
|
||||
const char *path,
|
||||
TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
char *parent_dir = NULL;
|
||||
SMB4ACL_T *pparentacl = NULL;
|
||||
SMB4ACL_T *pchildacl = NULL;
|
||||
SMB4ACE_T *pace;
|
||||
SMB_ACE4PROP_T ace;
|
||||
bool isdir;
|
||||
struct smb_filename *smb_fname = NULL;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
DEBUG(10, ("nfs4acls_inheritacl invoked for %s\n", path));
|
||||
smb_fname = synthetic_smb_fname(frame, path, NULL, NULL);
|
||||
if (smb_fname == NULL) {
|
||||
TALLOC_FREE(frame);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = SMB_VFS_STAT(handle->conn, smb_fname);
|
||||
if (ret == -1) {
|
||||
DEBUG(0,("nfs4acls_inheritacl: failed to stat "
|
||||
"directory %s. Error was %s\n",
|
||||
smb_fname_str_dbg(smb_fname),
|
||||
strerror(errno)));
|
||||
TALLOC_FREE(frame);
|
||||
return NULL;
|
||||
}
|
||||
isdir = S_ISDIR(smb_fname->st.st_ex_mode);
|
||||
|
||||
if (!parent_dirname(talloc_tos(),
|
||||
path,
|
||||
&parent_dir,
|
||||
NULL)) {
|
||||
TALLOC_FREE(frame);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = nfs4_get_nfs4_acl(handle, frame, parent_dir, &pparentacl);
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)
|
||||
&& strncmp(parent_dir, ".", 2) != 0) {
|
||||
pparentacl = nfs4acls_inheritacl(handle, parent_dir,
|
||||
frame);
|
||||
}
|
||||
else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
|
||||
pparentacl = nfs4acls_defaultacl(frame);
|
||||
|
||||
}
|
||||
else if (!NT_STATUS_IS_OK(status)) {
|
||||
TALLOC_FREE(frame);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pchildacl = smb_create_smb4acl(mem_ctx);
|
||||
if (pchildacl == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
TALLOC_FREE(frame);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (pace = smb_first_ace4(pparentacl); pace != NULL;
|
||||
pace = smb_next_ace4(pace)) {
|
||||
SMB4ACE_T *pchildace;
|
||||
ace = *smb_get_ace4(pace);
|
||||
if (isdir && !(ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
|
||||
|| !isdir && !(ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
|
||||
DEBUG(10, ("non inheriting ace type: %d, iflags: %x, "
|
||||
"flags: %x, mask: %x, who: %d\n",
|
||||
ace.aceType, ace.flags, ace.aceFlags,
|
||||
ace.aceMask, ace.who.id));
|
||||
continue;
|
||||
}
|
||||
DEBUG(10, ("inheriting ace type: %d, iflags: %x, "
|
||||
"flags: %x, mask: %x, who: %d\n",
|
||||
ace.aceType, ace.flags, ace.aceFlags,
|
||||
ace.aceMask, ace.who.id));
|
||||
ace.aceFlags |= SMB_ACE4_INHERITED_ACE;
|
||||
if ((isdir && (ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
|
||||
|| !isdir && (ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE))
|
||||
&& ace.aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) {
|
||||
ace.aceFlags &= ~SMB_ACE4_INHERIT_ONLY_ACE;
|
||||
}
|
||||
if (ace.aceFlags & SMB_ACE4_NO_PROPAGATE_INHERIT_ACE) {
|
||||
ace.aceFlags &= ~SMB_ACE4_FILE_INHERIT_ACE;
|
||||
ace.aceFlags &= ~SMB_ACE4_DIRECTORY_INHERIT_ACE;
|
||||
ace.aceFlags &= ~SMB_ACE4_NO_PROPAGATE_INHERIT_ACE;
|
||||
}
|
||||
pchildace = smb_add_ace4(pchildacl, &ace);
|
||||
if (pchildace == NULL) {
|
||||
DEBUG(0, ("talloc failed\n"));
|
||||
TALLOC_FREE(frame);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set a default ACL if we didn't inherit anything. */
|
||||
if (smb_first_ace4(pchildacl) == NULL) {
|
||||
TALLOC_FREE(pchildacl);
|
||||
pchildacl = nfs4acls_defaultacl(mem_ctx);
|
||||
}
|
||||
|
||||
/* store the returned ACL to get it directly in the
|
||||
future and avoid dynamic inheritance behavior. */
|
||||
nfs4acl_xattr_set_smb4acl(handle, path, pchildacl);
|
||||
|
||||
TALLOC_FREE(frame);
|
||||
return pchildacl;
|
||||
}
|
||||
|
||||
static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
|
||||
@ -285,11 +524,11 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
|
||||
status = nfs4_fget_nfs4_acl(handle, frame, fsp, &pacl);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
|
||||
status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
|
||||
mem_ctx, ppdesc);
|
||||
pacl = nfs4acls_inheritacl(handle, fsp->fsp_name->base_name,
|
||||
frame);
|
||||
}
|
||||
else if (!NT_STATUS_IS_OK(status)) {
|
||||
TALLOC_FREE(frame);
|
||||
return status;
|
||||
}
|
||||
@ -310,14 +549,9 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
|
||||
|
||||
status = nfs4_get_nfs4_acl(handle, frame, name, &pacl);
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
|
||||
status = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info,
|
||||
mem_ctx, ppdesc);
|
||||
pacl = nfs4acls_inheritacl(handle, name, frame);
|
||||
}
|
||||
TALLOC_FREE(frame);
|
||||
return status;
|
||||
}
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
else if (!NT_STATUS_IS_OK(status)) {
|
||||
TALLOC_FREE(frame);
|
||||
return status;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user