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 Compares two SEC_DESC structures
36 ********************************************************************/
38 bool sec_desc_equal(SEC_DESC
*s1
, SEC_DESC
*s2
)
50 /* Check top level stuff */
52 if (s1
->revision
!= s2
->revision
) {
53 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
54 s1
->revision
, s2
->revision
));
58 if (s1
->type
!= s2
->type
) {
59 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
64 /* Check owner and group */
66 if (!sid_equal(s1
->owner_sid
, s2
->owner_sid
)) {
67 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
68 sid_string_dbg(s1
->owner_sid
),
69 sid_string_dbg(s2
->owner_sid
)));
73 if (!sid_equal(s1
->group_sid
, s2
->group_sid
)) {
74 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
75 sid_string_dbg(s1
->group_sid
),
76 sid_string_dbg(s2
->group_sid
)));
80 /* Check ACLs present in one but not the other */
82 if ((s1
->dacl
&& !s2
->dacl
) || (!s1
->dacl
&& s2
->dacl
) ||
83 (s1
->sacl
&& !s2
->sacl
) || (!s1
->sacl
&& s2
->sacl
)) {
84 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
88 /* Sigh - we have to do it the hard way by iterating over all
89 the ACEs in the ACLs */
91 if (!sec_acl_equal(s1
->dacl
, s2
->dacl
) ||
92 !sec_acl_equal(s1
->sacl
, s2
->sacl
)) {
93 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
98 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
102 /*******************************************************************
103 Given a security_descriptor return the sec_info.
104 ********************************************************************/
106 uint32_t get_sec_info(const SEC_DESC
*sd
)
108 uint32_t sec_info
= ALL_SECURITY_INFORMATION
;
112 if (sd
->owner_sid
== NULL
) {
113 sec_info
&= ~OWNER_SECURITY_INFORMATION
;
115 if (sd
->group_sid
== NULL
) {
116 sec_info
&= ~GROUP_SECURITY_INFORMATION
;
118 if (sd
->sacl
== NULL
) {
119 sec_info
&= ~SACL_SECURITY_INFORMATION
;
121 if (sd
->dacl
== NULL
) {
122 sec_info
&= ~DACL_SECURITY_INFORMATION
;
129 /*******************************************************************
130 Merge part of security descriptor old_sec in to the empty sections of
131 security descriptor new_sec.
132 ********************************************************************/
134 SEC_DESC_BUF
*sec_desc_merge(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*new_sdb
, SEC_DESC_BUF
*old_sdb
)
136 DOM_SID
*owner_sid
, *group_sid
;
137 SEC_DESC_BUF
*return_sdb
;
138 SEC_ACL
*dacl
, *sacl
;
139 SEC_DESC
*psd
= NULL
;
143 /* Copy over owner and group sids. There seems to be no flag for
144 this so just check the pointer values. */
146 owner_sid
= new_sdb
->sd
->owner_sid
? new_sdb
->sd
->owner_sid
:
147 old_sdb
->sd
->owner_sid
;
149 group_sid
= new_sdb
->sd
->group_sid
? new_sdb
->sd
->group_sid
:
150 old_sdb
->sd
->group_sid
;
152 secdesc_type
= new_sdb
->sd
->type
;
154 /* Ignore changes to the system ACL. This has the effect of making
155 changes through the security tab audit button not sticking.
156 Perhaps in future Samba could implement these settings somehow. */
159 secdesc_type
&= ~SEC_DESC_SACL_PRESENT
;
161 /* Copy across discretionary ACL */
163 if (secdesc_type
& SEC_DESC_DACL_PRESENT
) {
164 dacl
= new_sdb
->sd
->dacl
;
166 dacl
= old_sdb
->sd
->dacl
;
169 /* Create new security descriptor from bits */
171 psd
= make_sec_desc(ctx
, new_sdb
->sd
->revision
, secdesc_type
,
172 owner_sid
, group_sid
, sacl
, dacl
, &secdesc_size
);
174 return_sdb
= make_sec_desc_buf(ctx
, secdesc_size
, psd
);
179 /*******************************************************************
180 Creates a SEC_DESC structure
181 ********************************************************************/
183 SEC_DESC
*make_sec_desc(TALLOC_CTX
*ctx
,
184 enum security_descriptor_revision revision
,
186 const DOM_SID
*owner_sid
, const DOM_SID
*grp_sid
,
187 SEC_ACL
*sacl
, SEC_ACL
*dacl
, size_t *sd_size
)
194 if(( dst
= TALLOC_ZERO_P(ctx
, SEC_DESC
)) == NULL
)
197 dst
->revision
= revision
;
201 dst
->type
|= SEC_DESC_SACL_PRESENT
;
203 dst
->type
|= SEC_DESC_DACL_PRESENT
;
205 dst
->owner_sid
= NULL
;
206 dst
->group_sid
= NULL
;
210 if(owner_sid
&& ((dst
->owner_sid
= sid_dup_talloc(dst
,owner_sid
)) == NULL
))
213 if(grp_sid
&& ((dst
->group_sid
= sid_dup_talloc(dst
,grp_sid
)) == NULL
))
216 if(sacl
&& ((dst
->sacl
= dup_sec_acl(dst
, sacl
)) == NULL
))
219 if(dacl
&& ((dst
->dacl
= dup_sec_acl(dst
, dacl
)) == NULL
))
222 offset
= SEC_DESC_HEADER_SIZE
;
225 * Work out the linearization sizes.
228 if (dst
->sacl
!= NULL
) {
229 offset
+= dst
->sacl
->size
;
231 if (dst
->dacl
!= NULL
) {
232 offset
+= dst
->dacl
->size
;
235 if (dst
->owner_sid
!= NULL
) {
236 offset
+= ndr_size_dom_sid(dst
->owner_sid
, NULL
, 0);
239 if (dst
->group_sid
!= NULL
) {
240 offset
+= ndr_size_dom_sid(dst
->group_sid
, NULL
, 0);
243 *sd_size
= (size_t)offset
;
252 /*******************************************************************
253 Duplicate a SEC_DESC structure.
254 ********************************************************************/
256 SEC_DESC
*dup_sec_desc(TALLOC_CTX
*ctx
, const SEC_DESC
*src
)
263 return make_sec_desc( ctx
, src
->revision
, src
->type
,
264 src
->owner_sid
, src
->group_sid
, src
->sacl
,
268 /*******************************************************************
269 Convert a secdesc into a byte stream
270 ********************************************************************/
271 NTSTATUS
marshall_sec_desc(TALLOC_CTX
*mem_ctx
,
272 struct security_descriptor
*secdesc
,
273 uint8
**data
, size_t *len
)
276 enum ndr_err_code ndr_err
;
278 ndr_err
= ndr_push_struct_blob(
279 &blob
, mem_ctx
, NULL
, secdesc
,
280 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
282 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
283 DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
284 ndr_errstr(ndr_err
)));
285 return ndr_map_error2ntstatus(ndr_err
);;
293 /*******************************************************************
294 Convert a secdesc_buf into a byte stream
295 ********************************************************************/
297 NTSTATUS
marshall_sec_desc_buf(TALLOC_CTX
*mem_ctx
,
298 struct sec_desc_buf
*secdesc_buf
,
299 uint8_t **data
, size_t *len
)
302 enum ndr_err_code ndr_err
;
304 ndr_err
= ndr_push_struct_blob(
305 &blob
, mem_ctx
, NULL
, secdesc_buf
,
306 (ndr_push_flags_fn_t
)ndr_push_sec_desc_buf
);
308 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
309 DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
310 ndr_errstr(ndr_err
)));
311 return ndr_map_error2ntstatus(ndr_err
);;
319 /*******************************************************************
320 Parse a byte stream into a secdesc
321 ********************************************************************/
322 NTSTATUS
unmarshall_sec_desc(TALLOC_CTX
*mem_ctx
, uint8
*data
, size_t len
,
323 struct security_descriptor
**psecdesc
)
326 enum ndr_err_code ndr_err
;
327 struct security_descriptor
*result
;
329 if ((data
== NULL
) || (len
== 0)) {
330 return NT_STATUS_INVALID_PARAMETER
;
333 result
= TALLOC_ZERO_P(mem_ctx
, struct security_descriptor
);
334 if (result
== NULL
) {
335 return NT_STATUS_NO_MEMORY
;
338 blob
= data_blob_const(data
, len
);
340 ndr_err
= ndr_pull_struct_blob(
341 &blob
, result
, NULL
, result
,
342 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
344 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
345 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
346 ndr_errstr(ndr_err
)));
348 return ndr_map_error2ntstatus(ndr_err
);;
355 /*******************************************************************
356 Parse a byte stream into a sec_desc_buf
357 ********************************************************************/
359 NTSTATUS
unmarshall_sec_desc_buf(TALLOC_CTX
*mem_ctx
, uint8_t *data
, size_t len
,
360 struct sec_desc_buf
**psecdesc_buf
)
363 enum ndr_err_code ndr_err
;
364 struct sec_desc_buf
*result
;
366 if ((data
== NULL
) || (len
== 0)) {
367 return NT_STATUS_INVALID_PARAMETER
;
370 result
= TALLOC_ZERO_P(mem_ctx
, struct sec_desc_buf
);
371 if (result
== NULL
) {
372 return NT_STATUS_NO_MEMORY
;
375 blob
= data_blob_const(data
, len
);
377 ndr_err
= ndr_pull_struct_blob(
378 &blob
, result
, NULL
, result
,
379 (ndr_pull_flags_fn_t
)ndr_pull_sec_desc_buf
);
381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
382 DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
383 ndr_errstr(ndr_err
)));
385 return ndr_map_error2ntstatus(ndr_err
);;
388 *psecdesc_buf
= result
;
392 /*******************************************************************
393 Creates a SEC_DESC structure with typical defaults.
394 ********************************************************************/
396 SEC_DESC
*make_standard_sec_desc(TALLOC_CTX
*ctx
, const DOM_SID
*owner_sid
, const DOM_SID
*grp_sid
,
397 SEC_ACL
*dacl
, size_t *sd_size
)
399 return make_sec_desc(ctx
, SECURITY_DESCRIPTOR_REVISION_1
,
400 SEC_DESC_SELF_RELATIVE
, owner_sid
, grp_sid
, NULL
,
404 /*******************************************************************
405 Creates a SEC_DESC_BUF structure.
406 ********************************************************************/
408 SEC_DESC_BUF
*make_sec_desc_buf(TALLOC_CTX
*ctx
, size_t len
, SEC_DESC
*sec_desc
)
412 if((dst
= TALLOC_ZERO_P(ctx
, SEC_DESC_BUF
)) == NULL
)
415 /* max buffer size (allocated size) */
416 dst
->sd_size
= (uint32
)len
;
418 if(sec_desc
&& ((dst
->sd
= dup_sec_desc(ctx
, sec_desc
)) == NULL
)) {
425 /*******************************************************************
426 Duplicates a SEC_DESC_BUF structure.
427 ********************************************************************/
429 SEC_DESC_BUF
*dup_sec_desc_buf(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*src
)
434 return make_sec_desc_buf( ctx
, src
->sd_size
, src
->sd
);
437 /*******************************************************************
438 Add a new SID with its permissions to SEC_DESC.
439 ********************************************************************/
441 NTSTATUS
sec_desc_add_sid(TALLOC_CTX
*ctx
, SEC_DESC
**psd
, DOM_SID
*sid
, uint32 mask
, size_t *sd_size
)
448 if (!ctx
|| !psd
|| !sid
|| !sd_size
)
449 return NT_STATUS_INVALID_PARAMETER
;
453 status
= sec_ace_add_sid(ctx
, &ace
, psd
[0]->dacl
->aces
, &psd
[0]->dacl
->num_aces
, sid
, mask
);
455 if (!NT_STATUS_IS_OK(status
))
458 if (!(dacl
= make_sec_acl(ctx
, psd
[0]->dacl
->revision
, psd
[0]->dacl
->num_aces
, ace
)))
459 return NT_STATUS_UNSUCCESSFUL
;
461 if (!(sd
= make_sec_desc(ctx
, psd
[0]->revision
, psd
[0]->type
, psd
[0]->owner_sid
,
462 psd
[0]->group_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
463 return NT_STATUS_UNSUCCESSFUL
;
470 /*******************************************************************
471 Modify a SID's permissions in a SEC_DESC.
472 ********************************************************************/
474 NTSTATUS
sec_desc_mod_sid(SEC_DESC
*sd
, DOM_SID
*sid
, uint32 mask
)
479 return NT_STATUS_INVALID_PARAMETER
;
481 status
= sec_ace_mod_sid(sd
->dacl
->aces
, sd
->dacl
->num_aces
, sid
, mask
);
483 if (!NT_STATUS_IS_OK(status
))
489 /*******************************************************************
490 Delete a SID from a SEC_DESC.
491 ********************************************************************/
493 NTSTATUS
sec_desc_del_sid(TALLOC_CTX
*ctx
, SEC_DESC
**psd
, DOM_SID
*sid
, size_t *sd_size
)
500 if (!ctx
|| !psd
[0] || !sid
|| !sd_size
)
501 return NT_STATUS_INVALID_PARAMETER
;
505 status
= sec_ace_del_sid(ctx
, &ace
, psd
[0]->dacl
->aces
, &psd
[0]->dacl
->num_aces
, sid
);
507 if (!NT_STATUS_IS_OK(status
))
510 if (!(dacl
= make_sec_acl(ctx
, psd
[0]->dacl
->revision
, psd
[0]->dacl
->num_aces
, ace
)))
511 return NT_STATUS_UNSUCCESSFUL
;
513 if (!(sd
= make_sec_desc(ctx
, psd
[0]->revision
, psd
[0]->type
, psd
[0]->owner_sid
,
514 psd
[0]->group_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
515 return NT_STATUS_UNSUCCESSFUL
;
523 * Determine if an ACE is inheritable
526 static bool is_inheritable_ace(const SEC_ACE
*ace
,
530 return ((ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) != 0);
533 if (ace
->flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
) {
537 if ((ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) &&
538 !(ace
->flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
)) {
545 /* Create a child security descriptor using another security descriptor as
546 the parent container. This child object can either be a container or
547 non-container object. */
549 NTSTATUS
se_create_child_secdesc(TALLOC_CTX
*ctx
,
552 const SEC_DESC
*parent_ctr
,
553 const DOM_SID
*owner_sid
,
554 const DOM_SID
*group_sid
,
557 SEC_ACL
*new_dacl
= NULL
, *the_acl
= NULL
;
558 SEC_ACE
*new_ace_list
= NULL
;
559 unsigned int new_ace_list_ndx
= 0, i
;
564 /* Currently we only process the dacl when creating the child. The
565 sacl should also be processed but this is left out as sacls are
566 not implemented in Samba at the moment.*/
568 the_acl
= parent_ctr
->dacl
;
570 if (the_acl
->num_aces
) {
571 if (2*the_acl
->num_aces
< the_acl
->num_aces
) {
572 return NT_STATUS_NO_MEMORY
;
575 if (!(new_ace_list
= TALLOC_ARRAY(ctx
, SEC_ACE
,
576 2*the_acl
->num_aces
))) {
577 return NT_STATUS_NO_MEMORY
;
583 for (i
= 0; i
< the_acl
->num_aces
; i
++) {
584 const SEC_ACE
*ace
= &the_acl
->aces
[i
];
585 SEC_ACE
*new_ace
= &new_ace_list
[new_ace_list_ndx
];
586 const DOM_SID
*ptrustee
= &ace
->trustee
;
587 const DOM_SID
*creator
= NULL
;
588 uint8 new_flags
= ace
->flags
;
590 if (!is_inheritable_ace(ace
, container
)) {
594 /* see the RAW-ACLS inheritance test for details on these rules */
598 new_flags
&= ~SEC_ACE_FLAG_INHERIT_ONLY
;
600 if (!(new_flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
601 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
603 if (new_flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
) {
608 /* The CREATOR sids are special when inherited */
609 if (sid_equal(ptrustee
, &global_sid_Creator_Owner
)) {
610 creator
= &global_sid_Creator_Owner
;
611 ptrustee
= owner_sid
;
612 } else if (sid_equal(ptrustee
, &global_sid_Creator_Group
)) {
613 creator
= &global_sid_Creator_Group
;
614 ptrustee
= group_sid
;
617 if (creator
&& container
&&
618 (new_flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
620 /* First add the regular ACE entry. */
621 init_sec_ace(new_ace
, ptrustee
, ace
->type
,
622 ace
->access_mask
, 0);
624 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
625 " inherited as %s:%d/0x%02x/0x%08x\n",
626 sid_string_dbg(&ace
->trustee
),
627 ace
->type
, ace
->flags
, ace
->access_mask
,
628 sid_string_dbg(&new_ace
->trustee
),
629 new_ace
->type
, new_ace
->flags
,
630 new_ace
->access_mask
));
634 /* Now add the extra creator ACE. */
635 new_ace
= &new_ace_list
[new_ace_list_ndx
];
638 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
639 } else if (container
&&
640 !(ace
->flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
)) {
641 ptrustee
= &ace
->trustee
;
644 init_sec_ace(new_ace
, ptrustee
, ace
->type
,
645 ace
->access_mask
, new_flags
);
647 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
648 " inherited as %s:%d/0x%02x/0x%08x\n",
649 sid_string_dbg(&ace
->trustee
),
650 ace
->type
, ace
->flags
, ace
->access_mask
,
651 sid_string_dbg(&ace
->trustee
),
652 new_ace
->type
, new_ace
->flags
,
653 new_ace
->access_mask
));
658 /* Create child security descriptor to return */
659 if (new_ace_list_ndx
) {
660 new_dacl
= make_sec_acl(ctx
,
666 return NT_STATUS_NO_MEMORY
;
670 *ppsd
= make_sec_desc(ctx
,
671 SECURITY_DESCRIPTOR_REVISION_1
,
672 SEC_DESC_SELF_RELATIVE
|SEC_DESC_DACL_PRESENT
,
679 return NT_STATUS_NO_MEMORY
;
684 NTSTATUS
se_create_child_secdesc_buf(TALLOC_CTX
*ctx
,
685 SEC_DESC_BUF
**ppsdb
,
686 const SEC_DESC
*parent_ctr
,
694 status
= se_create_child_secdesc(ctx
,
698 parent_ctr
->owner_sid
,
699 parent_ctr
->group_sid
,
701 if (!NT_STATUS_IS_OK(status
)) {
705 *ppsdb
= make_sec_desc_buf(ctx
, size
, sd
);
707 return NT_STATUS_NO_MEMORY
;