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