merging for 2.2.6pre1
[Samba.git] / source / rpc_parse / parse_sec.c
blobc9920a2b475806215b5a201128d26c030d59c6d6
1 /*
2 * Unix SMB/Netbios implementation.
3 * Version 1.9.
4 * RPC Pipe client / server routines
5 * Copyright (C) Andrew Tridgell 1992-1998,
6 * Copyright (C) Jeremy R. Allison 1995-1998
7 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
8 * Copyright (C) Paul Ashton 1997-1998.
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; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "includes.h"
27 #define SD_HEADER_SIZE 0x14
29 /*******************************************************************
30 Sets up a SEC_ACCESS structure.
31 ********************************************************************/
33 void init_sec_access(SEC_ACCESS *t, uint32 mask)
35 t->mask = mask;
38 /*******************************************************************
39 Reads or writes a SEC_ACCESS structure.
40 ********************************************************************/
42 BOOL sec_io_access(char *desc, SEC_ACCESS *t, prs_struct *ps, int depth)
44 if (t == NULL)
45 return False;
47 prs_debug(ps, depth, desc, "sec_io_access");
48 depth++;
50 if(!prs_uint32("mask", ps, depth, &(t->mask)))
51 return False;
53 return True;
57 /*******************************************************************
58 Sets up a SEC_ACE structure.
59 ********************************************************************/
61 void init_sec_ace(SEC_ACE *t, DOM_SID *sid, uint8 type, SEC_ACCESS mask, uint8 flag)
63 t->type = type;
64 t->flags = flag;
65 t->size = sid_size(sid) + 8;
66 t->info = mask;
68 ZERO_STRUCTP(&t->trustee);
69 sid_copy(&t->trustee, sid);
72 /*******************************************************************
73 Reads or writes a SEC_ACE structure.
74 ********************************************************************/
76 BOOL sec_io_ace(char *desc, SEC_ACE *psa, prs_struct *ps, int depth)
78 uint32 old_offset;
79 uint32 offset_ace_size;
81 if (psa == NULL)
82 return False;
84 prs_debug(ps, depth, desc, "sec_io_ace");
85 depth++;
87 old_offset = prs_offset(ps);
89 if(!prs_uint8("type ", ps, depth, &psa->type))
90 return False;
92 if(!prs_uint8("flags", ps, depth, &psa->flags))
93 return False;
95 if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size))
96 return False;
98 if(!sec_io_access("info ", &psa->info, ps, depth))
99 return False;
101 if(!smb_io_dom_sid("sid ", &psa->trustee , ps, depth))
102 return False;
104 if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset))
105 return False;
107 return True;
110 /*******************************************************************
111 Create a SEC_ACL structure.
112 ********************************************************************/
114 SEC_ACL *make_sec_acl(TALLOC_CTX *ctx, uint16 revision, int num_aces, SEC_ACE *ace_list)
116 SEC_ACL *dst;
117 int i;
119 if((dst = (SEC_ACL *)talloc_zero(ctx,sizeof(SEC_ACL))) == NULL)
120 return NULL;
122 dst->revision = revision;
123 dst->num_aces = num_aces;
124 dst->size = 8;
126 /* Now we need to return a non-NULL address for the ace list even
127 if the number of aces required is zero. This is because there
128 is a distinct difference between a NULL ace and an ace with zero
129 entries in it. This is achieved by checking that num_aces is a
130 positive number. */
132 if ((num_aces) &&
133 ((dst->ace = (SEC_ACE *)talloc(ctx, sizeof(SEC_ACE) * num_aces))
134 == NULL)) {
135 return NULL;
138 for (i = 0; i < num_aces; i++) {
139 dst->ace[i] = ace_list[i]; /* Structure copy. */
140 dst->size += ace_list[i].size;
143 return dst;
146 /*******************************************************************
147 Duplicate a SEC_ACL structure.
148 ********************************************************************/
150 SEC_ACL *dup_sec_acl(TALLOC_CTX *ctx, SEC_ACL *src)
152 if(src == NULL)
153 return NULL;
155 return make_sec_acl(ctx, src->revision, src->num_aces, src->ace);
158 /*******************************************************************
159 Reads or writes a SEC_ACL structure.
161 First of the xx_io_xx functions that allocates its data structures
162 for you as it reads them.
163 ********************************************************************/
165 BOOL sec_io_acl(char *desc, SEC_ACL **ppsa, prs_struct *ps, int depth)
167 int i;
168 uint32 old_offset;
169 uint32 offset_acl_size;
170 SEC_ACL *psa;
173 * Note that the size is always a multiple of 4 bytes due to the
174 * nature of the data structure. Therefore the prs_align() calls
175 * have been removed as they through us off when doing two-layer
176 * marshalling such as in the printing code (NEW_BUFFER). --jerry
179 if (ppsa == NULL)
180 return False;
182 psa = *ppsa;
184 if(UNMARSHALLING(ps) && psa == NULL) {
186 * This is a read and we must allocate the stuct to read into.
188 if((psa = (SEC_ACL *)prs_alloc_mem(ps, sizeof(SEC_ACL))) == NULL)
189 return False;
190 *ppsa = psa;
193 prs_debug(ps, depth, desc, "sec_io_acl");
194 depth++;
196 old_offset = prs_offset(ps);
198 if(!prs_uint16("revision", ps, depth, &psa->revision))
199 return False;
201 if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_acl_size))
202 return False;
204 if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces))
205 return False;
207 if (UNMARSHALLING(ps)) {
209 * Even if the num_aces is zero, allocate memory as there's a difference
210 * between a non-present DACL (allow all access) and a DACL with no ACE's
211 * (allow no access).
213 if((psa->ace = (SEC_ACE *)prs_alloc_mem(ps,sizeof(psa->ace[0]) * (psa->num_aces+1))) == NULL)
214 return False;
217 for (i = 0; i < psa->num_aces; i++) {
218 fstring tmp;
219 slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
220 if(!sec_io_ace(tmp, &psa->ace[i], ps, depth))
221 return False;
224 if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_acl_size, old_offset))
225 return False;
227 return True;
230 /*******************************************************************
231 Works out the linearization size of a SEC_DESC.
232 ********************************************************************/
234 size_t sec_desc_size(SEC_DESC *psd)
236 size_t offset;
238 if (!psd) return 0;
240 offset = SD_HEADER_SIZE;
242 /* don't align */
244 if (psd->owner_sid != NULL)
245 offset += sid_size(psd->owner_sid);
247 if (psd->grp_sid != NULL)
248 offset += sid_size(psd->grp_sid);
250 if (psd->sacl != NULL)
251 offset += psd->sacl->size;
253 if (psd->dacl != NULL)
254 offset += psd->dacl->size;
256 return offset;
259 /*******************************************************************
260 Compares two SEC_ACE structures
261 ********************************************************************/
263 BOOL sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
265 /* Trivial case */
267 if (!s1 && !s2) return True;
269 /* Check top level stuff */
271 if (s1->type != s2->type || s1->flags != s2->flags ||
272 s1->info.mask != s2->info.mask) {
273 return False;
276 /* Check SID */
278 if (!sid_equal(&s1->trustee, &s2->trustee)) {
279 return False;
282 return True;
285 /*******************************************************************
286 Compares two SEC_ACL structures
287 ********************************************************************/
289 BOOL sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
291 int i, j;
293 /* Trivial cases */
295 if (!s1 && !s2) return True;
296 if (!s1 || !s2) return False;
298 /* Check top level stuff */
300 if (s1->revision != s2->revision) {
301 DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
302 s1->revision, s2->revision));
303 return False;
306 if (s1->num_aces != s2->num_aces) {
307 DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
308 s1->revision, s2->revision));
309 return False;
312 /* The ACEs could be in any order so check each ACE in s1 against
313 each ACE in s2. */
315 for (i = 0; i < s1->num_aces; i++) {
316 BOOL found = False;
318 for (j = 0; j < s2->num_aces; j++) {
319 if (sec_ace_equal(&s1->ace[i], &s2->ace[j])) {
320 found = True;
321 break;
325 if (!found) return False;
328 return True;
331 /*******************************************************************
332 Compares two SEC_DESC structures
333 ********************************************************************/
335 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
337 /* Trivial case */
339 if (!s1 && !s2) {
340 goto done;
343 /* Check top level stuff */
345 if (s1->revision != s2->revision) {
346 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
347 s1->revision, s2->revision));
348 return False;
351 if (s1->type!= s2->type) {
352 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
353 s1->type, s2->type));
354 return False;
357 /* Check owner and group */
359 if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
360 fstring str1, str2;
362 sid_to_string(str1, s1->owner_sid);
363 sid_to_string(str2, s2->owner_sid);
365 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
366 str1, str2));
367 return False;
370 if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
371 fstring str1, str2;
373 sid_to_string(str1, s1->grp_sid);
374 sid_to_string(str2, s2->grp_sid);
376 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
377 str1, str2));
378 return False;
381 /* Check ACLs present in one but not the other */
383 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
384 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
385 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
386 return False;
389 /* Sigh - we have to do it the hard way by iterating over all
390 the ACEs in the ACLs */
392 if (!sec_acl_equal(s1->dacl, s2->dacl) ||
393 !sec_acl_equal(s1->sacl, s2->sacl)) {
394 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
395 return False;
398 done:
399 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
400 return True;
403 /*******************************************************************
404 Merge part of security descriptor old_sec in to the empty sections of
405 security descriptor new_sec.
406 ********************************************************************/
408 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
410 DOM_SID *owner_sid, *group_sid;
411 SEC_DESC_BUF *return_sdb;
412 SEC_ACL *dacl, *sacl;
413 SEC_DESC *psd = NULL;
414 uint16 secdesc_type;
415 size_t secdesc_size;
417 /* Copy over owner and group sids. There seems to be no flag for
418 this so just check the pointer values. */
420 owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
421 old_sdb->sec->owner_sid;
423 group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
424 old_sdb->sec->grp_sid;
426 secdesc_type = new_sdb->sec->type;
428 /* Ignore changes to the system ACL. This has the effect of making
429 changes through the security tab audit button not sticking.
430 Perhaps in future Samba could implement these settings somehow. */
432 sacl = NULL;
433 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
435 /* Copy across discretionary ACL */
437 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
438 dacl = new_sdb->sec->dacl;
439 } else {
440 dacl = old_sdb->sec->dacl;
443 /* Create new security descriptor from bits */
445 psd = make_sec_desc(ctx, new_sdb->sec->revision,
446 owner_sid, group_sid, sacl, dacl, &secdesc_size);
448 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
450 return(return_sdb);
453 /*******************************************************************
454 Tallocs a duplicate SID.
455 ********************************************************************/
457 static DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, DOM_SID *src)
459 DOM_SID *dst;
461 if(!src)
462 return NULL;
464 if((dst = talloc_zero(ctx, sizeof(DOM_SID))) != NULL) {
465 sid_copy( dst, src);
468 return dst;
471 /*******************************************************************
472 Creates a SEC_DESC structure
473 ********************************************************************/
475 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision,
476 DOM_SID *owner_sid, DOM_SID *grp_sid,
477 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
479 SEC_DESC *dst;
480 uint32 offset;
482 *sd_size = 0;
484 if(( dst = (SEC_DESC *)talloc_zero(ctx, sizeof(SEC_DESC))) == NULL)
485 return NULL;
487 dst->revision = revision;
488 dst->type = SEC_DESC_SELF_RELATIVE;
490 if (sacl) dst->type |= SEC_DESC_SACL_PRESENT;
491 if (dacl) dst->type |= SEC_DESC_DACL_PRESENT;
493 dst->off_owner_sid = 0;
494 dst->off_grp_sid = 0;
495 dst->off_sacl = 0;
496 dst->off_dacl = 0;
498 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
499 goto error_exit;
501 if(grp_sid && ((dst->grp_sid = sid_dup_talloc(ctx,grp_sid)) == NULL))
502 goto error_exit;
504 if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
505 goto error_exit;
507 if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
508 goto error_exit;
510 offset = 0;
513 * Work out the linearization sizes.
516 if (dst->owner_sid != NULL) {
518 if (offset == 0)
519 offset = SD_HEADER_SIZE;
521 dst->off_owner_sid = offset;
522 offset += sid_size(dst->owner_sid);
525 if (dst->grp_sid != NULL) {
527 if (offset == 0)
528 offset = SD_HEADER_SIZE;
530 dst->off_grp_sid = offset;
531 offset += sid_size(dst->grp_sid);
534 if (dst->sacl != NULL) {
536 if (offset == 0)
537 offset = SD_HEADER_SIZE;
539 dst->off_sacl = offset;
540 offset += dst->sacl->size;
543 if (dst->dacl != NULL) {
545 if (offset == 0)
546 offset = SD_HEADER_SIZE;
548 dst->off_dacl = offset;
549 offset += dst->dacl->size;
552 *sd_size = (size_t)((offset == 0) ? SD_HEADER_SIZE : offset);
553 return dst;
555 error_exit:
557 *sd_size = 0;
558 return NULL;
561 /*******************************************************************
562 Duplicate a SEC_DESC structure.
563 ********************************************************************/
565 SEC_DESC *dup_sec_desc( TALLOC_CTX *ctx, SEC_DESC *src)
567 size_t dummy;
569 if(src == NULL)
570 return NULL;
572 return make_sec_desc( ctx, src->revision,
573 src->owner_sid, src->grp_sid, src->sacl,
574 src->dacl, &dummy);
577 /*******************************************************************
578 Creates a SEC_DESC structure with typical defaults.
579 ********************************************************************/
581 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, DOM_SID *owner_sid, DOM_SID *grp_sid,
582 SEC_ACL *dacl, size_t *sd_size)
584 return make_sec_desc(ctx, SEC_DESC_REVISION,
585 owner_sid, grp_sid, NULL, dacl, sd_size);
588 /*******************************************************************
589 Reads or writes a SEC_DESC structure.
590 If reading and the *ppsd = NULL, allocates the structure.
591 ********************************************************************/
593 BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
595 uint32 old_offset;
596 uint32 max_offset = 0; /* after we're done, move offset to end */
597 uint32 tmp_offset = 0;
598 SEC_DESC *psd;
600 if (ppsd == NULL)
601 return False;
603 psd = *ppsd;
605 if (psd == NULL) {
606 if(UNMARSHALLING(ps)) {
607 if((psd = (SEC_DESC *)prs_alloc_mem(ps,sizeof(SEC_DESC))) == NULL)
608 return False;
609 *ppsd = psd;
610 } else {
611 /* Marshalling - just ignore. */
612 return True;
616 prs_debug(ps, depth, desc, "sec_io_desc");
617 depth++;
619 #if 0
621 * if alignment is needed, should be done by the the
622 * caller. Not here. This caused me problems when marshalling
623 * printer info into a buffer. --jerry
625 if(!prs_align(ps))
626 return False;
627 #endif
629 /* start of security descriptor stored for back-calc offset purposes */
630 old_offset = prs_offset(ps);
632 if(!prs_uint16("revision ", ps, depth, &psd->revision))
633 return False;
635 if(!prs_uint16("type ", ps, depth, &psd->type))
636 return False;
638 if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid))
639 return False;
641 if(!prs_uint32("off_grp_sid ", ps, depth, &psd->off_grp_sid))
642 return False;
644 if(!prs_uint32("off_sacl ", ps, depth, &psd->off_sacl))
645 return False;
647 if(!prs_uint32("off_dacl ", ps, depth, &psd->off_dacl))
648 return False;
650 max_offset = MAX(max_offset, prs_offset(ps));
652 if (psd->off_owner_sid != 0) {
654 tmp_offset = ps->data_offset;
655 if(!prs_set_offset(ps, old_offset + psd->off_owner_sid))
656 return False;
658 if (UNMARSHALLING(ps)) {
659 /* reading */
660 if((psd->owner_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->owner_sid))) == NULL)
661 return False;
664 if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
665 return False;
667 max_offset = MAX(max_offset, prs_offset(ps));
669 if (!prs_set_offset(ps,tmp_offset))
670 return False;
673 if (psd->off_grp_sid != 0) {
675 tmp_offset = ps->data_offset;
676 if(!prs_set_offset(ps, old_offset + psd->off_grp_sid))
677 return False;
679 if (UNMARSHALLING(ps)) {
680 /* reading */
681 if((psd->grp_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->grp_sid))) == NULL)
682 return False;
685 if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
686 return False;
688 max_offset = MAX(max_offset, prs_offset(ps));
690 if (!prs_set_offset(ps,tmp_offset))
691 return False;
694 if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) {
695 tmp_offset = ps->data_offset;
696 if(!prs_set_offset(ps, old_offset + psd->off_sacl))
697 return False;
698 if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
699 return False;
700 max_offset = MAX(max_offset, prs_offset(ps));
701 if (!prs_set_offset(ps,tmp_offset))
702 return False;
705 if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) {
706 tmp_offset = ps->data_offset;
707 if(!prs_set_offset(ps, old_offset + psd->off_dacl))
708 return False;
709 if(!sec_io_acl("dacl", &psd->dacl, ps, depth))
710 return False;
711 max_offset = MAX(max_offset, prs_offset(ps));
712 if (!prs_set_offset(ps,tmp_offset))
713 return False;
716 if(!prs_set_offset(ps, max_offset))
717 return False;
718 return True;
721 /*******************************************************************
722 Creates a SEC_DESC_BUF structure.
723 ********************************************************************/
725 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
727 SEC_DESC_BUF *dst;
729 if((dst = (SEC_DESC_BUF *)talloc_zero(ctx, sizeof(SEC_DESC_BUF))) == NULL)
730 return NULL;
732 /* max buffer size (allocated size) */
733 dst->max_len = (uint32)len;
734 dst->len = (uint32)len;
736 if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
737 return NULL;
740 dst->ptr = 0x1;
742 return dst;
745 /*******************************************************************
746 Duplicates a SEC_DESC_BUF structure.
747 ********************************************************************/
749 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
751 if(src == NULL)
752 return NULL;
754 return make_sec_desc_buf( ctx, src->len, src->sec);
757 /*******************************************************************
758 Reads or writes a SEC_DESC_BUF structure.
759 ********************************************************************/
761 BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
763 uint32 off_len;
764 uint32 off_max_len;
765 uint32 old_offset;
766 uint32 size;
767 SEC_DESC_BUF *psdb;
769 if (ppsdb == NULL)
770 return False;
772 psdb = *ppsdb;
774 if (UNMARSHALLING(ps) && psdb == NULL) {
775 if((psdb = (SEC_DESC_BUF *)prs_alloc_mem(ps,sizeof(SEC_DESC_BUF))) == NULL)
776 return False;
777 *ppsdb = psdb;
780 prs_debug(ps, depth, desc, "sec_io_desc_buf");
781 depth++;
783 if(!prs_align(ps))
784 return False;
786 if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len))
787 return False;
789 if(!prs_uint32 ("ptr ", ps, depth, &psdb->ptr))
790 return False;
792 if(!prs_uint32_pre("len ", ps, depth, &psdb->len, &off_len))
793 return False;
795 old_offset = prs_offset(ps);
797 /* reading, length is non-zero; writing, descriptor is non-NULL */
798 if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) {
799 if(!sec_io_desc("sec ", &psdb->sec, ps, depth))
800 return False;
803 if(!prs_align(ps))
804 return False;
806 size = prs_offset(ps) - old_offset;
807 if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size))
808 return False;
810 if(!prs_uint32_post("len ", ps, depth, &psdb->len, off_len, size))
811 return False;
813 return True;