2e83d0e966199aa44b3a14606ee9e38b781cb9c9
[wimlib] / src / security.c
1 /*
2  * security.c
3  *
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.
6  */
7
8 /*
9  * Copyright (C) 2012 Eric Biggers
10  *
11  * This file is part of wimlib, a library for working with WIM files.
12  *
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)
16  * any later version.
17  *
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
21  * details.
22  *
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/.
25  */
26
27 #include "wimlib_internal.h"
28 #include "io.h"
29 #include "security.h"
30
31 /* 
32  * Reads the security data from the metadata resource.
33  *
34  * @metadata_resource:  An array that contains the uncompressed metadata
35  *                              resource for the WIM file.
36  * @metadata_resource_len:      The length of @metadata_resource.  It MUST be at
37  *                              least 8 bytes.
38  * @sd_p:       A pointer to a pointer to a wim_security_data structure that
39  *              will be filled in with a pointer to a new wim_security_data
40  *              structure on success.
41  *
42  * Note: There is no `offset' argument because the security data is located at
43  * the beginning of the metadata resource.
44  */
45 int read_security_data(const u8 metadata_resource[], u64 metadata_resource_len,
46                        struct wim_security_data **sd_p)
47 {
48         struct wim_security_data *sd;
49         const u8 *p;
50         int ret;
51         u64 total_len;
52
53         sd = MALLOC(sizeof(struct wim_security_data));
54         if (!sd) {
55                 ERROR("Out of memory");
56                 return WIMLIB_ERR_NOMEM;
57         }
58         sd->sizes       = NULL;
59         sd->descriptors = NULL;
60         sd->refcnt      = 1;
61
62         p = metadata_resource;
63         p = get_u32(p, &sd->total_length);
64         p = get_u32(p, &sd->num_entries);
65
66         if (sd->num_entries > 0x7fffffff) {
67                 ERROR("Security data has too many entries!");
68                 ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
69                 goto out_free_sd;
70         }
71
72         /* Verify the listed total length of the security data is big enough to
73          * include the sizes array, verify that the file data is big enough to
74          * include it as well, then allocate the array of sizes.
75          *
76          * Note: The total length of the security data must fit in a 32-bit
77          * integer, even though each security descriptor size is a 64-bit
78          * integer.  This is stupid, and we need to be careful not to actually
79          * let the security descriptor sizes be over 0xffffffff.  */
80         if ((u64)sd->total_length > metadata_resource_len) {
81                 ERROR("Security data total length (%u) is bigger than the "
82                       "metadata resource length (%"PRIu64")",
83                       sd->total_length, metadata_resource_len);
84                 ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
85                 goto out_free_sd;
86         }
87
88         DEBUG("Reading security data: %u entries, length = %u",
89               sd->num_entries, sd->total_length);
90
91         if (sd->num_entries == 0) {
92                 /* No security data. */
93                 total_len = 8;
94                 goto out;
95         }
96
97         u64 sizes_size = (u64)sd->num_entries * sizeof(u64);
98         u64 size_no_descriptors = 8 + sizes_size;
99         if (size_no_descriptors > (u64)sd->total_length) {
100                 ERROR("Security data total length of %u is too short because "
101                       "there must be at least %"PRIu64" bytes of security data",
102                       sd->total_length, 8 + sizes_size);
103                 ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
104                 goto out_free_sd;
105         }
106         sd->sizes = MALLOC(sizes_size);
107         if (!sd->sizes) {
108                 ret = WIMLIB_ERR_NOMEM;
109                 goto out_free_sd;
110         }
111
112         /* Copy the sizes array in from the file data. */
113         p = get_bytes(p, sizes_size, sd->sizes);
114         array_to_le64(sd->sizes, sd->num_entries);
115
116         /* Allocate the array of pointers to descriptors, and read them in. */
117         sd->descriptors = CALLOC(sd->num_entries, sizeof(u8*));
118         if (!sd->descriptors) {
119                 ERROR("Out of memory while allocating security "
120                       "descriptors");
121                 ret = WIMLIB_ERR_NOMEM;
122                 goto out_free_sd;
123         }
124         total_len = size_no_descriptors;
125
126         for (u32 i = 0; i < sd->num_entries; i++) {
127                 /* Watch out for huge security descriptor sizes that could
128                  * overflow the total length and wrap it around. */
129                 if (total_len + sd->sizes[i] < total_len) {
130                         ERROR("Caught overflow in security descriptor lengths "
131                               "(current total length = %"PRIu64", security "
132                               "descriptor size = %"PRIu64")",
133                               total_len, sd->sizes[i]);
134                         ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
135                         goto out_free_sd;
136                 }
137                 total_len += sd->sizes[i];
138                 if (total_len > (u64)sd->total_length) {
139                         ERROR("Security data total length of %u is too short "
140                               "because there are at least %"PRIu64" bytes of "
141                               "security data", sd->total_length, total_len);
142                         ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
143                         goto out_free_sd;
144                 }
145                 sd->descriptors[i] = MALLOC(sd->sizes[i]);
146                 if (!sd->descriptors[i]) {
147                         ERROR("Out of memory while allocating security "
148                               "descriptors");
149                         ret = WIMLIB_ERR_NOMEM;
150                         goto out_free_sd;
151                 }
152                 p = get_bytes(p, sd->sizes[i], sd->descriptors[i]);
153         }
154 out:
155         sd->total_length = (u32)total_len;
156         *sd_p = sd;
157         return 0;
158 out_free_sd:
159         free_security_data(sd);
160         return ret;
161 }
162
163 /* 
164  * Writes security data to an in-memory buffer.
165  */
166 u8 *write_security_data(const struct wim_security_data *sd, u8 *p)
167 {
168         DEBUG("Writing security data (total_length = %"PRIu32", num_entries "
169               "= %"PRIu32")", sd->total_length, sd->num_entries);
170
171         u32 aligned_length = (sd->total_length + 7) & ~7;
172
173         u8 *orig_p = p;
174         p = put_u32(p, aligned_length);
175         p = put_u32(p, sd->num_entries);
176
177         for (u32 i = 0; i < sd->num_entries; i++)
178                 p = put_u64(p, sd->sizes[i]);
179
180         for (u32 i = 0; i < sd->num_entries; i++)
181                 p = put_bytes(p, sd->sizes[i], sd->descriptors[i]);
182
183         wimlib_assert(p - orig_p == sd->total_length);
184         p = put_zeroes(p, aligned_length - sd->total_length);
185
186         DEBUG("Successfully wrote security data.");
187         return p;
188 }
189
190 static void print_acl(const u8 *p, const char *type)
191 {
192         ACL *acl = (ACL*)p;
193         TO_LE16(acl->acl_size);
194         TO_LE16(acl->acl_count);
195         printf("    [%s ACL]\n", type);
196         printf("    Revision = %u\n", acl->revision);
197         printf("    ACL Size = %u\n", acl->acl_size);
198         printf("    ACE Count = %u\n", acl->ace_count);
199
200         p += sizeof(ACL);
201         for (uint i = 0; i < acl->ace_count; i++) {
202                 ACEHeader *hdr = (ACEHeader*)p;
203                 printf("        [ACE]\n");
204                 printf("        ACE type  = %d\n", hdr->type);
205                 printf("        ACE flags = 0x%x\n", hdr->flags);
206                 printf("        ACE size  = %u\n", hdr->size);
207                 AccessAllowedACE *aaa = (AccessAllowedACE*)hdr;
208                 printf("        ACE mask = %x\n", to_le32(aaa->mask));
209                 printf("        SID start = %u\n", to_le32(aaa->sid_start));
210                 p += hdr->size;
211         }
212         putchar('\n');
213 }
214
215 static void print_sid(const u8 *p, const char *type)
216 {
217         SID *sid = (SID*)p;
218         printf("    [%s SID]\n", type);
219         printf("    Revision = %u\n", sid->revision);
220         printf("    Subauthority count = %u\n", sid->sub_authority_count);
221         printf("    Identifier authority = ");
222         print_byte_field(sid->identifier_authority, sizeof(sid->identifier_authority));
223         putchar('\n');
224         for (uint i = 0; i < sid->sub_authority_count; i++)
225                 printf("    Subauthority %u = %u\n", i, to_le32(sid->sub_authority[i]));
226         putchar('\n');
227 }
228
229 static void print_security_descriptor(const u8 *p, u64 size)
230 {
231         SecurityDescriptor *sd = (SecurityDescriptor*)p;
232         TO_LE16(sd->security_descriptor_control);
233         TO_LE32(sd->owner_offset);
234         TO_LE32(sd->group_offset);
235         TO_LE32(sd->sacl_offset);
236         TO_LE32(sd->dacl_offset);
237         printf("Revision = %u\n", sd->revision);
238         printf("Security Descriptor Control = %#x\n", sd->security_descriptor_control);
239         printf("Owner offset = %u\n", sd->owner_offset);
240         printf("Group offset = %u\n", sd->group_offset);
241         printf("System ACL offset = %u\n", sd->sacl_offset);
242         printf("Discretionary ACL offset = %u\n", sd->dacl_offset);
243
244         if (sd->owner_offset != 0)
245                 print_sid(p + sd->owner_offset, "Owner");
246         if (sd->group_offset != 0)
247                 print_sid(p + sd->group_offset, "Group");
248         if (sd->sacl_offset != 0)
249                 print_acl(p + sd->sacl_offset, "System");
250         if (sd->dacl_offset != 0)
251                 print_acl(p + sd->dacl_offset, "Discretionary");
252 }
253
254 /* 
255  * Prints the security data for a WIM file.
256  */
257 void print_security_data(const struct wim_security_data *sd)
258 {
259         puts("[SECURITY DATA]");
260         printf("Length            = %"PRIu32" bytes\n", sd->total_length);
261         printf("Number of Entries = %"PRIu32"\n", sd->num_entries);
262
263         for (u32 i = 0; i < sd->num_entries; i++) {
264                 printf("[SecurityDescriptor %"PRIu32", length = %"PRIu64"]\n", 
265                        i, sd->sizes[i]);
266                 print_security_descriptor(sd->descriptors[i], sd->sizes[i]);
267                 putchar('\n');
268         }
269         putchar('\n');
270 }
271
272 void free_security_data(struct wim_security_data *sd)
273 {
274         if (!sd)
275                 return;
276         wimlib_assert(sd->refcnt != 0);
277         if (--sd->refcnt == 0) {
278                 u8 **descriptors = sd->descriptors;
279                 u32 num_entries  = sd->num_entries;
280                 if (descriptors)
281                         while (num_entries--)
282                                 FREE(*descriptors++);
283                 FREE(sd->sizes);
284                 FREE(sd->descriptors);
285                 FREE(sd);
286         }
287 }