source: trunk/lib/winsec.c @ 175

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

filled in additional, minimal documentation

  • Property svn:keywords set to Id
File size: 13.9 KB
Line 
1/*
2 *
3 * Copyright (C) 2005-2006,2009-2010 Timothy D. Morgan
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 *
20 * $Id: winsec.c 169 2010-03-03 19:24:58Z tim $
21 */
22
23/** @file */
24
25#include "winsec.h"
26
27
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}
35
36
37/******************************************************************************
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/******************************************************************************
47 * Parses a WINSEC_DESC structure and substructures.
48 ******************************************************************************/
49WINSEC_DESC* winsec_parse_desc(void* talloc_ctx, 
50                               const uint8_t* buf, uint32_t buf_len)
51{
52  WINSEC_DESC* ret_val;
53
54  if (buf == NULL || buf_len <  WINSEC_DESC_HEADER_SIZE)
55    return NULL;
56
57  if((ret_val = talloc(talloc_ctx, WINSEC_DESC)) == NULL)
58    return NULL;
59
60  ret_val->revision = buf[0];
61  ret_val->sbz1 = buf[1];
62  ret_val->control = SVAL(buf, 0x2);
63
64  if(!(ret_val->control & WINSEC_DESC_SELF_RELATIVE))
65    fprintf(stderr, "DEBUG: NOT self-relative!\n");
66
67  ret_val->off_owner_sid = IVAL(buf, 0x4);
68  ret_val->off_grp_sid = IVAL(buf, 0x8);
69  ret_val->off_sacl = IVAL(buf, 0xC);
70  ret_val->off_dacl = IVAL(buf, 0x10);
71
72  /* A basic sanity check to ensure our offsets are within our buffer.
73   * Additional length checking is done in secondary parsing functions.
74   */
75  if((ret_val->off_owner_sid >= buf_len)
76     || (ret_val->off_grp_sid >= buf_len)
77     || (ret_val->off_sacl >= buf_len)
78     || (ret_val->off_dacl >= buf_len))
79  {
80    talloc_free(ret_val);
81    return NULL;
82  }
83
84  if(ret_val->off_owner_sid == 0)
85    ret_val->owner_sid = NULL;
86  else
87  {
88    ret_val->owner_sid = winsec_parse_dom_sid(ret_val, 
89                                              buf + ret_val->off_owner_sid,
90                                              buf_len - ret_val->off_owner_sid);
91    if(ret_val->owner_sid == NULL)
92    {
93      talloc_free(ret_val);
94      return NULL;
95    }
96  }
97
98  if(ret_val->off_grp_sid == 0) 
99    ret_val->grp_sid = NULL;
100  else
101  {
102    ret_val->grp_sid = winsec_parse_dom_sid(ret_val, buf + ret_val->off_grp_sid,
103                                            buf_len - ret_val->off_grp_sid);
104    if(ret_val->grp_sid == NULL)
105    {
106      talloc_free(ret_val);
107      return NULL;
108    }
109  }
110
111  if((ret_val->control & WINSEC_DESC_SACL_PRESENT) && ret_val->off_sacl)
112  {
113    ret_val->sacl = winsec_parse_acl(ret_val, buf + ret_val->off_sacl,
114                                     buf_len - ret_val->off_sacl);
115    if(ret_val->sacl == NULL)
116    {
117      talloc_free(ret_val);
118      return NULL;
119    }
120  }
121  else
122    ret_val->sacl = NULL;
123
124  if((ret_val->control & WINSEC_DESC_DACL_PRESENT) && ret_val->off_dacl != 0) 
125  {
126    ret_val->dacl = winsec_parse_acl(ret_val, buf + ret_val->off_dacl,
127                                     buf_len - ret_val->off_dacl);
128    if(ret_val->dacl == NULL)
129    {
130      talloc_free(ret_val);
131      return NULL;
132    }
133  }
134  else
135    ret_val->dacl = NULL;
136
137  return ret_val;
138}
139
140
141/******************************************************************************
142 * Parses a WINSEC_ACL structure and all substructures.
143 ******************************************************************************/
144WINSEC_ACL* winsec_parse_acl(void* talloc_ctx,
145                             const uint8_t* buf, uint32_t buf_len)
146{
147  uint32_t i, offset;
148  WINSEC_ACL* ret_val;
149
150  /*
151   * Note that the size is always a multiple of 4 bytes due to the
152   * nature of the data structure.
153   */
154  if (buf == NULL || buf_len < 8)
155    return NULL;
156
157  if((ret_val = talloc(talloc_ctx, WINSEC_ACL)) == NULL)
158    return NULL;
159 
160  ret_val->revision = SVAL(buf, 0x0);
161  ret_val->size     = SVAL(buf, 0x2);
162  ret_val->num_aces = IVAL(buf, 0x4);
163
164  /* The num_aces can be at most around 4k because anything greater
165   * wouldn't fit in the 16 bit size even if every ace was as small as
166   * possible.
167   */
168  if((ret_val->size > buf_len) || (ret_val->num_aces > 4095))
169  {
170    talloc_free(ret_val);
171    return NULL;
172  }
173
174  /* Even if the num_aces is zero, allocate memory as there's a difference
175   * between a non-present DACL (allow all access) and a DACL with no ACE's
176   * (allow no access).
177   */
178  if((ret_val->aces = talloc_array(ret_val, WINSEC_ACE*, 
179                                   ret_val->num_aces+1)) == NULL)
180  {
181    talloc_free(ret_val);
182    return NULL;
183  }
184
185  offset = 8;
186  for(i=0; i < ret_val->num_aces; i++)
187  {
188    ret_val->aces[i] = winsec_parse_ace(ret_val->aces, 
189                                        buf+offset, buf_len-offset);
190    if(ret_val->aces[i] == NULL)
191    {
192      talloc_free(ret_val);
193      return NULL;
194    }
195
196    offset += ret_val->aces[i]->size;
197    if(offset > buf_len)
198    {
199      talloc_free(ret_val);
200      return NULL;
201    }
202  }
203  ret_val->aces[ret_val->num_aces] = NULL;
204
205  return ret_val;
206}
207
208
209/******************************************************************************
210 * Parses a WINSEC_ACE structure and all substructures.
211 ******************************************************************************/
212WINSEC_ACE* winsec_parse_ace(void* talloc_ctx,
213                             const uint8_t* buf, uint32_t buf_len)
214{
215  uint32_t offset;
216  WINSEC_ACE* ret_val;
217
218  if(buf == NULL || buf_len < WINSEC_ACE_MIN_SIZE)
219    return NULL;
220
221  if((ret_val = talloc(talloc_ctx, WINSEC_ACE)) == NULL)
222    return NULL;
223
224  ret_val->type = buf[0];
225  ret_val->flags = buf[1];
226  ret_val->size = SVAL(buf, 0x2);
227  ret_val->access_mask = IVAL(buf, 0x4);
228
229  offset = 0x8;
230
231  /* check whether object access is present */
232  if (winsec_ace_object(ret_val->type))
233  {
234    ret_val->obj_flags = IVAL(buf, offset);
235    offset += 4;
236
237    if(ret_val->obj_flags & WINSEC_ACE_OBJECT_PRESENT)
238    {
239      ret_val->obj_guid = winsec_parse_uuid(ret_val, 
240                                            buf+offset, buf_len-offset);
241      if(ret_val->obj_guid == NULL)
242      {
243        talloc_free(ret_val);
244        return NULL;
245      }
246      offset += sizeof(WINSEC_UUID);
247    }
248    else
249      ret_val->obj_guid = NULL;
250
251    if(ret_val->obj_flags & WINSEC_ACE_OBJECT_INHERITED_PRESENT)
252    {
253      ret_val->inh_guid = winsec_parse_uuid(ret_val, 
254                                            buf+offset, buf_len-offset);
255      if(ret_val->inh_guid == NULL)
256      {
257        talloc_free(ret_val);
258        return NULL;
259      }
260      offset += sizeof(WINSEC_UUID);
261    }
262    else
263      ret_val->inh_guid = NULL;
264  }
265
266  ret_val->trustee = winsec_parse_dom_sid(ret_val, buf+offset, buf_len-offset);
267  if(ret_val->trustee == NULL)
268  {
269    talloc_free(ret_val);
270    return NULL;
271  }
272 
273  return ret_val;
274}
275
276
277/******************************************************************************
278 * Parses a WINSEC_DOM_SID structure.
279 ******************************************************************************/
280WINSEC_DOM_SID* winsec_parse_dom_sid(void* talloc_ctx,
281                                     const uint8_t* buf, uint32_t buf_len)
282{
283  uint32_t i;
284  WINSEC_DOM_SID* ret_val;
285
286  if(buf == NULL || buf_len < 8)
287    return NULL;
288
289  /*  if((ret_val = (WINSEC_DOM_SID*)zalloc(sizeof(WINSEC_DOM_SID))) == NULL)*/
290  if((ret_val = talloc(talloc_ctx, WINSEC_DOM_SID)) == NULL)
291    return NULL;
292
293  ret_val->sid_rev_num = buf[0];
294  ret_val->num_auths = buf[1];
295  memcpy(ret_val->id_auth, buf+2, 6);
296
297  /* XXX: should really issue a warning here... */
298  if (ret_val->num_auths > WINSEC_MAX_SUBAUTHS)
299    ret_val->num_auths = WINSEC_MAX_SUBAUTHS;
300
301  if(buf_len < ret_val->num_auths*sizeof(uint32_t)+8)
302  {
303    talloc_free(ret_val);
304    return NULL;
305  }
306 
307  for(i=0; i < ret_val->num_auths; i++)
308    ret_val->sub_auths[i] = IVAL(buf, 8+i*sizeof(uint32_t));
309
310  return ret_val;
311}
312
313
314/******************************************************************************
315 * Parses a WINSEC_UUID struct.
316 ******************************************************************************/
317WINSEC_UUID* winsec_parse_uuid(void* talloc_ctx,
318                               const uint8_t* buf, uint32_t buf_len)
319{
320  WINSEC_UUID* ret_val;
321
322  if(buf == NULL || buf_len < sizeof(WINSEC_UUID))
323    return false;
324
325  if((ret_val = talloc(talloc_ctx, WINSEC_UUID)) == NULL)
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);
334
335  return ret_val;
336}
337
338
339/******************************************************************************
340 * Calculates the size of a SID.
341 ******************************************************************************/
342size_t winsec_sid_size(const WINSEC_DOM_SID* sid)
343{
344  if (sid == NULL)
345    return 0;
346
347  return sid->num_auths * sizeof(uint32_t) + 8;
348}
349
350
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)
355{
356  int i;
357
358  if (sid1 == sid2)
359    return 0;
360  if (!sid1)
361    return -1;
362  if (!sid2)
363    return 1;
364
365  if (sid1->sid_rev_num != sid2->sid_rev_num)
366    return sid1->sid_rev_num - sid2->sid_rev_num;
367
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];
371
372  return 0;
373}
374
375
376/******************************************************************************
377 * Compare two SIDs.
378 ******************************************************************************/
379int winsec_sid_compare(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
380{
381  int i;
382
383  if (sid1 == sid2)
384    return 0;
385  if (!sid1)
386    return -1;
387  if (!sid2)
388    return 1;
389
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;
393
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];
397
398  return winsec_sid_compare_auth(sid1, sid2);
399}
400
401
402/******************************************************************************
403 * Compare two SIDs.
404 ******************************************************************************/
405bool winsec_sid_equal(const WINSEC_DOM_SID* sid1, const WINSEC_DOM_SID* sid2)
406{
407  return winsec_sid_compare(sid1, sid2) == 0;
408}
409
410
411/******************************************************************************
412 * Compares two WINSEC_DESC structures.
413 ******************************************************************************/
414bool winsec_desc_equal(WINSEC_DESC* s1, WINSEC_DESC* s2)
415{
416  /* Trivial cases */
417  if (!s1 && !s2)
418    return true;
419  if (!s1 || !s2)
420    return false;
421
422  /* Check top level stuff */
423  if (s1->revision != s2->revision)
424    return false;
425
426  if (s1->control != s2->control)
427    return false;
428
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)) 
439  { return false; }
440
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)) 
444    return false;
445
446  return true;
447}
448
449
450
451/******************************************************************************
452 * Compares two WINSEC_ACL structures.
453 ******************************************************************************/
454bool winsec_acl_equal(WINSEC_ACL* s1, WINSEC_ACL* s2)
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
474  for (i = 0; i < s1->num_aces; i++)
475  {
476    bool found = false;
477
478    for (j = 0; j < s2->num_aces; j++) 
479    {
480      if (winsec_ace_equal(s1->aces[i], s2->aces[j])) 
481      {
482        found = true;
483        break;
484      }
485    }
486
487    if (!found)
488      return false;
489  }
490
491  return true;
492}
493
494
495/******************************************************************************
496 * Compares two WINSEC_ACE structures.
497 ******************************************************************************/
498bool winsec_ace_equal(WINSEC_ACE* s1, WINSEC_ACE* s2)
499{
500  /* Trivial cases */
501  if (!s1 && !s2) 
502    return true;
503  if (!s1 || !s2) 
504    return false;
505
506  /* Check top level stuff */
507  if (s1->type != s2->type || s1->flags != s2->flags ||
508      s1->access_mask != s2->access_mask)
509  { return false; }
510
511  /* Check SID */
512  if (!winsec_sid_equal(s1->trustee, s2->trustee))
513    return false;
514
515  return true;
516}
517
518
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; }
529
530  return false;
531}
Note: See TracBrowser for help on using the repository browser.