Support for copying security data
[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  * Copyright (C) 2012 Eric Biggers
8  *
9  * wimlib - Library for working with WIM files 
10  *
11  * This library is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU Lesser General Public License as published by the Free
13  * Software Foundation; either version 2.1 of the License, or (at your option) any
14  * later version.
15  *
16  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
17  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
18  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License along
21  * with this library; if not, write to the Free Software Foundation, Inc., 59
22  * Temple Place, Suite 330, Boston, MA 02111-1307 USA 
23  */
24
25 #include "wimlib_internal.h"
26 #include "io.h"
27 #include "security.h"
28
29 #ifdef ENABLE_SECURITY_DATA
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.
37  * @sd_p:       A pointer to a pointer wim_security_data structure that will be filled
38  *              in with a pointer to a new wim_security_data structure on success.
39  *
40  * Note: There is no `offset' argument because the security data is located at
41  * the beginning of the metadata resource.
42  */
43 int read_security_data(const u8 metadata_resource[], 
44                        u64 metadata_resource_len, struct wim_security_data **sd_p)
45 {
46         struct wim_security_data *sd;
47         const u8 *p;
48         u64 sizes_size;
49
50         if (metadata_resource_len < 8) {
51                 ERROR("Not enough space in %"PRIu64"-byte file resource for "
52                                 "security data!\n", metadata_resource_len);
53                 return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
54         }
55         sd = MALLOC(sizeof(struct wim_security_data));
56         if (!sd)
57                 return WIMLIB_ERR_NOMEM;
58         p = get_u32(metadata_resource, &sd->total_length);
59         p = get_u32(p, &sd->num_entries);
60
61         /* Verify the listed total length of the security data is big enough to
62          * include the sizes array, verify that the file data is big enough to
63          * include it as well, then allocate the array of sizes. */
64         sizes_size = sd->num_entries * sizeof(u64);
65
66         DEBUG("Reading security data with %u entries\n", sd->num_entries);
67
68         if (sd->num_entries == 0) {
69                 FREE(sd);
70                 return 0;
71         }
72
73         u64 size_no_descriptors = 8 + sizes_size;
74         if (size_no_descriptors > sd->total_length) {
75                 ERROR("Security data total length of %"PRIu64" is too short because\n"
76                                 "there must be at least %"PRIu64" bytes of security "
77                                 "data!\n", sd->total_length, 
78                                 8 + sizes_size);
79                 FREE(sd);
80                 return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
81         }
82         if (size_no_descriptors > metadata_resource_len) {
83                 ERROR("File resource of %"PRIu64" bytes is not big enough\n"
84                                 "to hold security data of at least %"PRIu64" "
85                                 "bytes!\n", metadata_resource_len, size_no_descriptors);
86                 FREE(sd);
87                 return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
88         }
89         sd->sizes = MALLOC(sizes_size);
90         if (!sd->sizes) {
91                 FREE(sd);
92                 return WIMLIB_ERR_NOMEM;
93         }
94
95         /* Copy the sizes array in from the file data. */
96         p = get_bytes(p, sizes_size, sd->sizes);
97         array_to_le64(sd->sizes, sd->num_entries);
98
99         /* Allocate the array of pointers to descriptors, and read them in. */
100         sd->descriptors = CALLOC(sd->num_entries, sizeof(u8*));
101         if (!sd->descriptors) {
102                 FREE(sd);
103                 FREE(sd->sizes);
104                 return WIMLIB_ERR_NOMEM;
105         }
106         u64 total_len = size_no_descriptors;
107
108         for (uint i = 0; i < sd->num_entries; i++) {
109                 total_len += sd->sizes[i];
110                 if (total_len > sd->total_length) {
111                         ERROR("Security data total length of %"PRIu64" is too "
112                                         "short because there are at least %"PRIu64" "
113                                         "bytes of security data!\n", 
114                                         sd->total_length, total_len);
115                         free_security_data(sd);
116                         return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
117                 }
118                 if (total_len > metadata_resource_len) {
119                         ERROR("File resource of %"PRIu64" bytes is not big enough "
120                                         "to hold security data of at least %"PRIu64" "
121                                         "bytes!\n", metadata_resource_len, total_len);
122                         free_security_data(sd);
123                         return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
124                 }
125                 sd->descriptors[i] = MALLOC(sd->sizes[i]);
126                 if (!sd->descriptors[i]) {
127                         free_security_data(sd);
128                         return WIMLIB_ERR_NOMEM;
129                 }
130                 p = get_bytes(p, sd->sizes[i], sd->descriptors[i]);
131         }
132         sd->refcnt = 1;
133         *sd_p = sd;
134         return 0;
135 }
136
137 /* 
138  * Writes security data to an in-memory buffer.
139  */
140 u8 *write_security_data(const struct wim_security_data *sd, u8 *p)
141 {
142         if (sd) {
143                 DEBUG("Writing security data (total_length = %u, "
144                                 "num_entries = %u)\n", sd->total_length, 
145                                 sd->num_entries);
146                 u8 *orig_p = p;
147                 p = put_u32(p, sd->total_length);
148                 p = put_u32(p, sd->num_entries);
149
150                 for (uint i = 0; i < sd->num_entries; i++)
151                         p = put_u64(p, sd->sizes[i]);
152
153                 for (uint i = 0; i < sd->num_entries; i++)
154                         p = put_bytes(p, sd->sizes[i], sd->descriptors[i]);
155
156                 wimlib_assert(p - orig_p <= sd->total_length);
157
158                 DEBUG("Successfully wrote security data.\n");
159                 return orig_p + sd->total_length;
160         } else {
161                 DEBUG("Writing security data (total_length = 8, "
162                                 "num_entries = 0)\n");
163                 p = put_u32(p, 8);
164                 return put_u32(p, 0);
165
166         }
167 }
168
169 /* XXX We don't actually do anything with the ACL's yet besides being able to
170  * print a few things.  It seems it would be a lot of work to have comprehensive
171  * support for all the weird flags and stuff, and Windows PE seems to be okay
172  * running from a WIM file that doesn't have any security data at all...  */
173
174 static void print_acl(const u8 *p)
175 {
176         ACL *acl = (ACL*)p;
177         TO_LE16(acl->acl_size);
178         TO_LE16(acl->acl_count);
179         printf("    [ACL]\n");
180         printf("    Revision = %u\n", acl->revision);
181         printf("    ACL Size = %u\n", acl->acl_size);
182         printf("    ACE Count = %u\n", acl->ace_count);
183
184         p += sizeof(ACL);
185         for (uint i = 0; i < acl->ace_count; i++) {
186                 ACEHeader *hdr = (ACEHeader*)p;
187                 printf("        [ACE]\n");
188                 printf("        ACE type  = %d\n", hdr->type);
189                 printf("        ACE flags = 0x%x\n", hdr->flags);
190                 printf("        ACE size  = %u\n", hdr->size);
191                 AccessAllowedACE *aaa = (AccessAllowedACE*)hdr;
192                 printf("        ACE mask = %x\n", to_le32(aaa->mask));
193                 printf("        SID start = %u\n", to_le32(aaa->sid_start));
194                 p += hdr->size;
195         }
196 }
197
198 static void print_sid(const u8 *p)
199 {
200         SID *sid = (SID*)p;
201         printf("    [SID]\n");
202         printf("    Revision = %u\n", sid->revision);
203         printf("    Subauthority count = %u\n", sid->sub_authority_count);
204         printf("    Identifier authority = ");
205         print_byte_field(sid->identifier_authority, sizeof(sid->identifier_authority));
206         putchar('\n');
207         for (uint i = 0; i < sid->sub_authority_count; i++)
208                 printf("    Subauthority %u = %u\n", i, to_le32(sid->sub_authority[i]));
209 }
210
211 static void print_security_descriptor(const u8 *p, u64 size)
212 {
213         SecurityDescriptor *sd = (SecurityDescriptor*)p;
214         TO_LE16(sd->security_descriptor_control);
215         TO_LE32(sd->owner_offset);
216         TO_LE32(sd->group_offset);
217         TO_LE32(sd->sacl_offset);
218         TO_LE32(sd->dacl_offset);
219         printf("Revision = %u\n", sd->revision);
220         printf("Security Descriptor Control = %u\n", sd->security_descriptor_control);
221         printf("Owner offset = %u\n", sd->owner_offset);
222         printf("Group offset = %u\n", sd->group_offset);
223         printf("System ACL offset = %u\n", sd->sacl_offset);
224         printf("Discretionary ACL offset = %u\n", sd->dacl_offset);
225
226         if (sd->owner_offset != 0)
227                 print_sid(p + sd->owner_offset);
228         if (sd->group_offset != 0)
229                 print_sid(p + sd->group_offset);
230         if (sd->sacl_offset != 0)
231                 print_acl(p + sd->sacl_offset);
232         if (sd->dacl_offset != 0)
233                 print_acl(p + sd->dacl_offset);
234 }
235
236 /* 
237  * Prints the security data for a WIM file.
238  */
239 void print_security_data(const struct wim_security_data *sd)
240 {
241         puts("[SECURITY DATA]");
242         if (sd) {
243                 printf("Length            = %u bytes\n", sd->total_length);
244                 printf("Number of Entries = %u\n", sd->num_entries);
245
246                 u64 num_entries = (u64)sd->num_entries;
247                 for (u64 i = 0; i < num_entries; i++) {
248                         printf("[SecurityDescriptor %"PRIu64", "
249                                         "length = %"PRIu64"]\n", 
250                                         i, sd->sizes[i]);
251                         print_security_descriptor(sd->descriptors[i], 
252                                                   sd->sizes[i]);
253                         putchar('\n');
254                 }
255         } else {
256                 puts("Length            = 8 bytes\n"
257                      "Number of Entries = 0");
258                 return;
259         }
260         putchar('\n');
261 }
262
263 void free_security_data(struct wim_security_data *sd)
264 {
265         if (!sd)
266                 return;
267         wimlib_assert(sd->refcnt >= 1);
268         if (sd->refcnt == 1) {
269                 u8 **descriptors = sd->descriptors;
270                 u32 num_entries = sd->num_entries;
271
272                 if (descriptors)
273                         while (num_entries--)
274                                 FREE(*descriptors++);
275                 FREE(sd->sizes);
276                 FREE(sd->descriptors);
277                 FREE(sd);
278         } else {
279                 sd->refcnt--;
280         }
281 }
282
283 #endif