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 Works out the linearization size of a SEC_DESC.
36 ********************************************************************/
38 size_t sec_desc_size(SEC_DESC *psd)
44 offset = SEC_DESC_HEADER_SIZE;
48 if (psd->owner_sid != NULL)
49 offset += sid_size(psd->owner_sid);
51 if (psd->group_sid != NULL)
52 offset += sid_size(psd->group_sid);
54 if (psd->sacl != NULL)
55 offset += psd->sacl->size;
57 if (psd->dacl != NULL)
58 offset += psd->dacl->size;
63 /*******************************************************************
64 Compares two SEC_DESC structures
65 ********************************************************************/
67 bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
79 /* Check top level stuff */
81 if (s1->revision != s2->revision) {
82 DEBUG(10, ("sec_desc_equal(): revision differs (%d != %d)\n",
83 s1->revision, s2->revision));
87 if (s1->type!= s2->type) {
88 DEBUG(10, ("sec_desc_equal(): type differs (%d != %d)\n",
93 /* Check owner and group */
95 if (!sid_equal(s1->owner_sid, s2->owner_sid)) {
98 sid_to_string(str1, s1->owner_sid);
99 sid_to_string(str2, s2->owner_sid);
101 DEBUG(10, ("sec_desc_equal(): owner differs (%s != %s)\n",
106 if (!sid_equal(s1->group_sid, s2->group_sid)) {
109 sid_to_string(str1, s1->group_sid);
110 sid_to_string(str2, s2->group_sid);
112 DEBUG(10, ("sec_desc_equal(): group differs (%s != %s)\n",
117 /* Check ACLs present in one but not the other */
119 if ((s1->dacl && !s2->dacl) || (!s1->dacl && s2->dacl) ||
120 (s1->sacl && !s2->sacl) || (!s1->sacl && s2->sacl)) {
121 DEBUG(10, ("sec_desc_equal(): dacl or sacl not present\n"));
125 /* Sigh - we have to do it the hard way by iterating over all
126 the ACEs in the ACLs */
128 if (!sec_acl_equal(s1->dacl, s2->dacl) ||
129 !sec_acl_equal(s1->sacl, s2->sacl)) {
130 DEBUG(10, ("sec_desc_equal(): dacl/sacl list not equal\n"));
135 DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
139 /*******************************************************************
140 Merge part of security descriptor old_sec in to the empty sections of
141 security descriptor new_sec.
142 ********************************************************************/
144 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
146 DOM_SID *owner_sid, *group_sid;
147 SEC_DESC_BUF *return_sdb;
148 SEC_ACL *dacl, *sacl;
149 SEC_DESC *psd = NULL;
153 /* Copy over owner and group sids. There seems to be no flag for
154 this so just check the pointer values. */
156 owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
157 old_sdb->sd->owner_sid;
159 group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
160 old_sdb->sd->group_sid;
162 secdesc_type = new_sdb->sd->type;
164 /* Ignore changes to the system ACL. This has the effect of making
165 changes through the security tab audit button not sticking.
166 Perhaps in future Samba could implement these settings somehow. */
169 secdesc_type &= ~SEC_DESC_SACL_PRESENT;
171 /* Copy across discretionary ACL */
173 if (secdesc_type & SEC_DESC_DACL_PRESENT) {
174 dacl = new_sdb->sd->dacl;
176 dacl = old_sdb->sd->dacl;
179 /* Create new security descriptor from bits */
181 psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
182 owner_sid, group_sid, sacl, dacl, &secdesc_size);
184 return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
189 /*******************************************************************
190 Creates a SEC_DESC structure
191 ********************************************************************/
193 SEC_DESC *make_sec_desc(TALLOC_CTX *ctx, uint16 revision, uint16 type,
194 const DOM_SID *owner_sid, const DOM_SID *grp_sid,
195 SEC_ACL *sacl, SEC_ACL *dacl, size_t *sd_size)
202 if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
205 dst->revision = revision;
209 dst->type |= SEC_DESC_SACL_PRESENT;
211 dst->type |= SEC_DESC_DACL_PRESENT;
213 dst->owner_sid = NULL;
214 dst->group_sid = NULL;
218 if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
221 if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
224 if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
227 if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
230 offset = SEC_DESC_HEADER_SIZE;
233 * Work out the linearization sizes.
236 if (dst->sacl != NULL) {
237 offset += dst->sacl->size;
239 if (dst->dacl != NULL) {
240 offset += dst->dacl->size;
243 if (dst->owner_sid != NULL) {
244 offset += sid_size(dst->owner_sid);
247 if (dst->group_sid != NULL) {
248 offset += sid_size(dst->group_sid);
251 *sd_size = (size_t)offset;
260 /*******************************************************************
261 Duplicate a SEC_DESC structure.
262 ********************************************************************/
264 SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
271 return make_sec_desc( ctx, src->revision, src->type,
272 src->owner_sid, src->group_sid, src->sacl,
276 /*******************************************************************
277 Convert a secdesc into a byte stream
278 ********************************************************************/
279 NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
280 struct security_descriptor *secdesc,
281 uint8 **data, size_t *len)
285 if (!prs_init(&ps, sec_desc_size(secdesc), mem_ctx, MARSHALL)) {
286 return NT_STATUS_NO_MEMORY;
289 if (!sec_io_desc("security_descriptor", &secdesc, &ps, 1)) {
291 return NT_STATUS_INVALID_PARAMETER;
294 if (!(*data = (uint8 *)talloc_memdup(mem_ctx, ps.data_p,
297 return NT_STATUS_NO_MEMORY;
300 *len = prs_offset(&ps);
305 /*******************************************************************
306 Parse a byte stream into a secdesc
307 ********************************************************************/
308 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
309 struct security_descriptor **psecdesc)
312 struct security_descriptor *secdesc = NULL;
314 if (!(secdesc = TALLOC_ZERO_P(mem_ctx, struct security_descriptor))) {
315 return NT_STATUS_NO_MEMORY;
318 if (!prs_init(&ps, 0, secdesc, UNMARSHALL)) {
319 return NT_STATUS_NO_MEMORY;
322 prs_give_memory(&ps, (char *)data, len, False);
324 if (!sec_io_desc("security_descriptor", &secdesc, &ps, 1)) {
325 return NT_STATUS_INVALID_PARAMETER;
333 /*******************************************************************
334 Creates a SEC_DESC structure with typical defaults.
335 ********************************************************************/
337 SEC_DESC *make_standard_sec_desc(TALLOC_CTX *ctx, const DOM_SID *owner_sid, const DOM_SID *grp_sid,
338 SEC_ACL *dacl, size_t *sd_size)
340 return make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
341 owner_sid, grp_sid, NULL, dacl, sd_size);
344 /*******************************************************************
345 Creates a SEC_DESC_BUF structure.
346 ********************************************************************/
348 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
352 if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
355 /* max buffer size (allocated size) */
356 dst->sd_size = (uint32)len;
358 if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
365 /*******************************************************************
366 Duplicates a SEC_DESC_BUF structure.
367 ********************************************************************/
369 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
374 return make_sec_desc_buf( ctx, src->sd_size, src->sd);
377 /*******************************************************************
378 Add a new SID with its permissions to SEC_DESC.
379 ********************************************************************/
381 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
388 if (!ctx || !psd || !sid || !sd_size)
389 return NT_STATUS_INVALID_PARAMETER;
393 status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
395 if (!NT_STATUS_IS_OK(status))
398 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
399 return NT_STATUS_UNSUCCESSFUL;
401 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
402 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
403 return NT_STATUS_UNSUCCESSFUL;
410 /*******************************************************************
411 Modify a SID's permissions in a SEC_DESC.
412 ********************************************************************/
414 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
419 return NT_STATUS_INVALID_PARAMETER;
421 status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
423 if (!NT_STATUS_IS_OK(status))
429 /*******************************************************************
430 Delete a SID from a SEC_DESC.
431 ********************************************************************/
433 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
440 if (!ctx || !psd[0] || !sid || !sd_size)
441 return NT_STATUS_INVALID_PARAMETER;
445 status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
447 if (!NT_STATUS_IS_OK(status))
450 if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
451 return NT_STATUS_UNSUCCESSFUL;
453 if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid,
454 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
455 return NT_STATUS_UNSUCCESSFUL;
462 /* Create a child security descriptor using another security descriptor as
463 the parent container. This child object can either be a container or
464 non-container object. */
466 SEC_DESC_BUF *se_create_child_secdesc(TALLOC_CTX *ctx, SEC_DESC *parent_ctr,
467 bool child_container)
471 SEC_ACL *new_dacl, *the_acl;
472 SEC_ACE *new_ace_list = NULL;
473 unsigned int new_ace_list_ndx = 0, i;
476 /* Currently we only process the dacl when creating the child. The
477 sacl should also be processed but this is left out as sacls are
478 not implemented in Samba at the moment.*/
480 the_acl = parent_ctr->dacl;
482 if (the_acl->num_aces) {
483 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE, the_acl->num_aces)))
489 for (i = 0; i < the_acl->num_aces; i++) {
490 SEC_ACE *ace = &the_acl->aces[i];
491 SEC_ACE *new_ace = &new_ace_list[new_ace_list_ndx];
493 bool inherit = False;
496 /* The OBJECT_INHERIT_ACE flag causes the ACE to be
497 inherited by non-container children objects. Container
498 children objects will inherit it as an INHERIT_ONLY
501 if (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) {
503 if (!child_container) {
504 new_flags |= SEC_ACE_FLAG_OBJECT_INHERIT;
506 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
512 /* The CONAINER_INHERIT_ACE flag means all child container
513 objects will inherit and use the ACE. */
515 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
516 if (!child_container) {
519 new_flags |= SEC_ACE_FLAG_CONTAINER_INHERIT;
523 /* The INHERIT_ONLY_ACE is not used by the se_access_check()
524 function for the parent container, but is inherited by
525 all child objects as a normal ACE. */
527 if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
528 /* Move along, nothing to see here */
531 /* The SEC_ACE_FLAG_NO_PROPAGATE_INHERIT flag means the ACE
532 is inherited by child objects but not grandchildren
533 objects. We clear the object inherit and container
534 inherit flags in the inherited ACE. */
536 if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
537 new_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT |
538 SEC_ACE_FLAG_CONTAINER_INHERIT);
541 /* Add ACE to ACE list */
546 init_sec_access(&new_ace->access_mask, ace->access_mask);
547 init_sec_ace(new_ace, &ace->trustee, ace->type,
548 new_ace->access_mask, new_flags);
550 sid_to_string(sid_str, &ace->trustee);
552 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
553 " inherited as %s:%d/0x%02x/0x%08x\n", sid_str,
554 ace->type, ace->flags, ace->access_mask,
555 sid_str, new_ace->type, new_ace->flags,
556 new_ace->access_mask));
561 /* Create child security descriptor to return */
563 new_dacl = make_sec_acl(ctx, ACL_REVISION, new_ace_list_ndx, new_ace_list);
565 /* Use the existing user and group sids. I don't think this is
566 correct. Perhaps the user and group should be passed in as
567 parameters by the caller? */
569 sd = make_sec_desc(ctx, SEC_DESC_REVISION, SEC_DESC_SELF_RELATIVE,
570 parent_ctr->owner_sid,
571 parent_ctr->group_sid,
575 sdb = make_sec_desc_buf(ctx, size, sd);
580 /*******************************************************************
581 Sets up a SEC_ACCESS structure.
582 ********************************************************************/
584 void init_sec_access(uint32 *t, uint32 mask)