From 361aa19e69d4176dd8c30f485cc637cd33308d62 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 10 Jul 2009 15:50:40 -0700 Subject: Add hash values to the xattr ACLS to determine when an underlying POSIX ACL is changed out from under us. Passes RAW-ACL test up to "invalid owner" problem when trying to create a file owned by Everyone. Now needs porting to modules/vfs_acl_tdb.c Jeremy. --- source3/modules/vfs_acl_xattr.c | 213 +++++++++++++++++++++++++++++----------- 1 file changed, 158 insertions(+), 55 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c index 66bf21c4f7..eb6653bcd1 100644 --- a/source3/modules/vfs_acl_xattr.c +++ b/source3/modules/vfs_acl_xattr.c @@ -27,13 +27,45 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS +static NTSTATUS create_acl_blob(const struct security_descriptor *psd, + DATA_BLOB *pblob, + uint8_t hash[16]); + +#define HASH_SECURITY_INFO (OWNER_SECURITY_INFORMATION | \ + GROUP_SECURITY_INFORMATION | \ + DACL_SECURITY_INFORMATION | \ + SACL_SECURITY_INFORMATION) + +/******************************************************************* + Hash a security descriptor. +*******************************************************************/ + +static NTSTATUS hash_sd(struct security_descriptor *psd, + uint8_t hash[16]) +{ + DATA_BLOB blob; + struct MD5Context tctx; + NTSTATUS status; + + memset(hash, '\0', 16); + status = create_acl_blob(psd, &blob, hash); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + MD5Init(&tctx); + MD5Update(&tctx, blob.data, blob.length); + MD5Final(hash, &tctx); + return NT_STATUS_OK; +} + /******************************************************************* Parse out a struct security_descriptor from a DATA_BLOB. *******************************************************************/ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, uint32 security_info, - struct security_descriptor **ppdesc) + struct security_descriptor **ppdesc, + uint8_t hash[16]) { TALLOC_CTX *ctx = talloc_tos(); struct xattr_NTACL xacl; @@ -64,6 +96,7 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, ? xacl.info.sd_hs->sd->dacl : NULL, &sd_size); + memcpy(hash, xacl.info.sd_hs->hash, 16); TALLOC_FREE(xacl.info.sd); return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; @@ -131,7 +164,9 @@ static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, Create a DATA_BLOB from a security descriptor. *******************************************************************/ -static NTSTATUS create_acl_blob(const struct security_descriptor *psd, DATA_BLOB *pblob) +static NTSTATUS create_acl_blob(const struct security_descriptor *psd, + DATA_BLOB *pblob, + uint8_t hash[16]) { struct xattr_NTACL xacl; struct security_descriptor_hash sd_hs; @@ -144,7 +179,7 @@ static NTSTATUS create_acl_blob(const struct security_descriptor *psd, DATA_BLOB xacl.version = 2; xacl.info.sd_hs = &sd_hs; xacl.info.sd_hs->sd = CONST_DISCARD(struct security_descriptor *, psd); - memset(&xacl.info.sd_hs->hash[0], '\0', 16); + memcpy(&xacl.info.sd_hs->hash[0], hash, 16); ndr_err = ndr_push_struct_blob( pblob, ctx, NULL, &xacl, @@ -242,9 +277,11 @@ static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle, uint32 security_info, struct security_descriptor **ppdesc) { - TALLOC_CTX *ctx = talloc_tos(); DATA_BLOB blob; NTSTATUS status; + uint8_t hash[16]; + uint8_t hash_tmp[16]; + struct security_descriptor *pdesc_next = NULL; if (fsp && name == NULL) { name = fsp->fsp_name; @@ -252,19 +289,74 @@ static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle, DEBUG(10, ("get_nt_acl_xattr_internal: name=%s\n", name)); - status = get_acl_blob(ctx, handle, fsp, name, &blob); + status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("get_acl_blob returned %s\n", nt_errstr(status))); return status; } - status = parse_acl_blob(&blob, security_info, ppdesc); + status = parse_acl_blob(&blob, security_info, ppdesc, &hash[0]); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("parse_acl_blob returned %s\n", nt_errstr(status))); return status; } + /* If there was no stored hash, don't check. */ + memset(&hash_tmp[0], '\0', 16); + if (memcmp(&hash[0], &hash_tmp[0], 16) == 0) { + /* No hash, goto return blob sd. */ + goto out; + } + + /* Get the full underlying sd, then hash. */ + if (fsp) { + status = SMB_VFS_NEXT_FGET_NT_ACL(handle, + fsp, + HASH_SECURITY_INFO, + &pdesc_next); + } else { + status = SMB_VFS_NEXT_GET_NT_ACL(handle, + name, + HASH_SECURITY_INFO, + &pdesc_next); + } + + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = hash_sd(pdesc_next, hash_tmp); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + if (memcmp(&hash[0], &hash_tmp[0], 16) == 0) { + TALLOC_FREE(pdesc_next); + /* Hash matches, return blob sd. */ + goto out; + } + + /* Hash doesn't match, return underlying sd. */ + + if (!(security_info & OWNER_SECURITY_INFORMATION)) { + pdesc_next->owner_sid = NULL; + } + if (!(security_info & GROUP_SECURITY_INFORMATION)) { + pdesc_next->group_sid = NULL; + } + if (!(security_info & DACL_SECURITY_INFORMATION)) { + pdesc_next->dacl = NULL; + } + if (!(security_info & SACL_SECURITY_INFORMATION)) { + pdesc_next->sacl = NULL; + } + + TALLOC_FREE(*ppdesc); + *ppdesc = pdesc_next; + + out: + TALLOC_FREE(blob.data); return status; } @@ -324,9 +416,11 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, NTSTATUS status; struct security_descriptor *parent_desc = NULL; struct security_descriptor *psd = NULL; + struct security_descriptor *pdesc_next = NULL; DATA_BLOB blob; size_t size; char *parent_name; + uint8_t hash[16]; if (!parent_dirname(ctx, fname, &parent_name, NULL)) { return NT_STATUS_NO_MEMORY; @@ -382,11 +476,9 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { if (fsp && fsp->posix_open) { - ret = vfs_lstat_smb_fname(handle->conn, fname, - &sbuf); + ret = vfs_lstat_smb_fname(handle->conn,fname, &sbuf); } else { - ret = vfs_stat_smb_fname(handle->conn, fname, - &sbuf); + ret = vfs_stat_smb_fname(handle->conn,fname, &sbuf); } } if (ret == -1) { @@ -403,7 +495,28 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, } } - status = create_acl_blob(psd, &blob); + /* Object exists. Read the current SD to get the hash. */ + if (fsp) { + status = SMB_VFS_NEXT_FGET_NT_ACL(handle, + fsp, + HASH_SECURITY_INFO, + &pdesc_next); + } else { + status = SMB_VFS_NEXT_GET_NT_ACL(handle, + fname, + HASH_SECURITY_INFO, + &pdesc_next); + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = hash_sd(pdesc_next, hash); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = create_acl_blob(psd, &blob, hash); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -430,6 +543,13 @@ static int open_acl_xattr(vfs_handle_struct *handle, char *fname = NULL; NTSTATUS status; + if (fsp->base_fsp) { + /* Stream open. Base filename open already did the ACL check. */ + DEBUG(10,("open_acl_xattr: stream open on %s\n", + smb_fname_str_dbg(smb_fname) )); + return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); + } + status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); if (!NT_STATUS_IS_OK(status)) { @@ -497,23 +617,8 @@ static int mkdir_acl_xattr(vfs_handle_struct *handle, const char *path, mode_t m static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info, struct security_descriptor **ppdesc) { - NTSTATUS status = get_nt_acl_xattr_internal(handle, fsp, + return get_nt_acl_xattr_internal(handle, fsp, NULL, security_info, ppdesc); - if (NT_STATUS_IS_OK(status)) { - if (DEBUGLEVEL >= 10) { - DEBUG(10,("fget_nt_acl_xattr: returning xattr sd for file %s\n", - fsp->fsp_name)); - NDR_PRINT_DEBUG(security_descriptor, *ppdesc); - } - return NT_STATUS_OK; - } - - DEBUG(10,("fget_nt_acl_xattr: failed to get xattr sd for file %s, Error %s\n", - fsp->fsp_name, - nt_errstr(status) )); - - return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, - security_info, ppdesc); } /********************************************************************* @@ -523,23 +628,8 @@ static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle, const char *name, uint32 security_info, struct security_descriptor **ppdesc) { - NTSTATUS status = get_nt_acl_xattr_internal(handle, NULL, + return get_nt_acl_xattr_internal(handle, NULL, name, security_info, ppdesc); - if (NT_STATUS_IS_OK(status)) { - if (DEBUGLEVEL >= 10) { - DEBUG(10,("get_nt_acl_xattr: returning xattr sd for file %s\n", - name)); - NDR_PRINT_DEBUG(security_descriptor, *ppdesc); - } - return NT_STATUS_OK; - } - - DEBUG(10,("get_nt_acl_xattr: failed to get xattr sd for file %s, Error %s\n", - name, - nt_errstr(status) )); - - return SMB_VFS_NEXT_GET_NT_ACL(handle, name, - security_info, ppdesc); } /********************************************************************* @@ -551,6 +641,8 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, { NTSTATUS status; DATA_BLOB blob; + struct security_descriptor *pdesc_next = NULL; + uint8_t hash[16]; if (DEBUGLEVEL >= 10) { DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n", @@ -559,11 +651,6 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, CONST_DISCARD(struct security_descriptor *,psd)); } - status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - /* Ensure owner and group are set. */ if (!psd->owner_sid || !psd->group_sid) { int ret; @@ -576,13 +663,9 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, } if (fsp->is_directory || fsp->fh->fd == -1) { if (fsp->posix_open) { - ret = vfs_lstat_smb_fname(fsp->conn, - fsp->fsp_name, - &sbuf); + ret = vfs_lstat_smb_fname(fsp->conn,fsp->fsp_name, &sbuf); } else { - ret = vfs_stat_smb_fname(fsp->conn, - fsp->fsp_name, - &sbuf); + ret = vfs_stat_smb_fname(fsp->conn,fsp->fsp_name, &sbuf); } } else { ret = SMB_VFS_FSTAT(fsp, &sbuf); @@ -600,6 +683,26 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, psd = nc_psd; } + status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Get the full underlying sd, then hash. */ + status = SMB_VFS_NEXT_FGET_NT_ACL(handle, + fsp, + HASH_SECURITY_INFO, + &pdesc_next); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = hash_sd(pdesc_next, hash); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + #if 0 if ((security_info_sent & DACL_SECURITY_INFORMATION) && psd->dacl != NULL && @@ -624,7 +727,7 @@ static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, NDR_PRINT_DEBUG(security_descriptor, CONST_DISCARD(struct security_descriptor *,psd)); } - create_acl_blob(psd, &blob); + create_acl_blob(psd, &blob, hash); store_acl_blob_fsp(handle, fsp, &blob); return NT_STATUS_OK; -- cgit