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