X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fntfs-3g_apply.c;h=0d054edb922737d46247908ea33c16e237b94219;hb=b838675b420f13b3771b91b4ab2d5eddc3e6492f;hp=28589698b7e9e3a8cc082d15091b377c2f73052c;hpb=bb6773105af4072cf0ce7e6c8276632d6110b03b;p=wimlib diff --git a/src/ntfs-3g_apply.c b/src/ntfs-3g_apply.c index 28589698..0d054edb 100644 --- a/src/ntfs-3g_apply.c +++ b/src/ntfs-3g_apply.c @@ -50,6 +50,7 @@ #include "wimlib/ntfs_3g.h" #include "wimlib/paths.h" #include "wimlib/resource.h" +#include "wimlib/security_descriptor.h" static ntfs_volume * ntfs_3g_apply_ctx_get_volume(struct apply_ctx *ctx) @@ -260,14 +261,14 @@ ntfs_3g_extract_stream(file_spec_t file, const utf16lechar *raw_stream_name, * to skip even more useless work (for example it fills resized * attributes with 0's, then we just override it.) */ ret = WIMLIB_ERR_WRITE; - if (ntfs_attr_truncate_solid(na, wim_resource_size(lte))) + if (ntfs_attr_truncate_solid(na, lte->size)) goto out_attr_close; /* Extract stream data to the NTFS attribute. */ extract_ctx.na = na; extract_ctx.offset = 0; - ret = extract_wim_resource(lte, wim_resource_size(lte), - ntfs_3g_extract_wim_chunk, &extract_ctx); + ret = extract_stream(lte, lte->size, + ntfs_3g_extract_wim_chunk, &extract_ctx); /* Clean up and return. */ out_attr_close: ntfs_attr_close(na); @@ -283,7 +284,8 @@ out: static int ntfs_3g_extract_unnamed_stream(file_spec_t file, struct wim_lookup_table_entry *lte, - struct apply_ctx *ctx) + struct apply_ctx *ctx, + struct wim_dentry *_ignore) { return ntfs_3g_extract_stream(file, NULL, 0, lte, ctx); } @@ -379,6 +381,113 @@ out: return ret; } +static size_t +sid_size(const wimlib_SID *sid) +{ + return offsetof(wimlib_SID, sub_authority) + + sizeof(le32) * sid->sub_authority_count; +} + +/* + * sd_fixup - Fix up a Windows NT security descriptor for libntfs-3g. + * + * libntfs-3g validates security descriptors before setting them, but old + * versions contain bugs causing it to reject unusual but valid security + * descriptors: + * + * - Versions before 2013.1.13 reject security descriptors ending with an empty + * SACL (System Access Control List). This bug can be worked around either by + * moving the empty SACL earlier in the security descriptor or by removing the + * SACL entirely. The latter work-around is valid because an empty SACL is + * equivalent to a "null", or non-existent, SACL. + * - Versions up to and including 2013.1.13 reject security descriptors ending + * with an empty DACL (Discretionary Access Control List). This is very + * similar to the SACL bug and should be fixed in the next release after + * 2013.1.13. However, removing the DACL is not a valid workaround because + * this changes the meaning of the security descriptor--- an empty DACL allows + * no access, whereas a "null" DACL allows all access. + * + * If the security descriptor was fixed, this function returns an allocated + * buffer containing the fixed security descriptor, and its size is updated. + * Otherwise (or if no memory is available) the original descriptor is returned. + */ +static u8 * +sd_fixup(const u8 *_desc, size_t *size_p) +{ + u32 owner_offset, group_offset, dacl_offset, sacl_offset; + bool owner_valid, group_valid; + size_t size = *size_p; + const wimlib_SECURITY_DESCRIPTOR_RELATIVE *desc = + (const wimlib_SECURITY_DESCRIPTOR_RELATIVE*)_desc; + wimlib_SECURITY_DESCRIPTOR_RELATIVE *desc_new; + const wimlib_SID *owner, *group, *sid; + + /* Don't attempt to fix clearly invalid security descriptors. */ + if (size < sizeof(wimlib_SECURITY_DESCRIPTOR_RELATIVE)) + return (u8*)_desc; + + if (le16_to_cpu(desc->control) & wimlib_SE_DACL_PRESENT) + dacl_offset = le32_to_cpu(desc->dacl_offset); + else + dacl_offset = 0; + + if (le16_to_cpu(desc->control) & wimlib_SE_SACL_PRESENT) + sacl_offset = le32_to_cpu(desc->sacl_offset); + else + sacl_offset = 0; + + /* Check if the security descriptor will be affected by one of the bugs. + * If not, do nothing and return. + * + * Note: HAVE_NTFS_MNT_RDONLY is defined if libntfs-3g is + * version 2013.1.13 or later. */ + if (!( + #if !defined(HAVE_NTFS_MNT_RDONLY) + (sacl_offset != 0 && sacl_offset == size - sizeof(wimlib_ACL)) || + #endif + (dacl_offset != 0 && dacl_offset == size - sizeof(wimlib_ACL)))) + return (u8*)_desc; + + owner_offset = le32_to_cpu(desc->owner_offset); + group_offset = le32_to_cpu(desc->group_offset); + owner = (const wimlib_SID*)((const u8*)desc + owner_offset); + group = (const wimlib_SID*)((const u8*)desc + group_offset); + + /* We'll try to move the owner or group SID to the end of the security + * descriptor to avoid the bug. This is only possible if at least one + * is valid. */ + owner_valid = (owner_offset != 0) && + (owner_offset % 4 == 0) && + (owner_offset <= size - sizeof(SID)) && + (owner_offset + sid_size(owner) <= size) && + (owner_offset >= sizeof(wimlib_SECURITY_DESCRIPTOR_RELATIVE)); + group_valid = (group_offset != 0) && + (group_offset % 4 == 0) && + (group_offset <= size - sizeof(SID)) && + (group_offset + sid_size(group) <= size) && + (group_offset >= sizeof(wimlib_SECURITY_DESCRIPTOR_RELATIVE)); + if (owner_valid) { + sid = owner; + } else if (group_valid) { + sid = group; + } else { + return (u8*)_desc; + } + + desc_new = MALLOC(size + sid_size(sid)); + if (desc_new == NULL) + return (u8*)_desc; + + memcpy(desc_new, desc, size); + if (owner_valid) + desc_new->owner_offset = cpu_to_le32(size); + else if (group_valid) + desc_new->group_offset = cpu_to_le32(size); + memcpy((u8*)desc_new + size, sid, sid_size(sid)); + *size_p = size + sid_size(sid); + return (u8*)desc_new; +} + static int ntfs_3g_set_security_descriptor(const char *path, const u8 *desc, size_t desc_size, struct apply_ctx *ctx) @@ -386,7 +495,8 @@ ntfs_3g_set_security_descriptor(const char *path, const u8 *desc, size_t desc_si ntfs_volume *vol; ntfs_inode *ni; struct SECURITY_CONTEXT sec_ctx; - int ret = 0; + u8 *desc_fixed; + int ret; vol = ntfs_3g_apply_ctx_get_volume(ctx); @@ -397,10 +507,19 @@ ntfs_3g_set_security_descriptor(const char *path, const u8 *desc, size_t desc_si memset(&sec_ctx, 0, sizeof(sec_ctx)); sec_ctx.vol = vol; - if (ntfs_set_ntfs_acl(&sec_ctx, ni, desc, desc_size, 0)) + desc_fixed = sd_fixup(desc, &desc_size); + + ret = 0; + + if (ntfs_set_ntfs_acl(&sec_ctx, ni, desc_fixed, desc_size, 0)) ret = WIMLIB_ERR_SET_SECURITY; + + if (desc_fixed != desc) + FREE(desc_fixed); + if (ntfs_inode_close(ni)) ret = WIMLIB_ERR_WRITE; + return ret; }