summaryrefslogtreecommitdiff
path: root/source3/modules/vfs_acl_common.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2012-10-10 16:36:47 +1100
committerAndrew Bartlett <abartlet@samba.org>2013-02-04 12:19:30 +0100
commit25526ed3f590e4fa90c237a37f08bb23f449dd8c (patch)
tree2173740139e6023950bb0acf293a94979b15f491 /source3/modules/vfs_acl_common.c
parent6a5f65b0e971f068ebae5b2f93a6dfccfaa93b26 (diff)
downloadsamba-25526ed3f590e4fa90c237a37f08bb23f449dd8c.tar.gz
samba-25526ed3f590e4fa90c237a37f08bb23f449dd8c.tar.bz2
samba-25526ed3f590e4fa90c237a37f08bb23f449dd8c.zip
vfs: Implement an improved vfs_acl_common that uses the hash of the system ACL
Where supported by the system ACL backend, this avoids hashing the result of the ACL mapping, instead hashing the original ACL, linearlised. For maximum robustness, the hash of the NT and system ACL are stored, along with the time and a description of the system ACL. This variety of extra metadata may assist some future implementation in determining which hash to validate. Andrew Bartlett Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Christian Ambach <ambi@samba.org>
Diffstat (limited to 'source3/modules/vfs_acl_common.c')
-rw-r--r--source3/modules/vfs_acl_common.c301
1 files changed, 250 insertions, 51 deletions
diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index e1555c7d9e..5d4327a628 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -87,9 +87,11 @@ static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
TALLOC_CTX *mem_ctx,
- struct security_descriptor **ppdesc,
- uint16_t *p_hash_type,
- uint8_t hash[XATTR_SD_HASH_SIZE])
+ struct security_descriptor **ppdesc,
+ uint16_t *p_hash_type,
+ uint16_t *p_version,
+ uint8_t hash[XATTR_SD_HASH_SIZE],
+ uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE])
{
struct xattr_NTACL xacl;
enum ndr_err_code ndr_err;
@@ -106,6 +108,8 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
return ndr_map_error2ntstatus(ndr_err);
}
+ *p_version = xacl.version;
+
switch (xacl.version) {
case 1:
*ppdesc = make_sec_desc(mem_ctx, SD_REVISION,
@@ -140,9 +144,22 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
xacl.info.sd_hs3->sd->dacl,
&sd_size);
*p_hash_type = xacl.info.sd_hs3->hash_type;
- /* Current version 3. */
+ /* Current version 3 (if no sys acl hash available). */
memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
break;
+ case 4:
+ *ppdesc = make_sec_desc(mem_ctx, SD_REVISION,
+ xacl.info.sd_hs4->sd->type | SEC_DESC_SELF_RELATIVE,
+ xacl.info.sd_hs4->sd->owner_sid,
+ xacl.info.sd_hs4->sd->group_sid,
+ xacl.info.sd_hs4->sd->sacl,
+ xacl.info.sd_hs4->sd->dacl,
+ &sd_size);
+ *p_hash_type = xacl.info.sd_hs4->hash_type;
+ /* Current version 4. */
+ memcpy(hash, xacl.info.sd_hs4->hash, XATTR_SD_HASH_SIZE);
+ memcpy(sys_acl_hash, xacl.info.sd_hs4->sys_acl_hash, XATTR_SD_HASH_SIZE);
+ break;
default:
TALLOC_FREE(frame);
return NT_STATUS_REVISION_MISMATCH;
@@ -154,7 +171,8 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
}
/*******************************************************************
- Create a DATA_BLOB from a security descriptor.
+ Create a DATA_BLOB from a hash of the security descriptor storead at
+ the system layer and the NT ACL we wish to preserve
*******************************************************************/
static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
@@ -190,6 +208,52 @@ static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
}
/*******************************************************************
+ Create a DATA_BLOB from a hash of the security descriptors
+ (system and NT) stored at the system layer and the NT ACL we wish
+ to preserve.
+*******************************************************************/
+
+static NTSTATUS create_sys_acl_blob(const struct security_descriptor *psd,
+ DATA_BLOB *pblob,
+ uint16_t hash_type,
+ uint8_t hash[XATTR_SD_HASH_SIZE],
+ const char *description,
+ uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE])
+{
+ struct xattr_NTACL xacl;
+ struct security_descriptor_hash_v4 sd_hs4;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *ctx = talloc_tos();
+ NTTIME nttime_now;
+ struct timeval now = timeval_current();
+ nttime_now = timeval_to_nttime(&now);
+
+ ZERO_STRUCT(xacl);
+ ZERO_STRUCT(sd_hs4);
+
+ xacl.version = 4;
+ xacl.info.sd_hs4 = &sd_hs4;
+ xacl.info.sd_hs4->sd = discard_const_p(struct security_descriptor, psd);
+ xacl.info.sd_hs4->hash_type = hash_type;
+ memcpy(&xacl.info.sd_hs4->hash[0], hash, XATTR_SD_HASH_SIZE);
+ xacl.info.sd_hs4->description = description;
+ xacl.info.sd_hs4->time = nttime_now;
+ memcpy(&xacl.info.sd_hs4->sys_acl_hash[0], sys_acl_hash, XATTR_SD_HASH_SIZE);
+
+ ndr_err = ndr_push_struct_blob(
+ pblob, ctx, &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;
+}
+
+/*******************************************************************
Add in 3 inheritable components for a non-inheritable directory ACL.
CREATOR_OWNER/CREATOR_GROUP/WORLD.
*******************************************************************/
@@ -307,14 +371,18 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
DATA_BLOB blob = data_blob_null;
NTSTATUS status;
uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
+ uint16_t xattr_version = 0;
uint8_t hash[XATTR_SD_HASH_SIZE];
+ uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE];
uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
+ uint8_t sys_acl_hash_tmp[XATTR_SD_HASH_SIZE];
struct security_descriptor *psd = NULL;
struct security_descriptor *pdesc_next = NULL;
bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
ACL_MODULE_NAME,
"ignore system acls",
false);
+ TALLOC_CTX *frame = talloc_stackframe();
if (fsp && name == NULL) {
name = fsp->fsp_name->base_name;
@@ -343,10 +411,18 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
"returned %s\n",
name,
nt_errstr(status)));
+ TALLOC_FREE(frame);
return status;
}
- status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
+ /* Ensure we don't leak psd_next if we don't choose it.
+ *
+ * We don't allocate it onto frame as it is preferred not to
+ * steal from a talloc pool.
+ */
+ talloc_steal(frame, pdesc_next);
+
+ status = get_acl_blob(frame, handle, fsp, name, &blob);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
nt_errstr(status)));
@@ -355,7 +431,7 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
}
status = parse_acl_blob(&blob, mem_ctx, &psd,
- &hash_type, &hash[0]);
+ &hash_type, &xattr_version, &hash[0], &sys_acl_hash[0]);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("parse_acl_blob returned %s\n",
nt_errstr(status)));
@@ -363,57 +439,125 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
goto out;
}
- /* Ensure the hash type is one we know. */
- switch (hash_type) {
- case XATTR_SD_HASH_TYPE_NONE:
- /* No hash, just return blob sd. */
- goto out;
- case XATTR_SD_HASH_TYPE_SHA256:
- break;
- default:
- DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
- "mismatch (%u) for file %s\n",
- (unsigned int)hash_type,
- name));
- TALLOC_FREE(psd);
- psd = pdesc_next;
+ /* Ensure we don't leak psd if we don't choose it.
+ *
+ * We don't allocate it onto frame as it is preferred not to
+ * steal from a talloc pool.
+ */
+ talloc_steal(frame, psd);
+
+ /* determine which type of xattr we got */
+ switch (xattr_version) {
+ case 1:
+ case 2:
+ /* These xattr types are unilatteral, they do not
+ * require confirmation of the hash. In particular,
+ * the NTVFS file server uses version 1, but
+ * 'samba-tool ntacl' can set these as well */
+ goto out;
+ case 3:
+ case 4:
+ if (ignore_file_system_acl) {
goto out;
- }
+ }
- if (ignore_file_system_acl) {
+ break;
+ default:
+ DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
+ "mismatch (%u) for file %s\n",
+ (unsigned int)hash_type,
+ name));
+ TALLOC_FREE(psd);
+ psd = pdesc_next;
goto out;
}
- status = hash_sd_sha256(pdesc_next, hash_tmp);
- if (!NT_STATUS_IS_OK(status)) {
+ /* determine which type of xattr we got */
+ if (hash_type != XATTR_SD_HASH_TYPE_SHA256) {
+ DEBUG(10, ("get_nt_acl_internal: ACL blob hash type "
+ "(%u) unexpected for file %s\n",
+ (unsigned int)hash_type,
+ name));
TALLOC_FREE(psd);
psd = pdesc_next;
goto out;
}
- if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
- /* Hash matches, return blob sd. */
- DEBUG(10, ("get_nt_acl_internal: blob hash "
- "matches for file %s\n",
- name ));
- goto out;
- }
+ /* determine which type of xattr we got */
+ switch (xattr_version) {
+ case 4:
+ {
+ int ret;
+ char *sys_acl_blob_description;
+ DATA_BLOB sys_acl_blob;
+ if (fsp) {
+ /* Get the full underlying sd, then hash. */
+ ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle,
+ fsp,
+ frame,
+ &sys_acl_blob_description,
+ &sys_acl_blob);
+ } else {
+ /* Get the full underlying sd, then hash. */
+ ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FILE(handle,
+ name,
+ frame,
+ &sys_acl_blob_description,
+ &sys_acl_blob);
+ }
+
+ /* If we fail to get the ACL blob (for some reason) then this
+ * is not fatal, we just work based on the NT ACL only */
+ if (ret == 0) {
+ status = hash_blob_sha256(sys_acl_blob, sys_acl_hash_tmp);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
- /* Hash doesn't match, return underlying sd. */
- DEBUG(10, ("get_nt_acl_internal: blob hash "
- "does not match for file %s - returning "
- "file system SD mapping.\n",
- name ));
+ if (memcmp(&sys_acl_hash[0], &sys_acl_hash_tmp[0],
+ XATTR_SD_HASH_SIZE) == 0) {
+ /* Hash matches, return blob sd. */
+ DEBUG(10, ("get_nt_acl_internal: blob hash "
+ "matches for file %s\n",
+ name ));
+ goto out;
+ }
+ }
- if (DEBUGLEVEL >= 10) {
- DEBUG(10,("get_nt_acl_internal: acl for blob hash for %s is:\n",
- name ));
- NDR_PRINT_DEBUG(security_descriptor, pdesc_next);
+ /* Otherwise, fall though and see if the NT ACL hash matches */
}
+ case 3:
+ status = hash_sd_sha256(pdesc_next, hash_tmp);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(psd);
+ psd = pdesc_next;
+ goto out;
+ }
+
+ if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
+ /* Hash matches, return blob sd. */
+ DEBUG(10, ("get_nt_acl_internal: blob hash "
+ "matches for file %s\n",
+ name ));
+ goto out;
+ }
- TALLOC_FREE(psd);
- psd = pdesc_next;
+ /* Hash doesn't match, return underlying sd. */
+ DEBUG(10, ("get_nt_acl_internal: blob hash "
+ "does not match for file %s - returning "
+ "file system SD mapping.\n",
+ name ));
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10,("get_nt_acl_internal: acl for blob hash for %s is:\n",
+ name ));
+ NDR_PRINT_DEBUG(security_descriptor, pdesc_next);
+ }
+ TALLOC_FREE(psd);
+ psd = pdesc_next;
+ }
out:
if (psd != pdesc_next) {
@@ -432,6 +576,7 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
if (fsp) {
status = vfs_stat_fsp(fsp);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
return status;
}
psbuf = &fsp->fsp_name->st;
@@ -440,6 +585,7 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
name,
&sbuf);
if (ret == -1) {
+ TALLOC_FREE(frame);
return map_nt_error_from_unix(errno);
}
}
@@ -452,6 +598,7 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
psbuf,
&psd);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
return status;
}
} else {
@@ -464,6 +611,7 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
psbuf,
psd);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
return status;
}
}
@@ -491,7 +639,6 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
}
TALLOC_FREE(blob.data);
- *ppdesc = psd;
if (DEBUGLEVEL >= 10) {
DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
@@ -499,6 +646,10 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
NDR_PRINT_DEBUG(security_descriptor, psd);
}
+ /* The VFS API is that the ACL is expected to be on mem_ctx */
+ *ppdesc = talloc_move(mem_ctx, &psd);
+
+ TALLOC_FREE(frame);
return NT_STATUS_OK;
}
@@ -538,11 +689,14 @@ static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
uint32_t security_info_sent, const struct security_descriptor *orig_psd)
{
NTSTATUS status;
- DATA_BLOB blob;
+ int ret;
+ DATA_BLOB blob, sys_acl_blob;
struct security_descriptor *pdesc_next = NULL;
struct security_descriptor *psd = NULL;
uint8_t hash[XATTR_SD_HASH_SIZE];
+ uint8_t sys_acl_hash[XATTR_SD_HASH_SIZE];
bool chown_needed = false;
+ char *sys_acl_description;
TALLOC_CTX *frame = talloc_stackframe();
if (DEBUGLEVEL >= 10) {
@@ -642,19 +796,64 @@ static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
return status;
}
+ /* Get the full underlying sd, then hash. */
+ ret = SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle,
+ fsp,
+ frame,
+ &sys_acl_description,
+ &sys_acl_blob);
+
+ /* If we fail to get the ACL blob (for some reason) then this
+ * is not fatal, we just work based on the NT ACL only */
+ if (ret != 0) {
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
+ fsp_str_dbg(fsp)));
+ NDR_PRINT_DEBUG(security_descriptor,
+ discard_const_p(struct security_descriptor, psd));
+
+ DEBUG(10,("fset_nt_acl_xattr: storing has in xattr sd based on \n"));
+ NDR_PRINT_DEBUG(security_descriptor,
+ discard_const_p(struct security_descriptor, pdesc_next));
+ }
+ status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("fset_nt_acl_xattr: create_acl_blob failed\n"));
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ status = store_acl_blob_fsp(handle, fsp, &blob);
+
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ status = hash_blob_sha256(sys_acl_blob, sys_acl_hash);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
if (DEBUGLEVEL >= 10) {
- DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
+ DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s based on system ACL\n",
fsp_str_dbg(fsp)));
NDR_PRINT_DEBUG(security_descriptor,
- discard_const_p(struct security_descriptor, psd));
+ discard_const_p(struct security_descriptor, psd));
- DEBUG(10,("fset_nt_acl_xattr: storing has in xattr sd based on \n"));
+ DEBUG(10,("fset_nt_acl_xattr: storing hash in xattr sd based on system ACL and:\n"));
NDR_PRINT_DEBUG(security_descriptor,
- discard_const_p(struct security_descriptor, pdesc_next));
+ discard_const_p(struct security_descriptor, pdesc_next));
}
- status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
+
+ /* We store hashes of both the sys ACL blob and the NT
+ * security desciptor mapped from that ACL so as to improve
+ * our chances against some inadvertant change breaking the
+ * hash used */
+ status = create_sys_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash,
+ sys_acl_description, sys_acl_hash);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("fset_nt_acl_xattr: create_acl_blob failed\n"));
+ DEBUG(10, ("fset_nt_acl_xattr: create_sys_acl_blob failed\n"));
TALLOC_FREE(frame);
return status;
}