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 "lib/util/smb_strtox.h"
27 #include "system/locale.h"
28 #include "lib/util/util_str_hex.h"
31 struct sddl_transition_state
{
32 const struct dom_sid
*machine_sid
;
33 const struct dom_sid
*domain_sid
;
34 const struct dom_sid
*forest_sid
;
42 static bool sddl_map_flag(
43 const struct flag_map
*map
,
48 while (map
->name
!= NULL
) {
49 size_t len
= strlen(map
->name
);
50 int cmp
= strncmp(map
->name
, str
, len
);
63 map a series of letter codes into a uint32_t
65 static bool sddl_map_flags(const struct flag_map
*map
, const char *str
,
66 uint32_t *pflags
, size_t *plen
,
67 bool unknown_flag_is_part_of_next_thing
)
69 const char *str0
= str
;
74 while (str
[0] != '\0' && isupper((unsigned char)str
[0])) {
79 found
= sddl_map_flag(map
, str
, &len
, &flags
);
91 * For ACL flags, unknown_flag_is_part_of_next_thing is set,
92 * and we expect some more stuff that isn't flags.
94 * For ACE flags, unknown_flag_is_part_of_next_thing is unset,
95 * and the flags have been tokenised into their own little
96 * string. We don't expect anything here, even whitespace.
98 if (*str
== '\0' || unknown_flag_is_part_of_next_thing
) {
101 DBG_WARNING("Unknown flag - '%s' in '%s'\n", str
, str0
);
107 a mapping between the 2 letter SID codes and sid strings
109 static const struct {
112 uint32_t machine_rid
;
116 { .code
= "WD", .sid
= SID_WORLD
},
118 { .code
= "CO", .sid
= SID_CREATOR_OWNER
},
119 { .code
= "CG", .sid
= SID_CREATOR_GROUP
},
120 { .code
= "OW", .sid
= SID_OWNER_RIGHTS
},
122 { .code
= "NU", .sid
= SID_NT_NETWORK
},
123 { .code
= "IU", .sid
= SID_NT_INTERACTIVE
},
124 { .code
= "SU", .sid
= SID_NT_SERVICE
},
125 { .code
= "AN", .sid
= SID_NT_ANONYMOUS
},
126 { .code
= "ED", .sid
= SID_NT_ENTERPRISE_DCS
},
127 { .code
= "PS", .sid
= SID_NT_SELF
},
128 { .code
= "AU", .sid
= SID_NT_AUTHENTICATED_USERS
},
129 { .code
= "RC", .sid
= SID_NT_RESTRICTED
},
130 { .code
= "SY", .sid
= SID_NT_SYSTEM
},
131 { .code
= "LS", .sid
= SID_NT_LOCAL_SERVICE
},
132 { .code
= "NS", .sid
= SID_NT_NETWORK_SERVICE
},
133 { .code
= "WR", .sid
= SID_SECURITY_RESTRICTED_CODE
},
135 { .code
= "BA", .sid
= SID_BUILTIN_ADMINISTRATORS
},
136 { .code
= "BU", .sid
= SID_BUILTIN_USERS
},
137 { .code
= "BG", .sid
= SID_BUILTIN_GUESTS
},
138 { .code
= "PU", .sid
= SID_BUILTIN_POWER_USERS
},
139 { .code
= "AO", .sid
= SID_BUILTIN_ACCOUNT_OPERATORS
},
140 { .code
= "SO", .sid
= SID_BUILTIN_SERVER_OPERATORS
},
141 { .code
= "PO", .sid
= SID_BUILTIN_PRINT_OPERATORS
},
142 { .code
= "BO", .sid
= SID_BUILTIN_BACKUP_OPERATORS
},
143 { .code
= "RE", .sid
= SID_BUILTIN_REPLICATOR
},
144 { .code
= "RU", .sid
= SID_BUILTIN_PREW2K
},
145 { .code
= "RD", .sid
= SID_BUILTIN_REMOTE_DESKTOP_USERS
},
146 { .code
= "NO", .sid
= SID_BUILTIN_NETWORK_CONF_OPERATORS
},
148 { .code
= "MU", .sid
= SID_BUILTIN_PERFMON_USERS
},
149 { .code
= "LU", .sid
= SID_BUILTIN_PERFLOG_USERS
},
150 { .code
= "IS", .sid
= SID_BUILTIN_IUSERS
},
151 { .code
= "CY", .sid
= SID_BUILTIN_CRYPTO_OPERATORS
},
152 { .code
= "ER", .sid
= SID_BUILTIN_EVENT_LOG_READERS
},
153 { .code
= "CD", .sid
= SID_BUILTIN_CERT_SERV_DCOM_ACCESS
},
154 { .code
= "RA", .sid
= SID_BUILTIN_RDS_REMOTE_ACCESS_SERVERS
},
155 { .code
= "ES", .sid
= SID_BUILTIN_RDS_ENDPOINT_SERVERS
},
156 { .code
= "MS", .sid
= SID_BUILTIN_RDS_MANAGEMENT_SERVERS
},
157 { .code
= "HA", .sid
= SID_BUILTIN_HYPER_V_ADMINS
},
158 { .code
= "AA", .sid
= SID_BUILTIN_ACCESS_CONTROL_ASSISTANCE_OPS
},
159 { .code
= "RM", .sid
= SID_BUILTIN_REMOTE_MANAGEMENT_USERS
},
161 { .code
= "UD", .sid
= SID_USER_MODE_DRIVERS
},
163 { .code
= "AC", .sid
= SID_SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE
},
165 { .code
= "LW", .sid
= SID_SECURITY_MANDATORY_LOW
},
166 { .code
= "ME", .sid
= SID_SECURITY_MANDATORY_MEDIUM
},
167 { .code
= "MP", .sid
= SID_SECURITY_MANDATORY_MEDIUM_PLUS
},
168 { .code
= "HI", .sid
= SID_SECURITY_MANDATORY_HIGH
},
169 { .code
= "SI", .sid
= SID_SECURITY_MANDATORY_SYSTEM
},
171 { .code
= "AS", .sid
= SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY
},
172 { .code
= "SS", .sid
= SID_SERVICE_ASSERTED_IDENTITY
},
174 { .code
= "RO", .forest_rid
= DOMAIN_RID_ENTERPRISE_READONLY_DCS
},
176 { .code
= "LA", .machine_rid
= DOMAIN_RID_ADMINISTRATOR
},
177 { .code
= "LG", .machine_rid
= DOMAIN_RID_GUEST
},
179 { .code
= "DA", .domain_rid
= DOMAIN_RID_ADMINS
},
180 { .code
= "DU", .domain_rid
= DOMAIN_RID_USERS
},
181 { .code
= "DG", .domain_rid
= DOMAIN_RID_GUESTS
},
182 { .code
= "DC", .domain_rid
= DOMAIN_RID_DOMAIN_MEMBERS
},
183 { .code
= "DD", .domain_rid
= DOMAIN_RID_DCS
},
184 { .code
= "CA", .domain_rid
= DOMAIN_RID_CERT_ADMINS
},
185 { .code
= "SA", .forest_rid
= DOMAIN_RID_SCHEMA_ADMINS
},
186 { .code
= "EA", .forest_rid
= DOMAIN_RID_ENTERPRISE_ADMINS
},
187 { .code
= "PA", .domain_rid
= DOMAIN_RID_POLICY_ADMINS
},
189 { .code
= "CN", .domain_rid
= DOMAIN_RID_CLONEABLE_CONTROLLERS
},
191 { .code
= "AP", .domain_rid
= DOMAIN_RID_PROTECTED_USERS
},
192 { .code
= "KA", .domain_rid
= DOMAIN_RID_KEY_ADMINS
},
193 { .code
= "EK", .forest_rid
= DOMAIN_RID_ENTERPRISE_KEY_ADMINS
},
195 { .code
= "RS", .domain_rid
= DOMAIN_RID_RAS_SERVERS
}
200 It can either be a special 2 letter code, or in S-* format
202 static struct dom_sid
*sddl_decode_sid(TALLOC_CTX
*mem_ctx
, const char **sddlp
,
203 struct sddl_transition_state
*state
)
205 const char *sddl
= (*sddlp
);
208 /* see if its in the numeric format */
209 if (strncmp(sddl
, "S-", 2) == 0) {
210 struct dom_sid
*sid
= NULL
;
211 char *sid_str
= NULL
;
212 const char *end
= NULL
;
214 size_t len
= strspn(sddl
+ 2, "-0123456789ABCDEFabcdefxX") + 2;
215 if (len
< 5) { /* S-1-x */
218 if (sddl
[len
- 1] == 'D' && sddl
[len
] == ':') {
220 * we have run into the "D:" dacl marker, mistaking it
221 * for a hex digit. There is no other way for this
222 * pair to occur at the end of a SID in SDDL.
227 sid_str
= talloc_strndup(mem_ctx
, sddl
, len
);
228 if (sid_str
== NULL
) {
231 sid
= talloc(mem_ctx
, struct dom_sid
);
233 TALLOC_FREE(sid_str
);
236 ok
= dom_sid_parse_endp(sid_str
, sid
, &end
);
238 DBG_WARNING("could not parse SID '%s'\n", sid_str
);
239 TALLOC_FREE(sid_str
);
243 if (end
- sid_str
!= len
) {
244 DBG_WARNING("trailing junk after SID '%s'\n", sid_str
);
245 TALLOC_FREE(sid_str
);
249 TALLOC_FREE(sid_str
);
254 /* now check for one of the special codes */
255 for (i
=0;i
<ARRAY_SIZE(sid_codes
);i
++) {
256 if (strncmp(sid_codes
[i
].code
, sddl
, 2) == 0) break;
258 if (i
== ARRAY_SIZE(sid_codes
)) {
259 DEBUG(1,("Unknown sddl sid code '%2.2s'\n", sddl
));
266 if (sid_codes
[i
].machine_rid
!= 0) {
267 return dom_sid_add_rid(mem_ctx
, state
->machine_sid
,
268 sid_codes
[i
].machine_rid
);
271 if (sid_codes
[i
].domain_rid
!= 0) {
272 return dom_sid_add_rid(mem_ctx
, state
->domain_sid
,
273 sid_codes
[i
].domain_rid
);
276 if (sid_codes
[i
].forest_rid
!= 0) {
277 return dom_sid_add_rid(mem_ctx
, state
->forest_sid
,
278 sid_codes
[i
].forest_rid
);
281 return dom_sid_parse_talloc(mem_ctx
, sid_codes
[i
].sid
);
284 static const struct flag_map ace_types
[] = {
285 { "AU", SEC_ACE_TYPE_SYSTEM_AUDIT
},
286 { "AL", SEC_ACE_TYPE_SYSTEM_ALARM
},
287 { "OA", SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT
},
288 { "OD", SEC_ACE_TYPE_ACCESS_DENIED_OBJECT
},
289 { "OU", SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT
},
290 { "OL", SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT
},
291 { "A", SEC_ACE_TYPE_ACCESS_ALLOWED
},
292 { "D", SEC_ACE_TYPE_ACCESS_DENIED
},
296 static const struct flag_map ace_flags
[] = {
297 { "OI", SEC_ACE_FLAG_OBJECT_INHERIT
},
298 { "CI", SEC_ACE_FLAG_CONTAINER_INHERIT
},
299 { "NP", SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
},
300 { "IO", SEC_ACE_FLAG_INHERIT_ONLY
},
301 { "ID", SEC_ACE_FLAG_INHERITED_ACE
},
302 { "SA", SEC_ACE_FLAG_SUCCESSFUL_ACCESS
},
303 { "FA", SEC_ACE_FLAG_FAILED_ACCESS
},
307 static const struct flag_map ace_access_mask
[] = {
308 { "CC", SEC_ADS_CREATE_CHILD
},
309 { "DC", SEC_ADS_DELETE_CHILD
},
310 { "LC", SEC_ADS_LIST
},
311 { "SW", SEC_ADS_SELF_WRITE
},
312 { "RP", SEC_ADS_READ_PROP
},
313 { "WP", SEC_ADS_WRITE_PROP
},
314 { "DT", SEC_ADS_DELETE_TREE
},
315 { "LO", SEC_ADS_LIST_OBJECT
},
316 { "CR", SEC_ADS_CONTROL_ACCESS
},
317 { "SD", SEC_STD_DELETE
},
318 { "RC", SEC_STD_READ_CONTROL
},
319 { "WD", SEC_STD_WRITE_DAC
},
320 { "WO", SEC_STD_WRITE_OWNER
},
321 { "GA", SEC_GENERIC_ALL
},
322 { "GX", SEC_GENERIC_EXECUTE
},
323 { "GW", SEC_GENERIC_WRITE
},
324 { "GR", SEC_GENERIC_READ
},
328 static const struct flag_map decode_ace_access_mask
[] = {
329 { "FA", FILE_GENERIC_ALL
},
330 { "FR", FILE_GENERIC_READ
},
331 { "FW", FILE_GENERIC_WRITE
},
332 { "FX", FILE_GENERIC_EXECUTE
},
337 static char *sddl_match_file_rights(TALLOC_CTX
*mem_ctx
,
342 /* try to find an exact match */
343 for (i
=0;decode_ace_access_mask
[i
].name
;i
++) {
344 if (decode_ace_access_mask
[i
].flag
== flags
) {
345 return talloc_strdup(mem_ctx
,
346 decode_ace_access_mask
[i
].name
);
352 static bool sddl_decode_access(const char *str
, uint32_t *pmask
)
354 const char *str0
= str
;
357 unsigned long long numeric_mask
;
360 * The access mask can be a number or a series of flags.
362 * Canonically the number is expressed in hexadecimal (with 0x), but
363 * per MS-DTYP and Windows behaviour, octal and decimal numbers are
366 * Windows has two behaviours we choose not to replicate:
368 * 1. numbers exceeding 0xffffffff are truncated at that point,
369 * turning on all access flags.
371 * 2. negative numbers are accepted, so e.g. -2 becomes 0xfffffffe.
373 numeric_mask
= smb_strtoull(str
, &end
, 0, &err
, SMB_STR_STANDARD
);
375 if (numeric_mask
> UINT32_MAX
) {
376 DBG_WARNING("Bad numeric flag value - %llu in %s\n",
380 if (end
- str
> sizeof("037777777777")) {
381 /* here's the tricky thing: if a number is big
382 * enough to overflow the uint64, it might end
383 * up small enough to fit in the uint32, and
384 * we'd miss that it overflowed. So we count
385 * the digits -- any more than 12 (for
386 * "037777777777") is too long for 32 bits,
387 * and the shortest 64-bit wrapping string is
388 * 19 (for "0x1" + 16 zeros).
390 DBG_WARNING("Bad numeric flag value in '%s'\n", str0
);
394 DBG_WARNING("Bad characters in '%s'\n", str0
);
397 *pmask
= numeric_mask
;
400 /* It's not a positive number, so we'll look for flags */
402 while ((str
[0] != '\0') &&
403 (isupper((unsigned char)str
[0]) || str
[0] == ' ')) {
407 while (str
[0] == ' ') {
409 * Following Windows we accept spaces between flags
410 * but not after flags. Not tabs, though, never tabs.
413 if (str
[0] == '\0') {
414 DBG_WARNING("trailing whitespace in flags "
419 found
= sddl_map_flag(
420 ace_access_mask
, str
, &len
, &flags
);
421 found
|= sddl_map_flag(
422 decode_ace_access_mask
, str
, &len
, &flags
);
424 DEBUG(1, ("Unknown flag - %s in %s\n", str
, str0
));
431 DBG_WARNING("Bad characters in '%s'\n", str0
);
439 static bool sddl_decode_guid(const char *str
, struct GUID
*guid
)
441 if (strlen(str
) != 36) {
444 return parse_guid_string(str
, guid
);
450 return true on success, false on failure
451 note that this routine modifies the string
453 static bool sddl_decode_ace(TALLOC_CTX
*mem_ctx
, struct security_ace
*ace
, char *str
,
454 struct sddl_transition_state
*state
)
466 /* parse out the 6 tokens */
469 char *ptr
= strchr(str
, ';');
470 if (ptr
== NULL
) return false;
477 ok
= sddl_map_flag(ace_types
, tok
[0], &len
, &v
);
479 DBG_WARNING("Unknown ACE type - %s\n", tok
[0]);
482 if (tok
[0][len
] != '\0') {
483 DBG_WARNING("Garbage after ACE type - %s\n", tok
[0]);
490 if (!sddl_map_flags(ace_flags
, tok
[1], &v
, NULL
, false)) {
496 ok
= sddl_decode_access(tok
[2], &ace
->access_mask
);
502 if (tok
[3][0] != 0) {
503 ok
= sddl_decode_guid(tok
[3], &ace
->object
.object
.type
.type
);
507 ace
->object
.object
.flags
|= SEC_ACE_OBJECT_TYPE_PRESENT
;
511 if (tok
[4][0] != 0) {
512 ok
= sddl_decode_guid(tok
[4],
513 &ace
->object
.object
.inherited_type
.inherited_type
);
517 ace
->object
.object
.flags
|= SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT
;
522 sid
= sddl_decode_sid(mem_ctx
, &s
, state
);
534 static const struct flag_map acl_flags
[] = {
535 { "P", SEC_DESC_DACL_PROTECTED
},
536 { "AR", SEC_DESC_DACL_AUTO_INHERIT_REQ
},
537 { "AI", SEC_DESC_DACL_AUTO_INHERITED
},
544 static struct security_acl
*sddl_decode_acl(struct security_descriptor
*sd
,
545 const char **sddlp
, uint32_t *flags
,
546 struct sddl_transition_state
*state
)
548 const char *sddl
= *sddlp
;
549 struct security_acl
*acl
;
554 acl
= talloc_zero(sd
, struct security_acl
);
555 if (acl
== NULL
) return NULL
;
556 acl
->revision
= SECURITY_ACL_REVISION_ADS
;
558 if (isupper(sddl
[0]) && sddl
[1] == ':') {
559 /* its an empty ACL */
563 /* work out the ACL flags */
564 if (!sddl_map_flags(acl_flags
, sddl
, flags
, &len
, true)) {
571 while (*sddl
== '(') {
573 len
= strcspn(sddl
+1, ")");
574 astr
= talloc_strndup(acl
, sddl
+1, len
);
575 if (astr
== NULL
|| sddl
[len
+1] != ')') {
579 acl
->aces
= talloc_realloc(acl
, acl
->aces
, struct security_ace
,
581 if (acl
->aces
== NULL
) {
585 if (!sddl_decode_ace(acl
->aces
, &acl
->aces
[acl
->num_aces
],
590 switch (acl
->aces
[acl
->num_aces
].type
) {
591 case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT
:
592 case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT
:
593 case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT
:
594 case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT
:
595 acl
->revision
= SECURITY_ACL_REVISION_ADS
;
610 decode a security descriptor in SDDL format
612 struct security_descriptor
*sddl_decode(TALLOC_CTX
*mem_ctx
, const char *sddl
,
613 const struct dom_sid
*domain_sid
)
615 struct sddl_transition_state state
= {
617 * TODO: verify .machine_rid values really belong to
618 * to the machine_sid on a member, once
619 * we pass machine_sid from the caller...
621 .machine_sid
= domain_sid
,
622 .domain_sid
= domain_sid
,
623 .forest_sid
= domain_sid
,
625 struct security_descriptor
*sd
;
626 sd
= talloc_zero(mem_ctx
, struct security_descriptor
);
628 sd
->revision
= SECURITY_DESCRIPTOR_REVISION_1
;
629 sd
->type
= SEC_DESC_SELF_RELATIVE
;
634 if (sddl
[1] != ':') goto failed
;
639 if (sd
->dacl
!= NULL
) goto failed
;
640 sd
->dacl
= sddl_decode_acl(sd
, &sddl
, &flags
, &state
);
641 if (sd
->dacl
== NULL
) goto failed
;
642 sd
->type
|= flags
| SEC_DESC_DACL_PRESENT
;
645 if (sd
->sacl
!= NULL
) goto failed
;
646 sd
->sacl
= sddl_decode_acl(sd
, &sddl
, &flags
, &state
);
647 if (sd
->sacl
== NULL
) goto failed
;
648 /* this relies on the SEC_DESC_SACL_* flags being
649 1 bit shifted from the SEC_DESC_DACL_* flags */
650 sd
->type
|= (flags
<<1) | SEC_DESC_SACL_PRESENT
;
653 if (sd
->owner_sid
!= NULL
) goto failed
;
654 sd
->owner_sid
= sddl_decode_sid(sd
, &sddl
, &state
);
655 if (sd
->owner_sid
== NULL
) goto failed
;
658 if (sd
->group_sid
!= NULL
) goto failed
;
659 sd
->group_sid
= sddl_decode_sid(sd
, &sddl
, &state
);
660 if (sd
->group_sid
== NULL
) goto failed
;
670 DEBUG(2,("Badly formatted SDDL '%s'\n", sddl
));
676 turn a set of flags into a string
678 static char *sddl_flags_to_string(TALLOC_CTX
*mem_ctx
, const struct flag_map
*map
,
679 uint32_t flags
, bool check_all
)
684 /* try to find an exact match */
685 for (i
=0;map
[i
].name
;i
++) {
686 if (map
[i
].flag
== flags
) {
687 return talloc_strdup(mem_ctx
, map
[i
].name
);
691 s
= talloc_strdup(mem_ctx
, "");
694 for (i
=0;map
[i
].name
;i
++) {
695 if ((flags
& map
[i
].flag
) != 0) {
696 s
= talloc_asprintf_append_buffer(s
, "%s", map
[i
].name
);
697 if (s
== NULL
) goto failed
;
698 flags
&= ~map
[i
].flag
;
702 if (check_all
&& flags
!= 0) {
714 encode a sid in SDDL format
716 static char *sddl_encode_sid(TALLOC_CTX
*mem_ctx
, const struct dom_sid
*sid
,
717 struct sddl_transition_state
*state
)
719 bool in_machine
= dom_sid_in_domain(state
->machine_sid
, sid
);
720 bool in_domain
= dom_sid_in_domain(state
->domain_sid
, sid
);
721 bool in_forest
= dom_sid_in_domain(state
->forest_sid
, sid
);
722 struct dom_sid_buf buf
;
723 const char *sidstr
= dom_sid_str_buf(sid
, &buf
);
727 if (sid
->num_auths
> 1) {
728 rid
= sid
->sub_auths
[sid
->num_auths
-1];
731 for (i
=0;i
<ARRAY_SIZE(sid_codes
);i
++) {
732 /* seen if its a well known sid */
733 if (sid_codes
[i
].sid
!= NULL
) {
736 cmp
= strcmp(sidstr
, sid_codes
[i
].sid
);
741 return talloc_strdup(mem_ctx
, sid_codes
[i
].code
);
748 if (in_machine
&& sid_codes
[i
].machine_rid
== rid
) {
749 return talloc_strdup(mem_ctx
, sid_codes
[i
].code
);
751 if (in_domain
&& sid_codes
[i
].domain_rid
== rid
) {
752 return talloc_strdup(mem_ctx
, sid_codes
[i
].code
);
754 if (in_forest
&& sid_codes
[i
].forest_rid
== rid
) {
755 return talloc_strdup(mem_ctx
, sid_codes
[i
].code
);
759 return talloc_strdup(mem_ctx
, sidstr
);
764 encode an ACE in SDDL format
766 static char *sddl_transition_encode_ace(TALLOC_CTX
*mem_ctx
, const struct security_ace
*ace
,
767 struct sddl_transition_state
*state
)
771 struct GUID_txt_buf object_buf
, iobject_buf
;
772 const char *sddl_type
="", *sddl_flags
="", *sddl_mask
="",
773 *sddl_object
="", *sddl_iobject
="", *sddl_trustee
="";
775 tmp_ctx
= talloc_new(mem_ctx
);
776 if (tmp_ctx
== NULL
) {
777 DEBUG(0, ("talloc_new failed\n"));
781 sddl_type
= sddl_flags_to_string(tmp_ctx
, ace_types
, ace
->type
, true);
782 if (sddl_type
== NULL
) {
786 sddl_flags
= sddl_flags_to_string(tmp_ctx
, ace_flags
, ace
->flags
,
788 if (sddl_flags
== NULL
) {
792 sddl_mask
= sddl_flags_to_string(tmp_ctx
, ace_access_mask
,
793 ace
->access_mask
, true);
794 if (sddl_mask
== NULL
) {
795 sddl_mask
= sddl_match_file_rights(tmp_ctx
,
797 if (sddl_mask
== NULL
) {
798 sddl_mask
= talloc_asprintf(tmp_ctx
, "0x%x",
801 if (sddl_mask
== NULL
) {
806 if (ace
->type
== SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT
||
807 ace
->type
== SEC_ACE_TYPE_ACCESS_DENIED_OBJECT
||
808 ace
->type
== SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT
||
809 ace
->type
== SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT
) {
810 const struct security_ace_object
*object
= &ace
->object
.object
;
812 if (ace
->object
.object
.flags
& SEC_ACE_OBJECT_TYPE_PRESENT
) {
813 sddl_object
= GUID_buf_string(
814 &object
->type
.type
, &object_buf
);
817 if (ace
->object
.object
.flags
&
818 SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT
) {
819 sddl_iobject
= GUID_buf_string(
820 &object
->inherited_type
.inherited_type
,
825 sddl_trustee
= sddl_encode_sid(tmp_ctx
, &ace
->trustee
, state
);
826 if (sddl_trustee
== NULL
) {
830 sddl
= talloc_asprintf(mem_ctx
, "%s;%s;%s;%s;%s;%s",
831 sddl_type
, sddl_flags
, sddl_mask
, sddl_object
,
832 sddl_iobject
, sddl_trustee
);
835 talloc_free(tmp_ctx
);
839 char *sddl_encode_ace(TALLOC_CTX
*mem_ctx
, const struct security_ace
*ace
,
840 const struct dom_sid
*domain_sid
)
842 struct sddl_transition_state state
= {
844 * TODO: verify .machine_rid values really belong to
845 * to the machine_sid on a member, once
846 * we pass machine_sid from the caller...
848 .machine_sid
= domain_sid
,
849 .domain_sid
= domain_sid
,
850 .forest_sid
= domain_sid
,
852 return sddl_transition_encode_ace(mem_ctx
, ace
, &state
);
856 encode an ACL in SDDL format
858 static char *sddl_encode_acl(TALLOC_CTX
*mem_ctx
, const struct security_acl
*acl
,
859 uint32_t flags
, struct sddl_transition_state
*state
)
864 /* add any ACL flags */
865 sddl
= sddl_flags_to_string(mem_ctx
, acl_flags
, flags
, false);
866 if (sddl
== NULL
) goto failed
;
868 /* now the ACEs, encoded in braces */
869 for (i
=0;i
<acl
->num_aces
;i
++) {
870 char *ace
= sddl_transition_encode_ace(sddl
, &acl
->aces
[i
], state
);
871 if (ace
== NULL
) goto failed
;
872 sddl
= talloc_asprintf_append_buffer(sddl
, "(%s)", ace
);
873 if (sddl
== NULL
) goto failed
;
886 encode a security descriptor to SDDL format
888 char *sddl_encode(TALLOC_CTX
*mem_ctx
, const struct security_descriptor
*sd
,
889 const struct dom_sid
*domain_sid
)
891 struct sddl_transition_state state
= {
893 * TODO: verify .machine_rid values really belong to
894 * to the machine_sid on a member, once
895 * we pass machine_sid from the caller...
897 .machine_sid
= domain_sid
,
898 .domain_sid
= domain_sid
,
899 .forest_sid
= domain_sid
,
904 /* start with a blank string */
905 sddl
= talloc_strdup(mem_ctx
, "");
906 if (sddl
== NULL
) goto failed
;
908 tmp_ctx
= talloc_new(mem_ctx
);
910 if (sd
->owner_sid
!= NULL
) {
911 char *sid
= sddl_encode_sid(tmp_ctx
, sd
->owner_sid
, &state
);
912 if (sid
== NULL
) goto failed
;
913 sddl
= talloc_asprintf_append_buffer(sddl
, "O:%s", sid
);
914 if (sddl
== NULL
) goto failed
;
917 if (sd
->group_sid
!= NULL
) {
918 char *sid
= sddl_encode_sid(tmp_ctx
, sd
->group_sid
, &state
);
919 if (sid
== NULL
) goto failed
;
920 sddl
= talloc_asprintf_append_buffer(sddl
, "G:%s", sid
);
921 if (sddl
== NULL
) goto failed
;
924 if ((sd
->type
& SEC_DESC_DACL_PRESENT
) && sd
->dacl
!= NULL
) {
925 char *acl
= sddl_encode_acl(tmp_ctx
, sd
->dacl
, sd
->type
, &state
);
926 if (acl
== NULL
) goto failed
;
927 sddl
= talloc_asprintf_append_buffer(sddl
, "D:%s", acl
);
928 if (sddl
== NULL
) goto failed
;
931 if ((sd
->type
& SEC_DESC_SACL_PRESENT
) && sd
->sacl
!= NULL
) {
932 char *acl
= sddl_encode_acl(tmp_ctx
, sd
->sacl
, sd
->type
>>1, &state
);
933 if (acl
== NULL
) goto failed
;
934 sddl
= talloc_asprintf_append_buffer(sddl
, "S:%s", acl
);
935 if (sddl
== NULL
) goto failed
;
938 talloc_free(tmp_ctx
);