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