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.
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
)
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
)
47 prs_debug(ps
, depth
, desc
, "sec_io_access");
50 if(!prs_uint32("mask", ps
, depth
, &(t
->mask
)))
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
)
65 t
->size
= sid_size(sid
) + 8;
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
)
79 uint32 offset_ace_size
;
84 prs_debug(ps
, depth
, desc
, "sec_io_ace");
87 old_offset
= prs_offset(ps
);
89 if(!prs_uint8("type ", ps
, depth
, &psa
->type
))
92 if(!prs_uint8("flags", ps
, depth
, &psa
->flags
))
95 if(!prs_uint16_pre("size ", ps
, depth
, &psa
->size
, &offset_ace_size
))
98 if(!sec_io_access("info ", &psa
->info
, ps
, depth
))
101 if(!smb_io_dom_sid("sid ", &psa
->trustee
, ps
, depth
))
104 if(!prs_uint16_post("size ", ps
, depth
, &psa
->size
, offset_ace_size
, old_offset
))
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
)
119 if((dst
= (SEC_ACL
*)talloc_zero(ctx
,sizeof(SEC_ACL
))) == NULL
)
122 dst
->revision
= revision
;
123 dst
->num_aces
= num_aces
;
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
133 ((dst
->ace
= (SEC_ACE
*)talloc(ctx
, sizeof(SEC_ACE
) * num_aces
))
138 for (i
= 0; i
< num_aces
; i
++) {
139 dst
->ace
[i
] = ace_list
[i
]; /* Structure copy. */
140 dst
->size
+= ace_list
[i
].size
;
146 /*******************************************************************
147 Duplicate a SEC_ACL structure.
148 ********************************************************************/
150 SEC_ACL
*dup_sec_acl(TALLOC_CTX
*ctx
, SEC_ACL
*src
)
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
)
169 uint32 offset_acl_size
;
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
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
)
193 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
)) {
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
213 if((psa
->ace
= (SEC_ACE
*)prs_alloc_mem(ps
,sizeof(psa
->ace
[0]) * (psa
->num_aces
+1))) == NULL
)
217 for (i
= 0; i
< psa
->num_aces
; i
++) {
219 slprintf(tmp
, sizeof(tmp
)-1, "ace_list[%02d]: ", i
);
220 if(!sec_io_ace(tmp
, &psa
->ace
[i
], ps
, depth
))
224 if(!prs_uint16_post("size ", ps
, depth
, &psa
->size
, offset_acl_size
, old_offset
))
230 /*******************************************************************
231 Works out the linearization size of a SEC_DESC.
232 ********************************************************************/
234 size_t sec_desc_size(SEC_DESC
*psd
)
240 offset
= SD_HEADER_SIZE
;
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
;
259 /*******************************************************************
260 Compares two SEC_ACE structures
261 ********************************************************************/
263 BOOL
sec_ace_equal(SEC_ACE
*s1
, SEC_ACE
*s2
)
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
) {
278 if (!sid_equal(&s1
->trustee
, &s2
->trustee
)) {
285 /*******************************************************************
286 Compares two SEC_ACL structures
287 ********************************************************************/
289 BOOL
sec_acl_equal(SEC_ACL
*s1
, SEC_ACL
*s2
)
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
));
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
));
312 /* The ACEs could be in any order so check each ACE in s1 against
315 for (i
= 0; i
< s1
->num_aces
; i
++) {
318 for (j
= 0; j
< s2
->num_aces
; j
++) {
319 if (sec_ace_equal(&s1
->ace
[i
], &s2
->ace
[j
])) {
325 if (!found
) return False
;
331 /*******************************************************************
332 Compares two SEC_DESC structures
333 ********************************************************************/
335 BOOL
sec_desc_equal(SEC_DESC
*s1
, SEC_DESC
*s2
)
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
));
351 if (s1
->type
!= s2
->type
) {
352 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
353 s1
->type
, s2
->type
));
357 /* Check owner and group */
359 if (!sid_equal(s1
->owner_sid
, s2
->owner_sid
)) {
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",
370 if (!sid_equal(s1
->grp_sid
, s2
->grp_sid
)) {
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",
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"));
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"));
399 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
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
;
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. */
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
;
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
);
453 /*******************************************************************
454 Tallocs a duplicate SID.
455 ********************************************************************/
457 static DOM_SID
*sid_dup_talloc(TALLOC_CTX
*ctx
, DOM_SID
*src
)
464 if((dst
= talloc_zero(ctx
, sizeof(DOM_SID
))) != NULL
) {
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
)
484 if(( dst
= (SEC_DESC
*)talloc_zero(ctx
, sizeof(SEC_DESC
))) == 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;
498 if(owner_sid
&& ((dst
->owner_sid
= sid_dup_talloc(ctx
,owner_sid
)) == NULL
))
501 if(grp_sid
&& ((dst
->grp_sid
= sid_dup_talloc(ctx
,grp_sid
)) == NULL
))
504 if(sacl
&& ((dst
->sacl
= dup_sec_acl(ctx
, sacl
)) == NULL
))
507 if(dacl
&& ((dst
->dacl
= dup_sec_acl(ctx
, dacl
)) == NULL
))
513 * Work out the linearization sizes.
516 if (dst
->owner_sid
!= NULL
) {
519 offset
= SD_HEADER_SIZE
;
521 dst
->off_owner_sid
= offset
;
522 offset
+= sid_size(dst
->owner_sid
);
525 if (dst
->grp_sid
!= NULL
) {
528 offset
= SD_HEADER_SIZE
;
530 dst
->off_grp_sid
= offset
;
531 offset
+= sid_size(dst
->grp_sid
);
534 if (dst
->sacl
!= NULL
) {
537 offset
= SD_HEADER_SIZE
;
539 dst
->off_sacl
= offset
;
540 offset
+= dst
->sacl
->size
;
543 if (dst
->dacl
!= NULL
) {
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
);
561 /*******************************************************************
562 Duplicate a SEC_DESC structure.
563 ********************************************************************/
565 SEC_DESC
*dup_sec_desc( TALLOC_CTX
*ctx
, SEC_DESC
*src
)
572 return make_sec_desc( ctx
, src
->revision
,
573 src
->owner_sid
, src
->grp_sid
, src
->sacl
,
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
)
596 uint32 max_offset
= 0; /* after we're done, move offset to end */
597 uint32 tmp_offset
= 0;
606 if(UNMARSHALLING(ps
)) {
607 if((psd
= (SEC_DESC
*)prs_alloc_mem(ps
,sizeof(SEC_DESC
))) == NULL
)
611 /* Marshalling - just ignore. */
616 prs_debug(ps
, depth
, desc
, "sec_io_desc");
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
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
))
635 if(!prs_uint16("type ", ps
, depth
, &psd
->type
))
638 if(!prs_uint32("off_owner_sid", ps
, depth
, &psd
->off_owner_sid
))
641 if(!prs_uint32("off_grp_sid ", ps
, depth
, &psd
->off_grp_sid
))
644 if(!prs_uint32("off_sacl ", ps
, depth
, &psd
->off_sacl
))
647 if(!prs_uint32("off_dacl ", ps
, depth
, &psd
->off_dacl
))
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
))
658 if (UNMARSHALLING(ps
)) {
660 if((psd
->owner_sid
= (DOM_SID
*)prs_alloc_mem(ps
,sizeof(*psd
->owner_sid
))) == NULL
)
664 if(!smb_io_dom_sid("owner_sid ", psd
->owner_sid
, ps
, depth
))
667 max_offset
= MAX(max_offset
, prs_offset(ps
));
669 if (!prs_set_offset(ps
,tmp_offset
))
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
))
679 if (UNMARSHALLING(ps
)) {
681 if((psd
->grp_sid
= (DOM_SID
*)prs_alloc_mem(ps
,sizeof(*psd
->grp_sid
))) == NULL
)
685 if(!smb_io_dom_sid("grp_sid", psd
->grp_sid
, ps
, depth
))
688 max_offset
= MAX(max_offset
, prs_offset(ps
));
690 if (!prs_set_offset(ps
,tmp_offset
))
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
))
698 if(!sec_io_acl("sacl", &psd
->sacl
, ps
, depth
))
700 max_offset
= MAX(max_offset
, prs_offset(ps
));
701 if (!prs_set_offset(ps
,tmp_offset
))
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
))
709 if(!sec_io_acl("dacl", &psd
->dacl
, ps
, depth
))
711 max_offset
= MAX(max_offset
, prs_offset(ps
));
712 if (!prs_set_offset(ps
,tmp_offset
))
716 if(!prs_set_offset(ps
, max_offset
))
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
)
729 if((dst
= (SEC_DESC_BUF
*)talloc_zero(ctx
, sizeof(SEC_DESC_BUF
))) == 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
)) {
745 /*******************************************************************
746 Duplicates a SEC_DESC_BUF structure.
747 ********************************************************************/
749 SEC_DESC_BUF
*dup_sec_desc_buf(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*src
)
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
)
774 if (UNMARSHALLING(ps
) && psdb
== NULL
) {
775 if((psdb
= (SEC_DESC_BUF
*)prs_alloc_mem(ps
,sizeof(SEC_DESC_BUF
))) == NULL
)
780 prs_debug(ps
, depth
, desc
, "sec_io_desc_buf");
786 if(!prs_uint32_pre("max_len", ps
, depth
, &psdb
->max_len
, &off_max_len
))
789 if(!prs_uint32 ("ptr ", ps
, depth
, &psdb
->ptr
))
792 if(!prs_uint32_pre("len ", ps
, depth
, &psdb
->len
, &off_len
))
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
))
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
))
810 if(!prs_uint32_post("len ", ps
, depth
, &psdb
->len
, off_len
, size
))