Revert "ldb: Remove Samba-specific symbols."
[Samba/ekacnet.git] / source3 / lib / secdesc.c
blobfc40b9ebf8cd580c402b245fa9c663ea55814215
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.
8 *
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"
26 /* Map generic permissions to file object specific permissions */
28 const struct generic_mapping file_generic_mapping = {
29 FILE_GENERIC_READ,
30 FILE_GENERIC_WRITE,
31 FILE_GENERIC_EXECUTE,
32 FILE_GENERIC_ALL
35 /*******************************************************************
36 Given a security_descriptor return the sec_info.
37 ********************************************************************/
39 uint32_t get_sec_info(const struct security_descriptor *sd)
41 uint32_t sec_info = ALL_SECURITY_INFORMATION;
43 SMB_ASSERT(sd);
45 if (sd->owner_sid == NULL) {
46 sec_info &= ~OWNER_SECURITY_INFORMATION;
48 if (sd->group_sid == NULL) {
49 sec_info &= ~GROUP_SECURITY_INFORMATION;
51 if (sd->sacl == NULL) {
52 sec_info &= ~SACL_SECURITY_INFORMATION;
54 if (sd->dacl == NULL) {
55 sec_info &= ~DACL_SECURITY_INFORMATION;
58 return sec_info;
62 /*******************************************************************
63 Merge part of security descriptor old_sec in to the empty sections of
64 security descriptor new_sec.
65 ********************************************************************/
67 struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb)
69 struct dom_sid *owner_sid, *group_sid;
70 struct sec_desc_buf *return_sdb;
71 struct security_acl *dacl, *sacl;
72 struct security_descriptor *psd = NULL;
73 uint16 secdesc_type;
74 size_t secdesc_size;
76 /* Copy over owner and group sids. There seems to be no flag for
77 this so just check the pointer values. */
79 owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
80 old_sdb->sd->owner_sid;
82 group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
83 old_sdb->sd->group_sid;
85 secdesc_type = new_sdb->sd->type;
87 /* Ignore changes to the system ACL. This has the effect of making
88 changes through the security tab audit button not sticking.
89 Perhaps in future Samba could implement these settings somehow. */
91 sacl = NULL;
92 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
94 /* Copy across discretionary ACL */
96 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
97 dacl = new_sdb->sd->dacl;
98 } else {
99 dacl = old_sdb->sd->dacl;
102 /* Create new security descriptor from bits */
104 psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
105 owner_sid, group_sid, sacl, dacl, &secdesc_size);
107 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
109 return(return_sdb);
112 struct security_descriptor *sec_desc_merge(TALLOC_CTX *ctx, struct security_descriptor *new_sdb, struct security_descriptor *old_sdb)
114 struct dom_sid *owner_sid, *group_sid;
115 struct security_acl *dacl, *sacl;
116 struct security_descriptor *psd = NULL;
117 uint16 secdesc_type;
118 size_t secdesc_size;
120 /* Copy over owner and group sids. There seems to be no flag for
121 this so just check the pointer values. */
123 owner_sid = new_sdb->owner_sid ? new_sdb->owner_sid :
124 old_sdb->owner_sid;
126 group_sid = new_sdb->group_sid ? new_sdb->group_sid :
127 old_sdb->group_sid;
129 secdesc_type = new_sdb->type;
131 /* Ignore changes to the system ACL. This has the effect of making
132 changes through the security tab audit button not sticking.
133 Perhaps in future Samba could implement these settings somehow. */
135 sacl = NULL;
136 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
138 /* Copy across discretionary ACL */
140 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
141 dacl = new_sdb->dacl;
142 } else {
143 dacl = old_sdb->dacl;
146 /* Create new security descriptor from bits */
147 psd = make_sec_desc(ctx, new_sdb->revision, secdesc_type,
148 owner_sid, group_sid, sacl, dacl, &secdesc_size);
150 return psd;
153 /*******************************************************************
154 Creates a struct security_descriptor structure
155 ********************************************************************/
157 #define SEC_DESC_HEADER_SIZE (2 * sizeof(uint16) + 4 * sizeof(uint32))
159 struct security_descriptor *make_sec_desc(TALLOC_CTX *ctx,
160 enum security_descriptor_revision revision,
161 uint16 type,
162 const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
163 struct security_acl *sacl, struct security_acl *dacl, size_t *sd_size)
165 struct security_descriptor *dst;
166 uint32 offset = 0;
168 *sd_size = 0;
170 if(( dst = TALLOC_ZERO_P(ctx, struct security_descriptor)) == NULL)
171 return NULL;
173 dst->revision = revision;
174 dst->type = type;
176 if (sacl)
177 dst->type |= SEC_DESC_SACL_PRESENT;
178 if (dacl)
179 dst->type |= SEC_DESC_DACL_PRESENT;
181 dst->owner_sid = NULL;
182 dst->group_sid = NULL;
183 dst->sacl = NULL;
184 dst->dacl = NULL;
186 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
187 goto error_exit;
189 if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
190 goto error_exit;
192 if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
193 goto error_exit;
195 if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
196 goto error_exit;
198 offset = SEC_DESC_HEADER_SIZE;
201 * Work out the linearization sizes.
204 if (dst->sacl != NULL) {
205 offset += dst->sacl->size;
207 if (dst->dacl != NULL) {
208 offset += dst->dacl->size;
211 if (dst->owner_sid != NULL) {
212 offset += ndr_size_dom_sid(dst->owner_sid, 0);
215 if (dst->group_sid != NULL) {
216 offset += ndr_size_dom_sid(dst->group_sid, 0);
219 *sd_size = (size_t)offset;
220 return dst;
222 error_exit:
224 *sd_size = 0;
225 return NULL;
228 /*******************************************************************
229 Duplicate a struct security_descriptor structure.
230 ********************************************************************/
232 struct security_descriptor *dup_sec_desc(TALLOC_CTX *ctx, const struct security_descriptor *src)
234 size_t dummy;
236 if(src == NULL)
237 return NULL;
239 return make_sec_desc( ctx, src->revision, src->type,
240 src->owner_sid, src->group_sid, src->sacl,
241 src->dacl, &dummy);
244 /*******************************************************************
245 Convert a secdesc into a byte stream
246 ********************************************************************/
247 NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
248 struct security_descriptor *secdesc,
249 uint8 **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 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 *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_P(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_P(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_P(ctx, struct sec_desc_buf)) == NULL)
387 return NULL;
389 /* max buffer size (allocated size) */
390 dst->sd_size = (uint32)len;
392 if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
393 return NULL;
396 return dst;
399 /*******************************************************************
400 Duplicates a struct sec_desc_buf structure.
401 ********************************************************************/
403 struct sec_desc_buf *dup_sec_desc_buf(TALLOC_CTX *ctx, struct sec_desc_buf *src)
405 if(src == NULL)
406 return NULL;
408 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
411 /*******************************************************************
412 Add a new SID with its permissions to struct security_descriptor.
413 ********************************************************************/
415 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, struct security_descriptor **psd, struct dom_sid *sid, uint32 mask, size_t *sd_size)
417 struct security_descriptor *sd = 0;
418 struct security_acl *dacl = 0;
419 struct security_ace *ace = 0;
420 NTSTATUS status;
422 if (!ctx || !psd || !sid || !sd_size)
423 return NT_STATUS_INVALID_PARAMETER;
425 *sd_size = 0;
427 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
429 if (!NT_STATUS_IS_OK(status))
430 return status;
432 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
433 return NT_STATUS_UNSUCCESSFUL;
435 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
436 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
437 return NT_STATUS_UNSUCCESSFUL;
439 *psd = sd;
440 sd = 0;
441 return NT_STATUS_OK;
444 /*******************************************************************
445 Modify a SID's permissions in a struct security_descriptor.
446 ********************************************************************/
448 NTSTATUS sec_desc_mod_sid(struct security_descriptor *sd, struct dom_sid *sid, uint32 mask)
450 NTSTATUS status;
452 if (!sd || !sid)
453 return NT_STATUS_INVALID_PARAMETER;
455 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
457 if (!NT_STATUS_IS_OK(status))
458 return status;
460 return NT_STATUS_OK;
463 /*******************************************************************
464 Delete a SID from a struct security_descriptor.
465 ********************************************************************/
467 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, struct security_descriptor **psd, struct dom_sid *sid, size_t *sd_size)
469 struct security_descriptor *sd = 0;
470 struct security_acl *dacl = 0;
471 struct security_ace *ace = 0;
472 NTSTATUS status;
474 if (!ctx || !psd[0] || !sid || !sd_size)
475 return NT_STATUS_INVALID_PARAMETER;
477 *sd_size = 0;
479 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
481 if (!NT_STATUS_IS_OK(status))
482 return status;
484 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
485 return NT_STATUS_UNSUCCESSFUL;
487 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
488 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
489 return NT_STATUS_UNSUCCESSFUL;
491 *psd = sd;
492 sd = 0;
493 return NT_STATUS_OK;
497 * Determine if an struct security_ace is inheritable
500 static bool is_inheritable_ace(const struct security_ace *ace,
501 bool container)
503 if (!container) {
504 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
507 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
508 return true;
511 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
512 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
513 return true;
516 return false;
520 * Does a security descriptor have any inheritable components for
521 * the newly created type ?
524 bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container)
526 unsigned int i;
527 const struct security_acl *the_acl = parent_ctr->dacl;
529 for (i = 0; i < the_acl->num_aces; i++) {
530 const struct security_ace *ace = &the_acl->aces[i];
532 if (is_inheritable_ace(ace, container)) {
533 return true;
536 return false;
539 /* Create a child security descriptor using another security descriptor as
540 the parent container. This child object can either be a container or
541 non-container object. */
543 NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
544 struct security_descriptor **ppsd,
545 size_t *psize,
546 const struct security_descriptor *parent_ctr,
547 const struct dom_sid *owner_sid,
548 const struct dom_sid *group_sid,
549 bool container)
551 struct security_acl *new_dacl = NULL, *the_acl = NULL;
552 struct security_ace *new_ace_list = NULL;
553 unsigned int new_ace_list_ndx = 0, i;
555 *ppsd = NULL;
556 *psize = 0;
558 /* Currently we only process the dacl when creating the child. The
559 sacl should also be processed but this is left out as sacls are
560 not implemented in Samba at the moment.*/
562 the_acl = parent_ctr->dacl;
564 if (the_acl->num_aces) {
565 if (2*the_acl->num_aces < the_acl->num_aces) {
566 return NT_STATUS_NO_MEMORY;
569 if (!(new_ace_list = TALLOC_ARRAY(ctx, struct security_ace,
570 2*the_acl->num_aces))) {
571 return NT_STATUS_NO_MEMORY;
573 } else {
574 new_ace_list = NULL;
577 for (i = 0; i < the_acl->num_aces; i++) {
578 const struct security_ace *ace = &the_acl->aces[i];
579 struct security_ace *new_ace = &new_ace_list[new_ace_list_ndx];
580 const struct dom_sid *ptrustee = &ace->trustee;
581 const struct dom_sid *creator = NULL;
582 uint8 new_flags = ace->flags;
584 if (!is_inheritable_ace(ace, container)) {
585 continue;
588 /* see the RAW-ACLS inheritance test for details on these rules */
589 if (!container) {
590 new_flags = 0;
591 } else {
592 new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
594 if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
595 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
597 if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
598 new_flags = 0;
602 /* The CREATOR sids are special when inherited */
603 if (sid_equal(ptrustee, &global_sid_Creator_Owner)) {
604 creator = &global_sid_Creator_Owner;
605 ptrustee = owner_sid;
606 } else if (sid_equal(ptrustee, &global_sid_Creator_Group)) {
607 creator = &global_sid_Creator_Group;
608 ptrustee = group_sid;
611 if (creator && container &&
612 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
614 /* First add the regular ACE entry. */
615 init_sec_ace(new_ace, ptrustee, ace->type,
616 ace->access_mask, 0);
618 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
619 " inherited as %s:%d/0x%02x/0x%08x\n",
620 sid_string_dbg(&ace->trustee),
621 ace->type, ace->flags, ace->access_mask,
622 sid_string_dbg(&new_ace->trustee),
623 new_ace->type, new_ace->flags,
624 new_ace->access_mask));
626 new_ace_list_ndx++;
628 /* Now add the extra creator ACE. */
629 new_ace = &new_ace_list[new_ace_list_ndx];
631 ptrustee = creator;
632 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
633 } else if (container &&
634 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
635 ptrustee = &ace->trustee;
638 init_sec_ace(new_ace, ptrustee, ace->type,
639 ace->access_mask, new_flags);
641 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
642 " inherited as %s:%d/0x%02x/0x%08x\n",
643 sid_string_dbg(&ace->trustee),
644 ace->type, ace->flags, ace->access_mask,
645 sid_string_dbg(&ace->trustee),
646 new_ace->type, new_ace->flags,
647 new_ace->access_mask));
649 new_ace_list_ndx++;
652 /* Create child security descriptor to return */
653 if (new_ace_list_ndx) {
654 new_dacl = make_sec_acl(ctx,
655 NT4_ACL_REVISION,
656 new_ace_list_ndx,
657 new_ace_list);
659 if (!new_dacl) {
660 return NT_STATUS_NO_MEMORY;
664 *ppsd = make_sec_desc(ctx,
665 SECURITY_DESCRIPTOR_REVISION_1,
666 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
667 owner_sid,
668 group_sid,
669 NULL,
670 new_dacl,
671 psize);
672 if (!*ppsd) {
673 return NT_STATUS_NO_MEMORY;
675 return NT_STATUS_OK;
678 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
679 struct sec_desc_buf **ppsdb,
680 const struct security_descriptor *parent_ctr,
681 bool container)
683 NTSTATUS status;
684 size_t size = 0;
685 struct security_descriptor *sd = NULL;
687 *ppsdb = NULL;
688 status = se_create_child_secdesc(ctx,
689 &sd,
690 &size,
691 parent_ctr,
692 parent_ctr->owner_sid,
693 parent_ctr->group_sid,
694 container);
695 if (!NT_STATUS_IS_OK(status)) {
696 return status;
699 *ppsdb = make_sec_desc_buf(ctx, size, sd);
700 if (!*ppsdb) {
701 return NT_STATUS_NO_MEMORY;
703 return NT_STATUS_OK;