4 * Read the security data from the WIM. Doing anything with the security data
5 * is not yet implemented other than printing some information about it.
9 * Copyright (C) 2012 Eric Biggers
11 * This file is part of wimlib, a library for working with WIM files.
13 * wimlib is free software; you can redistribute it and/or modify it under the
14 * terms of the GNU Lesser General Public License as published by the Free
15 * Software Foundation; either version 2.1 of the License, or (at your option)
18 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
19 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
20 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with wimlib; if not, see http://www.gnu.org/licenses/.
27 #include "wimlib_internal.h"
31 #ifdef ENABLE_SECURITY_DATA
34 * Reads the security data from the metadata resource.
36 * @metadata_resource: An array that contains the uncompressed metadata
37 * resource for the WIM file.
38 * @metadata_resource_len: The length of @metadata_resource. It MUST be at
40 * @sd_p: A pointer to a pointer to a wim_security_data structure that
41 * will be filled in with a pointer to a new wim_security_data
42 * structure on success.
44 * Note: There is no `offset' argument because the security data is located at
45 * the beginning of the metadata resource.
47 int read_security_data(const u8 metadata_resource[], u64 metadata_resource_len,
48 struct wim_security_data **sd_p)
50 struct wim_security_data *sd;
55 sd = MALLOC(sizeof(struct wim_security_data));
57 ERROR("Out of memory");
58 return WIMLIB_ERR_NOMEM;
61 sd->descriptors = NULL;
64 p = metadata_resource;
65 p = get_u32(p, &sd->total_length);
66 p = get_u32(p, &sd->num_entries);
68 /* Verify the listed total length of the security data is big enough to
69 * include the sizes array, verify that the file data is big enough to
70 * include it as well, then allocate the array of sizes.
72 * Note: The total length of the security data must fit in a 32-bit
73 * integer, even though each security descriptor size is a 64-bit
74 * integer. This is stupid, and we need to be careful not to actually
75 * let the security descriptor sizes be over 0xffffffff. */
76 if ((u64)sd->total_length > metadata_resource_len) {
77 ERROR("Security data total length (%u) is bigger than the "
78 "metadata resource length (%"PRIu64")",
79 sd->total_length, metadata_resource_len);
80 ret = WIMLIB_ERR_INVALID_RESOURCE_SIZE;
84 DEBUG("Reading security data: %u entries, length = %u",
85 sd->num_entries, sd->total_length);
87 if (sd->num_entries == 0) {
88 /* No security data. */
93 u64 sizes_size = (u64)sd->num_entries * sizeof(u64);
94 u64 size_no_descriptors = 8 + sizes_size;
95 if (size_no_descriptors > (u64)sd->total_length) {
96 ERROR("Security data total length of %u is too short because "
97 "there must be at least %"PRIu64" bytes of security data",
98 sd->total_length, 8 + sizes_size);
99 ret = WIMLIB_ERR_INVALID_RESOURCE_SIZE;
102 sd->sizes = MALLOC(sizes_size);
104 ret = WIMLIB_ERR_NOMEM;
108 /* Copy the sizes array in from the file data. */
109 p = get_bytes(p, sizes_size, sd->sizes);
110 array_to_le64(sd->sizes, sd->num_entries);
112 /* Allocate the array of pointers to descriptors, and read them in. */
113 sd->descriptors = CALLOC(sd->num_entries, sizeof(u8*));
114 if (!sd->descriptors) {
115 ERROR("Out of memory while allocating security "
117 ret = WIMLIB_ERR_NOMEM;
120 total_len = size_no_descriptors;
122 for (u32 i = 0; i < sd->num_entries; i++) {
123 /* Watch out for huge security descriptor sizes that could
124 * overflow the total length and wrap it around. */
125 if (total_len + sd->sizes[i] < total_len) {
126 ERROR("Caught overflow in security descriptor lengths "
127 "(current total length = %"PRIu64", security "
128 "descriptor size = %"PRIu64")",
129 total_len, sd->sizes[i]);
130 ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
133 total_len += sd->sizes[i];
134 if (total_len > (u64)sd->total_length) {
135 ERROR("Security data total length of %u is too short "
136 "because there are at least %"PRIu64" bytes of "
137 "security data", sd->total_length, total_len);
138 ret = WIMLIB_ERR_INVALID_RESOURCE_SIZE;
141 sd->descriptors[i] = MALLOC(sd->sizes[i]);
142 if (!sd->descriptors[i]) {
143 ERROR("Out of memory while allocating security "
145 ret = WIMLIB_ERR_NOMEM;
148 p = get_bytes(p, sd->sizes[i], sd->descriptors[i]);
151 sd->total_length = (u32)total_len;
155 free_security_data(sd);
160 * Writes security data to an in-memory buffer.
162 u8 *write_security_data(const struct wim_security_data *sd, u8 *p)
164 DEBUG("Writing security data (total_length = %"PRIu32", num_entries "
165 "= %"PRIu32")", sd->total_length, sd->num_entries);
168 p = put_u32(p, sd->total_length);
169 p = put_u32(p, sd->num_entries);
171 for (u32 i = 0; i < sd->num_entries; i++)
172 p = put_u64(p, sd->sizes[i]);
174 for (u32 i = 0; i < sd->num_entries; i++)
175 p = put_bytes(p, sd->sizes[i], sd->descriptors[i]);
177 wimlib_assert(p - orig_p == sd->total_length);
179 DEBUG("Successfully wrote security data.");
183 /* XXX We don't actually do anything with the ACL's yet besides being able to
184 * print a few things. It seems it would be a lot of work to have comprehensive
185 * support for all the weird flags and stuff, and Windows PE seems to be okay
186 * running from a WIM file that doesn't have any security data at all... */
188 static void print_acl(const u8 *p)
191 TO_LE16(acl->acl_size);
192 TO_LE16(acl->acl_count);
194 printf(" Revision = %u\n", acl->revision);
195 printf(" ACL Size = %u\n", acl->acl_size);
196 printf(" ACE Count = %u\n", acl->ace_count);
199 for (uint i = 0; i < acl->ace_count; i++) {
200 ACEHeader *hdr = (ACEHeader*)p;
202 printf(" ACE type = %d\n", hdr->type);
203 printf(" ACE flags = 0x%x\n", hdr->flags);
204 printf(" ACE size = %u\n", hdr->size);
205 AccessAllowedACE *aaa = (AccessAllowedACE*)hdr;
206 printf(" ACE mask = %x\n", to_le32(aaa->mask));
207 printf(" SID start = %u\n", to_le32(aaa->sid_start));
212 static void print_sid(const u8 *p)
216 printf(" Revision = %u\n", sid->revision);
217 printf(" Subauthority count = %u\n", sid->sub_authority_count);
218 printf(" Identifier authority = ");
219 print_byte_field(sid->identifier_authority, sizeof(sid->identifier_authority));
221 for (uint i = 0; i < sid->sub_authority_count; i++)
222 printf(" Subauthority %u = %u\n", i, to_le32(sid->sub_authority[i]));
225 static void print_security_descriptor(const u8 *p, u64 size)
227 SecurityDescriptor *sd = (SecurityDescriptor*)p;
228 TO_LE16(sd->security_descriptor_control);
229 TO_LE32(sd->owner_offset);
230 TO_LE32(sd->group_offset);
231 TO_LE32(sd->sacl_offset);
232 TO_LE32(sd->dacl_offset);
233 printf("Revision = %u\n", sd->revision);
234 printf("Security Descriptor Control = %u\n", sd->security_descriptor_control);
235 printf("Owner offset = %u\n", sd->owner_offset);
236 printf("Group offset = %u\n", sd->group_offset);
237 printf("System ACL offset = %u\n", sd->sacl_offset);
238 printf("Discretionary ACL offset = %u\n", sd->dacl_offset);
240 if (sd->owner_offset != 0)
241 print_sid(p + sd->owner_offset);
242 if (sd->group_offset != 0)
243 print_sid(p + sd->group_offset);
244 if (sd->sacl_offset != 0)
245 print_acl(p + sd->sacl_offset);
246 if (sd->dacl_offset != 0)
247 print_acl(p + sd->dacl_offset);
251 * Prints the security data for a WIM file.
253 void print_security_data(const struct wim_security_data *sd)
255 puts("[SECURITY DATA]");
256 printf("Length = %"PRIu32" bytes\n", sd->total_length);
257 printf("Number of Entries = %"PRIu32"\n", sd->num_entries);
259 for (u32 i = 0; i < sd->num_entries; i++) {
260 printf("[SecurityDescriptor %"PRIu32", length = %"PRIu64"]\n",
262 print_security_descriptor(sd->descriptors[i], sd->sizes[i]);
268 void free_security_data(struct wim_security_data *sd)
272 wimlib_assert(sd->refcnt >= 1);
273 if (sd->refcnt == 1) {
274 u8 **descriptors = sd->descriptors;
275 u32 num_entries = sd->num_entries;
277 while (num_entries--)
278 FREE(*descriptors++);
280 FREE(sd->descriptors);