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 Parse a byte stream into a secdesc
295 ********************************************************************/
296 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
297 struct security_descriptor **psecdesc)
300 enum ndr_err_code ndr_err;
301 struct security_descriptor *result;
303 if ((data == NULL) || (len == 0)) {
304 return NT_STATUS_INVALID_PARAMETER;
307 result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
308 if (result == NULL) {
309 return NT_STATUS_NO_MEMORY;
312 blob = data_blob_const(data, len);
314 ndr_err = ndr_pull_struct_blob(
315 &blob, result, NULL, result,
316 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
318 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
319 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
320 ndr_errstr(ndr_err)));
322 return ndr_map_error2ntstatus(ndr_err);;
329 /*******************************************************************
330 Creates a SEC_DESC structure with typical defaults.
331 ********************************************************************/
333 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
334 SEC_ACL *dacl, size_t *sd_size)
336 return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
337 SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
341 /*******************************************************************
342 Creates a SEC_DESC_BUF structure.
343 ********************************************************************/
345 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
349 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
352 /* max buffer size (allocated size) */
353 dst->sd_size = (uint32)len;
355 if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
362 /*******************************************************************
363 Duplicates a SEC_DESC_BUF structure.
364 ********************************************************************/
366 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
371 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
374 /*******************************************************************
375 Add a new SID with its permissions to SEC_DESC.
376 ********************************************************************/
378 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
385 if (!ctx || !psd || !sid || !sd_size)
386 return NT_STATUS_INVALID_PARAMETER;
390 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
392 if (!NT_STATUS_IS_OK(status))
395 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
396 return NT_STATUS_UNSUCCESSFUL;
398 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
399 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
400 return NT_STATUS_UNSUCCESSFUL;
407 /*******************************************************************
408 Modify a SID's permissions in a SEC_DESC.
409 ********************************************************************/
411 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
416 return NT_STATUS_INVALID_PARAMETER;
418 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
420 if (!NT_STATUS_IS_OK(status))
426 /*******************************************************************
427 Delete a SID from a SEC_DESC.
428 ********************************************************************/
430 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
437 if (!ctx || !psd[0] || !sid || !sd_size)
438 return NT_STATUS_INVALID_PARAMETER;
442 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
444 if (!NT_STATUS_IS_OK(status))
447 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
448 return NT_STATUS_UNSUCCESSFUL;
450 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
451 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
452 return NT_STATUS_UNSUCCESSFUL;
460 * Determine if an ACE is inheritable
463 static bool is_inheritable_ace(const SEC_ACE *ace,
467 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
470 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
474 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
475 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
482 /* Create a child security descriptor using another security descriptor as
483 the parent container. This child object can either be a container or
484 non-container object. */
486 NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
489 const SEC_DESC *parent_ctr,
490 const DOM_SID *owner_sid,
491 const DOM_SID *group_sid,
494 SEC_ACL *new_dacl = NULL, *the_acl = NULL;
495 SEC_ACE *new_ace_list = NULL;
496 unsigned int new_ace_list_ndx = 0, i;
501 /* Currently we only process the dacl when creating the child. The
502 sacl should also be processed but this is left out as sacls are
503 not implemented in Samba at the moment.*/
505 the_acl = parent_ctr->dacl;
507 if (the_acl->num_aces) {
508 if (2*the_acl->num_aces < the_acl->num_aces) {
509 return NT_STATUS_NO_MEMORY;
512 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE,
513 2*the_acl->num_aces))) {
514 return NT_STATUS_NO_MEMORY;
520 for (i = 0; i < the_acl->num_aces; i++) {
521 const SEC_ACE *ace = &the_acl->aces[i];
522 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
523 const DOM_SID *ptrustee = &ace->trustee;
524 const DOM_SID *creator = NULL;
525 uint8 new_flags = ace->flags;
527 if (!is_inheritable_ace(ace, container)) {
531 /* see the RAW-ACLS inheritance test for details on these rules */
535 new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
537 if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
538 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
540 if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
545 /* The CREATOR sids are special when inherited */
546 if (sid_equal(ptrustee, &global_sid_Creator_Owner)) {
547 creator = &global_sid_Creator_Owner;
548 ptrustee = owner_sid;
549 } else if (sid_equal(ptrustee, &global_sid_Creator_Group)) {
550 creator = &global_sid_Creator_Group;
551 ptrustee = group_sid;
554 if (creator && container &&
555 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
557 /* First add the regular ACE entry. */
558 init_sec_ace(new_ace, ptrustee, ace->type,
559 ace->access_mask, 0);
561 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
562 " inherited as %s:%d/0x%02x/0x%08x\n",
563 sid_string_dbg(&ace->trustee),
564 ace->type, ace->flags, ace->access_mask,
565 sid_string_dbg(&new_ace->trustee),
566 new_ace->type, new_ace->flags,
567 new_ace->access_mask));
571 /* Now add the extra creator ACE. */
572 new_ace = &new_ace_list[new_ace_list_ndx];
575 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
576 } else if (container &&
577 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
578 ptrustee = &ace->trustee;
581 init_sec_ace(new_ace, ptrustee, ace->type,
582 ace->access_mask, new_flags);
584 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
585 " inherited as %s:%d/0x%02x/0x%08x\n",
586 sid_string_dbg(&ace->trustee),
587 ace->type, ace->flags, ace->access_mask,
588 sid_string_dbg(&ace->trustee),
589 new_ace->type, new_ace->flags,
590 new_ace->access_mask));
595 /* Create child security descriptor to return */
596 if (new_ace_list_ndx) {
597 new_dacl = make_sec_acl(ctx,
603 return NT_STATUS_NO_MEMORY;
607 *ppsd = make_sec_desc(ctx,
608 SECURITY_DESCRIPTOR_REVISION_1,
609 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
616 return NT_STATUS_NO_MEMORY;
621 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
622 SEC_DESC_BUF **ppsdb,
623 const SEC_DESC *parent_ctr,
631 status = se_create_child_secdesc(ctx,
635 parent_ctr->owner_sid,
636 parent_ctr->group_sid,
638 if (!NT_STATUS_IS_OK(status)) {
642 *ppsdb = make_sec_desc_buf(ctx, size, sd);
644 return NT_STATUS_NO_MEMORY;