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

Last change on this file since 276 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.