2 * Unix SMB/Netbios implementation.
3 * SEC_DESC handling functions
4 * Copyright (C) Andrew Tridgell 1992-1998,
5 * Copyright (C) Jeremy R. Allison 1995-2003.
6 * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
7 * Copyright (C) Paul Ashton 1997-1998.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
25 /* Map generic permissions to file object specific permissions */
27 const struct generic_mapping file_generic_mapping
= {
34 /*******************************************************************
35 Works out the linearization size of a SEC_DESC.
36 ********************************************************************/
38 size_t sec_desc_size(SEC_DESC
*psd
)
44 offset
= SEC_DESC_HEADER_SIZE
;
48 if (psd
->owner_sid
!= NULL
)
49 offset
+= sid_size(psd
->owner_sid
);
51 if (psd
->group_sid
!= NULL
)
52 offset
+= sid_size(psd
->group_sid
);
54 if (psd
->sacl
!= NULL
)
55 offset
+= psd
->sacl
->size
;
57 if (psd
->dacl
!= NULL
)
58 offset
+= psd
->dacl
->size
;
63 /*******************************************************************
64 Compares two SEC_DESC structures
65 ********************************************************************/
67 bool sec_desc_equal(SEC_DESC
*s1
, SEC_DESC
*s2
)
79 /* Check top level stuff */
81 if (s1
->revision
!= s2
->revision
) {
82 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
83 s1
->revision
, s2
->revision
));
87 if (s1
->type
!= s2
->type
) {
88 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
93 /* Check owner and group */
95 if (!sid_equal(s1
->owner_sid
, s2
->owner_sid
)) {
96 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
97 sid_string_dbg(s1
->owner_sid
),
98 sid_string_dbg(s2
->owner_sid
)));
102 if (!sid_equal(s1
->group_sid
, s2
->group_sid
)) {
103 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
104 sid_string_dbg(s1
->group_sid
),
105 sid_string_dbg(s2
->group_sid
)));
109 /* Check ACLs present in one but not the other */
111 if ((s1
->dacl
&& !s2
->dacl
) || (!s1
->dacl
&& s2
->dacl
) ||
112 (s1
->sacl
&& !s2
->sacl
) || (!s1
->sacl
&& s2
->sacl
)) {
113 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
117 /* Sigh - we have to do it the hard way by iterating over all
118 the ACEs in the ACLs */
120 if (!sec_acl_equal(s1
->dacl
, s2
->dacl
) ||
121 !sec_acl_equal(s1
->sacl
, s2
->sacl
)) {
122 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
127 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
131 /*******************************************************************
132 Merge part of security descriptor old_sec in to the empty sections of
133 security descriptor new_sec.
134 ********************************************************************/
136 SEC_DESC_BUF
*sec_desc_merge(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*new_sdb
, SEC_DESC_BUF
*old_sdb
)
138 DOM_SID
*owner_sid
, *group_sid
;
139 SEC_DESC_BUF
*return_sdb
;
140 SEC_ACL
*dacl
, *sacl
;
141 SEC_DESC
*psd
= NULL
;
145 /* Copy over owner and group sids. There seems to be no flag for
146 this so just check the pointer values. */
148 owner_sid
= new_sdb
->sd
->owner_sid
? new_sdb
->sd
->owner_sid
:
149 old_sdb
->sd
->owner_sid
;
151 group_sid
= new_sdb
->sd
->group_sid
? new_sdb
->sd
->group_sid
:
152 old_sdb
->sd
->group_sid
;
154 secdesc_type
= new_sdb
->sd
->type
;
156 /* Ignore changes to the system ACL. This has the effect of making
157 changes through the security tab audit button not sticking.
158 Perhaps in future Samba could implement these settings somehow. */
161 secdesc_type
&= ~SEC_DESC_SACL_PRESENT
;
163 /* Copy across discretionary ACL */
165 if (secdesc_type
& SEC_DESC_DACL_PRESENT
) {
166 dacl
= new_sdb
->sd
->dacl
;
168 dacl
= old_sdb
->sd
->dacl
;
171 /* Create new security descriptor from bits */
173 psd
= make_sec_desc(ctx
, new_sdb
->sd
->revision
, secdesc_type
,
174 owner_sid
, group_sid
, sacl
, dacl
, &secdesc_size
);
176 return_sdb
= make_sec_desc_buf(ctx
, secdesc_size
, psd
);
181 /*******************************************************************
182 Creates a SEC_DESC structure
183 ********************************************************************/
185 SEC_DESC
*make_sec_desc(TALLOC_CTX
*ctx
,
186 enum security_descriptor_revision revision
,
188 const DOM_SID
*owner_sid
, const DOM_SID
*grp_sid
,
189 SEC_ACL
*sacl
, SEC_ACL
*dacl
, size_t *sd_size
)
196 if(( dst
= TALLOC_ZERO_P(ctx
, SEC_DESC
)) == NULL
)
199 dst
->revision
= revision
;
203 dst
->type
|= SEC_DESC_SACL_PRESENT
;
205 dst
->type
|= SEC_DESC_DACL_PRESENT
;
207 dst
->owner_sid
= NULL
;
208 dst
->group_sid
= NULL
;
212 if(owner_sid
&& ((dst
->owner_sid
= sid_dup_talloc(dst
,owner_sid
)) == NULL
))
215 if(grp_sid
&& ((dst
->group_sid
= sid_dup_talloc(dst
,grp_sid
)) == NULL
))
218 if(sacl
&& ((dst
->sacl
= dup_sec_acl(dst
, sacl
)) == NULL
))
221 if(dacl
&& ((dst
->dacl
= dup_sec_acl(dst
, dacl
)) == NULL
))
224 offset
= SEC_DESC_HEADER_SIZE
;
227 * Work out the linearization sizes.
230 if (dst
->sacl
!= NULL
) {
231 offset
+= dst
->sacl
->size
;
233 if (dst
->dacl
!= NULL
) {
234 offset
+= dst
->dacl
->size
;
237 if (dst
->owner_sid
!= NULL
) {
238 offset
+= sid_size(dst
->owner_sid
);
241 if (dst
->group_sid
!= NULL
) {
242 offset
+= sid_size(dst
->group_sid
);
245 *sd_size
= (size_t)offset
;
254 /*******************************************************************
255 Duplicate a SEC_DESC structure.
256 ********************************************************************/
258 SEC_DESC
*dup_sec_desc(TALLOC_CTX
*ctx
, const SEC_DESC
*src
)
265 return make_sec_desc( ctx
, src
->revision
, src
->type
,
266 src
->owner_sid
, src
->group_sid
, src
->sacl
,
270 /*******************************************************************
271 Convert a secdesc into a byte stream
272 ********************************************************************/
273 NTSTATUS
marshall_sec_desc(TALLOC_CTX
*mem_ctx
,
274 struct security_descriptor
*secdesc
,
275 uint8
**data
, size_t *len
)
279 if (!prs_init(&ps
, sec_desc_size(secdesc
), mem_ctx
, MARSHALL
)) {
280 return NT_STATUS_NO_MEMORY
;
283 if (!sec_io_desc("security_descriptor", &secdesc
, &ps
, 1)) {
285 return NT_STATUS_INVALID_PARAMETER
;
288 if (!(*data
= (uint8
*)talloc_memdup(mem_ctx
, ps
.data_p
,
291 return NT_STATUS_NO_MEMORY
;
294 *len
= prs_offset(&ps
);
299 /*******************************************************************
300 Parse a byte stream into a secdesc
301 ********************************************************************/
302 NTSTATUS
unmarshall_sec_desc(TALLOC_CTX
*mem_ctx
, uint8
*data
, size_t len
,
303 struct security_descriptor
**psecdesc
)
306 struct security_descriptor
*secdesc
= NULL
;
308 if (!(secdesc
= TALLOC_ZERO_P(mem_ctx
, struct security_descriptor
))) {
309 return NT_STATUS_NO_MEMORY
;
312 if (!prs_init(&ps
, 0, secdesc
, UNMARSHALL
)) {
313 return NT_STATUS_NO_MEMORY
;
316 prs_give_memory(&ps
, (char *)data
, len
, False
);
318 if (!sec_io_desc("security_descriptor", &secdesc
, &ps
, 1)) {
319 return NT_STATUS_INVALID_PARAMETER
;
327 /*******************************************************************
328 Creates a SEC_DESC structure with typical defaults.
329 ********************************************************************/
331 SEC_DESC
*make_standard_sec_desc(TALLOC_CTX
*ctx
, const DOM_SID
*owner_sid
, const DOM_SID
*grp_sid
,
332 SEC_ACL
*dacl
, size_t *sd_size
)
334 return make_sec_desc(ctx
, SECURITY_DESCRIPTOR_REVISION_1
,
335 SEC_DESC_SELF_RELATIVE
, owner_sid
, grp_sid
, NULL
,
339 /*******************************************************************
340 Creates a SEC_DESC_BUF structure.
341 ********************************************************************/
343 SEC_DESC_BUF
*make_sec_desc_buf(TALLOC_CTX
*ctx
, size_t len
, SEC_DESC
*sec_desc
)
347 if((dst
= TALLOC_ZERO_P(ctx
, SEC_DESC_BUF
)) == NULL
)
350 /* max buffer size (allocated size) */
351 dst
->sd_size
= (uint32
)len
;
353 if(sec_desc
&& ((dst
->sd
= dup_sec_desc(ctx
, sec_desc
)) == NULL
)) {
360 /*******************************************************************
361 Duplicates a SEC_DESC_BUF structure.
362 ********************************************************************/
364 SEC_DESC_BUF
*dup_sec_desc_buf(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*src
)
369 return make_sec_desc_buf( ctx
, src
->sd_size
, src
->sd
);
372 /*******************************************************************
373 Add a new SID with its permissions to SEC_DESC.
374 ********************************************************************/
376 NTSTATUS
sec_desc_add_sid(TALLOC_CTX
*ctx
, SEC_DESC
**psd
, DOM_SID
*sid
, uint32 mask
, size_t *sd_size
)
383 if (!ctx
|| !psd
|| !sid
|| !sd_size
)
384 return NT_STATUS_INVALID_PARAMETER
;
388 status
= sec_ace_add_sid(ctx
, &ace
, psd
[0]->dacl
->aces
, &psd
[0]->dacl
->num_aces
, sid
, mask
);
390 if (!NT_STATUS_IS_OK(status
))
393 if (!(dacl
= make_sec_acl(ctx
, psd
[0]->dacl
->revision
, psd
[0]->dacl
->num_aces
, ace
)))
394 return NT_STATUS_UNSUCCESSFUL
;
396 if (!(sd
= make_sec_desc(ctx
, psd
[0]->revision
, psd
[0]->type
, psd
[0]->owner_sid
,
397 psd
[0]->group_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
398 return NT_STATUS_UNSUCCESSFUL
;
405 /*******************************************************************
406 Modify a SID's permissions in a SEC_DESC.
407 ********************************************************************/
409 NTSTATUS
sec_desc_mod_sid(SEC_DESC
*sd
, DOM_SID
*sid
, uint32 mask
)
414 return NT_STATUS_INVALID_PARAMETER
;
416 status
= sec_ace_mod_sid(sd
->dacl
->aces
, sd
->dacl
->num_aces
, sid
, mask
);
418 if (!NT_STATUS_IS_OK(status
))
424 /*******************************************************************
425 Delete a SID from a SEC_DESC.
426 ********************************************************************/
428 NTSTATUS
sec_desc_del_sid(TALLOC_CTX
*ctx
, SEC_DESC
**psd
, DOM_SID
*sid
, size_t *sd_size
)
435 if (!ctx
|| !psd
[0] || !sid
|| !sd_size
)
436 return NT_STATUS_INVALID_PARAMETER
;
440 status
= sec_ace_del_sid(ctx
, &ace
, psd
[0]->dacl
->aces
, &psd
[0]->dacl
->num_aces
, sid
);
442 if (!NT_STATUS_IS_OK(status
))
445 if (!(dacl
= make_sec_acl(ctx
, psd
[0]->dacl
->revision
, psd
[0]->dacl
->num_aces
, ace
)))
446 return NT_STATUS_UNSUCCESSFUL
;
448 if (!(sd
= make_sec_desc(ctx
, psd
[0]->revision
, psd
[0]->type
, psd
[0]->owner_sid
,
449 psd
[0]->group_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
450 return NT_STATUS_UNSUCCESSFUL
;
457 /* Create a child security descriptor using another security descriptor as
458 the parent container. This child object can either be a container or
459 non-container object. */
461 SEC_DESC_BUF
*se_create_child_secdesc(TALLOC_CTX
*ctx
, SEC_DESC
*parent_ctr
,
462 bool child_container
)
466 SEC_ACL
*new_dacl
, *the_acl
;
467 SEC_ACE
*new_ace_list
= NULL
;
468 unsigned int new_ace_list_ndx
= 0, i
;
471 /* Currently we only process the dacl when creating the child. The
472 sacl should also be processed but this is left out as sacls are
473 not implemented in Samba at the moment.*/
475 the_acl
= parent_ctr
->dacl
;
477 if (the_acl
->num_aces
) {
478 if (!(new_ace_list
= TALLOC_ARRAY(ctx
, SEC_ACE
, the_acl
->num_aces
)))
484 for (i
= 0; i
< the_acl
->num_aces
; i
++) {
485 SEC_ACE
*ace
= &the_acl
->aces
[i
];
486 SEC_ACE
*new_ace
= &new_ace_list
[new_ace_list_ndx
];
488 bool inherit
= False
;
490 /* The OBJECT_INHERIT_ACE flag causes the ACE to be
491 inherited by non-container children objects. Container
492 children objects will inherit it as an INHERIT_ONLY
495 if (ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) {
497 if (!child_container
) {
498 new_flags
|= SEC_ACE_FLAG_OBJECT_INHERIT
;
500 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
506 /* The CONAINER_INHERIT_ACE flag means all child container
507 objects will inherit and use the ACE. */
509 if (ace
->flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
) {
510 if (!child_container
) {
513 new_flags
|= SEC_ACE_FLAG_CONTAINER_INHERIT
;
517 /* The INHERIT_ONLY_ACE is not used by the se_access_check()
518 function for the parent container, but is inherited by
519 all child objects as a normal ACE. */
521 if (ace
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
522 /* Move along, nothing to see here */
525 /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
526 is inherited by child objects but not grandchildren
527 objects. We clear the object inherit and container
528 inherit flags in the inherited ACE. */
530 if (ace
->flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
) {
531 new_flags
&= ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
532 SEC_ACE_FLAG_CONTAINER_INHERIT
);
535 /* Add ACE to ACE list */
540 init_sec_access(&new_ace
->access_mask
, ace
->access_mask
);
541 init_sec_ace(new_ace
, &ace
->trustee
, ace
->type
,
542 new_ace
->access_mask
, new_flags
);
544 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
545 " inherited as %s:%d/0x%02x/0x%08x\n",
546 sid_string_dbg(&ace
->trustee
),
547 ace
->type
, ace
->flags
, ace
->access_mask
,
548 sid_string_dbg(&ace
->trustee
),
549 new_ace
->type
, new_ace
->flags
,
550 new_ace
->access_mask
));
555 /* Create child security descriptor to return */
557 new_dacl
= make_sec_acl(ctx
, ACL_REVISION
, new_ace_list_ndx
, new_ace_list
);
559 /* Use the existing user and group sids. I don't think this is
560 correct. Perhaps the user and group should be passed in as
561 parameters by the caller? */
563 sd
= make_sec_desc(ctx
, SECURITY_DESCRIPTOR_REVISION_1
,
564 SEC_DESC_SELF_RELATIVE
,
565 parent_ctr
->owner_sid
,
566 parent_ctr
->group_sid
,
570 sdb
= make_sec_desc_buf(ctx
, size
, sd
);
575 /*******************************************************************
576 Sets up a SEC_ACCESS structure.
577 ********************************************************************/
579 void init_sec_access(uint32
*t
, uint32 mask
)