docs: Improve description of the share commands in man smb.conf.
[Samba/gebeck_regimport.git] / source3 / lib / secdesc.c
blob232bbca43c876d4b62766de73beef013bfb3fc64
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 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)
299 DATA_BLOB blob;
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)));
321 TALLOC_FREE(result);
322 return ndr_map_error2ntstatus(ndr_err);;
325 *psecdesc = result;
326 return NT_STATUS_OK;
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,
338 dacl, sd_size);
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)
347 SEC_DESC_BUF *dst;
349 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
350 return 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)) {
356 return NULL;
359 return dst;
362 /*******************************************************************
363 Duplicates a SEC_DESC_BUF structure.
364 ********************************************************************/
366 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
368 if(src == NULL)
369 return NULL;
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)
380 SEC_DESC *sd = 0;
381 SEC_ACL *dacl = 0;
382 SEC_ACE *ace = 0;
383 NTSTATUS status;
385 if (!ctx || !psd || !sid || !sd_size)
386 return NT_STATUS_INVALID_PARAMETER;
388 *sd_size = 0;
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))
393 return 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;
402 *psd = sd;
403 sd = 0;
404 return NT_STATUS_OK;
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)
413 NTSTATUS status;
415 if (!sd || !sid)
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))
421 return status;
423 return NT_STATUS_OK;
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)
432 SEC_DESC *sd = 0;
433 SEC_ACL *dacl = 0;
434 SEC_ACE *ace = 0;
435 NTSTATUS status;
437 if (!ctx || !psd[0] || !sid || !sd_size)
438 return NT_STATUS_INVALID_PARAMETER;
440 *sd_size = 0;
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))
445 return 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;
454 *psd = sd;
455 sd = 0;
456 return NT_STATUS_OK;
460 * Determine if an ACE is inheritable
463 static bool is_inheritable_ace(const SEC_ACE *ace,
464 bool container)
466 if (!container) {
467 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
470 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
471 return true;
474 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
475 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
476 return true;
479 return false;
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,
487 SEC_DESC **ppsd,
488 size_t *psize,
489 const SEC_DESC *parent_ctr,
490 const DOM_SID *owner_sid,
491 const DOM_SID *group_sid,
492 bool container)
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;
498 *ppsd = NULL;
499 *psize = 0;
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;
516 } else {
517 new_ace_list = NULL;
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)) {
528 continue;
531 /* see the RAW-ACLS inheritance test for details on these rules */
532 if (!container) {
533 new_flags = 0;
534 } else {
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) {
541 new_flags = 0;
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));
569 new_ace_list_ndx++;
571 /* Now add the extra creator ACE. */
572 new_ace = &new_ace_list[new_ace_list_ndx];
574 ptrustee = creator;
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));
592 new_ace_list_ndx++;
595 /* Create child security descriptor to return */
596 if (new_ace_list_ndx) {
597 new_dacl = make_sec_acl(ctx,
598 NT4_ACL_REVISION,
599 new_ace_list_ndx,
600 new_ace_list);
602 if (!new_dacl) {
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,
610 owner_sid,
611 group_sid,
612 NULL,
613 new_dacl,
614 psize);
615 if (!*ppsd) {
616 return NT_STATUS_NO_MEMORY;
618 return NT_STATUS_OK;
621 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
622 SEC_DESC_BUF **ppsdb,
623 const SEC_DESC *parent_ctr,
624 bool container)
626 NTSTATUS status;
627 size_t size = 0;
628 SEC_DESC *sd = NULL;
630 *ppsdb = NULL;
631 status = se_create_child_secdesc(ctx,
632 &sd,
633 &size,
634 parent_ctr,
635 parent_ctr->owner_sid,
636 parent_ctr->group_sid,
637 container);
638 if (!NT_STATUS_IS_OK(status)) {
639 return status;
642 *ppsdb = make_sec_desc_buf(ctx, size, sd);
643 if (!*ppsdb) {
644 return NT_STATUS_NO_MEMORY;
646 return NT_STATUS_OK;