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