libcli/secdesc: remove dup_sec_desc()
[Samba.git] / libcli / security / secdesc.c
blob44897b5953dc0e1874cf6945d543e165aba8da55
1 /*
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/>.
23 #include "includes.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "libcli/security/security.h"
27 #define ALL_SECURITY_INFORMATION (SECINFO_OWNER|SECINFO_GROUP|\
28 SECINFO_DACL|SECINFO_SACL|\
29 SECINFO_UNPROTECTED_SACL|\
30 SECINFO_UNPROTECTED_DACL|\
31 SECINFO_PROTECTED_SACL|\
32 SECINFO_PROTECTED_DACL)
34 /* Map generic permissions to file object specific permissions */
36 const struct generic_mapping file_generic_mapping = {
37 FILE_GENERIC_READ,
38 FILE_GENERIC_WRITE,
39 FILE_GENERIC_EXECUTE,
40 FILE_GENERIC_ALL
43 /*******************************************************************
44 Given a security_descriptor return the sec_info.
45 ********************************************************************/
47 uint32_t get_sec_info(const struct security_descriptor *sd)
49 uint32_t sec_info = ALL_SECURITY_INFORMATION;
51 SMB_ASSERT(sd);
53 if (sd->owner_sid == NULL) {
54 sec_info &= ~SECINFO_OWNER;
56 if (sd->group_sid == NULL) {
57 sec_info &= ~SECINFO_GROUP;
59 if (sd->sacl == NULL) {
60 sec_info &= ~SECINFO_SACL;
62 if (sd->dacl == NULL) {
63 sec_info &= ~SECINFO_DACL;
66 return sec_info;
70 /*******************************************************************
71 Merge part of security descriptor old_sec in to the empty sections of
72 security descriptor new_sec.
73 ********************************************************************/
75 struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb)
77 struct dom_sid *owner_sid, *group_sid;
78 struct sec_desc_buf *return_sdb;
79 struct security_acl *dacl, *sacl;
80 struct security_descriptor *psd = NULL;
81 uint16_t secdesc_type;
82 size_t secdesc_size;
84 /* Copy over owner and group sids. There seems to be no flag for
85 this so just check the pointer values. */
87 owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
88 old_sdb->sd->owner_sid;
90 group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
91 old_sdb->sd->group_sid;
93 secdesc_type = new_sdb->sd->type;
95 /* Ignore changes to the system ACL. This has the effect of making
96 changes through the security tab audit button not sticking.
97 Perhaps in future Samba could implement these settings somehow. */
99 sacl = NULL;
100 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
102 /* Copy across discretionary ACL */
104 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
105 dacl = new_sdb->sd->dacl;
106 } else {
107 dacl = old_sdb->sd->dacl;
110 /* Create new security descriptor from bits */
112 psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
113 owner_sid, group_sid, sacl, dacl, &secdesc_size);
115 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
117 return(return_sdb);
120 struct security_descriptor *sec_desc_merge(TALLOC_CTX *ctx, struct security_descriptor *new_sdb, struct security_descriptor *old_sdb)
122 struct dom_sid *owner_sid, *group_sid;
123 struct security_acl *dacl, *sacl;
124 struct security_descriptor *psd = NULL;
125 uint16_t secdesc_type;
126 size_t secdesc_size;
128 /* Copy over owner and group sids. There seems to be no flag for
129 this so just check the pointer values. */
131 owner_sid = new_sdb->owner_sid ? new_sdb->owner_sid :
132 old_sdb->owner_sid;
134 group_sid = new_sdb->group_sid ? new_sdb->group_sid :
135 old_sdb->group_sid;
137 secdesc_type = new_sdb->type;
139 /* Ignore changes to the system ACL. This has the effect of making
140 changes through the security tab audit button not sticking.
141 Perhaps in future Samba could implement these settings somehow. */
143 sacl = NULL;
144 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
146 /* Copy across discretionary ACL */
148 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
149 dacl = new_sdb->dacl;
150 } else {
151 dacl = old_sdb->dacl;
154 /* Create new security descriptor from bits */
155 psd = make_sec_desc(ctx, new_sdb->revision, secdesc_type,
156 owner_sid, group_sid, sacl, dacl, &secdesc_size);
158 return psd;
161 /*******************************************************************
162 Creates a struct security_descriptor structure
163 ********************************************************************/
165 #define SEC_DESC_HEADER_SIZE (2 * sizeof(uint16_t) + 4 * sizeof(uint32_t))
167 struct security_descriptor *make_sec_desc(TALLOC_CTX *ctx,
168 enum security_descriptor_revision revision,
169 uint16_t type,
170 const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
171 struct security_acl *sacl, struct security_acl *dacl, size_t *sd_size)
173 struct security_descriptor *dst;
174 uint32_t offset = 0;
176 if (sd_size != NULL) {
177 *sd_size = 0;
180 if(( dst = talloc_zero(ctx, struct security_descriptor)) == NULL)
181 return NULL;
183 dst->revision = revision;
184 dst->type = type;
186 if (sacl)
187 dst->type |= SEC_DESC_SACL_PRESENT;
188 if (dacl)
189 dst->type |= SEC_DESC_DACL_PRESENT;
191 dst->owner_sid = NULL;
192 dst->group_sid = NULL;
193 dst->sacl = NULL;
194 dst->dacl = NULL;
196 if(owner_sid && ((dst->owner_sid = dom_sid_dup(dst,owner_sid)) == NULL))
197 goto error_exit;
199 if(grp_sid && ((dst->group_sid = dom_sid_dup(dst,grp_sid)) == NULL))
200 goto error_exit;
202 if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
203 goto error_exit;
205 if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
206 goto error_exit;
208 if (sd_size == NULL) {
209 return dst;
212 offset = SEC_DESC_HEADER_SIZE;
215 * Work out the linearization sizes.
218 if (dst->sacl != NULL) {
219 offset += dst->sacl->size;
221 if (dst->dacl != NULL) {
222 offset += dst->dacl->size;
225 if (dst->owner_sid != NULL) {
226 offset += ndr_size_dom_sid(dst->owner_sid, 0);
229 if (dst->group_sid != NULL) {
230 offset += ndr_size_dom_sid(dst->group_sid, 0);
233 *sd_size = (size_t)offset;
234 return dst;
236 error_exit:
238 if (sd_size != NULL) {
239 *sd_size = 0;
241 return NULL;
244 /*******************************************************************
245 Convert a secdesc into a byte stream
246 ********************************************************************/
247 NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
248 const struct security_descriptor *secdesc,
249 uint8_t **data, size_t *len)
251 DATA_BLOB blob;
252 enum ndr_err_code ndr_err;
254 ndr_err = ndr_push_struct_blob(
255 &blob, mem_ctx, secdesc,
256 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
258 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
259 DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
260 ndr_errstr(ndr_err)));
261 return ndr_map_error2ntstatus(ndr_err);
264 *data = blob.data;
265 *len = blob.length;
266 return NT_STATUS_OK;
269 /*******************************************************************
270 Convert a secdesc_buf into a byte stream
271 ********************************************************************/
273 NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
274 const struct sec_desc_buf *secdesc_buf,
275 uint8_t **data, size_t *len)
277 DATA_BLOB blob;
278 enum ndr_err_code ndr_err;
280 ndr_err = ndr_push_struct_blob(
281 &blob, mem_ctx, secdesc_buf,
282 (ndr_push_flags_fn_t)ndr_push_sec_desc_buf);
284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
285 DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
286 ndr_errstr(ndr_err)));
287 return ndr_map_error2ntstatus(ndr_err);
290 *data = blob.data;
291 *len = blob.length;
292 return NT_STATUS_OK;
295 /*******************************************************************
296 Parse a byte stream into a secdesc
297 ********************************************************************/
298 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
299 struct security_descriptor **psecdesc)
301 DATA_BLOB blob;
302 enum ndr_err_code ndr_err;
303 struct security_descriptor *result;
305 if ((data == NULL) || (len == 0)) {
306 return NT_STATUS_INVALID_PARAMETER;
309 result = talloc_zero(mem_ctx, struct security_descriptor);
310 if (result == NULL) {
311 return NT_STATUS_NO_MEMORY;
314 blob = data_blob_const(data, len);
316 ndr_err = ndr_pull_struct_blob(&blob, result, result,
317 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
319 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
320 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
321 ndr_errstr(ndr_err)));
322 TALLOC_FREE(result);
323 return ndr_map_error2ntstatus(ndr_err);
326 *psecdesc = result;
327 return NT_STATUS_OK;
330 /*******************************************************************
331 Parse a byte stream into a sec_desc_buf
332 ********************************************************************/
334 NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
335 struct sec_desc_buf **psecdesc_buf)
337 DATA_BLOB blob;
338 enum ndr_err_code ndr_err;
339 struct sec_desc_buf *result;
341 if ((data == NULL) || (len == 0)) {
342 return NT_STATUS_INVALID_PARAMETER;
345 result = talloc_zero(mem_ctx, struct sec_desc_buf);
346 if (result == NULL) {
347 return NT_STATUS_NO_MEMORY;
350 blob = data_blob_const(data, len);
352 ndr_err = ndr_pull_struct_blob(&blob, result, result,
353 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
355 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
356 DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
357 ndr_errstr(ndr_err)));
358 TALLOC_FREE(result);
359 return ndr_map_error2ntstatus(ndr_err);
362 *psecdesc_buf = result;
363 return NT_STATUS_OK;
366 /*******************************************************************
367 Creates a struct security_descriptor structure with typical defaults.
368 ********************************************************************/
370 struct security_descriptor *make_standard_sec_desc(TALLOC_CTX *ctx, const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
371 struct security_acl *dacl, size_t *sd_size)
373 return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
374 SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
375 dacl, sd_size);
378 /*******************************************************************
379 Creates a struct sec_desc_buf structure.
380 ********************************************************************/
382 struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, struct security_descriptor *sec_desc)
384 struct sec_desc_buf *dst;
386 if((dst = talloc_zero(ctx, struct sec_desc_buf)) == NULL)
387 return NULL;
389 /* max buffer size (allocated size) */
390 dst->sd_size = (uint32_t)len;
392 if (sec_desc != NULL) {
393 dst->sd = security_descriptor_copy(ctx, sec_desc);
394 if (dst->sd == NULL) {
395 return NULL;
399 return dst;
402 /*******************************************************************
403 Duplicates a struct sec_desc_buf structure.
404 ********************************************************************/
406 struct sec_desc_buf *dup_sec_desc_buf(TALLOC_CTX *ctx, struct sec_desc_buf *src)
408 if(src == NULL)
409 return NULL;
411 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
414 /*******************************************************************
415 Modify a SID's permissions in a struct security_descriptor.
416 ********************************************************************/
418 NTSTATUS sec_desc_mod_sid(struct security_descriptor *sd, struct dom_sid *sid, uint32_t mask)
420 NTSTATUS status;
422 if (!sd || !sid)
423 return NT_STATUS_INVALID_PARAMETER;
425 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
427 if (!NT_STATUS_IS_OK(status))
428 return status;
430 return NT_STATUS_OK;
433 /*******************************************************************
434 Delete a SID from a struct security_descriptor.
435 ********************************************************************/
437 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, struct security_descriptor **psd, struct dom_sid *sid, size_t *sd_size)
439 struct security_descriptor *sd = 0;
440 struct security_acl *dacl = 0;
441 struct security_ace *ace = 0;
442 NTSTATUS status;
444 if (!ctx || !psd[0] || !sid || !sd_size)
445 return NT_STATUS_INVALID_PARAMETER;
447 *sd_size = 0;
449 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
451 if (!NT_STATUS_IS_OK(status))
452 return status;
454 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
455 return NT_STATUS_UNSUCCESSFUL;
457 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
458 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
459 return NT_STATUS_UNSUCCESSFUL;
461 *psd = sd;
462 sd = 0;
463 return NT_STATUS_OK;
467 * Determine if an struct security_ace is inheritable
470 static bool is_inheritable_ace(const struct security_ace *ace,
471 bool container)
473 if (!container) {
474 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
477 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
478 return true;
481 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
482 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
483 return true;
486 return false;
490 * Does a security descriptor have any inheritable components for
491 * the newly created type ?
494 bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container)
496 unsigned int i;
497 const struct security_acl *the_acl = parent_ctr->dacl;
499 if (the_acl == NULL) {
500 return false;
503 for (i = 0; i < the_acl->num_aces; i++) {
504 const struct security_ace *ace = &the_acl->aces[i];
506 if (is_inheritable_ace(ace, container)) {
507 return true;
510 return false;
513 /* Create a child security descriptor using another security descriptor as
514 the parent container. This child object can either be a container or
515 non-container object. */
517 NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
518 struct security_descriptor **ppsd,
519 size_t *psize,
520 const struct security_descriptor *parent_ctr,
521 const struct dom_sid *owner_sid,
522 const struct dom_sid *group_sid,
523 bool container)
525 struct security_acl *new_dacl = NULL, *the_acl = NULL;
526 struct security_ace *new_ace_list = NULL;
527 unsigned int new_ace_list_ndx = 0, i;
528 bool set_inherited_flags = (parent_ctr->type & SEC_DESC_DACL_AUTO_INHERITED);
530 TALLOC_CTX *frame;
532 *ppsd = NULL;
533 *psize = 0;
535 /* Currently we only process the dacl when creating the child. The
536 sacl should also be processed but this is left out as sacls are
537 not implemented in Samba at the moment.*/
539 the_acl = parent_ctr->dacl;
541 if (the_acl->num_aces) {
542 if (2*the_acl->num_aces < the_acl->num_aces) {
543 return NT_STATUS_NO_MEMORY;
546 if (!(new_ace_list = talloc_array(ctx, struct security_ace,
547 2*the_acl->num_aces))) {
548 return NT_STATUS_NO_MEMORY;
550 } else {
551 new_ace_list = NULL;
554 frame = talloc_stackframe();
556 for (i = 0; i < the_acl->num_aces; i++) {
557 const struct security_ace *ace = &the_acl->aces[i];
558 struct security_ace *new_ace = &new_ace_list[new_ace_list_ndx];
559 const struct dom_sid *ptrustee = &ace->trustee;
560 const struct dom_sid *creator = NULL;
561 uint8_t new_flags = ace->flags;
563 if (!is_inheritable_ace(ace, container)) {
564 continue;
567 /* see the RAW-ACLS inheritance test for details on these rules */
568 if (!container) {
569 new_flags = 0;
570 } else {
572 * We need to remove SEC_ACE_FLAG_INHERITED_ACE here
573 * if present because it should only be set if the
574 * parent has the AUTO_INHERITED bit set in the
575 * type/control field. If we don't it will slip through
576 * and create DACLs with incorrectly ordered ACEs
577 * when there are CREATOR_OWNER or CREATOR_GROUP
578 * ACEs.
580 new_flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY
581 | SEC_ACE_FLAG_INHERITED_ACE);
583 if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
584 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
586 if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
587 new_flags = 0;
591 /* The CREATOR sids are special when inherited */
592 if (dom_sid_equal(ptrustee, &global_sid_Creator_Owner)) {
593 creator = &global_sid_Creator_Owner;
594 ptrustee = owner_sid;
595 } else if (dom_sid_equal(ptrustee, &global_sid_Creator_Group)) {
596 creator = &global_sid_Creator_Group;
597 ptrustee = group_sid;
600 if (creator && container &&
601 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
603 /* First add the regular ACE entry. */
604 init_sec_ace(new_ace, ptrustee, ace->type,
605 ace->access_mask,
606 set_inherited_flags ? SEC_ACE_FLAG_INHERITED_ACE : 0);
608 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
609 " inherited as %s:%d/0x%02x/0x%08x\n",
610 dom_sid_string(frame, &ace->trustee),
611 ace->type, ace->flags, ace->access_mask,
612 dom_sid_string(frame, &new_ace->trustee),
613 new_ace->type, new_ace->flags,
614 new_ace->access_mask));
616 new_ace_list_ndx++;
618 /* Now add the extra creator ACE. */
619 new_ace = &new_ace_list[new_ace_list_ndx];
621 ptrustee = creator;
622 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
624 } else if (container &&
625 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
626 ptrustee = &ace->trustee;
629 init_sec_ace(new_ace, ptrustee, ace->type,
630 ace->access_mask, new_flags |
631 (set_inherited_flags ? SEC_ACE_FLAG_INHERITED_ACE : 0));
633 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
634 " inherited as %s:%d/0x%02x/0x%08x\n",
635 dom_sid_string(frame, &ace->trustee),
636 ace->type, ace->flags, ace->access_mask,
637 dom_sid_string(frame, &ace->trustee),
638 new_ace->type, new_ace->flags,
639 new_ace->access_mask));
641 new_ace_list_ndx++;
644 talloc_free(frame);
647 * remove duplicates
649 for (i=1; i < new_ace_list_ndx;) {
650 struct security_ace *ai = &new_ace_list[i];
651 unsigned int remaining, j;
652 bool remove_ace = false;
654 for (j=0; j < i; j++) {
655 struct security_ace *aj = &new_ace_list[j];
657 if (!sec_ace_equal(ai, aj)) {
658 continue;
661 remove_ace = true;
662 break;
665 if (!remove_ace) {
666 i++;
667 continue;
670 new_ace_list_ndx--;
671 remaining = new_ace_list_ndx - i;
672 if (remaining == 0) {
673 ZERO_STRUCT(new_ace_list[i]);
674 continue;
676 memmove(&new_ace_list[i], &new_ace_list[i+1],
677 sizeof(new_ace_list[i]) * remaining);
680 /* Create child security descriptor to return */
681 if (new_ace_list_ndx) {
682 new_dacl = make_sec_acl(ctx,
683 NT4_ACL_REVISION,
684 new_ace_list_ndx,
685 new_ace_list);
687 if (!new_dacl) {
688 return NT_STATUS_NO_MEMORY;
692 *ppsd = make_sec_desc(ctx,
693 SECURITY_DESCRIPTOR_REVISION_1,
694 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT|
695 (set_inherited_flags ? SEC_DESC_DACL_AUTO_INHERITED : 0),
696 owner_sid,
697 group_sid,
698 NULL,
699 new_dacl,
700 psize);
701 if (!*ppsd) {
702 return NT_STATUS_NO_MEMORY;
704 return NT_STATUS_OK;
707 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
708 struct sec_desc_buf **ppsdb,
709 const struct security_descriptor *parent_ctr,
710 bool container)
712 NTSTATUS status;
713 size_t size = 0;
714 struct security_descriptor *sd = NULL;
716 *ppsdb = NULL;
717 status = se_create_child_secdesc(ctx,
718 &sd,
719 &size,
720 parent_ctr,
721 parent_ctr->owner_sid,
722 parent_ctr->group_sid,
723 container);
724 if (!NT_STATUS_IS_OK(status)) {
725 return status;
728 *ppsdb = make_sec_desc_buf(ctx, size, sd);
729 if (!*ppsdb) {
730 return NT_STATUS_NO_MEMORY;
732 return NT_STATUS_OK;