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 Given a security_descriptor return the sec_info.
36 ********************************************************************/
38 uint32_t get_sec_info(const SEC_DESC
*sd
)
40 uint32_t sec_info
= ALL_SECURITY_INFORMATION
;
44 if (sd
->owner_sid
== NULL
) {
45 sec_info
&= ~OWNER_SECURITY_INFORMATION
;
47 if (sd
->group_sid
== NULL
) {
48 sec_info
&= ~GROUP_SECURITY_INFORMATION
;
50 if (sd
->sacl
== NULL
) {
51 sec_info
&= ~SACL_SECURITY_INFORMATION
;
53 if (sd
->dacl
== NULL
) {
54 sec_info
&= ~DACL_SECURITY_INFORMATION
;
61 /*******************************************************************
62 Merge part of security descriptor old_sec in to the empty sections of
63 security descriptor new_sec.
64 ********************************************************************/
66 SEC_DESC_BUF
*sec_desc_merge(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*new_sdb
, SEC_DESC_BUF
*old_sdb
)
68 DOM_SID
*owner_sid
, *group_sid
;
69 SEC_DESC_BUF
*return_sdb
;
75 /* Copy over owner and group sids. There seems to be no flag for
76 this so just check the pointer values. */
78 owner_sid
= new_sdb
->sd
->owner_sid
? new_sdb
->sd
->owner_sid
:
79 old_sdb
->sd
->owner_sid
;
81 group_sid
= new_sdb
->sd
->group_sid
? new_sdb
->sd
->group_sid
:
82 old_sdb
->sd
->group_sid
;
84 secdesc_type
= new_sdb
->sd
->type
;
86 /* Ignore changes to the system ACL. This has the effect of making
87 changes through the security tab audit button not sticking.
88 Perhaps in future Samba could implement these settings somehow. */
91 secdesc_type
&= ~SEC_DESC_SACL_PRESENT
;
93 /* Copy across discretionary ACL */
95 if (secdesc_type
& SEC_DESC_DACL_PRESENT
) {
96 dacl
= new_sdb
->sd
->dacl
;
98 dacl
= old_sdb
->sd
->dacl
;
101 /* Create new security descriptor from bits */
103 psd
= make_sec_desc(ctx
, new_sdb
->sd
->revision
, secdesc_type
,
104 owner_sid
, group_sid
, sacl
, dacl
, &secdesc_size
);
106 return_sdb
= make_sec_desc_buf(ctx
, secdesc_size
, psd
);
111 /*******************************************************************
112 Creates a SEC_DESC structure
113 ********************************************************************/
115 SEC_DESC
*make_sec_desc(TALLOC_CTX
*ctx
,
116 enum security_descriptor_revision revision
,
118 const DOM_SID
*owner_sid
, const DOM_SID
*grp_sid
,
119 SEC_ACL
*sacl
, SEC_ACL
*dacl
, size_t *sd_size
)
126 if(( dst
= TALLOC_ZERO_P(ctx
, SEC_DESC
)) == NULL
)
129 dst
->revision
= revision
;
133 dst
->type
|= SEC_DESC_SACL_PRESENT
;
135 dst
->type
|= SEC_DESC_DACL_PRESENT
;
137 dst
->owner_sid
= NULL
;
138 dst
->group_sid
= NULL
;
142 if(owner_sid
&& ((dst
->owner_sid
= sid_dup_talloc(dst
,owner_sid
)) == NULL
))
145 if(grp_sid
&& ((dst
->group_sid
= sid_dup_talloc(dst
,grp_sid
)) == NULL
))
148 if(sacl
&& ((dst
->sacl
= dup_sec_acl(dst
, sacl
)) == NULL
))
151 if(dacl
&& ((dst
->dacl
= dup_sec_acl(dst
, dacl
)) == NULL
))
154 offset
= SEC_DESC_HEADER_SIZE
;
157 * Work out the linearization sizes.
160 if (dst
->sacl
!= NULL
) {
161 offset
+= dst
->sacl
->size
;
163 if (dst
->dacl
!= NULL
) {
164 offset
+= dst
->dacl
->size
;
167 if (dst
->owner_sid
!= NULL
) {
168 offset
+= ndr_size_dom_sid(dst
->owner_sid
, NULL
, 0);
171 if (dst
->group_sid
!= NULL
) {
172 offset
+= ndr_size_dom_sid(dst
->group_sid
, NULL
, 0);
175 *sd_size
= (size_t)offset
;
184 /*******************************************************************
185 Duplicate a SEC_DESC structure.
186 ********************************************************************/
188 SEC_DESC
*dup_sec_desc(TALLOC_CTX
*ctx
, const SEC_DESC
*src
)
195 return make_sec_desc( ctx
, src
->revision
, src
->type
,
196 src
->owner_sid
, src
->group_sid
, src
->sacl
,
200 /*******************************************************************
201 Convert a secdesc into a byte stream
202 ********************************************************************/
203 NTSTATUS
marshall_sec_desc(TALLOC_CTX
*mem_ctx
,
204 struct security_descriptor
*secdesc
,
205 uint8
**data
, size_t *len
)
208 enum ndr_err_code ndr_err
;
210 ndr_err
= ndr_push_struct_blob(
211 &blob
, mem_ctx
, NULL
, secdesc
,
212 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
214 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
215 DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
216 ndr_errstr(ndr_err
)));
217 return ndr_map_error2ntstatus(ndr_err
);;
225 /*******************************************************************
226 Convert a secdesc_buf into a byte stream
227 ********************************************************************/
229 NTSTATUS
marshall_sec_desc_buf(TALLOC_CTX
*mem_ctx
,
230 struct sec_desc_buf
*secdesc_buf
,
231 uint8_t **data
, size_t *len
)
234 enum ndr_err_code ndr_err
;
236 ndr_err
= ndr_push_struct_blob(
237 &blob
, mem_ctx
, NULL
, secdesc_buf
,
238 (ndr_push_flags_fn_t
)ndr_push_sec_desc_buf
);
240 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
241 DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
242 ndr_errstr(ndr_err
)));
243 return ndr_map_error2ntstatus(ndr_err
);;
251 /*******************************************************************
252 Parse a byte stream into a secdesc
253 ********************************************************************/
254 NTSTATUS
unmarshall_sec_desc(TALLOC_CTX
*mem_ctx
, uint8
*data
, size_t len
,
255 struct security_descriptor
**psecdesc
)
258 enum ndr_err_code ndr_err
;
259 struct security_descriptor
*result
;
261 if ((data
== NULL
) || (len
== 0)) {
262 return NT_STATUS_INVALID_PARAMETER
;
265 result
= TALLOC_ZERO_P(mem_ctx
, struct security_descriptor
);
266 if (result
== NULL
) {
267 return NT_STATUS_NO_MEMORY
;
270 blob
= data_blob_const(data
, len
);
272 ndr_err
= ndr_pull_struct_blob(
273 &blob
, result
, NULL
, result
,
274 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
276 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
277 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
278 ndr_errstr(ndr_err
)));
280 return ndr_map_error2ntstatus(ndr_err
);;
287 /*******************************************************************
288 Parse a byte stream into a sec_desc_buf
289 ********************************************************************/
291 NTSTATUS
unmarshall_sec_desc_buf(TALLOC_CTX
*mem_ctx
, uint8_t *data
, size_t len
,
292 struct sec_desc_buf
**psecdesc_buf
)
295 enum ndr_err_code ndr_err
;
296 struct sec_desc_buf
*result
;
298 if ((data
== NULL
) || (len
== 0)) {
299 return NT_STATUS_INVALID_PARAMETER
;
302 result
= TALLOC_ZERO_P(mem_ctx
, struct sec_desc_buf
);
303 if (result
== NULL
) {
304 return NT_STATUS_NO_MEMORY
;
307 blob
= data_blob_const(data
, len
);
309 ndr_err
= ndr_pull_struct_blob(
310 &blob
, result
, NULL
, result
,
311 (ndr_pull_flags_fn_t
)ndr_pull_sec_desc_buf
);
313 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
314 DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
315 ndr_errstr(ndr_err
)));
317 return ndr_map_error2ntstatus(ndr_err
);;
320 *psecdesc_buf
= result
;
324 /*******************************************************************
325 Creates a SEC_DESC structure with typical defaults.
326 ********************************************************************/
328 SEC_DESC
*make_standard_sec_desc(TALLOC_CTX
*ctx
, const DOM_SID
*owner_sid
, const DOM_SID
*grp_sid
,
329 SEC_ACL
*dacl
, size_t *sd_size
)
331 return make_sec_desc(ctx
, SECURITY_DESCRIPTOR_REVISION_1
,
332 SEC_DESC_SELF_RELATIVE
, owner_sid
, grp_sid
, NULL
,
336 /*******************************************************************
337 Creates a SEC_DESC_BUF structure.
338 ********************************************************************/
340 SEC_DESC_BUF
*make_sec_desc_buf(TALLOC_CTX
*ctx
, size_t len
, SEC_DESC
*sec_desc
)
344 if((dst
= TALLOC_ZERO_P(ctx
, SEC_DESC_BUF
)) == NULL
)
347 /* max buffer size (allocated size) */
348 dst
->sd_size
= (uint32
)len
;
350 if(sec_desc
&& ((dst
->sd
= dup_sec_desc(ctx
, sec_desc
)) == NULL
)) {
357 /*******************************************************************
358 Duplicates a SEC_DESC_BUF structure.
359 ********************************************************************/
361 SEC_DESC_BUF
*dup_sec_desc_buf(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*src
)
366 return make_sec_desc_buf( ctx
, src
->sd_size
, src
->sd
);
369 /*******************************************************************
370 Add a new SID with its permissions to SEC_DESC.
371 ********************************************************************/
373 NTSTATUS
sec_desc_add_sid(TALLOC_CTX
*ctx
, SEC_DESC
**psd
, DOM_SID
*sid
, uint32 mask
, size_t *sd_size
)
380 if (!ctx
|| !psd
|| !sid
|| !sd_size
)
381 return NT_STATUS_INVALID_PARAMETER
;
385 status
= sec_ace_add_sid(ctx
, &ace
, psd
[0]->dacl
->aces
, &psd
[0]->dacl
->num_aces
, sid
, mask
);
387 if (!NT_STATUS_IS_OK(status
))
390 if (!(dacl
= make_sec_acl(ctx
, psd
[0]->dacl
->revision
, psd
[0]->dacl
->num_aces
, ace
)))
391 return NT_STATUS_UNSUCCESSFUL
;
393 if (!(sd
= make_sec_desc(ctx
, psd
[0]->revision
, psd
[0]->type
, psd
[0]->owner_sid
,
394 psd
[0]->group_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
395 return NT_STATUS_UNSUCCESSFUL
;
402 /*******************************************************************
403 Modify a SID's permissions in a SEC_DESC.
404 ********************************************************************/
406 NTSTATUS
sec_desc_mod_sid(SEC_DESC
*sd
, DOM_SID
*sid
, uint32 mask
)
411 return NT_STATUS_INVALID_PARAMETER
;
413 status
= sec_ace_mod_sid(sd
->dacl
->aces
, sd
->dacl
->num_aces
, sid
, mask
);
415 if (!NT_STATUS_IS_OK(status
))
421 /*******************************************************************
422 Delete a SID from a SEC_DESC.
423 ********************************************************************/
425 NTSTATUS
sec_desc_del_sid(TALLOC_CTX
*ctx
, SEC_DESC
**psd
, DOM_SID
*sid
, size_t *sd_size
)
432 if (!ctx
|| !psd
[0] || !sid
|| !sd_size
)
433 return NT_STATUS_INVALID_PARAMETER
;
437 status
= sec_ace_del_sid(ctx
, &ace
, psd
[0]->dacl
->aces
, &psd
[0]->dacl
->num_aces
, sid
);
439 if (!NT_STATUS_IS_OK(status
))
442 if (!(dacl
= make_sec_acl(ctx
, psd
[0]->dacl
->revision
, psd
[0]->dacl
->num_aces
, ace
)))
443 return NT_STATUS_UNSUCCESSFUL
;
445 if (!(sd
= make_sec_desc(ctx
, psd
[0]->revision
, psd
[0]->type
, psd
[0]->owner_sid
,
446 psd
[0]->group_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
447 return NT_STATUS_UNSUCCESSFUL
;
455 * Determine if an ACE is inheritable
458 static bool is_inheritable_ace(const SEC_ACE
*ace
,
462 return ((ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) != 0);
465 if (ace
->flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
) {
469 if ((ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) &&
470 !(ace
->flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
)) {
478 * Does a security descriptor have any inheritable components for
479 * the newly created type ?
482 bool sd_has_inheritable_components(const SEC_DESC
*parent_ctr
, bool container
)
485 const SEC_ACL
*the_acl
= parent_ctr
->dacl
;
487 for (i
= 0; i
< the_acl
->num_aces
; i
++) {
488 const SEC_ACE
*ace
= &the_acl
->aces
[i
];
490 if (is_inheritable_ace(ace
, container
)) {
497 /* Create a child security descriptor using another security descriptor as
498 the parent container. This child object can either be a container or
499 non-container object. */
501 NTSTATUS
se_create_child_secdesc(TALLOC_CTX
*ctx
,
504 const SEC_DESC
*parent_ctr
,
505 const DOM_SID
*owner_sid
,
506 const DOM_SID
*group_sid
,
509 SEC_ACL
*new_dacl
= NULL
, *the_acl
= NULL
;
510 SEC_ACE
*new_ace_list
= NULL
;
511 unsigned int new_ace_list_ndx
= 0, i
;
516 /* Currently we only process the dacl when creating the child. The
517 sacl should also be processed but this is left out as sacls are
518 not implemented in Samba at the moment.*/
520 the_acl
= parent_ctr
->dacl
;
522 if (the_acl
->num_aces
) {
523 if (2*the_acl
->num_aces
< the_acl
->num_aces
) {
524 return NT_STATUS_NO_MEMORY
;
527 if (!(new_ace_list
= TALLOC_ARRAY(ctx
, SEC_ACE
,
528 2*the_acl
->num_aces
))) {
529 return NT_STATUS_NO_MEMORY
;
535 for (i
= 0; i
< the_acl
->num_aces
; i
++) {
536 const SEC_ACE
*ace
= &the_acl
->aces
[i
];
537 SEC_ACE
*new_ace
= &new_ace_list
[new_ace_list_ndx
];
538 const DOM_SID
*ptrustee
= &ace
->trustee
;
539 const DOM_SID
*creator
= NULL
;
540 uint8 new_flags
= ace
->flags
;
542 if (!is_inheritable_ace(ace
, container
)) {
546 /* see the RAW-ACLS inheritance test for details on these rules */
550 new_flags
&= ~SEC_ACE_FLAG_INHERIT_ONLY
;
552 if (!(new_flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
553 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
555 if (new_flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
) {
560 /* The CREATOR sids are special when inherited */
561 if (sid_equal(ptrustee
, &global_sid_Creator_Owner
)) {
562 creator
= &global_sid_Creator_Owner
;
563 ptrustee
= owner_sid
;
564 } else if (sid_equal(ptrustee
, &global_sid_Creator_Group
)) {
565 creator
= &global_sid_Creator_Group
;
566 ptrustee
= group_sid
;
569 if (creator
&& container
&&
570 (new_flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
572 /* First add the regular ACE entry. */
573 init_sec_ace(new_ace
, ptrustee
, ace
->type
,
574 ace
->access_mask
, 0);
576 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
577 " inherited as %s:%d/0x%02x/0x%08x\n",
578 sid_string_dbg(&ace
->trustee
),
579 ace
->type
, ace
->flags
, ace
->access_mask
,
580 sid_string_dbg(&new_ace
->trustee
),
581 new_ace
->type
, new_ace
->flags
,
582 new_ace
->access_mask
));
586 /* Now add the extra creator ACE. */
587 new_ace
= &new_ace_list
[new_ace_list_ndx
];
590 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
591 } else if (container
&&
592 !(ace
->flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
)) {
593 ptrustee
= &ace
->trustee
;
596 init_sec_ace(new_ace
, ptrustee
, ace
->type
,
597 ace
->access_mask
, new_flags
);
599 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
600 " inherited as %s:%d/0x%02x/0x%08x\n",
601 sid_string_dbg(&ace
->trustee
),
602 ace
->type
, ace
->flags
, ace
->access_mask
,
603 sid_string_dbg(&ace
->trustee
),
604 new_ace
->type
, new_ace
->flags
,
605 new_ace
->access_mask
));
610 /* Create child security descriptor to return */
611 if (new_ace_list_ndx
) {
612 new_dacl
= make_sec_acl(ctx
,
618 return NT_STATUS_NO_MEMORY
;
622 *ppsd
= make_sec_desc(ctx
,
623 SECURITY_DESCRIPTOR_REVISION_1
,
624 SEC_DESC_SELF_RELATIVE
|SEC_DESC_DACL_PRESENT
,
631 return NT_STATUS_NO_MEMORY
;
636 NTSTATUS
se_create_child_secdesc_buf(TALLOC_CTX
*ctx
,
637 SEC_DESC_BUF
**ppsdb
,
638 const SEC_DESC
*parent_ctr
,
646 status
= se_create_child_secdesc(ctx
,
650 parent_ctr
->owner_sid
,
651 parent_ctr
->group_sid
,
653 if (!NT_STATUS_IS_OK(status
)) {
657 *ppsdb
= make_sec_desc_buf(ctx
, size
, sd
);
659 return NT_STATUS_NO_MEMORY
;