]> wimlib.net Git - wimlib/blobdiff - src/security.c
Compiler stuff
[wimlib] / src / security.c
index 7efc542b1e1de80a58dde1b8cf688cc170798782..5b0e81b3363f1b0372f741e4a56aedc52d6c06f4 100644 (file)
  * along with wimlib; if not, see http://www.gnu.org/licenses/.
  */
 
-#include "wimlib_internal.h"
-#include "buffer_io.h"
-#include "security.h"
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "wimlib/assert.h"
+#include "wimlib/buffer_io.h"
+#include "wimlib/error.h"
+#include "wimlib/security.h"
+#include "wimlib/sha1.h"
+#include "wimlib/util.h"
 
 /* At the start of each type of access control entry.  */
-typedef struct {
+typedef struct _ACE_HEADER {
        /* enum ace_type, specifies what type of ACE this is.  */
        u8 type;
 
@@ -36,32 +43,32 @@ typedef struct {
        u8 flags;
 
        /* Size of the access control entry. */
-       u8 size;
-} ACEHeader;
+       u16 size;
+} _packed_attribute ACE_HEADER;
 
 /* Grants rights to a user or group */
-typedef struct {
-       ACEHeader hdr;
+typedef struct _ACCESS_ALLOWED_ACE {
+       ACE_HEADER hdr;
        u32 mask;
        u32 sid_start;
-} AccessAllowedACE;
+} _packed_attribute ACCESS_ALLOWED_ACE;
 
 /* Denies rights to a user or group */
-typedef struct {
-       ACEHeader hdr;
+typedef struct _ACCESS_DENIED_ACE {
+       ACE_HEADER hdr;
        u32 mask;
        u32 sid_start;
-} AccessDeniedACE;
+} _packed_attribute ACCESS_DENIED_ACE;
 
-typedef struct {
-       ACEHeader hdr;
+typedef struct _SYSTEM_AUDIT_ACE {
+       ACE_HEADER hdr;
        u32 mask;
        u32 sid_start;
-} SystemAuditACE;
+} _packed_attribute SYSTEM_AUDIT_ACE;
 
 
 /* Header of an access control list. */
-typedef struct {
+typedef struct _ACL {
        /* ACL_REVISION or ACL_REVISION_DS */
        u8 revision;
 
@@ -77,10 +84,10 @@ typedef struct {
 
        /* padding */
        u16 sbz2;
-} ACL;
+} _packed_attribute ACL;
 
 /* A structure used to identify users or groups. */
-typedef struct {
+typedef struct _SID {
 
        /* example: 0x1 */
        u8  revision;
@@ -91,10 +98,10 @@ typedef struct {
        u8  identifier_authority[6];
 
        u32 sub_authority[0];
-} SID;
+} _packed_attribute SID;
 
 
-typedef struct {
+typedef struct _SECURITY_DESCRIPTOR_RELATIVE  {
        /* Example: 0x1 */
        u8 revision;
        /* Example: 0x0 */
@@ -119,7 +126,7 @@ typedef struct {
        /* Discretionary ACL. */
        /* Example: 0x34 */
        u32 dacl_offset;
-} SecurityDescriptor;
+} _packed_attribute SECURITY_DESCRIPTOR_RELATIVE;
 
 /*
  * This is a hack to work around a problem in libntfs-3g.  libntfs-3g validates
@@ -138,8 +145,8 @@ empty_sacl_fixup(u8 *descr, u64 *size_p)
        /* No-op if no NTFS-3g support, or if NTFS-3g is version 2013 or later
         * */
 #if defined(WITH_NTFS_3G) && !defined(HAVE_NTFS_MNT_RDONLY)
-       if (*size_p >= sizeof(SecurityDescriptor)) {
-               SecurityDescriptor *sd = (SecurityDescriptor*)descr;
+       if (*size_p >= sizeof(SECURITY_DESCRIPTOR_RELATIVE)) {
+               SECURITY_DESCRIPTOR_RELATIVE *sd = (SECURITY_DESCRIPTOR_RELATIVE*)descr;
                u32 sacl_offset = le32_to_cpu(sd->sacl_offset);
                if (sacl_offset == *size_p - sizeof(ACL)) {
                        sd->sacl_offset = cpu_to_le32(0);
@@ -149,6 +156,12 @@ empty_sacl_fixup(u8 *descr, u64 *size_p)
 #endif
 }
 
+struct wim_security_data *
+new_wim_security_data(void)
+{
+       return CALLOC(1, sizeof(struct wim_security_data));
+}
+
 /*
  * Reads the security data from the metadata resource.
  *
@@ -186,7 +199,6 @@ read_security_data(const u8 metadata_resource[], u64 metadata_resource_len,
        }
        sd->sizes       = NULL;
        sd->descriptors = NULL;
-       sd->refcnt      = 1;
 
        p = metadata_resource;
        p = get_u32(p, &sd->total_length);
@@ -315,7 +327,8 @@ out_free_sd:
  * Writes security data to an in-memory buffer.
  */
 u8 *
-write_security_data(const struct wim_security_data *sd, u8 *p)
+write_security_data(const struct wim_security_data * restrict sd,
+                   u8 * restrict p)
 {
        DEBUG("Writing security data (total_length = %"PRIu32", num_entries "
              "= %"PRIu32")", sd->total_length, sd->num_entries);
@@ -353,12 +366,12 @@ print_acl(const void *p, const tchar *type)
 
        p += sizeof(ACL);
        for (u16 i = 0; i < ace_count; i++) {
-               const ACEHeader *hdr = p;
+               const ACE_HEADER *hdr = p;
                tprintf(T("        [ACE]\n"));
                tprintf(T("        ACE type  = %d\n"), hdr->type);
                tprintf(T("        ACE flags = 0x%x\n"), hdr->flags);
                tprintf(T("        ACE size  = %u\n"), hdr->size);
-               const AccessAllowedACE *aaa = (const AccessAllowedACE*)hdr;
+               const ACCESS_ALLOWED_ACE *aaa = (const ACCESS_ALLOWED_ACE*)p;
                tprintf(T("        ACE mask = %x\n"), le32_to_cpu(aaa->mask));
                tprintf(T("        SID start = %u\n"), le32_to_cpu(aaa->sid_start));
                p += hdr->size;
@@ -375,7 +388,7 @@ print_sid(const void *p, const tchar *type)
        tprintf(T("    Subauthority count = %u\n"), sid->sub_authority_count);
        tprintf(T("    Identifier authority = "));
        print_byte_field(sid->identifier_authority,
-                        sizeof(sid->identifier_authority));
+                        sizeof(sid->identifier_authority), stdout);
        tputchar(T('\n'));
        for (u8 i = 0; i < sid->sub_authority_count; i++) {
                tprintf(T("    Subauthority %u = %u\n"),
@@ -387,7 +400,7 @@ print_sid(const void *p, const tchar *type)
 static void
 print_security_descriptor(const void *p, u64 size)
 {
-       const SecurityDescriptor *sd = p;
+       const SECURITY_DESCRIPTOR_RELATIVE *sd = p;
 
        u8 revision      = sd->revision;
        u16 control      = le16_to_cpu(sd->security_descriptor_control);
@@ -418,14 +431,12 @@ print_security_descriptor(const void *p, u64 size)
 void
 print_security_data(const struct wim_security_data *sd)
 {
-       wimlib_assert(sd != NULL);
-
        tputs(T("[SECURITY DATA]"));
        tprintf(T("Length            = %"PRIu32" bytes\n"), sd->total_length);
        tprintf(T("Number of Entries = %"PRIu32"\n"), sd->num_entries);
 
        for (u32 i = 0; i < sd->num_entries; i++) {
-               tprintf(T("[SecurityDescriptor %"PRIu32", length = %"PRIu64"]\n"),
+               tprintf(T("[SECURITY_DESCRIPTOR_RELATIVE %"PRIu32", length = %"PRIu64"]\n"),
                        i, sd->sizes[i]);
                print_security_descriptor(sd->descriptors[i], sd->sizes[i]);
                tputchar(T('\n'));
@@ -437,17 +448,14 @@ void
 free_security_data(struct wim_security_data *sd)
 {
        if (sd) {
-               wimlib_assert(sd->refcnt != 0);
-               if (--sd->refcnt == 0) {
-                       u8 **descriptors = sd->descriptors;
-                       u32 num_entries  = sd->num_entries;
-                       if (descriptors)
-                               while (num_entries--)
-                                       FREE(*descriptors++);
-                       FREE(sd->sizes);
-                       FREE(sd->descriptors);
-                       FREE(sd);
-               }
+               u8 **descriptors = sd->descriptors;
+               u32 num_entries  = sd->num_entries;
+               if (descriptors)
+                       while (num_entries--)
+                               FREE(*descriptors++);
+               FREE(sd->sizes);
+               FREE(sd->descriptors);
+               FREE(sd);
        }
 }
 
@@ -469,14 +477,20 @@ free_sd_tree(struct rb_node *node)
 
 /* Frees a security descriptor index set. */
 void
-destroy_sd_set(struct sd_set *sd_set)
+destroy_sd_set(struct wim_sd_set *sd_set, bool rollback)
 {
+       if (rollback) {
+               struct wim_security_data *sd = sd_set->sd;
+               for (s32 i = sd_set->orig_num_entries; i < sd->num_entries; i++)
+                       FREE(sd->descriptors[i]);
+               sd->num_entries = sd_set->orig_num_entries;
+       }
        free_sd_tree(sd_set->rb_root.rb_node);
 }
 
 /* Inserts a a new node into the security descriptor index tree. */
-static void
-insert_sd_node(struct sd_set *set, struct sd_node *new)
+static bool
+insert_sd_node(struct wim_sd_set *set, struct sd_node *new)
 {
        struct rb_root *root = &set->rb_root;
        struct rb_node **p = &(root->rb_node);
@@ -492,16 +506,17 @@ insert_sd_node(struct sd_set *set, struct sd_node *new)
                else if (cmp > 0)
                        p = &((*p)->rb_right);
                else
-                       wimlib_assert(0); /* Duplicate SHA1 message digest */
+                       return false; /* Duplicate security descriptor */
        }
        rb_link_node(&new->rb_node, rb_parent, p);
        rb_insert_color(&new->rb_node, root);
+       return true;
 }
 
 /* Returns the index of the security descriptor having a SHA1 message digest of
  * @hash.  If not found, return -1. */
 int
-lookup_sd(struct sd_set *set, const u8 hash[SHA1_HASH_SIZE])
+lookup_sd(struct wim_sd_set *set, const u8 hash[SHA1_HASH_SIZE])
 {
        struct rb_node *node = set->rb_root.rb_node;
 
@@ -526,17 +541,18 @@ lookup_sd(struct sd_set *set, const u8 hash[SHA1_HASH_SIZE])
  * return -1.
  */
 int
-sd_set_add_sd(struct sd_set *sd_set, const char descriptor[], size_t size)
+sd_set_add_sd(struct wim_sd_set *sd_set, const char *descriptor, size_t size)
 {
        u8 hash[SHA1_HASH_SIZE];
        int security_id;
        struct sd_node *new;
        u8 **descriptors;
        u64 *sizes;
-       u8 *descr_copy;
+       char *descr_copy;
        struct wim_security_data *sd;
+       bool bret;
 
-       sha1_buffer((const u8*)descriptor, size, hash);
+       sha1_buffer(descriptor, size, hash);
 
        security_id = lookup_sd(sd_set, hash);
        if (security_id >= 0) /* Identical descriptor already exists */
@@ -556,6 +572,9 @@ sd_set_add_sd(struct sd_set *sd_set, const char descriptor[], size_t size)
        new->security_id = sd->num_entries;
        copy_hash(new->hash, hash);
 
+       /* There typically are only a few dozen security descriptors in a
+        * directory tree, so expanding the array of security descriptors by
+        * only 1 extra space each time should not be a problem. */
        descriptors = REALLOC(sd->descriptors,
                              (sd->num_entries + 1) * sizeof(sd->descriptors[0]));
        if (!descriptors)
@@ -571,7 +590,8 @@ sd_set_add_sd(struct sd_set *sd_set, const char descriptor[], size_t size)
        sd->num_entries++;
        DEBUG("There are now %d security descriptors", sd->num_entries);
        sd->total_length += size + sizeof(sd->sizes[0]);
-       insert_sd_node(sd_set, new);
+       bret = insert_sd_node(sd_set, new);
+       wimlib_assert(bret);
        return new->security_id;
 out_free_descr:
        FREE(descr_copy);
@@ -580,3 +600,38 @@ out_free_node:
 out:
        return -1;
 }
+
+/* Initialize a `struct sd_set' mapping from SHA1 message digests of security
+ * descriptors to indices into the security descriptors table of the WIM image
+ * (security IDs).  */
+int
+init_sd_set(struct wim_sd_set *sd_set, struct wim_security_data *sd)
+{
+       int ret;
+
+       sd_set->sd = sd;
+       sd_set->rb_root.rb_node = NULL;
+
+       /* Remember the original number of security descriptors so that newly
+        * added ones can be rolled back if needed. */
+       sd_set->orig_num_entries = sd->num_entries;
+       for (s32 i = 0; i < sd->num_entries; i++) {
+               struct sd_node *new;
+
+               new = MALLOC(sizeof(struct sd_node));
+               if (!new) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out_destroy_sd_set;
+               }
+               sha1_buffer(sd->descriptors[i], sd->sizes[i], new->hash);
+               new->security_id = i;
+               if (!insert_sd_node(sd_set, new))
+                       FREE(new); /* Ignore duplicate security descriptor */
+       }
+       ret = 0;
+       goto out;
+out_destroy_sd_set:
+       destroy_sd_set(sd_set, false);
+out:
+       return ret;
+}