summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2009-07-10 15:50:40 -0700
committerJeremy Allison <jra@samba.org>2009-07-10 15:50:40 -0700
commit361aa19e69d4176dd8c30f485cc637cd33308d62 (patch)
tree18e9193cb955e22297dc8f7b3ec1fcff1b458ff1
parentafc6f607d5c8ba995b55464525edc8bf8f7a040c (diff)
downloadsamba-361aa19e69d4176dd8c30f485cc637cd33308d62.tar.gz
samba-361aa19e69d4176dd8c30f485cc637cd33308d62.tar.bz2
samba-361aa19e69d4176dd8c30f485cc637cd33308d62.zip
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.
-rw-r--r--source3/modules/vfs_acl_xattr.c213
1 files changed, 158 insertions, 55 deletions
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;