2 Unix SMB/CIFS implementation.
4 security descriptor description language functions
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "lib/util/debug.h"
24 #include "libcli/security/security.h"
25 #include "librpc/gen_ndr/ndr_misc.h"
26 #include "system/locale.h"
33 static bool sddl_map_flag(
34 const struct flag_map
*map
,
39 while (map
->name
!= NULL
) {
40 size_t len
= strlen(map
->name
);
41 int cmp
= strncmp(map
->name
, str
, len
);
54 map a series of letter codes into a uint32_t
56 static bool sddl_map_flags(const struct flag_map
*map
, const char *str
,
57 uint32_t *pflags
, size_t *plen
)
59 const char *str0
= str
;
64 while (str
[0] && isupper(str
[0])) {
69 found
= sddl_map_flag(map
, str
, &len
, &flags
);
71 DEBUG(1, ("Unknown flag - %s in %s\n", str
, str0
));
85 a mapping between the 2 letter SID codes and sid strings
92 { .code
= "WD", .sid
= SID_WORLD
},
94 { .code
= "CO", .sid
= SID_CREATOR_OWNER
},
95 { .code
= "CG", .sid
= SID_CREATOR_GROUP
},
96 { .code
= "OW", .sid
= SID_OWNER_RIGHTS
},
98 { .code
= "NU", .sid
= SID_NT_NETWORK
},
99 { .code
= "IU", .sid
= SID_NT_INTERACTIVE
},
100 { .code
= "SU", .sid
= SID_NT_SERVICE
},
101 { .code
= "AN", .sid
= SID_NT_ANONYMOUS
},
102 { .code
= "ED", .sid
= SID_NT_ENTERPRISE_DCS
},
103 { .code
= "PS", .sid
= SID_NT_SELF
},
104 { .code
= "AU", .sid
= SID_NT_AUTHENTICATED_USERS
},
105 { .code
= "RC", .sid
= SID_NT_RESTRICTED
},
106 { .code
= "SY", .sid
= SID_NT_SYSTEM
},
107 { .code
= "LS", .sid
= SID_NT_LOCAL_SERVICE
},
108 { .code
= "NS", .sid
= SID_NT_NETWORK_SERVICE
},
109 { .code
= "WR", .sid
= SID_SECURITY_RESTRICTED_CODE
},
111 { .code
= "BA", .sid
= SID_BUILTIN_ADMINISTRATORS
},
112 { .code
= "BU", .sid
= SID_BUILTIN_USERS
},
113 { .code
= "BG", .sid
= SID_BUILTIN_GUESTS
},
114 { .code
= "PU", .sid
= SID_BUILTIN_POWER_USERS
},
115 { .code
= "AO", .sid
= SID_BUILTIN_ACCOUNT_OPERATORS
},
116 { .code
= "SO", .sid
= SID_BUILTIN_SERVER_OPERATORS
},
117 { .code
= "PO", .sid
= SID_BUILTIN_PRINT_OPERATORS
},
118 { .code
= "BO", .sid
= SID_BUILTIN_BACKUP_OPERATORS
},
119 { .code
= "RE", .sid
= SID_BUILTIN_REPLICATOR
},
120 { .code
= "RU", .sid
= SID_BUILTIN_PREW2K
},
121 { .code
= "RD", .sid
= SID_BUILTIN_REMOTE_DESKTOP_USERS
},
122 { .code
= "NO", .sid
= SID_BUILTIN_NETWORK_CONF_OPERATORS
},
124 { .code
= "MU", .sid
= SID_BUILTIN_PERFMON_USERS
},
125 { .code
= "LU", .sid
= SID_BUILTIN_PERFLOG_USERS
},
126 { .code
= "IS", .sid
= SID_BUILTIN_IUSERS
},
127 { .code
= "CY", .sid
= SID_BUILTIN_CRYPTO_OPERATORS
},
128 { .code
= "ER", .sid
= SID_BUILTIN_EVENT_LOG_READERS
},
129 { .code
= "CD", .sid
= SID_BUILTIN_CERT_SERV_DCOM_ACCESS
},
130 { .code
= "RA", .sid
= SID_BUILTIN_RDS_REMOTE_ACCESS_SERVERS
},
131 { .code
= "ES", .sid
= SID_BUILTIN_RDS_ENDPOINT_SERVERS
},
132 { .code
= "MS", .sid
= SID_BUILTIN_RDS_MANAGEMENT_SERVERS
},
133 { .code
= "HA", .sid
= SID_BUILTIN_HYPER_V_ADMINS
},
134 { .code
= "AA", .sid
= SID_BUILTIN_ACCESS_CONTROL_ASSISTANCE_OPS
},
135 { .code
= "RM", .sid
= SID_BUILTIN_REMOTE_MANAGEMENT_USERS
},
137 { .code
= "UD", .sid
= SID_USER_MODE_DRIVERS
},
139 { .code
= "AC", .sid
= SID_SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE
},
141 { .code
= "LW", .sid
= SID_SECURITY_MANDATORY_LOW
},
142 { .code
= "ME", .sid
= SID_SECURITY_MANDATORY_MEDIUM
},
143 { .code
= "MP", .sid
= SID_SECURITY_MANDATORY_MEDIUM_PLUS
},
144 { .code
= "HI", .sid
= SID_SECURITY_MANDATORY_HIGH
},
145 { .code
= "SI", .sid
= SID_SECURITY_MANDATORY_SYSTEM
},
147 { .code
= "AS", .sid
= SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY
},
148 { .code
= "SS", .sid
= SID_SERVICE_ASSERTED_IDENTITY
},
150 { .code
= "RO", .sid
= NULL
, .rid
= DOMAIN_RID_ENTERPRISE_READONLY_DCS
},
152 { .code
= "LA", .sid
= NULL
, .rid
= DOMAIN_RID_ADMINISTRATOR
},
153 { .code
= "LG", .sid
= NULL
, .rid
= DOMAIN_RID_GUEST
},
155 { .code
= "DA", .sid
= NULL
, .rid
= DOMAIN_RID_ADMINS
},
156 { .code
= "DU", .sid
= NULL
, .rid
= DOMAIN_RID_USERS
},
157 { .code
= "DG", .sid
= NULL
, .rid
= DOMAIN_RID_GUESTS
},
158 { .code
= "DC", .sid
= NULL
, .rid
= DOMAIN_RID_DOMAIN_MEMBERS
},
159 { .code
= "DD", .sid
= NULL
, .rid
= DOMAIN_RID_DCS
},
160 { .code
= "CA", .sid
= NULL
, .rid
= DOMAIN_RID_CERT_ADMINS
},
161 { .code
= "SA", .sid
= NULL
, .rid
= DOMAIN_RID_SCHEMA_ADMINS
},
162 { .code
= "EA", .sid
= NULL
, .rid
= DOMAIN_RID_ENTERPRISE_ADMINS
},
163 { .code
= "PA", .sid
= NULL
, .rid
= DOMAIN_RID_POLICY_ADMINS
},
165 { .code
= "CN", .sid
= NULL
, .rid
= DOMAIN_RID_CLONEABLE_CONTROLLERS
},
167 { .code
= "AP", .sid
= NULL
, .rid
= DOMAIN_RID_PROTECTED_USERS
},
168 { .code
= "KA", .sid
= NULL
, .rid
= DOMAIN_RID_KEY_ADMINS
},
169 { .code
= "EK", .sid
= NULL
, .rid
= DOMAIN_RID_ENTERPRISE_KEY_ADMINS
},
171 { .code
= "RS", .sid
= NULL
, .rid
= DOMAIN_RID_RAS_SERVERS
}
176 It can either be a special 2 letter code, or in S-* format
178 static struct dom_sid
*sddl_decode_sid(TALLOC_CTX
*mem_ctx
, const char **sddlp
,
179 const struct dom_sid
*domain_sid
)
181 const char *sddl
= (*sddlp
);
184 /* see if its in the numeric format */
185 if (strncmp(sddl
, "S-", 2) == 0) {
188 size_t len
= strspn(sddl
+2, "-0123456789");
189 sid_str
= talloc_strndup(mem_ctx
, sddl
, len
+2);
194 sid
= dom_sid_parse_talloc(mem_ctx
, sid_str
);
195 talloc_free(sid_str
);
199 /* now check for one of the special codes */
200 for (i
=0;i
<ARRAY_SIZE(sid_codes
);i
++) {
201 if (strncmp(sid_codes
[i
].code
, sddl
, 2) == 0) break;
203 if (i
== ARRAY_SIZE(sid_codes
)) {
204 DEBUG(1,("Unknown sddl sid code '%2.2s'\n", sddl
));
210 if (sid_codes
[i
].sid
== NULL
) {
211 return dom_sid_add_rid(mem_ctx
, domain_sid
, sid_codes
[i
].rid
);
214 return dom_sid_parse_talloc(mem_ctx
, sid_codes
[i
].sid
);
217 static const struct flag_map ace_types
[] = {
218 { "AU", SEC_ACE_TYPE_SYSTEM_AUDIT
},
219 { "AL", SEC_ACE_TYPE_SYSTEM_ALARM
},
220 { "OA", SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT
},
221 { "OD", SEC_ACE_TYPE_ACCESS_DENIED_OBJECT
},
222 { "OU", SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT
},
223 { "OL", SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT
},
224 { "A", SEC_ACE_TYPE_ACCESS_ALLOWED
},
225 { "D", SEC_ACE_TYPE_ACCESS_DENIED
},
229 static const struct flag_map ace_flags
[] = {
230 { "OI", SEC_ACE_FLAG_OBJECT_INHERIT
},
231 { "CI", SEC_ACE_FLAG_CONTAINER_INHERIT
},
232 { "NP", SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
},
233 { "IO", SEC_ACE_FLAG_INHERIT_ONLY
},
234 { "ID", SEC_ACE_FLAG_INHERITED_ACE
},
235 { "SA", SEC_ACE_FLAG_SUCCESSFUL_ACCESS
},
236 { "FA", SEC_ACE_FLAG_FAILED_ACCESS
},
240 static const struct flag_map ace_access_mask
[] = {
241 { "RP", SEC_ADS_READ_PROP
},
242 { "WP", SEC_ADS_WRITE_PROP
},
243 { "CR", SEC_ADS_CONTROL_ACCESS
},
244 { "CC", SEC_ADS_CREATE_CHILD
},
245 { "DC", SEC_ADS_DELETE_CHILD
},
246 { "LC", SEC_ADS_LIST
},
247 { "LO", SEC_ADS_LIST_OBJECT
},
248 { "RC", SEC_STD_READ_CONTROL
},
249 { "WO", SEC_STD_WRITE_OWNER
},
250 { "WD", SEC_STD_WRITE_DAC
},
251 { "SD", SEC_STD_DELETE
},
252 { "DT", SEC_ADS_DELETE_TREE
},
253 { "SW", SEC_ADS_SELF_WRITE
},
254 { "GA", SEC_GENERIC_ALL
},
255 { "GR", SEC_GENERIC_READ
},
256 { "GW", SEC_GENERIC_WRITE
},
257 { "GX", SEC_GENERIC_EXECUTE
},
261 static const struct flag_map decode_ace_access_mask
[] = {
262 { "FA", FILE_ALL_ACCESS
},
263 { "FR", FILE_GENERIC_READ
},
264 { "FW", FILE_GENERIC_WRITE
},
265 { "FX", FILE_GENERIC_EXECUTE
},
269 static bool sddl_decode_access(const char *str
, uint32_t *pmask
)
271 const char *str0
= str
;
275 cmp
= strncmp(str
, "0x", 2);
277 *pmask
= strtol(str
, NULL
, 16);
281 while ((str
[0] != '\0') && isupper(str
[0])) {
286 found
= sddl_map_flag(
287 ace_access_mask
, str
, &len
, &flags
);
288 found
|= sddl_map_flag(
289 decode_ace_access_mask
, str
, &len
, &flags
);
291 DEBUG(1, ("Unknown flag - %s in %s\n", str
, str0
));
304 return true on success, false on failure
305 note that this routine modifies the string
307 static bool sddl_decode_ace(TALLOC_CTX
*mem_ctx
, struct security_ace
*ace
, char *str
,
308 const struct dom_sid
*domain_sid
)
319 /* parse out the 6 tokens */
322 char *ptr
= strchr(str
, ';');
323 if (ptr
== NULL
) return false;
330 if (!sddl_map_flags(ace_types
, tok
[0], &v
, NULL
)) {
336 if (!sddl_map_flags(ace_flags
, tok
[1], &v
, NULL
)) {
342 ok
= sddl_decode_access(tok
[2], &ace
->access_mask
);
348 if (tok
[3][0] != 0) {
349 NTSTATUS status
= GUID_from_string(tok
[3],
350 &ace
->object
.object
.type
.type
);
351 if (!NT_STATUS_IS_OK(status
)) {
354 ace
->object
.object
.flags
|= SEC_ACE_OBJECT_TYPE_PRESENT
;
358 if (tok
[4][0] != 0) {
359 NTSTATUS status
= GUID_from_string(tok
[4],
360 &ace
->object
.object
.inherited_type
.inherited_type
);
361 if (!NT_STATUS_IS_OK(status
)) {
364 ace
->object
.object
.flags
|= SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT
;
369 sid
= sddl_decode_sid(mem_ctx
, &s
, domain_sid
);
379 static const struct flag_map acl_flags
[] = {
380 { "P", SEC_DESC_DACL_PROTECTED
},
381 { "AR", SEC_DESC_DACL_AUTO_INHERIT_REQ
},
382 { "AI", SEC_DESC_DACL_AUTO_INHERITED
},
389 static struct security_acl
*sddl_decode_acl(struct security_descriptor
*sd
,
390 const char **sddlp
, uint32_t *flags
,
391 const struct dom_sid
*domain_sid
)
393 const char *sddl
= *sddlp
;
394 struct security_acl
*acl
;
399 acl
= talloc_zero(sd
, struct security_acl
);
400 if (acl
== NULL
) return NULL
;
401 acl
->revision
= SECURITY_ACL_REVISION_ADS
;
403 if (isupper(sddl
[0]) && sddl
[1] == ':') {
404 /* its an empty ACL */
408 /* work out the ACL flags */
409 if (!sddl_map_flags(acl_flags
, sddl
, flags
, &len
)) {
416 while (*sddl
== '(') {
418 len
= strcspn(sddl
+1, ")");
419 astr
= talloc_strndup(acl
, sddl
+1, len
);
420 if (astr
== NULL
|| sddl
[len
+1] != ')') {
424 acl
->aces
= talloc_realloc(acl
, acl
->aces
, struct security_ace
,
426 if (acl
->aces
== NULL
) {
430 if (!sddl_decode_ace(acl
->aces
, &acl
->aces
[acl
->num_aces
],
435 switch (acl
->aces
[acl
->num_aces
].type
) {
436 case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT
:
437 case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT
:
438 case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT
:
439 case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT
:
440 acl
->revision
= SECURITY_ACL_REVISION_ADS
;
455 decode a security descriptor in SDDL format
457 struct security_descriptor
*sddl_decode(TALLOC_CTX
*mem_ctx
, const char *sddl
,
458 const struct dom_sid
*domain_sid
)
460 struct security_descriptor
*sd
;
461 sd
= talloc_zero(mem_ctx
, struct security_descriptor
);
463 sd
->revision
= SECURITY_DESCRIPTOR_REVISION_1
;
464 sd
->type
= SEC_DESC_SELF_RELATIVE
;
469 if (sddl
[1] != ':') goto failed
;
474 if (sd
->dacl
!= NULL
) goto failed
;
475 sd
->dacl
= sddl_decode_acl(sd
, &sddl
, &flags
, domain_sid
);
476 if (sd
->dacl
== NULL
) goto failed
;
477 sd
->type
|= flags
| SEC_DESC_DACL_PRESENT
;
480 if (sd
->sacl
!= NULL
) goto failed
;
481 sd
->sacl
= sddl_decode_acl(sd
, &sddl
, &flags
, domain_sid
);
482 if (sd
->sacl
== NULL
) goto failed
;
483 /* this relies on the SEC_DESC_SACL_* flags being
484 1 bit shifted from the SEC_DESC_DACL_* flags */
485 sd
->type
|= (flags
<<1) | SEC_DESC_SACL_PRESENT
;
488 if (sd
->owner_sid
!= NULL
) goto failed
;
489 sd
->owner_sid
= sddl_decode_sid(sd
, &sddl
, domain_sid
);
490 if (sd
->owner_sid
== NULL
) goto failed
;
493 if (sd
->group_sid
!= NULL
) goto failed
;
494 sd
->group_sid
= sddl_decode_sid(sd
, &sddl
, domain_sid
);
495 if (sd
->group_sid
== NULL
) goto failed
;
503 DEBUG(2,("Badly formatted SDDL '%s'\n", sddl
));
509 turn a set of flags into a string
511 static char *sddl_flags_to_string(TALLOC_CTX
*mem_ctx
, const struct flag_map
*map
,
512 uint32_t flags
, bool check_all
)
517 /* try to find an exact match */
518 for (i
=0;map
[i
].name
;i
++) {
519 if (map
[i
].flag
== flags
) {
520 return talloc_strdup(mem_ctx
, map
[i
].name
);
524 s
= talloc_strdup(mem_ctx
, "");
527 for (i
=0;map
[i
].name
;i
++) {
528 if ((flags
& map
[i
].flag
) != 0) {
529 s
= talloc_asprintf_append_buffer(s
, "%s", map
[i
].name
);
530 if (s
== NULL
) goto failed
;
531 flags
&= ~map
[i
].flag
;
535 if (check_all
&& flags
!= 0) {
547 encode a sid in SDDL format
549 static char *sddl_encode_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
550 const struct dom_sid
*domain_sid
)
555 sidstr
= dom_sid_string(mem_ctx
, sid
);
556 if (sidstr
== NULL
) return NULL
;
558 /* seen if its a well known sid */
559 for (i
=0;sid_codes
[i
].sid
;i
++) {
560 if (strcmp(sidstr
, sid_codes
[i
].sid
) == 0) {
562 return talloc_strdup(mem_ctx
, sid_codes
[i
].code
);
566 /* or a well known rid in our domain */
567 if (dom_sid_in_domain(domain_sid
, sid
)) {
568 uint32_t rid
= sid
->sub_auths
[sid
->num_auths
-1];
569 for (;i
<ARRAY_SIZE(sid_codes
);i
++) {
570 if (rid
== sid_codes
[i
].rid
) {
572 return talloc_strdup(mem_ctx
, sid_codes
[i
].code
);
579 /* TODO: encode well known sids as two letter codes */
580 return dom_sid_string(mem_ctx
, sid
);
585 encode an ACE in SDDL format
587 char *sddl_encode_ace(TALLOC_CTX
*mem_ctx
, const struct security_ace
*ace
,
588 const struct dom_sid
*domain_sid
)
592 struct GUID_txt_buf object_buf
, iobject_buf
;
593 const char *sddl_type
="", *sddl_flags
="", *sddl_mask
="",
594 *sddl_object
="", *sddl_iobject
="", *sddl_trustee
="";
596 tmp_ctx
= talloc_new(mem_ctx
);
597 if (tmp_ctx
== NULL
) {
598 DEBUG(0, ("talloc_new failed\n"));
602 sddl_type
= sddl_flags_to_string(tmp_ctx
, ace_types
, ace
->type
, true);
603 if (sddl_type
== NULL
) {
607 sddl_flags
= sddl_flags_to_string(tmp_ctx
, ace_flags
, ace
->flags
,
609 if (sddl_flags
== NULL
) {
613 sddl_mask
= sddl_flags_to_string(tmp_ctx
, ace_access_mask
,
614 ace
->access_mask
, true);
615 if (sddl_mask
== NULL
) {
616 sddl_mask
= talloc_asprintf(tmp_ctx
, "0x%08x",
618 if (sddl_mask
== NULL
) {
623 if (ace
->type
== SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT
||
624 ace
->type
== SEC_ACE_TYPE_ACCESS_DENIED_OBJECT
||
625 ace
->type
== SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT
||
626 ace
->type
== SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT
) {
627 const struct security_ace_object
*object
= &ace
->object
.object
;
629 if (ace
->object
.object
.flags
& SEC_ACE_OBJECT_TYPE_PRESENT
) {
630 sddl_object
= GUID_buf_string(
631 &object
->type
.type
, &object_buf
);
634 if (ace
->object
.object
.flags
&
635 SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT
) {
636 sddl_iobject
= GUID_buf_string(
637 &object
->inherited_type
.inherited_type
,
642 sddl_trustee
= sddl_encode_sid(tmp_ctx
, &ace
->trustee
, domain_sid
);
643 if (sddl_trustee
== NULL
) {
647 sddl
= talloc_asprintf(mem_ctx
, "%s;%s;%s;%s;%s;%s",
648 sddl_type
, sddl_flags
, sddl_mask
, sddl_object
,
649 sddl_iobject
, sddl_trustee
);
652 talloc_free(tmp_ctx
);
657 encode an ACL in SDDL format
659 static char *sddl_encode_acl(TALLOC_CTX
*mem_ctx
, const struct security_acl
*acl
,
660 uint32_t flags
, const struct dom_sid
*domain_sid
)
665 /* add any ACL flags */
666 sddl
= sddl_flags_to_string(mem_ctx
, acl_flags
, flags
, false);
667 if (sddl
== NULL
) goto failed
;
669 /* now the ACEs, encoded in braces */
670 for (i
=0;i
<acl
->num_aces
;i
++) {
671 char *ace
= sddl_encode_ace(sddl
, &acl
->aces
[i
], domain_sid
);
672 if (ace
== NULL
) goto failed
;
673 sddl
= talloc_asprintf_append_buffer(sddl
, "(%s)", ace
);
674 if (sddl
== NULL
) goto failed
;
687 encode a security descriptor to SDDL format
689 char *sddl_encode(TALLOC_CTX
*mem_ctx
, const struct security_descriptor
*sd
,
690 const struct dom_sid
*domain_sid
)
695 /* start with a blank string */
696 sddl
= talloc_strdup(mem_ctx
, "");
697 if (sddl
== NULL
) goto failed
;
699 tmp_ctx
= talloc_new(mem_ctx
);
701 if (sd
->owner_sid
!= NULL
) {
702 char *sid
= sddl_encode_sid(tmp_ctx
, sd
->owner_sid
, domain_sid
);
703 if (sid
== NULL
) goto failed
;
704 sddl
= talloc_asprintf_append_buffer(sddl
, "O:%s", sid
);
705 if (sddl
== NULL
) goto failed
;
708 if (sd
->group_sid
!= NULL
) {
709 char *sid
= sddl_encode_sid(tmp_ctx
, sd
->group_sid
, domain_sid
);
710 if (sid
== NULL
) goto failed
;
711 sddl
= talloc_asprintf_append_buffer(sddl
, "G:%s", sid
);
712 if (sddl
== NULL
) goto failed
;
715 if ((sd
->type
& SEC_DESC_DACL_PRESENT
) && sd
->dacl
!= NULL
) {
716 char *acl
= sddl_encode_acl(tmp_ctx
, sd
->dacl
, sd
->type
, domain_sid
);
717 if (acl
== NULL
) goto failed
;
718 sddl
= talloc_asprintf_append_buffer(sddl
, "D:%s", acl
);
719 if (sddl
== NULL
) goto failed
;
722 if ((sd
->type
& SEC_DESC_SACL_PRESENT
) && sd
->sacl
!= NULL
) {
723 char *acl
= sddl_encode_acl(tmp_ctx
, sd
->sacl
, sd
->type
>>1, domain_sid
);
724 if (acl
== NULL
) goto failed
;
725 sddl
= talloc_asprintf_append_buffer(sddl
, "S:%s", acl
);
726 if (sddl
== NULL
) goto failed
;
729 talloc_free(tmp_ctx
);