Coverage Report

Created: 2025-11-16 06:57

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