source: trunk/lib/winsec.c @ 168

Last change on this file since 168 was 168, checked in by tim, 14 years ago

merged remaining smb_deps items into regfi

began formatting API comments for use with doxygen

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