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