2 * Unix SMB/Netbios implementation.
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.
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.
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)
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)
50 prs_debug(ps, depth, desc, "sec_io_access");
56 if(!prs_uint32("mask", ps, depth, &(t->mask)))
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)
71 t->size = sid_size(sid) + 8;
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)
85 uint32 offset_ace_size;
90 prs_debug(ps, depth, desc, "sec_io_ace");
96 old_offset = prs_offset(ps);
98 if(!prs_uint8("type ", ps, depth, &psa->type))
101 if(!prs_uint8("flags", ps, depth, &psa->flags))
104 if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_ace_size))
107 if(!sec_io_access("info ", &psa->info, ps, depth))
113 if(!smb_io_dom_sid("sid ", &psa->sid , ps, depth))
116 if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_ace_size, old_offset))
122 /*******************************************************************
123 Create a SEC_ACL structure.
124 ********************************************************************/
126 SEC_ACL *make_sec_acl(TALLOC_CTX *ctx, uint16 revision, int num_aces, SEC_ACE *ace_list)
131 if((dst = (SEC_ACL *)talloc_zero(ctx,sizeof(SEC_ACL))) == NULL)
134 dst->revision = revision;
135 dst->num_aces = num_aces;
138 if((dst->ace = (SEC_ACE *)talloc(ctx, sizeof(SEC_ACE) * num_aces )) == NULL) {
142 for (i = 0; i < num_aces; i++) {
143 dst->ace[i] = ace_list[i]; /* Structure copy. */
144 dst->size += ace_list[i].size;
150 /*******************************************************************
151 Duplicate a SEC_ACL structure.
152 ********************************************************************/
154 SEC_ACL *dup_sec_acl(TALLOC_CTX *ctx, SEC_ACL *src)
159 return make_sec_acl(ctx, src->revision, src->num_aces, src->ace);
162 /*******************************************************************
163 Reads or writes a SEC_ACL structure.
165 First of the xx_io_xx functions that allocates its data structures
166 for you as it reads them.
167 ********************************************************************/
169 BOOL sec_io_acl(char *desc, SEC_ACL **ppsa, prs_struct *ps, int depth)
173 uint32 offset_acl_size;
181 if(UNMARSHALLING(ps) && psa == NULL) {
183 * This is a read and we must allocate the stuct to read into.
185 if((psa = (SEC_ACL *)prs_alloc_mem(ps, sizeof(SEC_ACL))) == NULL)
190 prs_debug(ps, depth, desc, "sec_io_acl");
196 old_offset = prs_offset(ps);
198 if(!prs_uint16("revision", ps, depth, &psa->revision))
201 if(!prs_uint16_pre("size ", ps, depth, &psa->size, &offset_acl_size))
204 if(!prs_uint32("num_aces ", ps, depth, &psa->num_aces))
207 if (UNMARSHALLING(ps) && psa->num_aces != 0) {
209 if((psa->ace = (SEC_ACE *)prs_alloc_mem(ps,sizeof(psa->ace[0]) * psa->num_aces)) == NULL)
213 for (i = 0; i < psa->num_aces; i++) {
215 slprintf(tmp, sizeof(tmp)-1, "ace_list[%02d]: ", i);
216 if(!sec_io_ace(tmp, &psa->ace[i], ps, depth))
223 if(!prs_uint16_post("size ", ps, depth, &psa->size, offset_acl_size, old_offset))
229 /*******************************************************************
230 Works out the linearization size of a SEC_DESC.
231 ********************************************************************/
233 size_t sec_desc_size(SEC_DESC *psd)
239 offset = SD_HEADER_SIZE;
241 if (psd->owner_sid != NULL)
242 offset += ((sid_size(psd->owner_sid) + 3) & ~3);
244 if (psd->grp_sid != NULL)
245 offset += ((sid_size(psd->grp_sid) + 3) & ~3);
247 if (psd->sacl != NULL)
248 offset += ((psd->sacl->size + 3) & ~3);
250 if (psd->dacl != NULL)
251 offset += ((psd->dacl->size + 3) & ~3);
256 /*******************************************************************
257 Compares two SEC_ACE structures
258 ********************************************************************/
260 BOOL sec_ace_equal(SEC_ACE *s1, SEC_ACE *s2)
264 if (!s1 && !s2) return True;
266 /* Check top level stuff */
268 if (s1->type != s2->type || s1->flags != s2->flags ||
269 s1->info.mask != s2->info.mask) {
275 if (!sid_equal(&s1->sid, &s2->sid)) {
282 /*******************************************************************
283 Compares two SEC_ACL structures
284 ********************************************************************/
286 BOOL sec_acl_equal(SEC_ACL *s1, SEC_ACL *s2)
292 if (!s1 && !s2) return True;
294 /* Check top level stuff */
296 if (s1->revision != s2->revision) {
297 DEBUG(10, ("sec_acl_equal(): revision differs (%d != %d)\n",
298 s1->revision, s2->revision));
302 if (s1->num_aces != s2->num_aces) {
303 DEBUG(10, ("sec_acl_equal(): num_aces differs (%d != %d)\n",
304 s1->revision, s2->revision));
308 /* The ACEs could be in any order so check each ACE in s1 against
311 for (i = 0; i < s1->num_aces; i++) {
314 for (j = 0; j < s2->num_aces; j++) {
315 if (sec_ace_equal(&s1->ace[i], &s2->ace[j])) {
321 if (!found) return False;
327 /*******************************************************************
328 Compares two SEC_DESC structures
329 ********************************************************************/
331 BOOL sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
339 /* Check top level stuff */
341 if (s1->revision != s2->revision) {
342 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
343 s1->revision, s2->revision));
347 if (s1->type!= s2->type) {
348 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
349 s1->type, s2->type));
353 /* Check owner and group */
355 if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
358 sid_to_string(str1, s1->owner_sid);
359 sid_to_string(str2, s2->owner_sid);
361 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
366 if (!sid_equal(s1->grp_sid, s2->grp_sid)) {
369 sid_to_string(str1, s1->grp_sid);
370 sid_to_string(str2, s2->grp_sid);
372 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
377 /* Check ACLs present in one but not the other */
379 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
380 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
381 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
385 /* Sigh - we have to do it the hard way by iterating over all
386 the ACEs in the ACLs */
388 if (!sec_acl_equal(s1->dacl, s2->dacl) ||
389 !sec_acl_equal(s1->sacl, s2->sacl)) {
390 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
395 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
399 /*******************************************************************
400 Merge part of security descriptor old_sec in to the empty sections of
401 security descriptor new_sec.
402 ********************************************************************/
404 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
406 DOM_SID *owner_sid, *group_sid;
407 SEC_DESC_BUF *return_sdb;
408 SEC_ACL *dacl, *sacl;
409 SEC_DESC *psd = NULL;
413 /* Copy over owner and group sids. There seems to be no flag for
414 this so just check the pointer values. */
416 owner_sid = new_sdb->sec->owner_sid ? new_sdb->sec->owner_sid :
417 old_sdb->sec->owner_sid;
419 group_sid = new_sdb->sec->grp_sid ? new_sdb->sec->grp_sid :
420 old_sdb->sec->grp_sid;
422 secdesc_type = new_sdb->sec->type;
424 /* Ignore changes to the system ACL. This has the effect of making
425 changes through the security tab audit button not sticking.
426 Perhaps in future Samba could implement these settings somehow. */
429 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
431 /* Copy across discretionary ACL */
433 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
434 dacl = new_sdb->sec->dacl;
436 dacl = old_sdb->sec->dacl;
439 /* Create new security descriptor from bits */
441 psd = make_sec_desc(ctx, new_sdb->sec->revision,
442 owner_sid, group_sid, sacl, dacl, &secdesc_size);
444 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
449 /*******************************************************************
450 Tallocs a duplicate SID.
451 ********************************************************************/
453 static DOM_SID *sid_dup_talloc(TALLOC_CTX *ctx, DOM_SID *src)
460 if((dst = talloc_zero(ctx, sizeof(DOM_SID))) != NULL) {
467 /*******************************************************************
468 Creates a SEC_DESC structure
469 ********************************************************************/
471 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision,
472 DOM_SID *owner_sid, DOM_SID *grp_sid,
473 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
480 if(( dst = (SEC_DESC *)talloc_zero(ctx, sizeof(SEC_DESC))) == NULL)
483 dst->revision = revision;
484 dst->type = SEC_DESC_SELF_RELATIVE;
486 if (sacl) dst->type |= SEC_DESC_SACL_PRESENT;
487 if (dacl) dst->type |= SEC_DESC_DACL_PRESENT;
489 dst->off_owner_sid = 0;
490 dst->off_grp_sid = 0;
494 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(ctx,owner_sid)) == NULL))
497 if(grp_sid && ((dst->grp_sid = sid_dup_talloc(ctx,grp_sid)) == NULL))
500 if(sacl && ((dst->sacl = dup_sec_acl(ctx, sacl)) == NULL))
503 if(dacl && ((dst->dacl = dup_sec_acl(ctx, dacl)) == NULL))
509 * Work out the linearization sizes.
512 if (dst->owner_sid != NULL) {
515 offset = SD_HEADER_SIZE;
517 dst->off_owner_sid = offset;
518 offset += ((sid_size(dst->owner_sid) + 3) & ~3);
521 if (dst->grp_sid != NULL) {
524 offset = SD_HEADER_SIZE;
526 dst->off_grp_sid = offset;
527 offset += ((sid_size(dst->grp_sid) + 3) & ~3);
530 if (dst->sacl != NULL) {
533 offset = SD_HEADER_SIZE;
535 dst->off_sacl = offset;
536 offset += ((sacl->size + 3) & ~3);
539 if (dst->dacl != NULL) {
542 offset = SD_HEADER_SIZE;
544 dst->off_dacl = offset;
545 offset += ((dacl->size + 3) & ~3);
548 *sd_size = (size_t)((offset == 0) ? SD_HEADER_SIZE : offset);
557 /*******************************************************************
558 Duplicate a SEC_DESC structure.
559 ********************************************************************/
561 SEC_DESC *dup_sec_desc( TALLOC_CTX *ctx, SEC_DESC *src)
568 return make_sec_desc( ctx, src->revision,
569 src->owner_sid, src->grp_sid, src->sacl,
573 /*******************************************************************
574 Creates a SEC_DESC structure with typical defaults.
575 ********************************************************************/
577 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, DOM_SID *owner_sid, DOM_SID *grp_sid,
578 SEC_ACL *dacl, size_t *sd_size)
580 return make_sec_desc(ctx, SEC_DESC_REVISION,
581 owner_sid, grp_sid, NULL, dacl, sd_size);
584 /*******************************************************************
585 Reads or writes a SEC_DESC structure.
586 If reading and the *ppsd = NULL, allocates the structure.
587 ********************************************************************/
589 BOOL sec_io_desc(char *desc, SEC_DESC **ppsd, prs_struct *ps, int depth)
592 uint32 max_offset = 0; /* after we're done, move offset to end */
601 if(UNMARSHALLING(ps)) {
602 if((psd = (SEC_DESC *)prs_alloc_mem(ps,sizeof(SEC_DESC))) == NULL)
606 /* Marshalling - just ignore. */
611 prs_debug(ps, depth, desc, "sec_io_desc");
617 /* start of security descriptor stored for back-calc offset purposes */
618 old_offset = prs_offset(ps);
620 if(!prs_uint16("revision ", ps, depth, &psd->revision))
623 if(!prs_uint16("type ", ps, depth, &psd->type))
626 if(!prs_uint32("off_owner_sid", ps, depth, &psd->off_owner_sid))
629 if(!prs_uint32("off_grp_sid ", ps, depth, &psd->off_grp_sid))
632 if(!prs_uint32("off_sacl ", ps, depth, &psd->off_sacl))
635 if(!prs_uint32("off_dacl ", ps, depth, &psd->off_dacl))
638 max_offset = MAX(max_offset, prs_offset(ps));
640 if (psd->off_owner_sid != 0) {
642 if (UNMARSHALLING(ps)) {
643 if(!prs_set_offset(ps, old_offset + psd->off_owner_sid))
646 if((psd->owner_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->owner_sid))) == NULL)
650 if(!smb_io_dom_sid("owner_sid ", psd->owner_sid , ps, depth))
656 max_offset = MAX(max_offset, prs_offset(ps));
658 if (psd->off_grp_sid != 0) {
660 if (UNMARSHALLING(ps)) {
662 if(!prs_set_offset(ps, old_offset + psd->off_grp_sid))
664 if((psd->grp_sid = (DOM_SID *)prs_alloc_mem(ps,sizeof(*psd->grp_sid))) == NULL)
668 if(!smb_io_dom_sid("grp_sid", psd->grp_sid, ps, depth))
674 max_offset = MAX(max_offset, prs_offset(ps));
676 if ((psd->type & SEC_DESC_SACL_PRESENT) && psd->off_sacl) {
677 if(!prs_set_offset(ps, old_offset + psd->off_sacl))
679 if(!sec_io_acl("sacl", &psd->sacl, ps, depth))
685 max_offset = MAX(max_offset, prs_offset(ps));
687 if ((psd->type & SEC_DESC_DACL_PRESENT) && psd->off_dacl != 0) {
688 if(!prs_set_offset(ps, old_offset + psd->off_dacl))
690 if(!sec_io_acl("dacl", &psd->dacl, ps, depth))
696 max_offset = MAX(max_offset, prs_offset(ps));
698 if(!prs_set_offset(ps, max_offset))
703 /*******************************************************************
704 Creates a SEC_DESC_BUF structure.
705 ********************************************************************/
707 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
711 if((dst = (SEC_DESC_BUF *)talloc_zero(ctx, sizeof(SEC_DESC_BUF))) == NULL)
714 /* max buffer size (allocated size) */
715 dst->max_len = (uint32)len;
716 dst->len = (uint32)len;
718 if(sec_desc && ((dst->sec = dup_sec_desc(ctx, sec_desc)) == NULL)) {
727 /*******************************************************************
728 Duplicates a SEC_DESC_BUF structure.
729 ********************************************************************/
731 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
736 return make_sec_desc_buf( ctx, src->len, src->sec);
739 /*******************************************************************
740 Reads or writes a SEC_DESC_BUF structure.
741 ********************************************************************/
743 BOOL sec_io_desc_buf(char *desc, SEC_DESC_BUF **ppsdb, prs_struct *ps, int depth)
756 if (UNMARSHALLING(ps) && psdb == NULL) {
757 if((psdb = (SEC_DESC_BUF *)prs_alloc_mem(ps,sizeof(SEC_DESC_BUF))) == NULL)
762 prs_debug(ps, depth, desc, "sec_io_desc_buf");
768 if(!prs_uint32_pre("max_len", ps, depth, &psdb->max_len, &off_max_len))
771 if(!prs_uint32 ("ptr ", ps, depth, &psdb->ptr))
774 if(!prs_uint32_pre("len ", ps, depth, &psdb->len, &off_len))
777 old_offset = prs_offset(ps);
779 /* reading, length is non-zero; writing, descriptor is non-NULL */
780 if ((UNMARSHALLING(ps) && psdb->len != 0) || (MARSHALLING(ps) && psdb->sec != NULL)) {
781 if(!sec_io_desc("sec ", &psdb->sec, ps, depth))
788 size = prs_offset(ps) - old_offset;
789 if(!prs_uint32_post("max_len", ps, depth, &psdb->max_len, off_max_len, size == 0 ? psdb->max_len : size))
792 if(!prs_uint32_post("len ", ps, depth, &psdb->len, off_len, size))