Fix some compiler warnings
[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 #ifdef ENABLE_SECURITY_DATA
32
33 /* 
34  * Reads the security data from the metadata resource.
35  *
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.
39  * @sd_p:       A pointer to a pointer wim_security_data structure that will be filled
40  *              in with a pointer to a new wim_security_data 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[], 
46                        u64 metadata_resource_len, struct wim_security_data **sd_p)
47 {
48         struct wim_security_data *sd;
49         const u8 *p;
50         u64 sizes_size;
51
52         if (metadata_resource_len < 8) {
53                 ERROR("Not enough space in %"PRIu64"-byte file resource for "
54                                 "security data!\n", metadata_resource_len);
55                 return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
56         }
57         sd = MALLOC(sizeof(struct wim_security_data));
58         if (!sd)
59                 return WIMLIB_ERR_NOMEM;
60         p = get_u32(metadata_resource, &sd->total_length);
61         p = get_u32(p, &sd->num_entries);
62
63         /* Verify the listed total length of the security data is big enough to
64          * include the sizes array, verify that the file data is big enough to
65          * include it as well, then allocate the array of sizes. */
66         sizes_size = sd->num_entries * sizeof(u64);
67
68         DEBUG("Reading security data with %u entries\n", sd->num_entries);
69
70         if (sd->num_entries == 0) {
71                 FREE(sd);
72                 return 0;
73         }
74
75         u64 size_no_descriptors = 8 + sizes_size;
76         if (size_no_descriptors > sd->total_length) {
77                 ERROR("Security data total length of %u is too short because\n"
78                                 "there must be at least %"PRIu64" bytes of security "
79                                 "data!\n", sd->total_length, 
80                                 8 + sizes_size);
81                 FREE(sd);
82                 return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
83         }
84         if (size_no_descriptors > metadata_resource_len) {
85                 ERROR("File resource of %"PRIu64" bytes is not big enough\n"
86                                 "to hold security data of at least %"PRIu64" "
87                                 "bytes!\n", metadata_resource_len, size_no_descriptors);
88                 FREE(sd);
89                 return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
90         }
91         sd->sizes = MALLOC(sizes_size);
92         if (!sd->sizes) {
93                 FREE(sd);
94                 return WIMLIB_ERR_NOMEM;
95         }
96
97         /* Copy the sizes array in from the file data. */
98         p = get_bytes(p, sizes_size, sd->sizes);
99         array_to_le64(sd->sizes, sd->num_entries);
100
101         /* Allocate the array of pointers to descriptors, and read them in. */
102         sd->descriptors = CALLOC(sd->num_entries, sizeof(u8*));
103         if (!sd->descriptors) {
104                 FREE(sd);
105                 FREE(sd->sizes);
106                 return WIMLIB_ERR_NOMEM;
107         }
108         u64 total_len = size_no_descriptors;
109
110         for (uint i = 0; i < sd->num_entries; i++) {
111                 total_len += sd->sizes[i];
112                 if (total_len > sd->total_length) {
113                         ERROR("Security data total length of %u is too "
114                                         "short because there are at least %"PRIu64" "
115                                         "bytes of security data!\n", 
116                                         sd->total_length, total_len);
117                         free_security_data(sd);
118                         return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
119                 }
120                 if (total_len > metadata_resource_len) {
121                         ERROR("File resource of %"PRIu64" bytes is not big enough "
122                                         "to hold security data of at least %"PRIu64" "
123                                         "bytes!\n", metadata_resource_len, total_len);
124                         free_security_data(sd);
125                         return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
126                 }
127                 sd->descriptors[i] = MALLOC(sd->sizes[i]);
128                 if (!sd->descriptors[i]) {
129                         free_security_data(sd);
130                         return WIMLIB_ERR_NOMEM;
131                 }
132                 p = get_bytes(p, sd->sizes[i], sd->descriptors[i]);
133         }
134         sd->refcnt = 1;
135         *sd_p = sd;
136         return 0;
137 }
138
139 /* 
140  * Writes security data to an in-memory buffer.
141  */
142 u8 *write_security_data(const struct wim_security_data *sd, u8 *p)
143 {
144         if (sd) {
145                 DEBUG("Writing security data (total_length = %u, "
146                                 "num_entries = %u)\n", sd->total_length, 
147                                 sd->num_entries);
148                 u8 *orig_p = p;
149                 p = put_u32(p, sd->total_length);
150                 p = put_u32(p, sd->num_entries);
151
152                 for (uint i = 0; i < sd->num_entries; i++)
153                         p = put_u64(p, sd->sizes[i]);
154
155                 for (uint i = 0; i < sd->num_entries; i++)
156                         p = put_bytes(p, sd->sizes[i], sd->descriptors[i]);
157
158                 wimlib_assert(p - orig_p <= sd->total_length);
159
160                 DEBUG("Successfully wrote security data.\n");
161                 return orig_p + sd->total_length;
162         } else {
163                 DEBUG("Writing security data (total_length = 8, "
164                                 "num_entries = 0)\n");
165                 p = put_u32(p, 8);
166                 return put_u32(p, 0);
167
168         }
169 }
170
171 /* XXX We don't actually do anything with the ACL's yet besides being able to
172  * print a few things.  It seems it would be a lot of work to have comprehensive
173  * support for all the weird flags and stuff, and Windows PE seems to be okay
174  * running from a WIM file that doesn't have any security data at all...  */
175
176 static void print_acl(const u8 *p)
177 {
178         ACL *acl = (ACL*)p;
179         TO_LE16(acl->acl_size);
180         TO_LE16(acl->acl_count);
181         printf("    [ACL]\n");
182         printf("    Revision = %u\n", acl->revision);
183         printf("    ACL Size = %u\n", acl->acl_size);
184         printf("    ACE Count = %u\n", acl->ace_count);
185
186         p += sizeof(ACL);
187         for (uint i = 0; i < acl->ace_count; i++) {
188                 ACEHeader *hdr = (ACEHeader*)p;
189                 printf("        [ACE]\n");
190                 printf("        ACE type  = %d\n", hdr->type);
191                 printf("        ACE flags = 0x%x\n", hdr->flags);
192                 printf("        ACE size  = %u\n", hdr->size);
193                 AccessAllowedACE *aaa = (AccessAllowedACE*)hdr;
194                 printf("        ACE mask = %x\n", to_le32(aaa->mask));
195                 printf("        SID start = %u\n", to_le32(aaa->sid_start));
196                 p += hdr->size;
197         }
198 }
199
200 static void print_sid(const u8 *p)
201 {
202         SID *sid = (SID*)p;
203         printf("    [SID]\n");
204         printf("    Revision = %u\n", sid->revision);
205         printf("    Subauthority count = %u\n", sid->sub_authority_count);
206         printf("    Identifier authority = ");
207         print_byte_field(sid->identifier_authority, sizeof(sid->identifier_authority));
208         putchar('\n');
209         for (uint i = 0; i < sid->sub_authority_count; i++)
210                 printf("    Subauthority %u = %u\n", i, to_le32(sid->sub_authority[i]));
211 }
212
213 static void print_security_descriptor(const u8 *p, u64 size)
214 {
215         SecurityDescriptor *sd = (SecurityDescriptor*)p;
216         TO_LE16(sd->security_descriptor_control);
217         TO_LE32(sd->owner_offset);
218         TO_LE32(sd->group_offset);
219         TO_LE32(sd->sacl_offset);
220         TO_LE32(sd->dacl_offset);
221         printf("Revision = %u\n", sd->revision);
222         printf("Security Descriptor Control = %u\n", sd->security_descriptor_control);
223         printf("Owner offset = %u\n", sd->owner_offset);
224         printf("Group offset = %u\n", sd->group_offset);
225         printf("System ACL offset = %u\n", sd->sacl_offset);
226         printf("Discretionary ACL offset = %u\n", sd->dacl_offset);
227
228         if (sd->owner_offset != 0)
229                 print_sid(p + sd->owner_offset);
230         if (sd->group_offset != 0)
231                 print_sid(p + sd->group_offset);
232         if (sd->sacl_offset != 0)
233                 print_acl(p + sd->sacl_offset);
234         if (sd->dacl_offset != 0)
235                 print_acl(p + sd->dacl_offset);
236 }
237
238 /* 
239  * Prints the security data for a WIM file.
240  */
241 void print_security_data(const struct wim_security_data *sd)
242 {
243         puts("[SECURITY DATA]");
244         if (sd) {
245                 printf("Length            = %u bytes\n", sd->total_length);
246                 printf("Number of Entries = %u\n", sd->num_entries);
247
248                 u64 num_entries = (u64)sd->num_entries;
249                 for (u64 i = 0; i < num_entries; i++) {
250                         printf("[SecurityDescriptor %"PRIu64", "
251                                         "length = %"PRIu64"]\n", 
252                                         i, sd->sizes[i]);
253                         print_security_descriptor(sd->descriptors[i], 
254                                                   sd->sizes[i]);
255                         putchar('\n');
256                 }
257         } else {
258                 puts("Length            = 8 bytes\n"
259                      "Number of Entries = 0");
260         }
261         putchar('\n');
262 }
263
264 void free_security_data(struct wim_security_data *sd)
265 {
266         if (!sd)
267                 return;
268         wimlib_assert(sd->refcnt >= 1);
269         if (sd->refcnt == 1) {
270                 u8 **descriptors = sd->descriptors;
271                 u32 num_entries = sd->num_entries;
272
273                 if (descriptors)
274                         while (num_entries--)
275                                 FREE(*descriptors++);
276                 FREE(sd->sizes);
277                 FREE(sd->descriptors);
278                 FREE(sd);
279         } else {
280                 sd->refcnt--;
281         }
282 }
283
284 #endif