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 struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb)
68 DOM_SID *owner_sid, *group_sid;
69 struct 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 SEC_DESC *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC *new_sdb, SEC_DESC *old_sdb)
113 DOM_SID *owner_sid, *group_sid;
114 SEC_ACL *dacl, *sacl;
115 SEC_DESC *psd = NULL;
119 /* Copy over owner and group sids. There seems to be no flag for
120 this so just check the pointer values. */
122 owner_sid = new_sdb->owner_sid ? new_sdb->owner_sid :
125 group_sid = new_sdb->group_sid ? new_sdb->group_sid :
128 secdesc_type = new_sdb->type;
130 /* Ignore changes to the system ACL. This has the effect of making
131 changes through the security tab audit button not sticking.
132 Perhaps in future Samba could implement these settings somehow. */
135 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
137 /* Copy across discretionary ACL */
139 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
140 dacl = new_sdb->dacl;
142 dacl = old_sdb->dacl;
145 /* Create new security descriptor from bits */
146 psd = make_sec_desc(ctx, new_sdb->revision, secdesc_type,
147 owner_sid, group_sid, sacl, dacl, &secdesc_size);
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 Convert a secdesc_buf into a byte stream
268 ********************************************************************/
270 NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
271 struct sec_desc_buf *secdesc_buf,
272 uint8_t **data, size_t *len)
275 enum ndr_err_code ndr_err;
277 ndr_err = ndr_push_struct_blob(
278 &blob, mem_ctx, secdesc_buf,
279 (ndr_push_flags_fn_t)ndr_push_sec_desc_buf);
281 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
282 DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
283 ndr_errstr(ndr_err)));
284 return ndr_map_error2ntstatus(ndr_err);;
292 /*******************************************************************
293 Parse a byte stream into a secdesc
294 ********************************************************************/
295 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
296 struct security_descriptor **psecdesc)
299 enum ndr_err_code ndr_err;
300 struct security_descriptor *result;
302 if ((data == NULL) || (len == 0)) {
303 return NT_STATUS_INVALID_PARAMETER;
306 result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
307 if (result == NULL) {
308 return NT_STATUS_NO_MEMORY;
311 blob = data_blob_const(data, len);
313 ndr_err = ndr_pull_struct_blob(&blob, result, result,
314 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
316 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
317 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
318 ndr_errstr(ndr_err)));
320 return ndr_map_error2ntstatus(ndr_err);;
327 /*******************************************************************
328 Parse a byte stream into a sec_desc_buf
329 ********************************************************************/
331 NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
332 struct sec_desc_buf **psecdesc_buf)
335 enum ndr_err_code ndr_err;
336 struct sec_desc_buf *result;
338 if ((data == NULL) || (len == 0)) {
339 return NT_STATUS_INVALID_PARAMETER;
342 result = TALLOC_ZERO_P(mem_ctx, struct sec_desc_buf);
343 if (result == NULL) {
344 return NT_STATUS_NO_MEMORY;
347 blob = data_blob_const(data, len);
349 ndr_err = ndr_pull_struct_blob(&blob, result, result,
350 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
352 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
353 DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
354 ndr_errstr(ndr_err)));
356 return ndr_map_error2ntstatus(ndr_err);;
359 *psecdesc_buf = result;
363 /*******************************************************************
364 Creates a SEC_DESC structure with typical defaults.
365 ********************************************************************/
367 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
368 SEC_ACL *dacl, size_t *sd_size)
370 return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
371 SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
375 /*******************************************************************
376 Creates a struct sec_desc_buf structure.
377 ********************************************************************/
379 struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
381 struct sec_desc_buf *dst;
383 if((dst = TALLOC_ZERO_P(ctx, struct sec_desc_buf)) == NULL)
386 /* max buffer size (allocated size) */
387 dst->sd_size = (uint32)len;
389 if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
396 /*******************************************************************
397 Duplicates a struct sec_desc_buf structure.
398 ********************************************************************/
400 struct sec_desc_buf *dup_sec_desc_buf(TALLOC_CTX *ctx, struct sec_desc_buf *src)
405 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
408 /*******************************************************************
409 Add a new SID with its permissions to SEC_DESC.
410 ********************************************************************/
412 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
416 struct security_ace *ace = 0;
419 if (!ctx || !psd || !sid || !sd_size)
420 return NT_STATUS_INVALID_PARAMETER;
424 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
426 if (!NT_STATUS_IS_OK(status))
429 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
430 return NT_STATUS_UNSUCCESSFUL;
432 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
433 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
434 return NT_STATUS_UNSUCCESSFUL;
441 /*******************************************************************
442 Modify a SID's permissions in a SEC_DESC.
443 ********************************************************************/
445 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
450 return NT_STATUS_INVALID_PARAMETER;
452 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
454 if (!NT_STATUS_IS_OK(status))
460 /*******************************************************************
461 Delete a SID from a SEC_DESC.
462 ********************************************************************/
464 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
468 struct security_ace *ace = 0;
471 if (!ctx || !psd[0] || !sid || !sd_size)
472 return NT_STATUS_INVALID_PARAMETER;
476 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
478 if (!NT_STATUS_IS_OK(status))
481 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
482 return NT_STATUS_UNSUCCESSFUL;
484 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
485 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
486 return NT_STATUS_UNSUCCESSFUL;
494 * Determine if an struct security_ace is inheritable
497 static bool is_inheritable_ace(const struct security_ace *ace,
501 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
504 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
508 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
509 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
517 * Does a security descriptor have any inheritable components for
518 * the newly created type ?
521 bool sd_has_inheritable_components(const SEC_DESC *parent_ctr, bool container)
524 const SEC_ACL *the_acl = parent_ctr->dacl;
526 for (i = 0; i < the_acl->num_aces; i++) {
527 const struct security_ace *ace = &the_acl->aces[i];
529 if (is_inheritable_ace(ace, container)) {
536 /* Create a child security descriptor using another security descriptor as
537 the parent container. This child object can either be a container or
538 non-container object. */
540 NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
543 const SEC_DESC *parent_ctr,
544 const DOM_SID *owner_sid,
545 const DOM_SID *group_sid,
548 SEC_ACL *new_dacl = NULL, *the_acl = NULL;
549 struct security_ace *new_ace_list = NULL;
550 unsigned int new_ace_list_ndx = 0, i;
555 /* Currently we only process the dacl when creating the child. The
556 sacl should also be processed but this is left out as sacls are
557 not implemented in Samba at the moment.*/
559 the_acl = parent_ctr->dacl;
561 if (the_acl->num_aces) {
562 if (2*the_acl->num_aces < the_acl->num_aces) {
563 return NT_STATUS_NO_MEMORY;
566 if (!(new_ace_list = TALLOC_ARRAY(ctx, struct security_ace,
567 2*the_acl->num_aces))) {
568 return NT_STATUS_NO_MEMORY;
574 for (i = 0; i < the_acl->num_aces; i++) {
575 const struct security_ace *ace = &the_acl->aces[i];
576 struct security_ace *new_ace = &new_ace_list[new_ace_list_ndx];
577 const DOM_SID *ptrustee = &ace->trustee;
578 const DOM_SID *creator = NULL;
579 uint8 new_flags = ace->flags;
581 if (!is_inheritable_ace(ace, container)) {
585 /* see the RAW-ACLS inheritance test for details on these rules */
589 new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
591 if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
592 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
594 if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
599 /* The CREATOR sids are special when inherited */
600 if (sid_equal(ptrustee, &global_sid_Creator_Owner)) {
601 creator = &global_sid_Creator_Owner;
602 ptrustee = owner_sid;
603 } else if (sid_equal(ptrustee, &global_sid_Creator_Group)) {
604 creator = &global_sid_Creator_Group;
605 ptrustee = group_sid;
608 if (creator && container &&
609 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
611 /* First add the regular ACE entry. */
612 init_sec_ace(new_ace, ptrustee, ace->type,
613 ace->access_mask, 0);
615 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
616 " inherited as %s:%d/0x%02x/0x%08x\n",
617 sid_string_dbg(&ace->trustee),
618 ace->type, ace->flags, ace->access_mask,
619 sid_string_dbg(&new_ace->trustee),
620 new_ace->type, new_ace->flags,
621 new_ace->access_mask));
625 /* Now add the extra creator ACE. */
626 new_ace = &new_ace_list[new_ace_list_ndx];
629 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
630 } else if (container &&
631 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
632 ptrustee = &ace->trustee;
635 init_sec_ace(new_ace, ptrustee, ace->type,
636 ace->access_mask, new_flags);
638 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
639 " inherited as %s:%d/0x%02x/0x%08x\n",
640 sid_string_dbg(&ace->trustee),
641 ace->type, ace->flags, ace->access_mask,
642 sid_string_dbg(&ace->trustee),
643 new_ace->type, new_ace->flags,
644 new_ace->access_mask));
649 /* Create child security descriptor to return */
650 if (new_ace_list_ndx) {
651 new_dacl = make_sec_acl(ctx,
657 return NT_STATUS_NO_MEMORY;
661 *ppsd = make_sec_desc(ctx,
662 SECURITY_DESCRIPTOR_REVISION_1,
663 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
670 return NT_STATUS_NO_MEMORY;
675 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
676 struct sec_desc_buf **ppsdb,
677 const SEC_DESC *parent_ctr,
685 status = se_create_child_secdesc(ctx,
689 parent_ctr->owner_sid,
690 parent_ctr->group_sid,
692 if (!NT_STATUS_IS_OK(status)) {
696 *ppsdb = make_sec_desc_buf(ctx, size, sd);
698 return NT_STATUS_NO_MEMORY;