source: trunk/lib/winsec.c @ 147

Last change on this file since 147 was 147, checked in by tim, 15 years ago

added talloc library

incorporated talloc into winsec and lru_cache modules

introduced talloc into SK caching system

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