diff options
-rw-r--r-- | source3/include/proto.h | 13 | ||||
-rw-r--r-- | source3/lib/secdesc.c | 194 | ||||
-rw-r--r-- | source3/modules/vfs_acl_xattr.c | 256 | ||||
-rw-r--r-- | source3/printing/nt_printing.c | 6 |
4 files changed, 319 insertions, 150 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h index e4a445bcd0..b227a30f00 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -758,8 +758,17 @@ SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src); NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size); NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask); NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size); -SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr, - bool child_container); +NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx, + SEC_DESC **ppsd, + size_t *psize, + const SEC_DESC *parent_ctr, + const DOM_SID *owner_sid, + const DOM_SID *group_sid, + bool container); +NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx, + SEC_DESC_BUF **ppsdb, + const SEC_DESC *parent_ctr, + bool container); /* The following definitions come from lib/select.c */ diff --git a/source3/lib/secdesc.c b/source3/lib/secdesc.c index 52ff067d6a..6afc165c0f 100644 --- a/source3/lib/secdesc.c +++ b/source3/lib/secdesc.c @@ -429,19 +429,47 @@ NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t return NT_STATUS_OK; } +/* + * Determine if an ACE is inheritable + */ + +static bool is_inheritable_ace(const SEC_ACE *ace, + bool container) +{ + if (!container) { + return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0); + } + + if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) { + return true; + } + + if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) && + !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) { + return true; + } + + return false; +} + /* Create a child security descriptor using another security descriptor as the parent container. This child object can either be a container or non-container object. */ -SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr, - bool child_container) +NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx, + SEC_DESC **ppsd, + size_t *psize, + const SEC_DESC *parent_ctr, + const DOM_SID *owner_sid, + const DOM_SID *group_sid, + bool container) { - SEC_DESC_BUF *sdb; - SEC_DESC *sd; - SEC_ACL *new_dacl, *the_acl; + SEC_ACL *new_dacl = NULL, *the_acl = NULL; SEC_ACE *new_ace_list = NULL; unsigned int new_ace_list_ndx = 0, i; - size_t size; + + *ppsd = NULL; + *psize = 0; /* Currently we only process the dacl when creating the child. The sacl should also be processed but this is left out as sacls are @@ -450,71 +478,78 @@ SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr, the_acl = parent_ctr->dacl; if (the_acl->num_aces) { - if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces))) - return NULL; + if (2*the_acl->num_aces < the_acl->num_aces) { + return NT_STATUS_NO_MEMORY; + } + + if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, + 2*the_acl->num_aces))) { + return NT_STATUS_NO_MEMORY; + } } else { new_ace_list = NULL; } for (i = 0; i < the_acl->num_aces; i++) { - SEC_ACE *ace = &the_acl->aces[i]; + const SEC_ACE *ace = &the_acl->aces[i]; SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx]; - uint8 new_flags = 0; - bool inherit = False; + const DOM_SID *ptrustee = &ace->trustee; + const DOM_SID *creator = NULL; + uint8 new_flags = ace->flags; - /* The OBJECT_INHERIT_ACE flag causes the ACE to be - inherited by non-container children objects. Container - children objects will inherit it as an INHERIT_ONLY - ACE. */ + if (!is_inheritable_ace(ace, container)) { + continue; + } - if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) { + /* see the RAW-ACLS inheritance test for details on these rules */ + if (!container) { + new_flags = 0; + } else { + new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY; - if (!child_container) { - new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT; - } else { + if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) { new_flags |= SEC_ACE_FLAG_INHERIT_ONLY; } - - inherit = True; + if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { + new_flags = 0; + } } - /* The CONAINER_INHERIT_ACE flag means all child container - objects will inherit and use the ACE. */ - - if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) { - if (!child_container) { - inherit = False; - } else { - new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT; - } + /* The CREATOR sids are special when inherited */ + if (sid_equal(ptrustee, &global_sid_Creator_Owner)) { + creator = &global_sid_Creator_Owner; + ptrustee = owner_sid; + } else if (sid_equal(ptrustee, &global_sid_Creator_Group)) { + creator = &global_sid_Creator_Group; + ptrustee = group_sid; } - /* The INHERIT_ONLY_ACE is not used by the se_access_check() - function for the parent container, but is inherited by - all child objects as a normal ACE. */ + if (creator && container && + (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) { - if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) { - /* Move along, nothing to see here */ - } + /* First add the regular ACE entry with flags = 0. */ + init_sec_ace(new_ace, ptrustee, ace->type, + ace->access_mask, 0); - /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE - is inherited by child objects but not grandchildren - objects. We clear the object inherit and container - inherit flags in the inherited ACE. */ + DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x" + " inherited as %s:%d/0x%02x/0x%08x\n", + sid_string_dbg(&ace->trustee), + ace->type, ace->flags, ace->access_mask, + sid_string_dbg(&new_ace->trustee), + new_ace->type, new_ace->flags, + new_ace->access_mask)); - if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { - new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT | - SEC_ACE_FLAG_CONTAINER_INHERIT); - } + new_ace_list_ndx++; - /* Add ACE to ACE list */ + /* Now add the extra creator ACE. */ + new_ace = &new_ace_list[new_ace_list_ndx]; - if (!inherit) - continue; + ptrustee = creator; + new_flags |= SEC_ACE_FLAG_INHERIT_ONLY; + } - new_ace->access_mask = ace->access_mask; - init_sec_ace(new_ace, &ace->trustee, ace->type, - new_ace->access_mask, new_flags); + init_sec_ace(new_ace, ptrustee, ace->type, + ace->access_mask, new_flags); DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x " " inherited as %s:%d/0x%02x/0x%08x\n", @@ -528,21 +563,54 @@ SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr, } /* Create child security descriptor to return */ - - new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list); - /* Use the existing user and group sids. I don't think this is - correct. Perhaps the user and group should be passed in as - parameters by the caller? */ + new_dacl = make_sec_acl(ctx, + ACL_REVISION, + new_ace_list_ndx, + new_ace_list); - sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1, - SEC_DESC_SELF_RELATIVE, - parent_ctr->owner_sid, - parent_ctr->group_sid, - parent_ctr->sacl, - new_dacl, &size); + if (!new_dacl) { + return NT_STATUS_NO_MEMORY; + } + *ppsd = make_sec_desc(ctx, + SECURITY_DESCRIPTOR_REVISION_1, + SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT| + SEC_DESC_DACL_DEFAULTED, + owner_sid, + group_sid, + NULL, + new_dacl, + psize); + if (!*ppsd) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; +} - sdb = make_sec_desc_buf(ctx, size, sd); +NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx, + SEC_DESC_BUF **ppsdb, + const SEC_DESC *parent_ctr, + bool container) +{ + NTSTATUS status; + size_t size = 0; + SEC_DESC *sd = NULL; + + *ppsdb = NULL; + status = se_create_child_secdesc(ctx, + &sd, + &size, + parent_ctr, + parent_ctr->owner_sid, + parent_ctr->group_sid, + container); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - return sdb; + *ppsdb = make_sec_desc_buf(ctx, size, sd); + if (!*ppsdb) { + return NT_STATUS_NO_MEMORY; + } + return NT_STATUS_OK; } diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c index 241751c6a6..a802dac554 100644 --- a/source3/modules/vfs_acl_xattr.c +++ b/source3/modules/vfs_acl_xattr.c @@ -36,7 +36,6 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, struct xattr_NTACL xacl; enum ndr_err_code ndr_err; size_t sd_size; - struct timespec ts; ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl, (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL); @@ -51,17 +50,29 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, return NT_STATUS_REVISION_MISMATCH; } - /* - * Check that the ctime timestamp is ealier - * than the stored timestamp. - */ - - ts = nt_time_to_unix_timespec(&xacl.info.sd_ts->last_changed); - - if (timespec_compare(&cts, &ts) > 0) { - DEBUG(5, ("parse_acl_blob: stored ACL out of date.\n")); - return NT_STATUS_EA_CORRUPT_ERROR; +#if 0 + { + struct timespec ts; + /* Arg. This doesn't work. Too many activities + * change the ctime. May have to roll back to + * version 1. + */ + /* + * Check that the ctime timestamp is ealier + * than the stored timestamp. + */ + + ts = nt_time_to_unix_timespec(&xacl.info.sd_ts->last_changed); + + if (timespec_compare(&cts, &ts) > 0) { + DEBUG(5, ("parse_acl_blob: stored ACL out of date " + "(%s > %s.\n", + timestring(ctx, cts.tv_sec), + timestring(ctx, ts.tv_sec))); + return NT_STATUS_EA_CORRUPT_ERROR; + } } +#endif *ppdesc = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE, (security_info & OWNER_SECURITY_INFORMATION) @@ -133,6 +144,78 @@ static NTSTATUS get_acl_blob(TALLOC_CTX *ctx, return NT_STATUS_OK; } +static NTSTATUS create_acl_blob(const SEC_DESC *psd, DATA_BLOB *pblob) +{ + struct xattr_NTACL xacl; + struct security_descriptor_timestamp sd_ts; + enum ndr_err_code ndr_err; + TALLOC_CTX *ctx = talloc_tos(); + struct timespec curr = timespec_current(); + + ZERO_STRUCT(xacl); + ZERO_STRUCT(sd_ts); + + /* Horrid hack as setting an xattr changes the ctime + * on Linux. This gives a race of 1 second during + * which we would not see a POSIX ACL set. + */ + curr.tv_sec += 1; + + xacl.version = 2; + xacl.info.sd_ts = &sd_ts; + xacl.info.sd_ts->sd = CONST_DISCARD(SEC_DESC *, psd); + unix_timespec_to_nt_time(&xacl.info.sd_ts->last_changed, curr); + + DEBUG(10, ("create_acl_blob: timestamp stored as %s\n", + timestring(ctx, curr.tv_sec) )); + + ndr_err = ndr_push_struct_blob( + pblob, ctx, NULL, &xacl, + (ndr_push_flags_fn_t)ndr_push_xattr_NTACL); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n", + ndr_errstr(ndr_err))); + return ndr_map_error2ntstatus(ndr_err);; + } + + return NT_STATUS_OK; +} + +static NTSTATUS store_acl_blob(files_struct *fsp, + DATA_BLOB *pblob) +{ + int ret; + int saved_errno = 0; + + DEBUG(10,("store_acl_blob: storing blob length %u on file %s\n", + (unsigned int)pblob->length, fsp->fsp_name)); + + become_root(); + if (fsp->fh->fd != -1) { + ret = SMB_VFS_FSETXATTR(fsp, XATTR_NTACL_NAME, + pblob->data, pblob->length, 0); + } else { + ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name, + XATTR_NTACL_NAME, + pblob->data, pblob->length, 0); + } + if (ret) { + saved_errno = errno; + } + unbecome_root(); + if (ret) { + errno = saved_errno; + DEBUG(5, ("store_acl_blob: setting attr failed for file %s" + "with error %s\n", + fsp->fsp_name, + strerror(errno) )); + return map_nt_error_from_unix(errno); + } + return NT_STATUS_OK; +} + + static NTSTATUS get_nt_acl_xattr_internal(vfs_handle_struct *handle, files_struct *fsp, const char *name, @@ -188,10 +271,72 @@ static int mkdir_acl_xattr(vfs_handle_struct *handle, const char *path, mode_t * inheritance for new files. *********************************************************************/ -static int open_acl_xattr(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode) +static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, + const char *fname, + files_struct *fsp) +{ + TALLOC_CTX *ctx = talloc_tos(); + NTSTATUS status; + SEC_DESC *parent_desc = NULL; + SEC_DESC *psd = NULL; + DATA_BLOB blob; + size_t size; + char *parent_name; + + if (!parent_dirname_talloc(ctx, + fname, + &parent_name, + NULL)) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10,("inherit_new_acl: check directory %s\n", + parent_name)); + + status = get_nt_acl_xattr_internal(handle, + NULL, + parent_name, + DACL_SECURITY_INFORMATION, + &parent_desc); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("inherit_new_acl: directory %s failed " + "to get acl %s\n", + parent_name, + nt_errstr(status) )); + return status; + } + + /* Create an inherited descriptor from the parent. */ + status = se_create_child_secdesc(ctx, + &psd, + &size, + parent_desc, + &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX], + &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX], + false); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = create_acl_blob(psd, &blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return store_acl_blob(fsp, &blob); +} + +/********************************************************************* + Check ACL on open. For new files inherit from parent directory. +*********************************************************************/ + +static int open_acl_xattr(vfs_handle_struct *handle, + const char *fname, + files_struct *fsp, + int flags, + mode_t mode) { uint32_t access_granted = 0; SEC_DESC *pdesc = NULL; + bool file_existed = true; NTSTATUS status = get_nt_acl_xattr_internal(handle, NULL, fname, @@ -209,9 +354,24 @@ static int open_acl_xattr(vfs_handle_struct *handle, const char *fname, files_s errno = map_errno_from_nt_status(status); return -1; } - } + } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + file_existed = false; + } + + DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for " + "file %s returned %s\n", + fname, + nt_errstr(status) )); + + fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); + + if (!file_existed && fsp->fh->fd != -1) { + /* File was created. Inherit from parent directory. */ + string_set(&fsp->fsp_name, fname); + inherit_new_acl(handle, fname, fsp); + } - return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); + return fsp->fh->fd; } static NTSTATUS fget_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, @@ -238,74 +398,6 @@ static NTSTATUS get_nt_acl_xattr(vfs_handle_struct *handle, security_info, ppdesc); } -static NTSTATUS create_acl_blob(const SEC_DESC *psd, DATA_BLOB *pblob) -{ - struct xattr_NTACL xacl; - struct security_descriptor_timestamp sd_ts; - enum ndr_err_code ndr_err; - TALLOC_CTX *ctx = talloc_tos(); - struct timespec curr = timespec_current(); - - ZERO_STRUCT(xacl); - ZERO_STRUCT(sd_ts); - - /* Horrid hack as setting an xattr changes the ctime - * on Linux. This gives a race of 1 second during - * which we would not see a POSIX ACL set. - */ - curr.tv_sec += 1; - - xacl.version = 2; - xacl.info.sd_ts = &sd_ts; - xacl.info.sd_ts->sd = CONST_DISCARD(SEC_DESC *, psd); - unix_timespec_to_nt_time(&xacl.info.sd_ts->last_changed, curr); - - ndr_err = ndr_push_struct_blob( - pblob, ctx, NULL, &xacl, - (ndr_push_flags_fn_t)ndr_push_xattr_NTACL); - - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n", - ndr_errstr(ndr_err))); - return ndr_map_error2ntstatus(ndr_err);; - } - - return NT_STATUS_OK; -} - -static NTSTATUS store_acl_blob(files_struct *fsp, - DATA_BLOB *pblob) -{ - int ret; - int saved_errno = 0; - - DEBUG(10,("store_acl_blob: storing blob length %u on file %s\n", - (unsigned int)pblob->length, fsp->fsp_name)); - - become_root(); - if (fsp->fh->fd != -1) { - ret = SMB_VFS_FSETXATTR(fsp, XATTR_NTACL_NAME, - pblob->data, pblob->length, 0); - } else { - ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name, - XATTR_NTACL_NAME, - pblob->data, pblob->length, 0); - } - if (ret) { - saved_errno = errno; - } - unbecome_root(); - if (ret) { - errno = saved_errno; - DEBUG(5, ("store_acl_blob: setting attr failed for file %s" - "with error %s\n", - fsp->fsp_name, - strerror(errno) )); - return map_nt_error_from_unix(errno); - } - return NT_STATUS_OK; -} - static NTSTATUS fset_nt_acl_xattr(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd) { diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 1826fa88ed..5ec0e1e9f3 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -5811,11 +5811,11 @@ bool print_access_check(struct auth_serversupplied_info *server_info, int snum, against. This is because print jobs are child objects objects of a printer. */ - secdesc = se_create_child_secdesc(mem_ctx, parent_secdesc->sd, False); + status = se_create_child_secdesc_buf(mem_ctx, &secdesc, parent_secdesc->sd, False); - if (!secdesc) { + if (!NT_STATUS_IS_OK(status)) { talloc_destroy(mem_ctx); - errno = ENOMEM; + errno = map_errno_from_nt_status(status); return False; } |