source: trunk/lib/winsec.c @ 148

Last change on this file since 148 was 148, checked in by tim, 15 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
RevLine 
[132]1/*
[133]2 * This file contains refactored Samba code used to interpret Windows
3 * Security Descriptors. See:
[132]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 *
[133]23 * $Id: winsec.c 148 2009-02-22 23:22:59Z tim $
[132]24 */
25
[147]26#include "winsec.h"
[132]27
28
[147]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}
[132]36
[147]37
[134]38/******************************************************************************
[147]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/******************************************************************************
[134]48 * Parses a WINSEC_DESC structure and substructures.
49 ******************************************************************************/
[147]50WINSEC_DESC* winsec_parse_desc(void* talloc_ctx, 
51                               const uint8_t* buf, uint32_t buf_len)
[132]52{
[134]53  WINSEC_DESC* ret_val;
[132]54
[134]55  if (buf == NULL || buf_len <  WINSEC_DESC_HEADER_SIZE)
56    return NULL;
[148]57
[147]58  if((ret_val = talloc(talloc_ctx, WINSEC_DESC)) == NULL)
59    return NULL;
[133]60
[134]61  ret_val->revision = buf[0];
62  ret_val->sbz1 = buf[1];
63  ret_val->control = SVAL(buf, 0x2);
[133]64
[134]65  if(!(ret_val->control & WINSEC_DESC_SELF_RELATIVE))
66    fprintf(stderr, "DEBUG: NOT self-relative!\n");
[132]67
[134]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);
[133]72
[134]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))
[133]80  {
[147]81    talloc_free(ret_val);
[134]82    return NULL;
[133]83  }
[132]84
[148]85  if(ret_val->off_owner_sid == 0)
86    ret_val->owner_sid = NULL;
87  else
[133]88  {
[147]89    ret_val->owner_sid = winsec_parse_dom_sid(ret_val, 
90                                              buf + ret_val->off_owner_sid,
[134]91                                              buf_len - ret_val->off_owner_sid);
92    if(ret_val->owner_sid == NULL)
[133]93    {
[147]94      talloc_free(ret_val);
[134]95      return NULL;
[133]96    }
97  }
[132]98
[148]99  if(ret_val->off_grp_sid == 0) 
100    ret_val->grp_sid = NULL;
101  else
[133]102  {
[147]103    ret_val->grp_sid = winsec_parse_dom_sid(ret_val, buf + ret_val->off_grp_sid,
[134]104                                            buf_len - ret_val->off_grp_sid);
105    if(ret_val->grp_sid == NULL)
[133]106    {
[147]107      talloc_free(ret_val);
[134]108      return NULL;
[133]109    }
110  }
[132]111
[148]112  if((ret_val->control & WINSEC_DESC_SACL_PRESENT) && ret_val->off_sacl)
[133]113  {
[147]114    ret_val->sacl = winsec_parse_acl(ret_val, buf + ret_val->off_sacl,
[134]115                                     buf_len - ret_val->off_sacl);
116    if(ret_val->sacl == NULL)
[133]117    {
[147]118      talloc_free(ret_val);
[134]119      return NULL;
[133]120    }
121  }
[148]122  else
123    ret_val->sacl = NULL;
[132]124
[148]125  if((ret_val->control & WINSEC_DESC_DACL_PRESENT) && ret_val->off_dacl != 0) 
[133]126  {
[147]127    ret_val->dacl = winsec_parse_acl(ret_val, buf + ret_val->off_dacl,
[134]128                                     buf_len - ret_val->off_dacl);
129    if(ret_val->dacl == NULL)
[133]130    {
[147]131      talloc_free(ret_val);
[134]132      return NULL;
[133]133    }
134  }
[148]135  else
136    ret_val->dacl = NULL;
[132]137
[134]138  return ret_val;
[132]139}
140
141
[134]142/******************************************************************************
143 * Parses a WINSEC_ACL structure and all substructures.
144 ******************************************************************************/
[147]145WINSEC_ACL* winsec_parse_acl(void* talloc_ctx,
146                             const uint8_t* buf, uint32_t buf_len)
[132]147{
[134]148  uint32_t i, offset;
149  WINSEC_ACL* ret_val;
[132]150
[134]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;
[148]157
[147]158  if((ret_val = talloc(talloc_ctx, WINSEC_ACL)) == NULL)
159    return NULL;
[134]160 
161  ret_val->revision = SVAL(buf, 0x0);
162  ret_val->size     = SVAL(buf, 0x2);
163  ret_val->num_aces = IVAL(buf, 0x4);
[132]164
[134]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  {
[147]171    talloc_free(ret_val);
[134]172    return NULL;
173  }
[132]174
[134]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   */
[147]179  if((ret_val->aces = talloc_array(ret_val, WINSEC_ACE*, 
180                                   ret_val->num_aces+1)) == NULL)
[133]181  {
[147]182    talloc_free(ret_val);
[134]183    return NULL;
[133]184  }
[132]185
[134]186  offset = 8;
187  for(i=0; i < ret_val->num_aces; i++)
188  {
[147]189    ret_val->aces[i] = winsec_parse_ace(ret_val->aces, 
190                                        buf+offset, buf_len-offset);
[134]191    if(ret_val->aces[i] == NULL)
192    {
[147]193      talloc_free(ret_val);
[134]194      return NULL;
195    }
[132]196
[134]197    offset += ret_val->aces[i]->size;
198    if(offset > buf_len)
199    {
[147]200      talloc_free(ret_val);
[134]201      return NULL;
202    }
203  }
[148]204  ret_val->aces[ret_val->num_aces] = NULL;
[132]205
[134]206  return ret_val;
[132]207}
208
209
[134]210/******************************************************************************
211 * Parses a WINSEC_ACE structure and all substructures.
212 ******************************************************************************/
[147]213WINSEC_ACE* winsec_parse_ace(void* talloc_ctx,
214                             const uint8_t* buf, uint32_t buf_len)
[132]215{
[134]216  uint32_t offset;
217  WINSEC_ACE* ret_val;
[132]218
[134]219  if(buf == NULL || buf_len < WINSEC_ACE_MIN_SIZE)
220    return NULL;
[132]221
[147]222  if((ret_val = talloc(talloc_ctx, WINSEC_ACE)) == NULL)
[134]223    return NULL;
[132]224
[134]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);
[132]229
[134]230  offset = 0x8;
[132]231
232  /* check whether object access is present */
[134]233  if (winsec_ace_object(ret_val->type))
[132]234  {
[134]235    ret_val->obj_flags = IVAL(buf, offset);
236    offset += 4;
[132]237
[134]238    if(ret_val->obj_flags & WINSEC_ACE_OBJECT_PRESENT)
239    {
[147]240      ret_val->obj_guid = winsec_parse_uuid(ret_val, 
241                                            buf+offset, buf_len-offset);
[134]242      if(ret_val->obj_guid == NULL)
243      {
[147]244        talloc_free(ret_val);
[134]245        return NULL;
246      }
247      offset += sizeof(WINSEC_UUID);
248    }
[148]249    else
250      ret_val->obj_guid = NULL;
[132]251
[134]252    if(ret_val->obj_flags & WINSEC_ACE_OBJECT_INHERITED_PRESENT)
253    {
[147]254      ret_val->inh_guid = winsec_parse_uuid(ret_val, 
255                                            buf+offset, buf_len-offset);
[134]256      if(ret_val->inh_guid == NULL)
257      {
[147]258        talloc_free(ret_val);
[134]259        return NULL;
260      }
261      offset += sizeof(WINSEC_UUID);
262    }
[148]263    else
264      ret_val->inh_guid = NULL;
[134]265  }
[132]266
[147]267  ret_val->trustee = winsec_parse_dom_sid(ret_val, buf+offset, buf_len-offset);
[134]268  if(ret_val->trustee == NULL)
269  {
[147]270    talloc_free(ret_val);
271    return NULL;
[132]272  }
[134]273 
274  return ret_val;
[132]275}
276
277
[134]278/******************************************************************************
279 * Parses a WINSEC_DOM_SID structure.
280 ******************************************************************************/
[147]281WINSEC_DOM_SID* winsec_parse_dom_sid(void* talloc_ctx,
282                                     const uint8_t* buf, uint32_t buf_len)
[132]283{
[134]284  uint32_t i;
285  WINSEC_DOM_SID* ret_val;
[132]286
[134]287  if(buf == NULL || buf_len < 8)
288    return NULL;
[132]289
[147]290  /*  if((ret_val = (WINSEC_DOM_SID*)zalloc(sizeof(WINSEC_DOM_SID))) == NULL)*/
291  if((ret_val = talloc(talloc_ctx, WINSEC_DOM_SID)) == NULL)
[134]292    return NULL;
[132]293
[134]294  ret_val->sid_rev_num = buf[0];
295  ret_val->num_auths = buf[1];
296  memcpy(ret_val->id_auth, buf+2, 6);
[132]297
[134]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)
[132]303  {
[147]304    talloc_free(ret_val);
[134]305    return NULL;
[132]306  }
[134]307 
308  for(i=0; i < ret_val->num_auths; i++)
309    ret_val->sub_auths[i] = IVAL(buf, 8+i*sizeof(uint32_t));
[132]310
[134]311  return ret_val;
312}
[132]313
314
[134]315/******************************************************************************
316 * Parses a WINSEC_UUID struct.
317 ******************************************************************************/
[147]318WINSEC_UUID* winsec_parse_uuid(void* talloc_ctx,
319                               const uint8_t* buf, uint32_t buf_len)
[134]320{
321  WINSEC_UUID* ret_val;
322
323  if(buf == NULL || buf_len < sizeof(WINSEC_UUID))
[133]324    return false;
[132]325
[147]326  if((ret_val = talloc(talloc_ctx, WINSEC_UUID)) == NULL)
[134]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);
[132]335
[134]336  return ret_val;
[132]337}
338
339
[134]340/******************************************************************************
341 * Calculates the size of a SID.
342 ******************************************************************************/
343size_t winsec_sid_size(const WINSEC_DOM_SID* sid)
[132]344{
[133]345  if (sid == NULL)
346    return 0;
[132]347
[134]348  return sid->num_auths * sizeof(uint32_t) + 8;
[133]349}
[132]350
351
[134]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)
[133]356{
357  int i;
[132]358
[133]359  if (sid1 == sid2)
360    return 0;
361  if (!sid1)
362    return -1;
363  if (!sid2)
364    return 1;
[132]365
[133]366  if (sid1->sid_rev_num != sid2->sid_rev_num)
367    return sid1->sid_rev_num - sid2->sid_rev_num;
[132]368
[133]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];
[132]372
[133]373  return 0;
374}
[132]375
376
[134]377/******************************************************************************
378 * Compare two SIDs.
379 ******************************************************************************/
380int winsec_sid_compare(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
[133]381{
382  int i;
[132]383
[133]384  if (sid1 == sid2)
385    return 0;
386  if (!sid1)
387    return -1;
388  if (!sid2)
389    return 1;
[132]390
[133]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;
[132]394
[133]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];
[132]398
[134]399  return winsec_sid_compare_auth(sid1, sid2);
[133]400}
[132]401
402
[134]403/******************************************************************************
404 * Compare two SIDs.
405 ******************************************************************************/
406bool winsec_sid_equal(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
[133]407{
[134]408  return winsec_sid_compare(sid1, sid2) == 0;
[133]409}
[132]410
411
[134]412/******************************************************************************
413 * Compares two WINSEC_DESC structures.
414 ******************************************************************************/
415bool winsec_desc_equal(WINSEC_DESC* s1, WINSEC_DESC* s2)
[133]416{
[134]417  /* Trivial cases */
418  if (!s1 && !s2)
[133]419    return true;
[134]420  if (!s1 || !s2)
421    return false;
[132]422
[134]423  /* Check top level stuff */
424  if (s1->revision != s2->revision)
425    return false;
[132]426
[134]427  if (s1->control != s2->control)
[132]428    return false;
429
[134]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)) 
[132]440  { return false; }
441
[134]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)) 
[132]445    return false;
446
447  return true;
448}
449
450
[134]451
452/******************************************************************************
453 * Compares two WINSEC_ACL structures.
454 ******************************************************************************/
455bool winsec_acl_equal(WINSEC_ACL* s1, WINSEC_ACL* s2)
[132]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
[134]475  for (i = 0; i < s1->num_aces; i++)
[132]476  {
477    bool found = false;
478
479    for (j = 0; j < s2->num_aces; j++) 
480    {
[134]481      if (winsec_ace_equal(s1->aces[i], s2->aces[j])) 
[132]482      {
483        found = true;
484        break;
485      }
486    }
487
488    if (!found)
489      return false;
490  }
491
492  return true;
493}
494
495
[134]496/******************************************************************************
497 * Compares two WINSEC_ACE structures.
498 ******************************************************************************/
499bool winsec_ace_equal(WINSEC_ACE* s1, WINSEC_ACE* s2)
[132]500{
501  /* Trivial cases */
[134]502  if (!s1 && !s2) 
[132]503    return true;
[134]504  if (!s1 || !s2) 
[132]505    return false;
506
507  /* Check top level stuff */
[134]508  if (s1->type != s2->type || s1->flags != s2->flags ||
509      s1->access_mask != s2->access_mask)
510  { return false; }
[132]511
[134]512  /* Check SID */
513  if (!winsec_sid_equal(s1->trustee, s2->trustee))
[132]514    return false;
515
[134]516  return true;
517}
[132]518
519
[134]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; }
[132]530
[134]531  return false;
[132]532}
Note: See TracBrowser for help on using the repository browser.