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 Merge part of security descriptor old_sec in to the empty sections of
104 security descriptor new_sec.
105 ********************************************************************/
107 SEC_DESC_BUF
*sec_desc_merge(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*new_sdb
, SEC_DESC_BUF
*old_sdb
)
109 DOM_SID
*owner_sid
, *group_sid
;
110 SEC_DESC_BUF
*return_sdb
;
111 SEC_ACL
*dacl
, *sacl
;
112 SEC_DESC
*psd
= NULL
;
116 /* Copy over owner and group sids. There seems to be no flag for
117 this so just check the pointer values. */
119 owner_sid
= new_sdb
->sd
->owner_sid
? new_sdb
->sd
->owner_sid
:
120 old_sdb
->sd
->owner_sid
;
122 group_sid
= new_sdb
->sd
->group_sid
? new_sdb
->sd
->group_sid
:
123 old_sdb
->sd
->group_sid
;
125 secdesc_type
= new_sdb
->sd
->type
;
127 /* Ignore changes to the system ACL. This has the effect of making
128 changes through the security tab audit button not sticking.
129 Perhaps in future Samba could implement these settings somehow. */
132 secdesc_type
&= ~SEC_DESC_SACL_PRESENT
;
134 /* Copy across discretionary ACL */
136 if (secdesc_type
& SEC_DESC_DACL_PRESENT
) {
137 dacl
= new_sdb
->sd
->dacl
;
139 dacl
= old_sdb
->sd
->dacl
;
142 /* Create new security descriptor from bits */
144 psd
= make_sec_desc(ctx
, new_sdb
->sd
->revision
, secdesc_type
,
145 owner_sid
, group_sid
, sacl
, dacl
, &secdesc_size
);
147 return_sdb
= make_sec_desc_buf(ctx
, secdesc_size
, psd
);
152 /*******************************************************************
153 Creates a SEC_DESC structure
154 ********************************************************************/
156 SEC_DESC
*make_sec_desc(TALLOC_CTX
*ctx
,
157 enum security_descriptor_revision revision
,
159 const DOM_SID
*owner_sid
, const DOM_SID
*grp_sid
,
160 SEC_ACL
*sacl
, SEC_ACL
*dacl
, size_t *sd_size
)
167 if(( dst
= TALLOC_ZERO_P(ctx
, SEC_DESC
)) == NULL
)
170 dst
->revision
= revision
;
174 dst
->type
|= SEC_DESC_SACL_PRESENT
;
176 dst
->type
|= SEC_DESC_DACL_PRESENT
;
178 dst
->owner_sid
= NULL
;
179 dst
->group_sid
= NULL
;
183 if(owner_sid
&& ((dst
->owner_sid
= sid_dup_talloc(dst
,owner_sid
)) == NULL
))
186 if(grp_sid
&& ((dst
->group_sid
= sid_dup_talloc(dst
,grp_sid
)) == NULL
))
189 if(sacl
&& ((dst
->sacl
= dup_sec_acl(dst
, sacl
)) == NULL
))
192 if(dacl
&& ((dst
->dacl
= dup_sec_acl(dst
, dacl
)) == NULL
))
195 offset
= SEC_DESC_HEADER_SIZE
;
198 * Work out the linearization sizes.
201 if (dst
->sacl
!= NULL
) {
202 offset
+= dst
->sacl
->size
;
204 if (dst
->dacl
!= NULL
) {
205 offset
+= dst
->dacl
->size
;
208 if (dst
->owner_sid
!= NULL
) {
209 offset
+= ndr_size_dom_sid(dst
->owner_sid
, 0);
212 if (dst
->group_sid
!= NULL
) {
213 offset
+= ndr_size_dom_sid(dst
->group_sid
, 0);
216 *sd_size
= (size_t)offset
;
225 /*******************************************************************
226 Duplicate a SEC_DESC structure.
227 ********************************************************************/
229 SEC_DESC
*dup_sec_desc(TALLOC_CTX
*ctx
, const SEC_DESC
*src
)
236 return make_sec_desc( ctx
, src
->revision
, src
->type
,
237 src
->owner_sid
, src
->group_sid
, src
->sacl
,
241 /*******************************************************************
242 Convert a secdesc into a byte stream
243 ********************************************************************/
244 NTSTATUS
marshall_sec_desc(TALLOC_CTX
*mem_ctx
,
245 struct security_descriptor
*secdesc
,
246 uint8
**data
, size_t *len
)
249 enum ndr_err_code ndr_err
;
251 ndr_err
= ndr_push_struct_blob(
252 &blob
, mem_ctx
, secdesc
,
253 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
255 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
256 DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
257 ndr_errstr(ndr_err
)));
258 return ndr_map_error2ntstatus(ndr_err
);;
266 /*******************************************************************
267 Parse a byte stream into a secdesc
268 ********************************************************************/
269 NTSTATUS
unmarshall_sec_desc(TALLOC_CTX
*mem_ctx
, uint8
*data
, size_t len
,
270 struct security_descriptor
**psecdesc
)
273 enum ndr_err_code ndr_err
;
274 struct security_descriptor
*result
;
276 if ((data
== NULL
) || (len
== 0)) {
277 return NT_STATUS_INVALID_PARAMETER
;
280 result
= TALLOC_ZERO_P(mem_ctx
, struct security_descriptor
);
281 if (result
== NULL
) {
282 return NT_STATUS_NO_MEMORY
;
285 blob
= data_blob_const(data
, len
);
287 ndr_err
= ndr_pull_struct_blob(
288 &blob
, result
, result
,
289 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
291 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
292 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
293 ndr_errstr(ndr_err
)));
295 return ndr_map_error2ntstatus(ndr_err
);;
302 /*******************************************************************
303 Creates a SEC_DESC structure with typical defaults.
304 ********************************************************************/
306 SEC_DESC
*make_standard_sec_desc(TALLOC_CTX
*ctx
, const DOM_SID
*owner_sid
, const DOM_SID
*grp_sid
,
307 SEC_ACL
*dacl
, size_t *sd_size
)
309 return make_sec_desc(ctx
, SECURITY_DESCRIPTOR_REVISION_1
,
310 SEC_DESC_SELF_RELATIVE
, owner_sid
, grp_sid
, NULL
,
314 /*******************************************************************
315 Creates a SEC_DESC_BUF structure.
316 ********************************************************************/
318 SEC_DESC_BUF
*make_sec_desc_buf(TALLOC_CTX
*ctx
, size_t len
, SEC_DESC
*sec_desc
)
322 if((dst
= TALLOC_ZERO_P(ctx
, SEC_DESC_BUF
)) == NULL
)
325 /* max buffer size (allocated size) */
326 dst
->sd_size
= (uint32
)len
;
328 if(sec_desc
&& ((dst
->sd
= dup_sec_desc(ctx
, sec_desc
)) == NULL
)) {
335 /*******************************************************************
336 Duplicates a SEC_DESC_BUF structure.
337 ********************************************************************/
339 SEC_DESC_BUF
*dup_sec_desc_buf(TALLOC_CTX
*ctx
, SEC_DESC_BUF
*src
)
344 return make_sec_desc_buf( ctx
, src
->sd_size
, src
->sd
);
347 /*******************************************************************
348 Add a new SID with its permissions to SEC_DESC.
349 ********************************************************************/
351 NTSTATUS
sec_desc_add_sid(TALLOC_CTX
*ctx
, SEC_DESC
**psd
, DOM_SID
*sid
, uint32 mask
, size_t *sd_size
)
358 if (!ctx
|| !psd
|| !sid
|| !sd_size
)
359 return NT_STATUS_INVALID_PARAMETER
;
363 status
= sec_ace_add_sid(ctx
, &ace
, psd
[0]->dacl
->aces
, &psd
[0]->dacl
->num_aces
, sid
, mask
);
365 if (!NT_STATUS_IS_OK(status
))
368 if (!(dacl
= make_sec_acl(ctx
, psd
[0]->dacl
->revision
, psd
[0]->dacl
->num_aces
, ace
)))
369 return NT_STATUS_UNSUCCESSFUL
;
371 if (!(sd
= make_sec_desc(ctx
, psd
[0]->revision
, psd
[0]->type
, psd
[0]->owner_sid
,
372 psd
[0]->group_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
373 return NT_STATUS_UNSUCCESSFUL
;
380 /*******************************************************************
381 Modify a SID's permissions in a SEC_DESC.
382 ********************************************************************/
384 NTSTATUS
sec_desc_mod_sid(SEC_DESC
*sd
, DOM_SID
*sid
, uint32 mask
)
389 return NT_STATUS_INVALID_PARAMETER
;
391 status
= sec_ace_mod_sid(sd
->dacl
->aces
, sd
->dacl
->num_aces
, sid
, mask
);
393 if (!NT_STATUS_IS_OK(status
))
399 /*******************************************************************
400 Delete a SID from a SEC_DESC.
401 ********************************************************************/
403 NTSTATUS
sec_desc_del_sid(TALLOC_CTX
*ctx
, SEC_DESC
**psd
, DOM_SID
*sid
, size_t *sd_size
)
410 if (!ctx
|| !psd
[0] || !sid
|| !sd_size
)
411 return NT_STATUS_INVALID_PARAMETER
;
415 status
= sec_ace_del_sid(ctx
, &ace
, psd
[0]->dacl
->aces
, &psd
[0]->dacl
->num_aces
, sid
);
417 if (!NT_STATUS_IS_OK(status
))
420 if (!(dacl
= make_sec_acl(ctx
, psd
[0]->dacl
->revision
, psd
[0]->dacl
->num_aces
, ace
)))
421 return NT_STATUS_UNSUCCESSFUL
;
423 if (!(sd
= make_sec_desc(ctx
, psd
[0]->revision
, psd
[0]->type
, psd
[0]->owner_sid
,
424 psd
[0]->group_sid
, psd
[0]->sacl
, dacl
, sd_size
)))
425 return NT_STATUS_UNSUCCESSFUL
;
433 * Determine if an ACE is inheritable
436 static bool is_inheritable_ace(const SEC_ACE
*ace
,
440 return ((ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) != 0);
443 if (ace
->flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
) {
447 if ((ace
->flags
& SEC_ACE_FLAG_OBJECT_INHERIT
) &&
448 !(ace
->flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
)) {
455 /* Create a child security descriptor using another security descriptor as
456 the parent container. This child object can either be a container or
457 non-container object. */
459 NTSTATUS
se_create_child_secdesc(TALLOC_CTX
*ctx
,
462 const SEC_DESC
*parent_ctr
,
463 const DOM_SID
*owner_sid
,
464 const DOM_SID
*group_sid
,
467 SEC_ACL
*new_dacl
= NULL
, *the_acl
= NULL
;
468 SEC_ACE
*new_ace_list
= NULL
;
469 unsigned int new_ace_list_ndx
= 0, i
;
474 /* Currently we only process the dacl when creating the child. The
475 sacl should also be processed but this is left out as sacls are
476 not implemented in Samba at the moment.*/
478 the_acl
= parent_ctr
->dacl
;
480 if (the_acl
->num_aces
) {
481 if (2*the_acl
->num_aces
< the_acl
->num_aces
) {
482 return NT_STATUS_NO_MEMORY
;
485 if (!(new_ace_list
= TALLOC_ARRAY(ctx
, SEC_ACE
,
486 2*the_acl
->num_aces
))) {
487 return NT_STATUS_NO_MEMORY
;
493 for (i
= 0; i
< the_acl
->num_aces
; i
++) {
494 const SEC_ACE
*ace
= &the_acl
->aces
[i
];
495 SEC_ACE
*new_ace
= &new_ace_list
[new_ace_list_ndx
];
496 const DOM_SID
*ptrustee
= &ace
->trustee
;
497 const DOM_SID
*creator
= NULL
;
498 uint8 new_flags
= ace
->flags
;
500 if (!is_inheritable_ace(ace
, container
)) {
504 /* see the RAW-ACLS inheritance test for details on these rules */
508 new_flags
&= ~SEC_ACE_FLAG_INHERIT_ONLY
;
510 if (!(new_flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
511 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
513 if (new_flags
& SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
) {
518 /* The CREATOR sids are special when inherited */
519 if (sid_equal(ptrustee
, &global_sid_Creator_Owner
)) {
520 creator
= &global_sid_Creator_Owner
;
521 ptrustee
= owner_sid
;
522 } else if (sid_equal(ptrustee
, &global_sid_Creator_Group
)) {
523 creator
= &global_sid_Creator_Group
;
524 ptrustee
= group_sid
;
527 if (creator
&& container
&&
528 (new_flags
& SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
530 /* First add the regular ACE entry. */
531 init_sec_ace(new_ace
, ptrustee
, ace
->type
,
532 ace
->access_mask
, SEC_ACE_FLAG_INHERITED_ACE
);
534 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
535 " inherited as %s:%d/0x%02x/0x%08x\n",
536 sid_string_dbg(&ace
->trustee
),
537 ace
->type
, ace
->flags
, ace
->access_mask
,
538 sid_string_dbg(&new_ace
->trustee
),
539 new_ace
->type
, new_ace
->flags
,
540 new_ace
->access_mask
));
544 /* Now add the extra creator ACE. */
545 new_ace
= &new_ace_list
[new_ace_list_ndx
];
548 new_flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
551 init_sec_ace(new_ace
, ptrustee
, ace
->type
,
552 ace
->access_mask
, new_flags
| SEC_ACE_FLAG_INHERITED_ACE
);
554 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
555 " inherited as %s:%d/0x%02x/0x%08x\n",
556 sid_string_dbg(&ace
->trustee
),
557 ace
->type
, ace
->flags
, ace
->access_mask
,
558 sid_string_dbg(&ace
->trustee
),
559 new_ace
->type
, new_ace
->flags
,
560 new_ace
->access_mask
));
565 /* Create child security descriptor to return */
567 new_dacl
= make_sec_acl(ctx
,
573 return NT_STATUS_NO_MEMORY
;
575 *ppsd
= make_sec_desc(ctx
,
576 SECURITY_DESCRIPTOR_REVISION_1
,
577 SEC_DESC_SELF_RELATIVE
|SEC_DESC_DACL_PRESENT
|
578 SEC_DESC_DACL_DEFAULTED
,
585 return NT_STATUS_NO_MEMORY
;
590 NTSTATUS
se_create_child_secdesc_buf(TALLOC_CTX
*ctx
,
591 SEC_DESC_BUF
**ppsdb
,
592 const SEC_DESC
*parent_ctr
,
600 status
= se_create_child_secdesc(ctx
,
604 parent_ctr
->owner_sid
,
605 parent_ctr
->group_sid
,
607 if (!NT_STATUS_IS_OK(status
)) {
611 *ppsdb
= make_sec_desc_buf(ctx
, size
, sd
);
613 return NT_STATUS_NO_MEMORY
;