b9ed955dee04bbbe961d39ebc68ce2be539c19fe
[samba.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 #include "../librpc/gen_ndr/ndr_security.h"
25
26 #define ALL_SECURITY_INFORMATION (SECINFO_OWNER|SECINFO_GROUP|\
27                                         SECINFO_DACL|SECINFO_SACL|\
28                                         SECINFO_UNPROTECTED_SACL|\
29                                         SECINFO_UNPROTECTED_DACL|\
30                                         SECINFO_PROTECTED_SACL|\
31                                         SECINFO_PROTECTED_DACL)
32
33 /* Map generic permissions to file object specific permissions */
34
35 const struct generic_mapping file_generic_mapping = {
36         FILE_GENERIC_READ,
37         FILE_GENERIC_WRITE,
38         FILE_GENERIC_EXECUTE,
39         FILE_GENERIC_ALL
40 };
41
42 /*******************************************************************
43  Given a security_descriptor return the sec_info.
44 ********************************************************************/
45
46 uint32_t get_sec_info(const struct security_descriptor *sd)
47 {
48         uint32_t sec_info = ALL_SECURITY_INFORMATION;
49
50         SMB_ASSERT(sd);
51
52         if (sd->owner_sid == NULL) {
53                 sec_info &= ~SECINFO_OWNER;
54         }
55         if (sd->group_sid == NULL) {
56                 sec_info &= ~SECINFO_GROUP;
57         }
58         if (sd->sacl == NULL) {
59                 sec_info &= ~SECINFO_SACL;
60         }
61         if (sd->dacl == NULL) {
62                 sec_info &= ~SECINFO_DACL;
63         }
64
65         return sec_info;
66 }
67
68
69 /*******************************************************************
70  Merge part of security descriptor old_sec in to the empty sections of 
71  security descriptor new_sec.
72 ********************************************************************/
73
74 struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb)
75 {
76         struct dom_sid *owner_sid, *group_sid;
77         struct sec_desc_buf *return_sdb;
78         struct security_acl *dacl, *sacl;
79         struct security_descriptor *psd = NULL;
80         uint16 secdesc_type;
81         size_t secdesc_size;
82
83         /* Copy over owner and group sids.  There seems to be no flag for
84            this so just check the pointer values. */
85
86         owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
87                 old_sdb->sd->owner_sid;
88
89         group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
90                 old_sdb->sd->group_sid;
91         
92         secdesc_type = new_sdb->sd->type;
93
94         /* Ignore changes to the system ACL.  This has the effect of making
95            changes through the security tab audit button not sticking. 
96            Perhaps in future Samba could implement these settings somehow. */
97
98         sacl = NULL;
99         secdesc_type &= ~SEC_DESC_SACL_PRESENT;
100
101         /* Copy across discretionary ACL */
102
103         if (secdesc_type & SEC_DESC_DACL_PRESENT) {
104                 dacl = new_sdb->sd->dacl;
105         } else {
106                 dacl = old_sdb->sd->dacl;
107         }
108
109         /* Create new security descriptor from bits */
110
111         psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
112                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
113
114         return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
115
116         return(return_sdb);
117 }
118
119 struct security_descriptor *sec_desc_merge(TALLOC_CTX *ctx, struct security_descriptor *new_sdb, struct security_descriptor *old_sdb)
120 {
121         struct dom_sid *owner_sid, *group_sid;
122         struct security_acl *dacl, *sacl;
123         struct security_descriptor *psd = NULL;
124         uint16 secdesc_type;
125         size_t secdesc_size;
126
127         /* Copy over owner and group sids.  There seems to be no flag for
128            this so just check the pointer values. */
129
130         owner_sid = new_sdb->owner_sid ? new_sdb->owner_sid :
131                 old_sdb->owner_sid;
132
133         group_sid = new_sdb->group_sid ? new_sdb->group_sid :
134                 old_sdb->group_sid;
135
136         secdesc_type = new_sdb->type;
137
138         /* Ignore changes to the system ACL.  This has the effect of making
139            changes through the security tab audit button not sticking.
140            Perhaps in future Samba could implement these settings somehow. */
141
142         sacl = NULL;
143         secdesc_type &= ~SEC_DESC_SACL_PRESENT;
144
145         /* Copy across discretionary ACL */
146
147         if (secdesc_type & SEC_DESC_DACL_PRESENT) {
148                 dacl = new_sdb->dacl;
149         } else {
150                 dacl = old_sdb->dacl;
151         }
152
153         /* Create new security descriptor from bits */
154         psd = make_sec_desc(ctx, new_sdb->revision, secdesc_type,
155                             owner_sid, group_sid, sacl, dacl, &secdesc_size);
156
157         return psd;
158 }
159
160 /*******************************************************************
161  Creates a struct security_descriptor structure
162 ********************************************************************/
163
164 #define  SEC_DESC_HEADER_SIZE (2 * sizeof(uint16) + 4 * sizeof(uint32))
165
166 struct security_descriptor *make_sec_desc(TALLOC_CTX *ctx,
167                         enum security_descriptor_revision revision,
168                         uint16 type,
169                         const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
170                         struct security_acl *sacl, struct security_acl *dacl, size_t *sd_size)
171 {
172         struct security_descriptor *dst;
173         uint32 offset     = 0;
174
175         *sd_size = 0;
176
177         if(( dst = TALLOC_ZERO_P(ctx, struct security_descriptor)) == NULL)
178                 return NULL;
179
180         dst->revision = revision;
181         dst->type = type;
182
183         if (sacl)
184                 dst->type |= SEC_DESC_SACL_PRESENT;
185         if (dacl)
186                 dst->type |= SEC_DESC_DACL_PRESENT;
187
188         dst->owner_sid = NULL;
189         dst->group_sid   = NULL;
190         dst->sacl      = NULL;
191         dst->dacl      = NULL;
192
193         if(owner_sid && ((dst->owner_sid = sid_dup_talloc(dst,owner_sid)) == NULL))
194                 goto error_exit;
195
196         if(grp_sid && ((dst->group_sid = sid_dup_talloc(dst,grp_sid)) == NULL))
197                 goto error_exit;
198
199         if(sacl && ((dst->sacl = dup_sec_acl(dst, sacl)) == NULL))
200                 goto error_exit;
201
202         if(dacl && ((dst->dacl = dup_sec_acl(dst, dacl)) == NULL))
203                 goto error_exit;
204
205         offset = SEC_DESC_HEADER_SIZE;
206
207         /*
208          * Work out the linearization sizes.
209          */
210
211         if (dst->sacl != NULL) {
212                 offset += dst->sacl->size;
213         }
214         if (dst->dacl != NULL) {
215                 offset += dst->dacl->size;
216         }
217
218         if (dst->owner_sid != NULL) {
219                 offset += ndr_size_dom_sid(dst->owner_sid, 0);
220         }
221
222         if (dst->group_sid != NULL) {
223                 offset += ndr_size_dom_sid(dst->group_sid, 0);
224         }
225
226         *sd_size = (size_t)offset;
227         return dst;
228
229 error_exit:
230
231         *sd_size = 0;
232         return NULL;
233 }
234
235 /*******************************************************************
236  Duplicate a struct security_descriptor structure.
237 ********************************************************************/
238
239 struct security_descriptor *dup_sec_desc(TALLOC_CTX *ctx, const struct security_descriptor *src)
240 {
241         size_t dummy;
242
243         if(src == NULL)
244                 return NULL;
245
246         return make_sec_desc( ctx, src->revision, src->type,
247                                 src->owner_sid, src->group_sid, src->sacl,
248                                 src->dacl, &dummy);
249 }
250
251 /*******************************************************************
252  Convert a secdesc into a byte stream
253 ********************************************************************/
254 NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
255                            struct security_descriptor *secdesc,
256                            uint8 **data, size_t *len)
257 {
258         DATA_BLOB blob;
259         enum ndr_err_code ndr_err;
260
261         ndr_err = ndr_push_struct_blob(
262                 &blob, mem_ctx, secdesc,
263                 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
264
265         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
266                 DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
267                           ndr_errstr(ndr_err)));
268                 return ndr_map_error2ntstatus(ndr_err);;
269         }
270
271         *data = blob.data;
272         *len = blob.length;
273         return NT_STATUS_OK;
274 }
275
276 /*******************************************************************
277  Convert a secdesc_buf into a byte stream
278 ********************************************************************/
279
280 NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
281                                struct sec_desc_buf *secdesc_buf,
282                                uint8_t **data, size_t *len)
283 {
284         DATA_BLOB blob;
285         enum ndr_err_code ndr_err;
286
287         ndr_err = ndr_push_struct_blob(
288                 &blob, mem_ctx, secdesc_buf,
289                 (ndr_push_flags_fn_t)ndr_push_sec_desc_buf);
290
291         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
292                 DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
293                           ndr_errstr(ndr_err)));
294                 return ndr_map_error2ntstatus(ndr_err);;
295         }
296
297         *data = blob.data;
298         *len = blob.length;
299         return NT_STATUS_OK;
300 }
301
302 /*******************************************************************
303  Parse a byte stream into a secdesc
304 ********************************************************************/
305 NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len,
306                              struct security_descriptor **psecdesc)
307 {
308         DATA_BLOB blob;
309         enum ndr_err_code ndr_err;
310         struct security_descriptor *result;
311
312         if ((data == NULL) || (len == 0)) {
313                 return NT_STATUS_INVALID_PARAMETER;
314         }
315
316         result = TALLOC_ZERO_P(mem_ctx, struct security_descriptor);
317         if (result == NULL) {
318                 return NT_STATUS_NO_MEMORY;
319         }
320
321         blob = data_blob_const(data, len);
322
323         ndr_err = ndr_pull_struct_blob(&blob, result, result,
324                 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
325
326         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
327                 DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
328                           ndr_errstr(ndr_err)));
329                 TALLOC_FREE(result);
330                 return ndr_map_error2ntstatus(ndr_err);;
331         }
332
333         *psecdesc = result;
334         return NT_STATUS_OK;
335 }
336
337 /*******************************************************************
338  Parse a byte stream into a sec_desc_buf
339 ********************************************************************/
340
341 NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
342                                  struct sec_desc_buf **psecdesc_buf)
343 {
344         DATA_BLOB blob;
345         enum ndr_err_code ndr_err;
346         struct sec_desc_buf *result;
347
348         if ((data == NULL) || (len == 0)) {
349                 return NT_STATUS_INVALID_PARAMETER;
350         }
351
352         result = TALLOC_ZERO_P(mem_ctx, struct sec_desc_buf);
353         if (result == NULL) {
354                 return NT_STATUS_NO_MEMORY;
355         }
356
357         blob = data_blob_const(data, len);
358
359         ndr_err = ndr_pull_struct_blob(&blob, result, result,
360                 (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
361
362         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
363                 DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
364                           ndr_errstr(ndr_err)));
365                 TALLOC_FREE(result);
366                 return ndr_map_error2ntstatus(ndr_err);;
367         }
368
369         *psecdesc_buf = result;
370         return NT_STATUS_OK;
371 }
372
373 /*******************************************************************
374  Creates a struct security_descriptor structure with typical defaults.
375 ********************************************************************/
376
377 struct security_descriptor *make_standard_sec_desc(TALLOC_CTX *ctx, const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
378                                  struct security_acl *dacl, size_t *sd_size)
379 {
380         return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
381                              SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
382                              dacl, sd_size);
383 }
384
385 /*******************************************************************
386  Creates a struct sec_desc_buf structure.
387 ********************************************************************/
388
389 struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, struct security_descriptor *sec_desc)
390 {
391         struct sec_desc_buf *dst;
392
393         if((dst = TALLOC_ZERO_P(ctx, struct sec_desc_buf)) == NULL)
394                 return NULL;
395
396         /* max buffer size (allocated size) */
397         dst->sd_size = (uint32)len;
398         
399         if(sec_desc && ((dst->sd = dup_sec_desc(ctx, sec_desc)) == NULL)) {
400                 return NULL;
401         }
402
403         return dst;
404 }
405
406 /*******************************************************************
407  Duplicates a struct sec_desc_buf structure.
408 ********************************************************************/
409
410 struct sec_desc_buf *dup_sec_desc_buf(TALLOC_CTX *ctx, struct sec_desc_buf *src)
411 {
412         if(src == NULL)
413                 return NULL;
414
415         return make_sec_desc_buf( ctx, src->sd_size, src->sd);
416 }
417
418 /*******************************************************************
419  Add a new SID with its permissions to struct security_descriptor.
420 ********************************************************************/
421
422 NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, struct security_descriptor **psd, struct dom_sid *sid, uint32 mask, size_t *sd_size)
423 {
424         struct security_descriptor *sd   = 0;
425         struct security_acl  *dacl = 0;
426         struct security_ace  *ace  = 0;
427         NTSTATUS  status;
428
429         if (!ctx || !psd || !sid || !sd_size)
430                 return NT_STATUS_INVALID_PARAMETER;
431
432         *sd_size = 0;
433
434         status = sec_ace_add_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid, mask);
435         
436         if (!NT_STATUS_IS_OK(status))
437                 return status;
438
439         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
440                 return NT_STATUS_UNSUCCESSFUL;
441         
442         if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid, 
443                 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
444                 return NT_STATUS_UNSUCCESSFUL;
445
446         *psd = sd;
447          sd  = 0;
448         return NT_STATUS_OK;
449 }
450
451 /*******************************************************************
452  Modify a SID's permissions in a struct security_descriptor.
453 ********************************************************************/
454
455 NTSTATUS sec_desc_mod_sid(struct security_descriptor *sd, struct dom_sid *sid, uint32 mask)
456 {
457         NTSTATUS status;
458
459         if (!sd || !sid)
460                 return NT_STATUS_INVALID_PARAMETER;
461
462         status = sec_ace_mod_sid(sd->dacl->aces, sd->dacl->num_aces, sid, mask);
463
464         if (!NT_STATUS_IS_OK(status))
465                 return status;
466         
467         return NT_STATUS_OK;
468 }
469
470 /*******************************************************************
471  Delete a SID from a struct security_descriptor.
472 ********************************************************************/
473
474 NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, struct security_descriptor **psd, struct dom_sid *sid, size_t *sd_size)
475 {
476         struct security_descriptor *sd   = 0;
477         struct security_acl  *dacl = 0;
478         struct security_ace  *ace  = 0;
479         NTSTATUS  status;
480
481         if (!ctx || !psd[0] || !sid || !sd_size)
482                 return NT_STATUS_INVALID_PARAMETER;
483
484         *sd_size = 0;
485         
486         status = sec_ace_del_sid(ctx, &ace, psd[0]->dacl->aces, &psd[0]->dacl->num_aces, sid);
487
488         if (!NT_STATUS_IS_OK(status))
489                 return status;
490
491         if (!(dacl = make_sec_acl(ctx, psd[0]->dacl->revision, psd[0]->dacl->num_aces, ace)))
492                 return NT_STATUS_UNSUCCESSFUL;
493         
494         if (!(sd = make_sec_desc(ctx, psd[0]->revision, psd[0]->type, psd[0]->owner_sid, 
495                 psd[0]->group_sid, psd[0]->sacl, dacl, sd_size)))
496                 return NT_STATUS_UNSUCCESSFUL;
497
498         *psd = sd;
499          sd  = 0;
500         return NT_STATUS_OK;
501 }
502
503 /*
504  * Determine if an struct security_ace is inheritable
505  */
506
507 static bool is_inheritable_ace(const struct security_ace *ace,
508                                 bool container)
509 {
510         if (!container) {
511                 return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
512         }
513
514         if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
515                 return true;
516         }
517
518         if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
519                         !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
520                 return true;
521         }
522
523         return false;
524 }
525
526 /*
527  * Does a security descriptor have any inheritable components for
528  * the newly created type ?
529  */
530
531 bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container)
532 {
533         unsigned int i;
534         const struct security_acl *the_acl = parent_ctr->dacl;
535
536         for (i = 0; i < the_acl->num_aces; i++) {
537                 const struct security_ace *ace = &the_acl->aces[i];
538
539                 if (is_inheritable_ace(ace, container)) {
540                         return true;
541                 }
542         }
543         return false;
544 }
545
546 /* Create a child security descriptor using another security descriptor as
547    the parent container.  This child object can either be a container or
548    non-container object. */
549
550 NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
551                                         struct security_descriptor **ppsd,
552                                         size_t *psize,
553                                         const struct security_descriptor *parent_ctr,
554                                         const struct dom_sid *owner_sid,
555                                         const struct dom_sid *group_sid,
556                                         bool container)
557 {
558         struct security_acl *new_dacl = NULL, *the_acl = NULL;
559         struct security_ace *new_ace_list = NULL;
560         unsigned int new_ace_list_ndx = 0, i;
561
562         *ppsd = NULL;
563         *psize = 0;
564
565         /* Currently we only process the dacl when creating the child.  The
566            sacl should also be processed but this is left out as sacls are
567            not implemented in Samba at the moment.*/
568
569         the_acl = parent_ctr->dacl;
570
571         if (the_acl->num_aces) {
572                 if (2*the_acl->num_aces < the_acl->num_aces) {
573                         return NT_STATUS_NO_MEMORY;
574                 }
575
576                 if (!(new_ace_list = TALLOC_ARRAY(ctx, struct security_ace,
577                                                 2*the_acl->num_aces))) {
578                         return NT_STATUS_NO_MEMORY;
579                 }
580         } else {
581                 new_ace_list = NULL;
582         }
583
584         for (i = 0; i < the_acl->num_aces; i++) {
585                 const struct security_ace *ace = &the_acl->aces[i];
586                 struct security_ace *new_ace = &new_ace_list[new_ace_list_ndx];
587                 const struct dom_sid *ptrustee = &ace->trustee;
588                 const struct dom_sid *creator = NULL;
589                 uint8 new_flags = ace->flags;
590
591                 if (!is_inheritable_ace(ace, container)) {
592                         continue;
593                 }
594
595                 /* see the RAW-ACLS inheritance test for details on these rules */
596                 if (!container) {
597                         new_flags = 0;
598                 } else {
599                         new_flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
600
601                         if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
602                                 new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
603                         }
604                         if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
605                                 new_flags = 0;
606                         }
607                 }
608
609                 /* The CREATOR sids are special when inherited */
610                 if (sid_equal(ptrustee, &global_sid_Creator_Owner)) {
611                         creator = &global_sid_Creator_Owner;
612                         ptrustee = owner_sid;
613                 } else if (sid_equal(ptrustee, &global_sid_Creator_Group)) {
614                         creator = &global_sid_Creator_Group;
615                         ptrustee = group_sid;
616                 }
617
618                 if (creator && container &&
619                                 (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
620
621                         /* First add the regular ACE entry. */
622                         init_sec_ace(new_ace, ptrustee, ace->type,
623                                 ace->access_mask, 0);
624
625                         DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
626                                 " inherited as %s:%d/0x%02x/0x%08x\n",
627                                 sid_string_dbg(&ace->trustee),
628                                 ace->type, ace->flags, ace->access_mask,
629                                 sid_string_dbg(&new_ace->trustee),
630                                 new_ace->type, new_ace->flags,
631                                 new_ace->access_mask));
632
633                         new_ace_list_ndx++;
634
635                         /* Now add the extra creator ACE. */
636                         new_ace = &new_ace_list[new_ace_list_ndx];
637
638                         ptrustee = creator;
639                         new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
640                 } else if (container &&
641                                 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
642                         ptrustee = &ace->trustee;
643                 }
644
645                 init_sec_ace(new_ace, ptrustee, ace->type,
646                              ace->access_mask, new_flags);
647
648                 DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
649                           " inherited as %s:%d/0x%02x/0x%08x\n",
650                           sid_string_dbg(&ace->trustee),
651                           ace->type, ace->flags, ace->access_mask,
652                           sid_string_dbg(&ace->trustee),
653                           new_ace->type, new_ace->flags,
654                           new_ace->access_mask));
655
656                 new_ace_list_ndx++;
657         }
658
659         /* Create child security descriptor to return */
660         if (new_ace_list_ndx) {
661                 new_dacl = make_sec_acl(ctx,
662                                 NT4_ACL_REVISION,
663                                 new_ace_list_ndx,
664                                 new_ace_list);
665
666                 if (!new_dacl) {
667                         return NT_STATUS_NO_MEMORY;
668                 }
669         }
670
671         *ppsd = make_sec_desc(ctx,
672                         SECURITY_DESCRIPTOR_REVISION_1,
673                         SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
674                         owner_sid,
675                         group_sid,
676                         NULL,
677                         new_dacl,
678                         psize);
679         if (!*ppsd) {
680                 return NT_STATUS_NO_MEMORY;
681         }
682         return NT_STATUS_OK;
683 }
684
685 NTSTATUS se_create_child_secdesc_buf(TALLOC_CTX *ctx,
686                                         struct sec_desc_buf **ppsdb,
687                                         const struct security_descriptor *parent_ctr,
688                                         bool container)
689 {
690         NTSTATUS status;
691         size_t size = 0;
692         struct security_descriptor *sd = NULL;
693
694         *ppsdb = NULL;
695         status = se_create_child_secdesc(ctx,
696                                         &sd,
697                                         &size,
698                                         parent_ctr,
699                                         parent_ctr->owner_sid,
700                                         parent_ctr->group_sid,
701                                         container);
702         if (!NT_STATUS_IS_OK(status)) {
703                 return status;
704         }
705
706         *ppsdb = make_sec_desc_buf(ctx, size, sd);
707         if (!*ppsdb) {
708                 return NT_STATUS_NO_MEMORY;
709         }
710         return NT_STATUS_OK;
711 }