source: releases/1.0.0/lib/winsec.c@ 293

Last change on this file since 293 was 261, checked in by tim, 14 years ago

readded windows file descriptor hack
copyright notices

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