Merged Tim's fixes from appliance-head.
[Samba.git] / source / rpc_parse / parse_sec.c
blobe2ca2202e1647f0b8373daf2de467a1869bedf99
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.
26 #include "includes.h"
28 extern int DEBUGLEVEL;
30 #define SD_HEADER_SIZE 0x14
32 /*******************************************************************
33 Sets up a SEC_ACCESS structure.
34 ********************************************************************/
36 void init_sec_access(SEC_ACCESS *t, uint32 mask)
38 t->mask = mask;
41 /*******************************************************************
42 Reads or writes a SEC_ACCESS structure.
43 ********************************************************************/
45 BOOL sec_io_access(char *desc, SEC_ACCESS *t, prs_struct *ps, int depth)
47 if (t == NULL)
48 return False;
50 prs_debug(ps, depth, desc, "sec_io_access");
51 depth++;
53 if(!prs_align(ps))
54 return False;
56 if(!prs_uint32("mask", ps, depth, &(t->mask)))
57 return False;
59 return True;
63 /*******************************************************************
64 Sets up a SEC_ACE structure.
65 ********************************************************************/
67 void init_sec_ace(SEC_ACE *t, DOM_SID *sid, uint8 type, SEC_ACCESS mask, uint8 flag)
69 t->type = type;
70 t->flags = flag;
71 t->size = sid_size(sid) + 8;
72 t->info = mask;
74 ZERO_STRUCTP(&t->sid);
75 sid_copy(&t->sid, sid);
78 /*******************************************************************
79 Reads or writes a SEC_ACE structure.
80 ********************************************************************/
82 BOOL sec_io_ace(char *desc, SEC_ACE *psa, prs_struct *ps, int depth)
84 uint32 old_offset;
85 uint32 offset_ace_size;
87 if (psa == NULL)
88 return False;
90 prs_debug(ps, depth, desc, "sec_io_ace");
91 depth++;
93 if(!prs_align(ps))
94 return False;
96 old_offset = prs_offset(ps);
98 if(!prs_uint8("type ", ps, depth, &psa->type))
99 return False;
101 if(!prs_uint8("flags", ps, depth, &psa->flags))
102 return False;
104 if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size))
105 return False;
107 if(!sec_io_access("info ", &psa->info, ps, depth))
108 return False;
110 if(!prs_align(ps))
111 return False;
113 if(!smb_io_dom_sid("sid ", &psa->sid , ps, depth))
114 return False;
116 if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset))
117 return False;
119 return True;
122 /*******************************************************************
123 Create a SEC_ACL structure.
124 ********************************************************************/
126 SEC_ACL *make_sec_acl(uint16 revision, int num_aces, SEC_ACE *ace_list)
128 SEC_ACL *dst;
129 int i;
131 if((dst = (SEC_ACL *)malloc(sizeof(SEC_ACL))) == NULL)
132 return NULL;
134 ZERO_STRUCTP(dst);
136 dst->revision = revision;
137 dst->num_aces = num_aces;
138 dst->size = 8;
140 if((dst->ace = (SEC_ACE *)malloc( sizeof(SEC_ACE) * num_aces )) == NULL) {
141 free_sec_acl(&dst);
142 return NULL;
145 for (i = 0; i < num_aces; i++) {
146 dst->ace[i] = ace_list[i]; /* Structure copy. */
147 dst->size += ace_list[i].size;
150 return dst;
153 /*******************************************************************
154 Duplicate a SEC_ACL structure.
155 ********************************************************************/
157 SEC_ACL *dup_sec_acl( SEC_ACL *src)
159 if(src == NULL)
160 return NULL;
162 return make_sec_acl( src->revision, src->num_aces, src->ace);
165 /*******************************************************************
166 Delete a SEC_ACL structure.
167 ********************************************************************/
169 void free_sec_acl(SEC_ACL **ppsa)
171 SEC_ACL *psa;
173 if(ppsa == NULL || *ppsa == NULL)
174 return;
176 psa = *ppsa;
177 if (psa->ace != NULL)
178 free(psa->ace);
180 free(psa);
181 *ppsa = NULL;
184 /*******************************************************************
185 Reads or writes a SEC_ACL structure.
187 First of the xx_io_xx functions that allocates its data structures
188 for you as it reads them.
189 ********************************************************************/
191 BOOL sec_io_acl(char *desc, SEC_ACL **ppsa, prs_struct *ps, int depth)
193 int i;
194 uint32 old_offset;
195 uint32 offset_acl_size;
196 SEC_ACL *psa;
198 if (ppsa == NULL)
199 return False;
201 psa = *ppsa;
203 if(UNMARSHALLING(ps) && psa == NULL) {
205 * This is a read and we must allocate the stuct to read into.
207 if((psa = (SEC_ACL *)malloc(sizeof(SEC_ACL))) == NULL)
208 return False;
209 ZERO_STRUCTP(psa);
210 *ppsa = psa;
213 prs_debug(ps, depth, desc, "sec_io_acl");
214 depth++;
216 if(!prs_align(ps))
217 return False;
219 old_offset = prs_offset(ps);
221 if(!prs_uint16("revision", ps, depth, &psa->revision))
222 return False;
224 if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_acl_size))
225 return False;
227 if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces))
228 return False;
230 if (UNMARSHALLING(ps) && psa->num_aces != 0) {
231 /* reading */
232 if((psa->ace = malloc(sizeof(psa->ace[0]) * psa->num_aces)) == NULL)
233 return False;
234 ZERO_STRUCTP(psa->ace);
237 for (i = 0; i < psa->num_aces; i++) {
238 fstring tmp;
239 slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
240 if(!sec_io_ace(tmp, &psa->ace[i], ps, depth))
241 return False;
244 if(!prs_align(ps))
245 return False;
247 if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_acl_size, old_offset))
248 return False;
250 return True;
253 /*******************************************************************
254 Works out the linearization size of a SEC_DESC.
255 ********************************************************************/
257 size_t sec_desc_size(SEC_DESC *psd)
259 size_t offset;
261 if (!psd) return 0;
263 offset = SD_HEADER_SIZE;
265 if (psd->owner_sid != NULL)
266 offset += ((sid_size(psd->owner_sid) + 3) & ~3);
268 if (psd->grp_sid != NULL)
269 offset += ((sid_size(psd->grp_sid) + 3) & ~3);
271 if (psd->sacl != NULL)
272 offset += ((psd->sacl->size + 3) & ~3);
274 if (psd->dacl != NULL)
275 offset += ((psd->dacl->size + 3) & ~3);
277 return offset;
280 /*******************************************************************
281 Compares two SEC_ACE structures
282 ********************************************************************/
284 BOOL sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
286 /* Trivial case */
288 if (!s1 && !s2) return True;
290 /* Check top level stuff */
292 if (s1->type != s2->type || s1->flags != s2->flags ||
293 s1->info.mask != s2->info.mask) {
294 return False;
297 /* Check SID */
299 if (!sid_equal(&s1->sid, &s2->sid)) {
300 return False;
303 return True;
306 /*******************************************************************
307 Compares two SEC_ACL structures
308 ********************************************************************/
310 BOOL sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
312 int i, j;
314 /* Trivial case */
316 if (!s1 && !s2) return True;
318 /* Check top level stuff */
320 if (s1->revision != s2->revision) {
321 DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
322 s1->revision, s2->revision));
323 return False;
326 if (s1->num_aces != s2->num_aces) {
327 DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
328 s1->revision, s2->revision));
329 return False;
332 /* The ACEs could be in any order so check each ACE in s1 against
333 each ACE in s2. */
335 for (i = 0; i < s1->num_aces; i++) {
336 BOOL found = False;
338 for (j = 0; j < s2->num_aces; j++) {
339 if (sec_ace_equal(&s1->ace[i], &s2->ace[j])) {
340 found = True;
341 break;
345 if (!found) return False;
348 return True;
351 /*******************************************************************
352 Compares two SEC_DESC structures
353 ********************************************************************/
355 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
357 /* Trivial case */
359 if (!s1 && !s2) {
360 goto done;
363 /* Check top level stuff */
365 if (s1->revision != s2->revision) {
366 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
367 s1->revision, s2->revision));
368 return False;
371 if (s1->type!= s2->type) {
372 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
373 s1->type, s2->type));
374 return False;
377 /* Check owner and group */
379 if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
380 fstring str1, str2;
382 sid_to_string(str1, s1->owner_sid);
383 sid_to_string(str2, s2->owner_sid);
385 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
386 str1, str2));
387 return False;
390 if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
391 fstring str1, str2;
393 sid_to_string(str1, s1->grp_sid);
394 sid_to_string(str2, s2->grp_sid);
396 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
397 str1, str2));
398 return False;
401 /* Check ACLs present in one but not the other */
403 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
404 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
405 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
406 return False;
409 /* Sigh - we have to do it the hard way by iterating over all
410 the ACEs in the ACLs */
412 if (!sec_acl_equal(s1->dacl, s2->dacl) ||
413 !sec_acl_equal(s1->sacl, s2->sacl)) {
414 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
415 return False;
418 done:
419 DEBUG(10, ("sec_equal(): secdescs are identical\n"));
420 return True;
423 /*******************************************************************
424 Merge part of security descriptor old_sec in to the empty sections of
425 security descriptor new_sec.
426 ********************************************************************/
428 SEC_DESC_BUF *sec_desc_merge(SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
430 DOM_SID *owner_sid, *group_sid;
431 SEC_DESC_BUF *return_sdb;
432 SEC_ACL *dacl, *sacl;
433 SEC_DESC *psd = NULL;
434 uint16 secdesc_type;
435 size_t secdesc_size;
437 /* Copy over owner and group sids. There seems to be no flag for
438 this so just check the pointer values. */
440 owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
441 old_sdb->sec->owner_sid;
443 group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
444 old_sdb->sec->grp_sid;
446 secdesc_type = new_sdb->sec->type;
448 /* Ignore changes to the system ACL. This has the effect of making
449 changes through the security tab audit button not sticking.
450 Perhaps in future Samba could implement these settings somehow. */
452 sacl = NULL;
453 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
455 /* Copy across discretionary ACL */
457 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
458 dacl = new_sdb->sec->dacl;
459 } else {
460 dacl = old_sdb->sec->dacl;
463 /* Create new security descriptor from bits */
465 psd = make_sec_desc(new_sdb->sec->revision,
466 owner_sid, group_sid, sacl, dacl, &secdesc_size);
468 return_sdb = make_sec_desc_buf(secdesc_size, psd);
470 free_sec_desc(&psd);
472 return(return_sdb);
475 /*******************************************************************
476 Creates a SEC_DESC structure
477 ********************************************************************/
479 SEC_DESC *make_sec_desc(uint16 revision,
480 DOM_SID *owner_sid, DOM_SID *grp_sid,
481 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
483 SEC_DESC *dst;
484 uint32 offset;
486 *sd_size = 0;
488 if(( dst = (SEC_DESC *)malloc(sizeof(SEC_DESC))) == NULL)
489 return NULL;
491 ZERO_STRUCTP(dst);
493 dst->revision = revision;
494 dst->type = SEC_DESC_SELF_RELATIVE;
496 if (sacl) dst->type |= SEC_DESC_SACL_PRESENT;
497 if (dacl) dst->type |= SEC_DESC_DACL_PRESENT;
499 dst->off_owner_sid = 0;
500 dst->off_grp_sid = 0;
501 dst->off_sacl = 0;
502 dst->off_dacl = 0;
504 if(owner_sid && ((dst->owner_sid = sid_dup(owner_sid)) == NULL))
505 goto error_exit;
507 if(grp_sid && ((dst->grp_sid = sid_dup(grp_sid)) == NULL))
508 goto error_exit;
510 if(sacl && ((dst->sacl = dup_sec_acl(sacl)) == NULL))
511 goto error_exit;
513 if(dacl && ((dst->dacl = dup_sec_acl(dacl)) == NULL))
514 goto error_exit;
516 offset = 0;
519 * Work out the linearization sizes.
522 if (dst->owner_sid != NULL) {
524 if (offset == 0)
525 offset = SD_HEADER_SIZE;
527 dst->off_owner_sid = offset;
528 offset += ((sid_size(dst->owner_sid) + 3) & ~3);
531 if (dst->grp_sid != NULL) {
533 if (offset == 0)
534 offset = SD_HEADER_SIZE;
536 dst->off_grp_sid = offset;
537 offset += ((sid_size(dst->grp_sid) + 3) & ~3);
540 if (dst->sacl != NULL) {
542 if (offset == 0)
543 offset = SD_HEADER_SIZE;
545 dst->off_sacl = offset;
546 offset += ((sacl->size + 3) & ~3);
549 if (dst->dacl != NULL) {
551 if (offset == 0)
552 offset = SD_HEADER_SIZE;
554 dst->off_dacl = offset;
555 offset += ((dacl->size + 3) & ~3);
558 *sd_size = (size_t)((offset == 0) ? SD_HEADER_SIZE : offset);
559 return dst;
561 error_exit:
563 *sd_size = 0;
564 free_sec_desc(&dst);
565 return NULL;
568 /*******************************************************************
569 Duplicate a SEC_DESC structure.
570 ********************************************************************/
572 SEC_DESC *dup_sec_desc( SEC_DESC *src)
574 size_t dummy;
576 if(src == NULL)
577 return NULL;
579 return make_sec_desc( src->revision,
580 src->owner_sid, src->grp_sid, src->sacl,
581 src->dacl, &dummy);
584 /*******************************************************************
585 Deletes a SEC_DESC structure
586 ********************************************************************/
588 void free_sec_desc(SEC_DESC **ppsd)
590 SEC_DESC *psd;
592 if(ppsd == NULL || *ppsd == NULL)
593 return;
595 psd = *ppsd;
597 free_sec_acl(&psd->dacl);
598 free_sec_acl(&psd->dacl);
599 free(psd->owner_sid);
600 free(psd->grp_sid);
601 free(psd);
602 *ppsd = NULL;
605 /*******************************************************************
606 Creates a SEC_DESC structure with typical defaults.
607 ********************************************************************/
609 SEC_DESC *make_standard_sec_desc(DOM_SID *owner_sid, DOM_SID *grp_sid,
610 SEC_ACL *dacl, size_t *sd_size)
612 return make_sec_desc(SEC_DESC_REVISION,
613 owner_sid, grp_sid, NULL, dacl, sd_size);
616 /*******************************************************************
617 Reads or writes a SEC_DESC structure.
618 If reading and the *ppsd = NULL, allocates the structure.
619 ********************************************************************/
621 BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
623 uint32 old_offset;
624 uint32 max_offset = 0; /* after we're done, move offset to end */
625 SEC_DESC *psd;
627 if (ppsd == NULL)
628 return False;
630 psd = *ppsd;
632 if (psd == NULL) {
633 if(UNMARSHALLING(ps)) {
634 if((psd = (SEC_DESC *)malloc(sizeof(SEC_DESC))) == NULL)
635 return False;
636 ZERO_STRUCTP(psd);
637 *ppsd = psd;
638 } else {
639 /* Marshalling - just ignore. */
640 return True;
644 prs_debug(ps, depth, desc, "sec_io_desc");
645 depth++;
647 if(!prs_align(ps))
648 return False;
650 /* start of security descriptor stored for back-calc offset purposes */
651 old_offset = prs_offset(ps);
653 if(!prs_uint16("revision ", ps, depth, &psd->revision))
654 return False;
656 if(!prs_uint16("type ", ps, depth, &psd->type))
657 return False;
659 if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid))
660 return False;
662 if(!prs_uint32("off_grp_sid ", ps, depth, &psd->off_grp_sid))
663 return False;
665 if(!prs_uint32("off_sacl ", ps, depth, &psd->off_sacl))
666 return False;
668 if(!prs_uint32("off_dacl ", ps, depth, &psd->off_dacl))
669 return False;
671 max_offset = MAX(max_offset, prs_offset(ps));
673 if (psd->off_owner_sid != 0) {
675 if (UNMARSHALLING(ps)) {
676 if(!prs_set_offset(ps, old_offset + psd->off_owner_sid))
677 return False;
678 /* reading */
679 if((psd->owner_sid = malloc(sizeof(*psd->owner_sid))) == NULL)
680 return False;
681 ZERO_STRUCTP(psd->owner_sid);
684 if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
685 return False;
686 if(!prs_align(ps))
687 return False;
690 max_offset = MAX(max_offset, prs_offset(ps));
692 if (psd->off_grp_sid != 0) {
694 if (UNMARSHALLING(ps)) {
695 /* reading */
696 if(!prs_set_offset(ps, old_offset + psd->off_grp_sid))
697 return False;
698 if((psd->grp_sid = malloc(sizeof(*psd->grp_sid))) == NULL)
699 return False;
700 ZERO_STRUCTP(psd->grp_sid);
703 if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
704 return False;
705 if(!prs_align(ps))
706 return False;
709 max_offset = MAX(max_offset, prs_offset(ps));
711 if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) {
712 if(!prs_set_offset(ps, old_offset + psd->off_sacl))
713 return False;
714 if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
715 return False;
716 if(!prs_align(ps))
717 return False;
720 max_offset = MAX(max_offset, prs_offset(ps));
722 if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) {
723 if(!prs_set_offset(ps, old_offset + psd->off_dacl))
724 return False;
725 if(!sec_io_acl("dacl", &psd->dacl, ps, depth))
726 return False;
727 if(!prs_align(ps))
728 return False;
731 max_offset = MAX(max_offset, prs_offset(ps));
733 if(!prs_set_offset(ps, max_offset))
734 return False;
735 return True;
738 /*******************************************************************
739 Creates a SEC_DESC_BUF structure.
740 ********************************************************************/
742 SEC_DESC_BUF *make_sec_desc_buf(size_t len, SEC_DESC *sec_desc)
744 SEC_DESC_BUF *dst;
746 if((dst = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF))) == NULL)
747 return NULL;
749 ZERO_STRUCTP(dst);
751 /* max buffer size (allocated size) */
752 dst->max_len = (uint32)len;
753 dst->len = (uint32)len;
755 if(sec_desc && ((dst->sec = dup_sec_desc(sec_desc)) == NULL)) {
756 free_sec_desc_buf(&dst);
757 return NULL;
760 return dst;
763 /*******************************************************************
764 Duplicates a SEC_DESC_BUF structure.
765 ********************************************************************/
767 SEC_DESC_BUF *dup_sec_desc_buf(SEC_DESC_BUF *src)
769 if(src == NULL)
770 return NULL;
772 return make_sec_desc_buf( src->len, src->sec);
775 /*******************************************************************
776 Deletes a SEC_DESC_BUF structure.
777 ********************************************************************/
779 void free_sec_desc_buf(SEC_DESC_BUF **ppsdb)
781 SEC_DESC_BUF *psdb;
783 if(ppsdb == NULL || *ppsdb == NULL)
784 return;
786 psdb = *ppsdb;
787 free_sec_desc(&psdb->sec);
788 free(psdb);
789 *ppsdb = NULL;
793 /*******************************************************************
794 Reads or writes a SEC_DESC_BUF structure.
795 ********************************************************************/
797 BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
799 uint32 off_len;
800 uint32 off_max_len;
801 uint32 old_offset;
802 uint32 size;
803 SEC_DESC_BUF *psdb;
805 if (ppsdb == NULL)
806 return False;
808 psdb = *ppsdb;
810 if (UNMARSHALLING(ps) && psdb == NULL) {
811 if((psdb = (SEC_DESC_BUF *)malloc(sizeof(SEC_DESC_BUF))) == NULL)
812 return False;
813 ZERO_STRUCTP(psdb);
814 *ppsdb = psdb;
817 prs_debug(ps, depth, desc, "sec_io_desc_buf");
818 depth++;
820 if(!prs_align(ps))
821 return False;
823 if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len))
824 return False;
826 if(!prs_uint32 ("undoc ", ps, depth, &psdb->undoc))
827 return False;
829 if(!prs_uint32_pre("len ", ps, depth, &psdb->len, &off_len))
830 return False;
832 old_offset = prs_offset(ps);
834 /* reading, length is non-zero; writing, descriptor is non-NULL */
835 if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) {
836 if(!sec_io_desc("sec ", &psdb->sec, ps, depth))
837 return False;
840 if(!prs_align(ps))
841 return False;
843 size = prs_offset(ps) - old_offset;
844 if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size))
845 return False;
847 if(!prs_uint32_post("len ", ps, depth, &psdb->len, off_len, size))
848 return False;
850 return True;