WHATSNEW: Update release notes.
[Samba.git] / source3 / lib / secdesc.c
bloba81c4ae82a2e3ba8150527af896ffa8e382d4ac9
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"
25 /* Map generic permissions to file object specific permissions */
27 const struct generic_mapping file_generic_mapping = {
28 FILE_GENERIC_READ,
29 FILE_GENERIC_WRITE,
30 FILE_GENERIC_EXECUTE,
31 FILE_GENERIC_ALL
34 /*******************************************************************
35 Compares two SEC_DESC structures
36 ********************************************************************/
38 bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
40 /* Trivial case */
42 if (!s1 && !s2) {
43 goto done;
46 if (!s1 || !s2) {
47 return False;
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));
55 return False;
58 if (s1->type!= s2->type) {
59 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
60 s1->type, s2->type));
61 return False;
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)));
70 return False;
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)));
77 return False;
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"));
85 return False;
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"));
94 return False;
97 done:
98 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
99 return True;
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;
110 SMB_ASSERT(sd);
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;
125 return sec_info;
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;
140 uint16 secdesc_type;
141 size_t secdesc_size;
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. */
158 sacl = NULL;
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;
165 } else {
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);
176 return(return_sdb);
179 /*******************************************************************
180 Creates a SEC_DESC structure
181 ********************************************************************/
183 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx,
184 enum security_descriptor_revision revision,
185 uint16 type,
186 const DOM_SID *owner_sid, const DOM_SID *grp_sid,
187 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
189 SEC_DESC *dst;
190 uint32 offset = 0;
192 *sd_size = 0;
194 if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
195 return NULL;
197 dst->revision = revision;
198 dst->type = type;
200 if (sacl)
201 dst->type |= SEC_DESC_SACL_PRESENT;
202 if (dacl)
203 dst->type |= SEC_DESC_DACL_PRESENT;
205 dst->owner_sid = NULL;
206 dst->group_sid = NULL;
207 dst->sacl = NULL;
208 dst->dacl = NULL;
210 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
211 goto error_exit;
213 if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
214 goto error_exit;
216 if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
217 goto error_exit;
219 if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
220 goto error_exit;
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;
244 return dst;
246 error_exit:
248 *sd_size = 0;
249 return NULL;
252 /*******************************************************************
253 Duplicate a SEC_DESC structure.
254 ********************************************************************/
256 SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
258 size_t dummy;
260 if(src == NULL)
261 return NULL;
263 return make_sec_desc( ctx, src->revision, src->type,
264 src->owner_sid, src->group_sid, src->sacl,
265 src->dacl, &dummy);
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)
275 DATA_BLOB blob;
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);;
288 *data = blob.data;
289 *len = blob.length;
290 return NT_STATUS_OK;
293 /*******************************************************************
294 Convert a secdesc_buf into a byte stream
295 ********************************************************************/
297 NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
298 struct sec_desc_buf *secdesc_buf,
299 uint8_t **data, size_t *len)
301 DATA_BLOB blob;
302 enum ndr_err_code ndr_err;
304 ndr_err = ndr_push_struct_blob(
305 &blob, mem_ctx, NULL, secdesc_buf,
306 (ndr_push_flags_fn_t)ndr_push_sec_desc_buf);
308 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
309 DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
310 ndr_errstr(ndr_err)));
311 return ndr_map_error2ntstatus(ndr_err);;
314 *data = blob.data;
315 *len = blob.length;
316 return NT_STATUS_OK;
319 /*******************************************************************
320 Parse a byte stream into a secdesc
321 ********************************************************************/
322 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
323 struct security_descriptor **psecdesc)
325 DATA_BLOB blob;
326 enum ndr_err_code ndr_err;
327 struct security_descriptor *result;
329 if ((data == NULL) || (len == 0)) {
330 return NT_STATUS_INVALID_PARAMETER;
333 result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
334 if (result == NULL) {
335 return NT_STATUS_NO_MEMORY;
338 blob = data_blob_const(data, len);
340 ndr_err = ndr_pull_struct_blob(
341 &blob, result, NULL, result,
342 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
344 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
345 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
346 ndr_errstr(ndr_err)));
347 TALLOC_FREE(result);
348 return ndr_map_error2ntstatus(ndr_err);;
351 *psecdesc = result;
352 return NT_STATUS_OK;
355 /*******************************************************************
356 Parse a byte stream into a sec_desc_buf
357 ********************************************************************/
359 NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
360 struct sec_desc_buf **psecdesc_buf)
362 DATA_BLOB blob;
363 enum ndr_err_code ndr_err;
364 struct sec_desc_buf *result;
366 if ((data == NULL) || (len == 0)) {
367 return NT_STATUS_INVALID_PARAMETER;
370 result = TALLOC_ZERO_P(mem_ctx, struct sec_desc_buf);
371 if (result == NULL) {
372 return NT_STATUS_NO_MEMORY;
375 blob = data_blob_const(data, len);
377 ndr_err = ndr_pull_struct_blob(
378 &blob, result, NULL, result,
379 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
382 DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
383 ndr_errstr(ndr_err)));
384 TALLOC_FREE(result);
385 return ndr_map_error2ntstatus(ndr_err);;
388 *psecdesc_buf = result;
389 return NT_STATUS_OK;
392 /*******************************************************************
393 Creates a SEC_DESC structure with typical defaults.
394 ********************************************************************/
396 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
397 SEC_ACL *dacl, size_t *sd_size)
399 return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
400 SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
401 dacl, sd_size);
404 /*******************************************************************
405 Creates a SEC_DESC_BUF structure.
406 ********************************************************************/
408 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
410 SEC_DESC_BUF *dst;
412 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
413 return NULL;
415 /* max buffer size (allocated size) */
416 dst->sd_size = (uint32)len;
418 if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
419 return NULL;
422 return dst;
425 /*******************************************************************
426 Duplicates a SEC_DESC_BUF structure.
427 ********************************************************************/
429 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
431 if(src == NULL)
432 return NULL;
434 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
437 /*******************************************************************
438 Add a new SID with its permissions to SEC_DESC.
439 ********************************************************************/
441 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
443 SEC_DESC *sd = 0;
444 SEC_ACL *dacl = 0;
445 SEC_ACE *ace = 0;
446 NTSTATUS status;
448 if (!ctx || !psd || !sid || !sd_size)
449 return NT_STATUS_INVALID_PARAMETER;
451 *sd_size = 0;
453 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
455 if (!NT_STATUS_IS_OK(status))
456 return status;
458 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
459 return NT_STATUS_UNSUCCESSFUL;
461 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
462 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
463 return NT_STATUS_UNSUCCESSFUL;
465 *psd = sd;
466 sd = 0;
467 return NT_STATUS_OK;
470 /*******************************************************************
471 Modify a SID's permissions in a SEC_DESC.
472 ********************************************************************/
474 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
476 NTSTATUS status;
478 if (!sd || !sid)
479 return NT_STATUS_INVALID_PARAMETER;
481 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
483 if (!NT_STATUS_IS_OK(status))
484 return status;
486 return NT_STATUS_OK;
489 /*******************************************************************
490 Delete a SID from a SEC_DESC.
491 ********************************************************************/
493 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
495 SEC_DESC *sd = 0;
496 SEC_ACL *dacl = 0;
497 SEC_ACE *ace = 0;
498 NTSTATUS status;
500 if (!ctx || !psd[0] || !sid || !sd_size)
501 return NT_STATUS_INVALID_PARAMETER;
503 *sd_size = 0;
505 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
507 if (!NT_STATUS_IS_OK(status))
508 return status;
510 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
511 return NT_STATUS_UNSUCCESSFUL;
513 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
514 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
515 return NT_STATUS_UNSUCCESSFUL;
517 *psd = sd;
518 sd = 0;
519 return NT_STATUS_OK;
523 * Determine if an ACE is inheritable
526 static bool is_inheritable_ace(const SEC_ACE *ace,
527 bool container)
529 if (!container) {
530 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
533 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
534 return true;
537 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
538 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
539 return true;
542 return false;
545 /* Create a child security descriptor using another security descriptor as
546 the parent container. This child object can either be a container or
547 non-container object. */
549 NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
550 SEC_DESC **ppsd,
551 size_t *psize,
552 const SEC_DESC *parent_ctr,
553 const DOM_SID *owner_sid,
554 const DOM_SID *group_sid,
555 bool container)
557 SEC_ACL *new_dacl = NULL, *the_acl = NULL;
558 SEC_ACE *new_ace_list = NULL;
559 unsigned int new_ace_list_ndx = 0, i;
561 *ppsd = NULL;
562 *psize = 0;
564 /* Currently we only process the dacl when creating the child. The
565 sacl should also be processed but this is left out as sacls are
566 not implemented in Samba at the moment.*/
568 the_acl = parent_ctr->dacl;
570 if (the_acl->num_aces) {
571 if (2*the_acl->num_aces < the_acl->num_aces) {
572 return NT_STATUS_NO_MEMORY;
575 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE,
576 2*the_acl->num_aces))) {
577 return NT_STATUS_NO_MEMORY;
579 } else {
580 new_ace_list = NULL;
583 for (i = 0; i < the_acl->num_aces; i++) {
584 const SEC_ACE *ace = &the_acl->aces[i];
585 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
586 const DOM_SID *ptrustee = &ace->trustee;
587 const DOM_SID *creator = NULL;
588 uint8 new_flags = ace->flags;
590 if (!is_inheritable_ace(ace, container)) {
591 continue;
594 /* see the RAW-ACLS inheritance test for details on these rules */
595 if (!container) {
596 new_flags = 0;
597 } else {
598 new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
600 if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
601 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
603 if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
604 new_flags = 0;
608 /* The CREATOR sids are special when inherited */
609 if (sid_equal(ptrustee, &global_sid_Creator_Owner)) {
610 creator = &global_sid_Creator_Owner;
611 ptrustee = owner_sid;
612 } else if (sid_equal(ptrustee, &global_sid_Creator_Group)) {
613 creator = &global_sid_Creator_Group;
614 ptrustee = group_sid;
617 if (creator && container &&
618 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
620 /* First add the regular ACE entry. */
621 init_sec_ace(new_ace, ptrustee, ace->type,
622 ace->access_mask, 0);
624 DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
625 " inherited as %s:%d/0x%02x/0x%08x\n",
626 sid_string_dbg(&ace->trustee),
627 ace->type, ace->flags, ace->access_mask,
628 sid_string_dbg(&new_ace->trustee),
629 new_ace->type, new_ace->flags,
630 new_ace->access_mask));
632 new_ace_list_ndx++;
634 /* Now add the extra creator ACE. */
635 new_ace = &new_ace_list[new_ace_list_ndx];
637 ptrustee = creator;
638 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
639 } else if (container &&
640 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
641 ptrustee = &ace->trustee;
644 init_sec_ace(new_ace, ptrustee, ace->type,
645 ace->access_mask, new_flags);
647 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
648 " inherited as %s:%d/0x%02x/0x%08x\n",
649 sid_string_dbg(&ace->trustee),
650 ace->type, ace->flags, ace->access_mask,
651 sid_string_dbg(&ace->trustee),
652 new_ace->type, new_ace->flags,
653 new_ace->access_mask));
655 new_ace_list_ndx++;
658 /* Create child security descriptor to return */
659 if (new_ace_list_ndx) {
660 new_dacl = make_sec_acl(ctx,
661 NT4_ACL_REVISION,
662 new_ace_list_ndx,
663 new_ace_list);
665 if (!new_dacl) {
666 return NT_STATUS_NO_MEMORY;
670 *ppsd = make_sec_desc(ctx,
671 SECURITY_DESCRIPTOR_REVISION_1,
672 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
673 owner_sid,
674 group_sid,
675 NULL,
676 new_dacl,
677 psize);
678 if (!*ppsd) {
679 return NT_STATUS_NO_MEMORY;
681 return NT_STATUS_OK;
684 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
685 SEC_DESC_BUF **ppsdb,
686 const SEC_DESC *parent_ctr,
687 bool container)
689 NTSTATUS status;
690 size_t size = 0;
691 SEC_DESC *sd = NULL;
693 *ppsdb = NULL;
694 status = se_create_child_secdesc(ctx,
695 &sd,
696 &size,
697 parent_ctr,
698 parent_ctr->owner_sid,
699 parent_ctr->group_sid,
700 container);
701 if (!NT_STATUS_IS_OK(status)) {
702 return status;
705 *ppsdb = make_sec_desc_buf(ctx, size, sd);
706 if (!*ppsdb) {
707 return NT_STATUS_NO_MEMORY;
709 return NT_STATUS_OK;