Merge branch 'master' of ssh://git.samba.org/data/git/samba into master-devel
[nivanova/samba-autobuild/.git] / source3 / lib / secdesc.c
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.
13  *  
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.
18  *  
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/>.
21  */
22
23 #include "includes.h"
24
25 /* Map generic permissions to file object specific permissions */
26
27 const struct generic_mapping file_generic_mapping = {
28         FILE_GENERIC_READ,
29         FILE_GENERIC_WRITE,
30         FILE_GENERIC_EXECUTE,
31         FILE_GENERIC_ALL
32 };
33
34 /*******************************************************************
35  Compares two SEC_DESC structures
36 ********************************************************************/
37
38 bool sec_desc_equal(SEC_DESC *s1, SEC_DESC *s2)
39 {
40         /* Trivial case */
41
42         if (!s1 && !s2) {
43                 goto done;
44         }
45
46         if (!s1 || !s2) {
47                 return False;
48         }
49
50         /* Check top level stuff */
51
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;
56         }
57
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;
62         }
63
64         /* Check owner and group */
65
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;
71         }
72
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;
78         }
79
80         /* Check ACLs present in one but not the other */
81
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;
86         }
87
88         /* Sigh - we have to do it the hard way by iterating over all
89            the ACEs in the ACLs */
90
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;
95         }
96
97  done:
98         DEBUG(10, ("sec_desc_equal(): secdescs are identical\n"));
99         return True;
100 }
101
102 /*******************************************************************
103  Given a security_descriptor return the sec_info.
104 ********************************************************************/
105
106 uint32_t get_sec_info(const SEC_DESC *sd)
107 {
108         uint32_t sec_info = ALL_SECURITY_INFORMATION;
109
110         SMB_ASSERT(sd);
111
112         if (sd->owner_sid == NULL) {
113                 sec_info &= ~OWNER_SECURITY_INFORMATION;
114         }
115         if (sd->group_sid == NULL) {
116                 sec_info &= ~GROUP_SECURITY_INFORMATION;
117         }
118         if (sd->sacl == NULL) {
119                 sec_info &= ~SACL_SECURITY_INFORMATION;
120         }
121         if (sd->dacl == NULL) {
122                 sec_info &= ~DACL_SECURITY_INFORMATION;
123         }
124
125         return sec_info;
126 }
127
128
129 /*******************************************************************
130  Merge part of security descriptor old_sec in to the empty sections of 
131  security descriptor new_sec.
132 ********************************************************************/
133
134 SEC_DESC_BUF *sec_desc_merge(TALLOC_CTX *ctx, SEC_DESC_BUF *new_sdb, SEC_DESC_BUF *old_sdb)
135 {
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;
142
143         /* Copy over owner and group sids.  There seems to be no flag for
144            this so just check the pointer values. */
145
146         owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
147                 old_sdb->sd->owner_sid;
148
149         group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
150                 old_sdb->sd->group_sid;
151         
152         secdesc_type = new_sdb->sd->type;
153
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. */
157
158         sacl = NULL;
159         secdesc_type &= ~SEC_DESC_SACL_PRESENT;
160
161         /* Copy across discretionary ACL */
162
163         if (secdesc_type & SEC_DESC_DACL_PRESENT) {
164                 dacl = new_sdb->sd->dacl;
165         } else {
166                 dacl = old_sdb->sd->dacl;
167         }
168
169         /* Create new security descriptor from bits */
170
171         psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
172                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
173
174         return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
175
176         return(return_sdb);
177 }
178
179 /*******************************************************************
180  Creates a SEC_DESC structure
181 ********************************************************************/
182
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)
188 {
189         SEC_DESC *dst;
190         uint32 offset     = 0;
191
192         *sd_size = 0;
193
194         if(( dst = TALLOC_ZERO_P(ctx, SEC_DESC)) == NULL)
195                 return NULL;
196
197         dst->revision = revision;
198         dst->type = type;
199
200         if (sacl)
201                 dst->type |= SEC_DESC_SACL_PRESENT;
202         if (dacl)
203                 dst->type |= SEC_DESC_DACL_PRESENT;
204
205         dst->owner_sid = NULL;
206         dst->group_sid   = NULL;
207         dst->sacl      = NULL;
208         dst->dacl      = NULL;
209
210         if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
211                 goto error_exit;
212
213         if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
214                 goto error_exit;
215
216         if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
217                 goto error_exit;
218
219         if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
220                 goto error_exit;
221
222         offset = SEC_DESC_HEADER_SIZE;
223
224         /*
225          * Work out the linearization sizes.
226          */
227
228         if (dst->sacl != NULL) {
229                 offset += dst->sacl->size;
230         }
231         if (dst->dacl != NULL) {
232                 offset += dst->dacl->size;
233         }
234
235         if (dst->owner_sid != NULL) {
236                 offset += ndr_size_dom_sid(dst->owner_sid, NULL, 0);
237         }
238
239         if (dst->group_sid != NULL) {
240                 offset += ndr_size_dom_sid(dst->group_sid, NULL, 0);
241         }
242
243         *sd_size = (size_t)offset;
244         return dst;
245
246 error_exit:
247
248         *sd_size = 0;
249         return NULL;
250 }
251
252 /*******************************************************************
253  Duplicate a SEC_DESC structure.  
254 ********************************************************************/
255
256 SEC_DESC *dup_sec_desc(TALLOC_CTX *ctx, const SEC_DESC *src)
257 {
258         size_t dummy;
259
260         if(src == NULL)
261                 return NULL;
262
263         return make_sec_desc( ctx, src->revision, src->type,
264                                 src->owner_sid, src->group_sid, src->sacl,
265                                 src->dacl, &dummy);
266 }
267
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)
274 {
275         DATA_BLOB blob;
276         enum ndr_err_code ndr_err;
277
278         ndr_err = ndr_push_struct_blob(
279                 &blob, mem_ctx, NULL, secdesc,
280                 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
281
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);;
286         }
287
288         *data = blob.data;
289         *len = blob.length;
290         return NT_STATUS_OK;
291 }
292
293 /*******************************************************************
294  Convert a secdesc_buf into a byte stream
295 ********************************************************************/
296
297 NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
298                                struct sec_desc_buf *secdesc_buf,
299                                uint8_t **data, size_t *len)
300 {
301         DATA_BLOB blob;
302         enum ndr_err_code ndr_err;
303
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);
307
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);;
312         }
313
314         *data = blob.data;
315         *len = blob.length;
316         return NT_STATUS_OK;
317 }
318
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)
324 {
325         DATA_BLOB blob;
326         enum ndr_err_code ndr_err;
327         struct security_descriptor *result;
328
329         if ((data == NULL) || (len == 0)) {
330                 return NT_STATUS_INVALID_PARAMETER;
331         }
332
333         result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
334         if (result == NULL) {
335                 return NT_STATUS_NO_MEMORY;
336         }
337
338         blob = data_blob_const(data, len);
339
340         ndr_err = ndr_pull_struct_blob(
341                 &blob, result, NULL, result,
342                 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
343
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);;
349         }
350
351         *psecdesc = result;
352         return NT_STATUS_OK;
353 }
354
355 /*******************************************************************
356  Parse a byte stream into a sec_desc_buf
357 ********************************************************************/
358
359 NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
360                                  struct sec_desc_buf **psecdesc_buf)
361 {
362         DATA_BLOB blob;
363         enum ndr_err_code ndr_err;
364         struct sec_desc_buf *result;
365
366         if ((data == NULL) || (len == 0)) {
367                 return NT_STATUS_INVALID_PARAMETER;
368         }
369
370         result = TALLOC_ZERO_P(mem_ctx, struct sec_desc_buf);
371         if (result == NULL) {
372                 return NT_STATUS_NO_MEMORY;
373         }
374
375         blob = data_blob_const(data, len);
376
377         ndr_err = ndr_pull_struct_blob(
378                 &blob, result, NULL, result,
379                 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
380
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);;
386         }
387
388         *psecdesc_buf = result;
389         return NT_STATUS_OK;
390 }
391
392 /*******************************************************************
393  Creates a SEC_DESC structure with typical defaults.
394 ********************************************************************/
395
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)
398 {
399         return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
400                              SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
401                              dacl, sd_size);
402 }
403
404 /*******************************************************************
405  Creates a SEC_DESC_BUF structure.
406 ********************************************************************/
407
408 SEC_DESC_BUF *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, SEC_DESC *sec_desc)
409 {
410         SEC_DESC_BUF *dst;
411
412         if((dst = TALLOC_ZERO_P(ctx, SEC_DESC_BUF)) == NULL)
413                 return NULL;
414
415         /* max buffer size (allocated size) */
416         dst->sd_size = (uint32)len;
417         
418         if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
419                 return NULL;
420         }
421
422         return dst;
423 }
424
425 /*******************************************************************
426  Duplicates a SEC_DESC_BUF structure.
427 ********************************************************************/
428
429 SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src)
430 {
431         if(src == NULL)
432                 return NULL;
433
434         return make_sec_desc_buf( ctx, src->sd_size, src->sd);
435 }
436
437 /*******************************************************************
438  Add a new SID with its permissions to SEC_DESC.
439 ********************************************************************/
440
441 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size)
442 {
443         SEC_DESC *sd   = 0;
444         SEC_ACL  *dacl = 0;
445         SEC_ACE  *ace  = 0;
446         NTSTATUS  status;
447
448         if (!ctx || !psd || !sid || !sd_size)
449                 return NT_STATUS_INVALID_PARAMETER;
450
451         *sd_size = 0;
452
453         status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
454         
455         if (!NT_STATUS_IS_OK(status))
456                 return status;
457
458         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
459                 return NT_STATUS_UNSUCCESSFUL;
460         
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;
464
465         *psd = sd;
466          sd  = 0;
467         return NT_STATUS_OK;
468 }
469
470 /*******************************************************************
471  Modify a SID's permissions in a SEC_DESC.
472 ********************************************************************/
473
474 NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask)
475 {
476         NTSTATUS status;
477
478         if (!sd || !sid)
479                 return NT_STATUS_INVALID_PARAMETER;
480
481         status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
482
483         if (!NT_STATUS_IS_OK(status))
484                 return status;
485         
486         return NT_STATUS_OK;
487 }
488
489 /*******************************************************************
490  Delete a SID from a SEC_DESC.
491 ********************************************************************/
492
493 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size)
494 {
495         SEC_DESC *sd   = 0;
496         SEC_ACL  *dacl = 0;
497         SEC_ACE  *ace  = 0;
498         NTSTATUS  status;
499
500         if (!ctx || !psd[0] || !sid || !sd_size)
501                 return NT_STATUS_INVALID_PARAMETER;
502
503         *sd_size = 0;
504         
505         status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
506
507         if (!NT_STATUS_IS_OK(status))
508                 return status;
509
510         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
511                 return NT_STATUS_UNSUCCESSFUL;
512         
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;
516
517         *psd = sd;
518          sd  = 0;
519         return NT_STATUS_OK;
520 }
521
522 /*
523  * Determine if an ACE is inheritable
524  */
525
526 static bool is_inheritable_ace(const SEC_ACE *ace,
527                                 bool container)
528 {
529         if (!container) {
530                 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
531         }
532
533         if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
534                 return true;
535         }
536
537         if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
538                         !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
539                 return true;
540         }
541
542         return false;
543 }
544
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. */
548
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)
556 {
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;
560
561         *ppsd = NULL;
562         *psize = 0;
563
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.*/
567
568         the_acl = parent_ctr->dacl;
569
570         if (the_acl->num_aces) {
571                 if (2*the_acl->num_aces < the_acl->num_aces) {
572                         return NT_STATUS_NO_MEMORY;
573                 }
574
575                 if (!(new_ace_list = TALLOC_ARRAY(ctx, SEC_ACE,
576                                                 2*the_acl->num_aces))) {
577                         return NT_STATUS_NO_MEMORY;
578                 }
579         } else {
580                 new_ace_list = NULL;
581         }
582
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;
589
590                 if (!is_inheritable_ace(ace, container)) {
591                         continue;
592                 }
593
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;
599
600                         if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
601                                 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
602                         }
603                         if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
604                                 new_flags = 0;
605                         }
606                 }
607
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;
615                 }
616
617                 if (creator && container &&
618                                 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
619
620                         /* First add the regular ACE entry. */
621                         init_sec_ace(new_ace, ptrustee, ace->type,
622                                 ace->access_mask, 0);
623
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));
631
632                         new_ace_list_ndx++;
633
634                         /* Now add the extra creator ACE. */
635                         new_ace = &new_ace_list[new_ace_list_ndx];
636
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;
642                 }
643
644                 init_sec_ace(new_ace, ptrustee, ace->type,
645                              ace->access_mask, new_flags);
646
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));
654
655                 new_ace_list_ndx++;
656         }
657
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);
664
665                 if (!new_dacl) {
666                         return NT_STATUS_NO_MEMORY;
667                 }
668         }
669
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;
680         }
681         return NT_STATUS_OK;
682 }
683
684 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
685                                         SEC_DESC_BUF **ppsdb,
686                                         const SEC_DESC *parent_ctr,
687                                         bool container)
688 {
689         NTSTATUS status;
690         size_t size = 0;
691         SEC_DESC *sd = NULL;
692
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;
703         }
704
705         *ppsdb = make_sec_desc_buf(ctx, size, sd);
706         if (!*ppsdb) {
707                 return NT_STATUS_NO_MEMORY;
708         }
709         return NT_STATUS_OK;
710 }