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

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

integrated talloc into range_list

fixed some uninitialized structure values in the winsec library

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