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