source: trunk/lib/winsec.c @ 257

Last change on this file since 257 was 257, checked in by tim, 13 years ago

documentation fixes/additions

  • Property svn:keywords set to Id
File size: 14.6 KB
RevLine 
[169]1/*
[132]2 *
[169]3 * Copyright (C) 2005-2006,2009-2010 Timothy D. Morgan
[132]4 * Copyright (C) 1992-2005 Samba development team
5 *               (see individual files under Subversion for details.)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 3 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
[133]20 * $Id: winsec.c 257 2011-06-17 00:13:13Z tim $
[132]21 */
22
[169]23/** @file */
24
[147]25#include "winsec.h"
[132]26
27
[147]28/******************************************************************************
29 * Non-talloc() interface for parsing a descriptor.
30 ******************************************************************************/
31WINSEC_DESC* winsec_parse_descriptor(const uint8_t* buf, uint32_t buf_len)
32{
33  return winsec_parse_desc(NULL, buf, buf_len);
34}
[132]35
[147]36
[134]37/******************************************************************************
[147]38 * Free a descriptor.  Not needed if using talloc and a parent context is freed.
39 ******************************************************************************/
40void winsec_free_descriptor(WINSEC_DESC* desc)
41{
42  talloc_free(desc);
43}
44
45
46/******************************************************************************
[134]47 * Parses a WINSEC_DESC structure and substructures.
48 ******************************************************************************/
[147]49WINSEC_DESC* winsec_parse_desc(void* talloc_ctx, 
50                               const uint8_t* buf, uint32_t buf_len)
[132]51{
[134]52  WINSEC_DESC* ret_val;
[132]53
[134]54  if (buf == NULL || buf_len <  WINSEC_DESC_HEADER_SIZE)
55    return NULL;
[148]56
[147]57  if((ret_val = talloc(talloc_ctx, WINSEC_DESC)) == NULL)
58    return NULL;
[133]59
[134]60  ret_val->revision = buf[0];
61  ret_val->sbz1 = buf[1];
62  ret_val->control = SVAL(buf, 0x2);
[133]63
[257]64  /* XXX: should probably reject any non-self relative */
[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);
[253]229  ret_val->obj_guid = NULL;
230  ret_val->inh_guid = NULL;
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 = talloc(talloc_ctx, WINSEC_UUID)) == NULL)
[134]325    return NULL;
326 
327  ret_val->time_low = IVAL(buf, 0x0);
328  ret_val->time_mid = SVAL(buf, 0x4);
329  ret_val->time_hi_and_version = SVAL(buf, 0x6);
330 
331  memcpy(ret_val->clock_seq, buf+0x8, 2);
332  memcpy(ret_val->node, buf+0xB, 6);
[132]333
[134]334  return ret_val;
[132]335}
336
337
[134]338/******************************************************************************
339 * Calculates the size of a SID.
340 ******************************************************************************/
341size_t winsec_sid_size(const WINSEC_DOM_SID* sid)
[132]342{
[133]343  if (sid == NULL)
344    return 0;
[132]345
[134]346  return sid->num_auths * sizeof(uint32_t) + 8;
[133]347}
[132]348
349
[134]350/******************************************************************************
351 * Compare the auth portion of two SIDs.
352 ******************************************************************************/
353int winsec_sid_compare_auth(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
[133]354{
355  int i;
[132]356
[133]357  if (sid1 == sid2)
358    return 0;
359  if (!sid1)
360    return -1;
361  if (!sid2)
362    return 1;
[132]363
[133]364  if (sid1->sid_rev_num != sid2->sid_rev_num)
365    return sid1->sid_rev_num - sid2->sid_rev_num;
[132]366
[133]367  for (i = 0; i < 6; i++)
368    if (sid1->id_auth[i] != sid2->id_auth[i])
369      return sid1->id_auth[i] - sid2->id_auth[i];
[132]370
[133]371  return 0;
372}
[132]373
374
[134]375/******************************************************************************
376 * Compare two SIDs.
377 ******************************************************************************/
378int winsec_sid_compare(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
[133]379{
380  int i;
[132]381
[133]382  if (sid1 == sid2)
383    return 0;
384  if (!sid1)
385    return -1;
386  if (!sid2)
387    return 1;
[132]388
[133]389  /* Compare most likely different rids, first: i.e start at end */
390  if (sid1->num_auths != sid2->num_auths)
391    return sid1->num_auths - sid2->num_auths;
[132]392
[133]393  for (i = sid1->num_auths-1; i >= 0; --i)
394    if (sid1->sub_auths[i] != sid2->sub_auths[i])
395      return sid1->sub_auths[i] - sid2->sub_auths[i];
[132]396
[134]397  return winsec_sid_compare_auth(sid1, sid2);
[133]398}
[132]399
400
[134]401/******************************************************************************
402 * Compare two SIDs.
403 ******************************************************************************/
404bool winsec_sid_equal(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
[133]405{
[134]406  return winsec_sid_compare(sid1, sid2) == 0;
[133]407}
[132]408
409
[134]410/******************************************************************************
[253]411 ******************************************************************************/
412char* winsec_sid2str(const WINSEC_DOM_SID* sid)
413{
414  uint32_t i, size = WINSEC_MAX_SUBAUTHS*11 + 24;
415  uint32_t left = size;
416  uint8_t comps = sid->num_auths;
417  char* ret_val = malloc(size);
418 
419  if(ret_val == NULL)
420    return NULL;
421
422  if(comps > WINSEC_MAX_SUBAUTHS)
423    comps = WINSEC_MAX_SUBAUTHS;
424
425  left -= sprintf(ret_val, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
426
427  for (i = 0; i < comps; i++) 
428    left -= snprintf(ret_val+(size-left), left, "-%u", sid->sub_auths[i]);
429
430  return ret_val;
431}
432
433
434/******************************************************************************
[134]435 * Compares two WINSEC_DESC structures.
436 ******************************************************************************/
437bool winsec_desc_equal(WINSEC_DESC* s1, WINSEC_DESC* s2)
[133]438{
[134]439  /* Trivial cases */
440  if (!s1 && !s2)
[133]441    return true;
[134]442  if (!s1 || !s2)
443    return false;
[132]444
[134]445  /* Check top level stuff */
446  if (s1->revision != s2->revision)
447    return false;
[132]448
[134]449  if (s1->control != s2->control)
[132]450    return false;
451
[134]452  /* Check owner and group */
453  if (!winsec_sid_equal(s1->owner_sid, s2->owner_sid))
454    return false;
455
456  if (!winsec_sid_equal(s1->grp_sid, s2->grp_sid)) 
457    return false;
458
459  /* Check ACLs present in one but not the other */
460  if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
461      (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) 
[132]462  { return false; }
463
[134]464  /* Sigh - we have to do it the hard way by iterating over all
465     the ACEs in the ACLs */
466  if(!winsec_acl_equal(s1->dacl, s2->dacl) || !winsec_acl_equal(s1->sacl, s2->sacl)) 
[132]467    return false;
468
469  return true;
470}
471
472
[134]473
474/******************************************************************************
475 * Compares two WINSEC_ACL structures.
476 ******************************************************************************/
477bool winsec_acl_equal(WINSEC_ACL* s1, WINSEC_ACL* s2)
[132]478{
479  unsigned int i, j;
480
481  /* Trivial cases */
482  if (!s1 && !s2) 
483    return true;
484  if (!s1 || !s2) 
485    return false;
486
487  /* Check top level stuff */
488  if (s1->revision != s2->revision)
489    return false;
490
491  if (s1->num_aces != s2->num_aces)
492    return false;
493
494  /* The ACEs could be in any order so check each ACE in s1 against
495     each ACE in s2. */
496
[134]497  for (i = 0; i < s1->num_aces; i++)
[132]498  {
499    bool found = false;
500
501    for (j = 0; j < s2->num_aces; j++) 
502    {
[134]503      if (winsec_ace_equal(s1->aces[i], s2->aces[j])) 
[132]504      {
505        found = true;
506        break;
507      }
508    }
509
510    if (!found)
511      return false;
512  }
513
514  return true;
515}
516
517
[134]518/******************************************************************************
519 * Compares two WINSEC_ACE structures.
520 ******************************************************************************/
521bool winsec_ace_equal(WINSEC_ACE* s1, WINSEC_ACE* s2)
[132]522{
523  /* Trivial cases */
[134]524  if (!s1 && !s2) 
[132]525    return true;
[134]526  if (!s1 || !s2) 
[132]527    return false;
528
529  /* Check top level stuff */
[134]530  if (s1->type != s2->type || s1->flags != s2->flags ||
531      s1->access_mask != s2->access_mask)
532  { return false; }
[132]533
[134]534  /* Check SID */
535  if (!winsec_sid_equal(s1->trustee, s2->trustee))
[132]536    return false;
537
[134]538  return true;
539}
[132]540
541
[134]542/******************************************************************************
543 * Check if ACE has OBJECT type.
544 ******************************************************************************/
545bool winsec_ace_object(uint8_t type)
546{
547  if (type == WINSEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
548      type == WINSEC_ACE_TYPE_ACCESS_DENIED_OBJECT ||
549      type == WINSEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ||
550      type == WINSEC_ACE_TYPE_SYSTEM_ALARM_OBJECT) 
551  { return true; }
[132]552
[134]553  return false;
[132]554}
Note: See TracBrowser for help on using the repository browser.