source: releases/0.10.0/lib/winsec.c@ 209

Last change on this file since 209 was 134, checked in by tim, 16 years ago

rewrote winsec library, stripping out Samba dependencies

eliminated remaining Samba prs functions

added support for 'li' subkey list records

  • Property svn:keywords set to Id
File size: 13.6 KB
Line 
1/*
2 * This file contains refactored Samba code used to interpret Windows
3 * Security Descriptors. See:
4 * http://websvn.samba.org/cgi-bin/viewcvs.cgi/trunk/source/
5 *
6 * Copyright (C) 2005-2006,2009 Timothy D. Morgan
7 * Copyright (C) 1992-2005 Samba development team
8 * (see individual files under Subversion for details.)
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 3 of the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * $Id: winsec.c 134 2009-01-16 18:36:04Z tim $
24 */
25
26#include "../include/winsec.h"
27
28
29
30/******************************************************************************
31 * Parses a WINSEC_DESC structure and substructures.
32 ******************************************************************************/
33WINSEC_DESC* winsec_parse_desc(const uint8_t* buf, uint32_t buf_len)
34{
35 WINSEC_DESC* ret_val;
36
37 if (buf == NULL || buf_len < WINSEC_DESC_HEADER_SIZE)
38 return NULL;
39
40 if((ret_val = (WINSEC_DESC*)zalloc(sizeof(WINSEC_DESC))) == NULL)
41 return NULL;
42
43 ret_val->revision = buf[0];
44 ret_val->sbz1 = buf[1];
45 ret_val->control = SVAL(buf, 0x2);
46
47 if(!(ret_val->control & WINSEC_DESC_SELF_RELATIVE))
48 fprintf(stderr, "DEBUG: NOT self-relative!\n");
49
50 ret_val->off_owner_sid = IVAL(buf, 0x4);
51 ret_val->off_grp_sid = IVAL(buf, 0x8);
52 ret_val->off_sacl = IVAL(buf, 0xC);
53 ret_val->off_dacl = IVAL(buf, 0x10);
54
55 /* A basic sanity check to ensure our offsets are within our buffer.
56 * Additional length checking is done in secondary parsing functions.
57 */
58 if((ret_val->off_owner_sid >= buf_len)
59 || (ret_val->off_grp_sid >= buf_len)
60 || (ret_val->off_sacl >= buf_len)
61 || (ret_val->off_dacl >= buf_len))
62 {
63 free(ret_val);
64 return NULL;
65 }
66
67 if(ret_val->off_owner_sid != 0)
68 {
69 ret_val->owner_sid = winsec_parse_dom_sid(buf + ret_val->off_owner_sid,
70 buf_len - ret_val->off_owner_sid);
71 if(ret_val->owner_sid == NULL)
72 {
73 free(ret_val);
74 return NULL;
75 }
76 }
77
78 if (ret_val->off_grp_sid != 0)
79 {
80 ret_val->grp_sid = winsec_parse_dom_sid(buf + ret_val->off_grp_sid,
81 buf_len - ret_val->off_grp_sid);
82 if(ret_val->grp_sid == NULL)
83 {
84 if(ret_val->owner_sid != NULL)
85 free(ret_val->owner_sid);
86 free(ret_val);
87 return NULL;
88 }
89 }
90
91 if ((ret_val->control & WINSEC_DESC_SACL_PRESENT) && ret_val->off_sacl)
92 {
93 ret_val->sacl = winsec_parse_acl(buf + ret_val->off_sacl,
94 buf_len - ret_val->off_sacl);
95 if(ret_val->sacl == NULL)
96 {
97 if(ret_val->owner_sid != NULL)
98 free(ret_val->owner_sid);
99 if(ret_val->grp_sid != NULL)
100 free(ret_val->grp_sid);
101 free(ret_val);
102 return NULL;
103 }
104 }
105
106 if ((ret_val->control & WINSEC_DESC_DACL_PRESENT) && ret_val->off_dacl != 0)
107 {
108 ret_val->dacl = winsec_parse_acl(buf + ret_val->off_dacl,
109 buf_len - ret_val->off_dacl);
110 if(ret_val->dacl == NULL)
111 {
112 if(ret_val->owner_sid != NULL)
113 free(ret_val->owner_sid);
114 if(ret_val->grp_sid != NULL)
115 free(ret_val->grp_sid);
116 if(ret_val->sacl != NULL)
117 free(ret_val->sacl);
118 free(ret_val);
119 return NULL;
120 }
121 }
122
123 return ret_val;
124}
125
126
127/******************************************************************************
128 * Parses a WINSEC_ACL structure and all substructures.
129 ******************************************************************************/
130WINSEC_ACL* winsec_parse_acl(const uint8_t* buf, uint32_t buf_len)
131{
132 uint32_t i, offset;
133 WINSEC_ACL* ret_val;
134
135 /*
136 * Note that the size is always a multiple of 4 bytes due to the
137 * nature of the data structure.
138 */
139 if (buf == NULL || buf_len < 8)
140 return NULL;
141
142 if((ret_val = (WINSEC_ACL*)zalloc(sizeof(WINSEC_ACL))) == NULL)
143 return NULL;
144
145 ret_val->revision = SVAL(buf, 0x0);
146 ret_val->size = SVAL(buf, 0x2);
147 ret_val->num_aces = IVAL(buf, 0x4);
148
149 /* The num_aces can be at most around 4k because anything greater
150 * wouldn't fit in the 16 bit size even if every ace was as small as
151 * possible.
152 */
153 if((ret_val->size > buf_len) || (ret_val->num_aces > 4095))
154 {
155 free(ret_val);
156 return NULL;
157 }
158
159 /* Even if the num_aces is zero, allocate memory as there's a difference
160 * between a non-present DACL (allow all access) and a DACL with no ACE's
161 * (allow no access).
162 */
163 if((ret_val->aces = (WINSEC_ACE**)zcalloc(sizeof(WINSEC_ACE*),
164 ret_val->num_aces+1)) == NULL)
165 {
166 free(ret_val);
167 return NULL;
168 }
169
170 offset = 8;
171 for(i=0; i < ret_val->num_aces; i++)
172 {
173 ret_val->aces[i] = winsec_parse_ace(buf+offset, buf_len-offset);
174 if(ret_val->aces[i] == NULL)
175 {
176 free(ret_val->aces);
177 free(ret_val);
178 return NULL;
179 }
180
181 offset += ret_val->aces[i]->size;
182 if(offset > buf_len)
183 {
184 free(ret_val->aces);
185 free(ret_val);
186 return NULL;
187 }
188 }
189
190 return ret_val;
191}
192
193
194/******************************************************************************
195 * Parses a WINSEC_ACE structure and all substructures.
196 ******************************************************************************/
197WINSEC_ACE* winsec_parse_ace(const uint8_t* buf, uint32_t buf_len)
198{
199 uint32_t offset;
200 WINSEC_ACE* ret_val;
201
202 if(buf == NULL || buf_len < WINSEC_ACE_MIN_SIZE)
203 return NULL;
204
205 if((ret_val = (WINSEC_ACE*)zalloc(sizeof(WINSEC_ACE))) == NULL)
206 return NULL;
207
208 ret_val->type = buf[0];
209 ret_val->flags = buf[1];
210 ret_val->size = SVAL(buf, 0x2);
211 ret_val->access_mask = IVAL(buf, 0x4);
212
213 offset = 0x8;
214
215 /* check whether object access is present */
216 if (winsec_ace_object(ret_val->type))
217 {
218 ret_val->obj_flags = IVAL(buf, offset);
219 offset += 4;
220
221 if(ret_val->obj_flags & WINSEC_ACE_OBJECT_PRESENT)
222 {
223 ret_val->obj_guid = winsec_parse_uuid(buf+offset, buf_len-offset);
224 if(ret_val->obj_guid == NULL)
225 {
226 free(ret_val);
227 return NULL;
228 }
229 offset += sizeof(WINSEC_UUID);
230 }
231
232 if(ret_val->obj_flags & WINSEC_ACE_OBJECT_INHERITED_PRESENT)
233 {
234 ret_val->inh_guid = winsec_parse_uuid(buf+offset, buf_len-offset);
235 if(ret_val->inh_guid == NULL)
236 {
237 if(ret_val->obj_guid != NULL)
238 free(ret_val->obj_guid);
239 free(ret_val);
240 return NULL;
241 }
242 offset += sizeof(WINSEC_UUID);
243 }
244 }
245
246 ret_val->trustee = winsec_parse_dom_sid(buf+offset, buf_len-offset);
247 if(ret_val->trustee == NULL)
248 {
249 if(ret_val->obj_guid != NULL)
250 free(ret_val->obj_guid);
251 if(ret_val->inh_guid != NULL)
252 free(ret_val->inh_guid);
253 free(ret_val);
254 return NULL;
255 }
256
257 return ret_val;
258}
259
260
261/******************************************************************************
262 * Parses a WINSEC_DOM_SID structure.
263 ******************************************************************************/
264WINSEC_DOM_SID* winsec_parse_dom_sid(const uint8_t* buf, uint32_t buf_len)
265{
266 uint32_t i;
267 WINSEC_DOM_SID* ret_val;
268
269 if(buf == NULL || buf_len < 8)
270 return NULL;
271
272 if((ret_val = (WINSEC_DOM_SID*)zalloc(sizeof(WINSEC_DOM_SID))) == NULL)
273 return NULL;
274
275 ret_val->sid_rev_num = buf[0];
276 ret_val->num_auths = buf[1];
277 memcpy(ret_val->id_auth, buf+2, 6);
278
279 /* XXX: should really issue a warning here... */
280 if (ret_val->num_auths > WINSEC_MAX_SUBAUTHS)
281 ret_val->num_auths = WINSEC_MAX_SUBAUTHS;
282
283 if(buf_len < ret_val->num_auths*sizeof(uint32_t)+8)
284 {
285 free(ret_val);
286 return NULL;
287 }
288
289 for(i=0; i < ret_val->num_auths; i++)
290 ret_val->sub_auths[i] = IVAL(buf, 8+i*sizeof(uint32_t));
291
292 return ret_val;
293}
294
295
296/******************************************************************************
297 * Parses a WINSEC_UUID struct.
298 ******************************************************************************/
299WINSEC_UUID* winsec_parse_uuid(const uint8_t* buf, uint32_t buf_len)
300{
301 WINSEC_UUID* ret_val;
302
303 if(buf == NULL || buf_len < sizeof(WINSEC_UUID))
304 return false;
305
306 if((ret_val = (WINSEC_UUID*)zalloc(sizeof(WINSEC_UUID))) == NULL)
307 return NULL;
308
309 ret_val->time_low = IVAL(buf, 0x0);
310 ret_val->time_mid = SVAL(buf, 0x4);
311 ret_val->time_hi_and_version = SVAL(buf, 0x6);
312
313 memcpy(ret_val->clock_seq, buf+0x8, 2);
314 memcpy(ret_val->node, buf+0xB, 6);
315
316 return ret_val;
317}
318
319
320/******************************************************************************
321 * Calculates the size of a SID.
322 ******************************************************************************/
323/*size_t sid_size(const WINSEC_DOM_SID *sid)*/
324size_t winsec_sid_size(const WINSEC_DOM_SID* sid)
325{
326 if (sid == NULL)
327 return 0;
328
329 return sid->num_auths * sizeof(uint32_t) + 8;
330}
331
332
333/******************************************************************************
334 * Compare the auth portion of two SIDs.
335 ******************************************************************************/
336/*int sid_compare_auth(const WINSEC_DOM_SID *sid1, const WINSEC_DOM_SID *sid2)*/
337int winsec_sid_compare_auth(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
338{
339 int i;
340
341 if (sid1 == sid2)
342 return 0;
343 if (!sid1)
344 return -1;
345 if (!sid2)
346 return 1;
347
348 if (sid1->sid_rev_num != sid2->sid_rev_num)
349 return sid1->sid_rev_num - sid2->sid_rev_num;
350
351 for (i = 0; i < 6; i++)
352 if (sid1->id_auth[i] != sid2->id_auth[i])
353 return sid1->id_auth[i] - sid2->id_auth[i];
354
355 return 0;
356}
357
358
359/******************************************************************************
360 * Compare two SIDs.
361 ******************************************************************************/
362/*int sid_compare(const WINSEC_DOM_SID *sid1, const WINSEC_DOM_SID *sid2)*/
363int winsec_sid_compare(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
364{
365 int i;
366
367 if (sid1 == sid2)
368 return 0;
369 if (!sid1)
370 return -1;
371 if (!sid2)
372 return 1;
373
374 /* Compare most likely different rids, first: i.e start at end */
375 if (sid1->num_auths != sid2->num_auths)
376 return sid1->num_auths - sid2->num_auths;
377
378 for (i = sid1->num_auths-1; i >= 0; --i)
379 if (sid1->sub_auths[i] != sid2->sub_auths[i])
380 return sid1->sub_auths[i] - sid2->sub_auths[i];
381
382 return winsec_sid_compare_auth(sid1, sid2);
383}
384
385
386/******************************************************************************
387 * Compare two SIDs.
388 ******************************************************************************/
389bool winsec_sid_equal(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
390{
391 return winsec_sid_compare(sid1, sid2) == 0;
392}
393
394
395/******************************************************************************
396 * Compares two WINSEC_DESC structures.
397 ******************************************************************************/
398bool winsec_desc_equal(WINSEC_DESC* s1, WINSEC_DESC* s2)
399{
400 /* Trivial cases */
401 if (!s1 && !s2)
402 return true;
403 if (!s1 || !s2)
404 return false;
405
406 /* Check top level stuff */
407 if (s1->revision != s2->revision)
408 return false;
409
410 if (s1->control != s2->control)
411 return false;
412
413 /* Check owner and group */
414 if (!winsec_sid_equal(s1->owner_sid, s2->owner_sid))
415 return false;
416
417 if (!winsec_sid_equal(s1->grp_sid, s2->grp_sid))
418 return false;
419
420 /* Check ACLs present in one but not the other */
421 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
422 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl))
423 { return false; }
424
425 /* Sigh - we have to do it the hard way by iterating over all
426 the ACEs in the ACLs */
427 if(!winsec_acl_equal(s1->dacl, s2->dacl) || !winsec_acl_equal(s1->sacl, s2->sacl))
428 return false;
429
430 return true;
431}
432
433
434
435/******************************************************************************
436 * Compares two WINSEC_ACL structures.
437 ******************************************************************************/
438bool winsec_acl_equal(WINSEC_ACL* s1, WINSEC_ACL* s2)
439{
440 unsigned int i, j;
441
442 /* Trivial cases */
443 if (!s1 && !s2)
444 return true;
445 if (!s1 || !s2)
446 return false;
447
448 /* Check top level stuff */
449 if (s1->revision != s2->revision)
450 return false;
451
452 if (s1->num_aces != s2->num_aces)
453 return false;
454
455 /* The ACEs could be in any order so check each ACE in s1 against
456 each ACE in s2. */
457
458 for (i = 0; i < s1->num_aces; i++)
459 {
460 bool found = false;
461
462 for (j = 0; j < s2->num_aces; j++)
463 {
464 if (winsec_ace_equal(s1->aces[i], s2->aces[j]))
465 {
466 found = true;
467 break;
468 }
469 }
470
471 if (!found)
472 return false;
473 }
474
475 return true;
476}
477
478
479/******************************************************************************
480 * Compares two WINSEC_ACE structures.
481 ******************************************************************************/
482bool winsec_ace_equal(WINSEC_ACE* s1, WINSEC_ACE* s2)
483{
484 /* Trivial cases */
485 if (!s1 && !s2)
486 return true;
487 if (!s1 || !s2)
488 return false;
489
490 /* Check top level stuff */
491 if (s1->type != s2->type || s1->flags != s2->flags ||
492 s1->access_mask != s2->access_mask)
493 { return false; }
494
495 /* Check SID */
496 if (!winsec_sid_equal(s1->trustee, s2->trustee))
497 return false;
498
499 return true;
500}
501
502
503/******************************************************************************
504 * Check if ACE has OBJECT type.
505 ******************************************************************************/
506bool winsec_ace_object(uint8_t type)
507{
508 if (type == WINSEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
509 type == WINSEC_ACE_TYPE_ACCESS_DENIED_OBJECT ||
510 type == WINSEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ||
511 type == WINSEC_ACE_TYPE_SYSTEM_ALARM_OBJECT)
512 { return true; }
513
514 return false;
515}
Note: See TracBrowser for help on using the repository browser.