source: trunk/lib/winsec.c@ 242

Last change on this file since 242 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
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 169 2010-03-03 19:24:58Z 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
[134]64 if(!(ret_val->control & WINSEC_DESC_SELF_RELATIVE))
65 fprintf(stderr, "DEBUG: NOT self-relative!\n");
[132]66
[134]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);
[133]71
[134]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))
[133]79 {
[147]80 talloc_free(ret_val);
[134]81 return NULL;
[133]82 }
[132]83
[148]84 if(ret_val->off_owner_sid == 0)
85 ret_val->owner_sid = NULL;
86 else
[133]87 {
[147]88 ret_val->owner_sid = winsec_parse_dom_sid(ret_val,
89 buf + ret_val->off_owner_sid,
[134]90 buf_len - ret_val->off_owner_sid);
91 if(ret_val->owner_sid == NULL)
[133]92 {
[147]93 talloc_free(ret_val);
[134]94 return NULL;
[133]95 }
96 }
[132]97
[148]98 if(ret_val->off_grp_sid == 0)
99 ret_val->grp_sid = NULL;
100 else
[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
[148]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 }
[148]121 else
122 ret_val->sacl = NULL;
[132]123
[148]124 if((ret_val->control & WINSEC_DESC_DACL_PRESENT) && ret_val->off_dacl != 0)
[133]125 {
[147]126 ret_val->dacl = winsec_parse_acl(ret_val, buf + ret_val->off_dacl,
[134]127 buf_len - ret_val->off_dacl);
128 if(ret_val->dacl == NULL)
[133]129 {
[147]130 talloc_free(ret_val);
[134]131 return NULL;
[133]132 }
133 }
[148]134 else
135 ret_val->dacl = NULL;
[132]136
[134]137 return ret_val;
[132]138}
139
140
[134]141/******************************************************************************
142 * Parses a WINSEC_ACL structure and all substructures.
143 ******************************************************************************/
[147]144WINSEC_ACL* winsec_parse_acl(void* talloc_ctx,
145 const uint8_t* buf, uint32_t buf_len)
[132]146{
[134]147 uint32_t i, offset;
148 WINSEC_ACL* ret_val;
[132]149
[134]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;
[148]156
[147]157 if((ret_val = talloc(talloc_ctx, WINSEC_ACL)) == NULL)
158 return NULL;
[134]159
160 ret_val->revision = SVAL(buf, 0x0);
161 ret_val->size = SVAL(buf, 0x2);
162 ret_val->num_aces = IVAL(buf, 0x4);
[132]163
[134]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 {
[147]170 talloc_free(ret_val);
[134]171 return NULL;
172 }
[132]173
[134]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 */
[147]178 if((ret_val->aces = talloc_array(ret_val, WINSEC_ACE*,
179 ret_val->num_aces+1)) == NULL)
[133]180 {
[147]181 talloc_free(ret_val);
[134]182 return NULL;
[133]183 }
[132]184
[134]185 offset = 8;
186 for(i=0; i < ret_val->num_aces; i++)
187 {
[147]188 ret_val->aces[i] = winsec_parse_ace(ret_val->aces,
189 buf+offset, buf_len-offset);
[134]190 if(ret_val->aces[i] == NULL)
191 {
[147]192 talloc_free(ret_val);
[134]193 return NULL;
194 }
[132]195
[134]196 offset += ret_val->aces[i]->size;
197 if(offset > buf_len)
198 {
[147]199 talloc_free(ret_val);
[134]200 return NULL;
201 }
202 }
[148]203 ret_val->aces[ret_val->num_aces] = NULL;
[132]204
[134]205 return ret_val;
[132]206}
207
208
[134]209/******************************************************************************
210 * Parses a WINSEC_ACE structure and all substructures.
211 ******************************************************************************/
[147]212WINSEC_ACE* winsec_parse_ace(void* talloc_ctx,
213 const uint8_t* buf, uint32_t buf_len)
[132]214{
[134]215 uint32_t offset;
216 WINSEC_ACE* ret_val;
[132]217
[134]218 if(buf == NULL || buf_len < WINSEC_ACE_MIN_SIZE)
219 return NULL;
[132]220
[147]221 if((ret_val = talloc(talloc_ctx, WINSEC_ACE)) == NULL)
[134]222 return NULL;
[132]223
[134]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);
[132]228
[134]229 offset = 0x8;
[132]230
231 /* check whether object access is present */
[134]232 if (winsec_ace_object(ret_val->type))
[132]233 {
[134]234 ret_val->obj_flags = IVAL(buf, offset);
235 offset += 4;
[132]236
[134]237 if(ret_val->obj_flags & WINSEC_ACE_OBJECT_PRESENT)
238 {
[147]239 ret_val->obj_guid = winsec_parse_uuid(ret_val,
240 buf+offset, buf_len-offset);
[134]241 if(ret_val->obj_guid == NULL)
242 {
[147]243 talloc_free(ret_val);
[134]244 return NULL;
245 }
246 offset += sizeof(WINSEC_UUID);
247 }
[148]248 else
249 ret_val->obj_guid = NULL;
[132]250
[134]251 if(ret_val->obj_flags & WINSEC_ACE_OBJECT_INHERITED_PRESENT)
252 {
[147]253 ret_val->inh_guid = winsec_parse_uuid(ret_val,
254 buf+offset, buf_len-offset);
[134]255 if(ret_val->inh_guid == NULL)
256 {
[147]257 talloc_free(ret_val);
[134]258 return NULL;
259 }
260 offset += sizeof(WINSEC_UUID);
261 }
[148]262 else
263 ret_val->inh_guid = NULL;
[134]264 }
[132]265
[147]266 ret_val->trustee = winsec_parse_dom_sid(ret_val, buf+offset, buf_len-offset);
[134]267 if(ret_val->trustee == NULL)
268 {
[147]269 talloc_free(ret_val);
270 return NULL;
[132]271 }
[134]272
273 return ret_val;
[132]274}
275
276
[134]277/******************************************************************************
278 * Parses a WINSEC_DOM_SID structure.
279 ******************************************************************************/
[147]280WINSEC_DOM_SID* winsec_parse_dom_sid(void* talloc_ctx,
281 const uint8_t* buf, uint32_t buf_len)
[132]282{
[134]283 uint32_t i;
284 WINSEC_DOM_SID* ret_val;
[132]285
[134]286 if(buf == NULL || buf_len < 8)
287 return NULL;
[132]288
[147]289 /* if((ret_val = (WINSEC_DOM_SID*)zalloc(sizeof(WINSEC_DOM_SID))) == NULL)*/
290 if((ret_val = talloc(talloc_ctx, WINSEC_DOM_SID)) == NULL)
[134]291 return NULL;
[132]292
[134]293 ret_val->sid_rev_num = buf[0];
294 ret_val->num_auths = buf[1];
295 memcpy(ret_val->id_auth, buf+2, 6);
[132]296
[134]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)
[132]302 {
[147]303 talloc_free(ret_val);
[134]304 return NULL;
[132]305 }
[134]306
307 for(i=0; i < ret_val->num_auths; i++)
308 ret_val->sub_auths[i] = IVAL(buf, 8+i*sizeof(uint32_t));
[132]309
[134]310 return ret_val;
311}
[132]312
313
[134]314/******************************************************************************
315 * Parses a WINSEC_UUID struct.
316 ******************************************************************************/
[147]317WINSEC_UUID* winsec_parse_uuid(void* talloc_ctx,
318 const uint8_t* buf, uint32_t buf_len)
[134]319{
320 WINSEC_UUID* ret_val;
321
322 if(buf == NULL || buf_len < sizeof(WINSEC_UUID))
[133]323 return false;
[132]324
[147]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.