libcli/security: Avoid includes.h
[samba.git] / libcli / security / sddl.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    security descriptor description language functions
5
6    Copyright (C) Andrew Tridgell                2005
7
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.
12
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.
17
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/>.
20 */
21
22 #include "replace.h"
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"
27
28 struct flag_map {
29         const char *name;
30         uint32_t flag;
31 };
32
33 static bool sddl_map_flag(
34         const struct flag_map *map,
35         const char *str,
36         size_t *plen,
37         uint32_t *pflag)
38 {
39         while (map->name != NULL) {
40                 size_t len = strlen(map->name);
41                 int cmp = strncmp(map->name, str, len);
42
43                 if (cmp == 0) {
44                         *plen = len;
45                         *pflag = map->flag;
46                         return true;
47                 }
48                 map += 1;
49         }
50         return false;
51 }
52
53 /*
54   map a series of letter codes into a uint32_t
55 */
56 static bool sddl_map_flags(const struct flag_map *map, const char *str,
57                            uint32_t *pflags, size_t *plen)
58 {
59         const char *str0 = str;
60         if (plen != NULL) {
61                 *plen = 0;
62         }
63         *pflags = 0;
64         while (str[0] && isupper(str[0])) {
65                 size_t len;
66                 uint32_t flags;
67                 bool found;
68
69                 found = sddl_map_flag(map, str, &len, &flags);
70                 if (!found) {
71                         DEBUG(1, ("Unknown flag - %s in %s\n", str, str0));
72                         return false;
73                 }
74
75                 *pflags |= flags;
76                 if (plen != NULL) {
77                         *plen += len;
78                 }
79                 str += len;
80         }
81         return true;
82 }
83
84 /*
85   a mapping between the 2 letter SID codes and sid strings
86 */
87 static const struct {
88         const char *code;
89         const char *sid;
90         uint32_t rid;
91 } sid_codes[] = {
92         { .code = "WD", .sid = SID_WORLD },
93
94         { .code = "CO", .sid = SID_CREATOR_OWNER },
95         { .code = "CG", .sid = SID_CREATOR_GROUP },
96         { .code = "OW", .sid = SID_OWNER_RIGHTS },
97
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 },
110
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 },
123
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 },
136
137         { .code = "UD", .sid = SID_USER_MODE_DRIVERS },
138
139         { .code = "AC", .sid = SID_SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE },
140
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 },
146
147         { .code = "AS", .sid = SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY },
148         { .code = "SS", .sid = SID_SERVICE_ASSERTED_IDENTITY },
149
150         { .code = "RO", .sid = NULL, .rid = DOMAIN_RID_ENTERPRISE_READONLY_DCS },
151
152         { .code = "LA", .sid = NULL, .rid = DOMAIN_RID_ADMINISTRATOR },
153         { .code = "LG", .sid = NULL, .rid = DOMAIN_RID_GUEST },
154
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 },
164
165         { .code = "CN", .sid = NULL, .rid = DOMAIN_RID_CLONEABLE_CONTROLLERS },
166
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 },
170
171         { .code = "RS", .sid = NULL, .rid = DOMAIN_RID_RAS_SERVERS }
172 };
173
174 /*
175   decode a SID
176   It can either be a special 2 letter code, or in S-* format
177 */
178 static struct dom_sid *sddl_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp,
179                                        const struct dom_sid *domain_sid)
180 {
181         const char *sddl = (*sddlp);
182         size_t i;
183
184         /* see if its in the numeric format */
185         if (strncmp(sddl, "S-", 2) == 0) {
186                 struct dom_sid *sid;
187                 char *sid_str;
188                 size_t len = strspn(sddl+2, "-0123456789");
189                 sid_str = talloc_strndup(mem_ctx, sddl, len+2);
190                 if (!sid_str) {
191                         return NULL;
192                 }
193                 (*sddlp) += len+2;
194                 sid = dom_sid_parse_talloc(mem_ctx, sid_str);
195                 talloc_free(sid_str);
196                 return sid;
197         }
198
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;
202         }
203         if (i == ARRAY_SIZE(sid_codes)) {
204                 DEBUG(1,("Unknown sddl sid code '%2.2s'\n", sddl));
205                 return NULL;
206         }
207
208         (*sddlp) += 2;
209
210         if (sid_codes[i].sid == NULL) {
211                 return dom_sid_add_rid(mem_ctx, domain_sid, sid_codes[i].rid);
212         }
213
214         return dom_sid_parse_talloc(mem_ctx, sid_codes[i].sid);
215 }
216
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 },
226         { NULL, 0 }
227 };
228
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 },
237         { NULL, 0 },
238 };
239
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 },
258         { NULL, 0 }
259 };
260
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 },
266         { NULL, 0 },
267 };
268
269 static bool sddl_decode_access(const char *str, uint32_t *pmask)
270 {
271         const char *str0 = str;
272         uint32_t mask = 0;
273         int cmp;
274
275         cmp = strncmp(str, "0x", 2);
276         if (cmp == 0) {
277                 *pmask = strtol(str, NULL, 16);
278                 return true;
279         }
280
281         while ((str[0] != '\0') && isupper(str[0])) {
282                 uint32_t flags = 0;
283                 size_t len = 0;
284                 bool found;
285
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);
290                 if (!found) {
291                         DEBUG(1, ("Unknown flag - %s in %s\n", str, str0));
292                         return false;
293                 }
294                 mask |= flags;
295                 str += len;
296         }
297
298         *pmask = mask;
299         return true;
300 }
301
302 /*
303   decode an ACE
304   return true on success, false on failure
305   note that this routine modifies the string
306 */
307 static bool sddl_decode_ace(TALLOC_CTX *mem_ctx, struct security_ace *ace, char *str,
308                             const struct dom_sid *domain_sid)
309 {
310         const char *tok[6];
311         const char *s;
312         int i;
313         uint32_t v;
314         struct dom_sid *sid;
315         bool ok;
316
317         ZERO_STRUCTP(ace);
318
319         /* parse out the 6 tokens */
320         tok[0] = str;
321         for (i=0;i<5;i++) {
322                 char *ptr = strchr(str, ';');
323                 if (ptr == NULL) return false;
324                 *ptr = 0;
325                 str = ptr+1;
326                 tok[i+1] = str;
327         }
328
329         /* parse ace type */
330         if (!sddl_map_flags(ace_types, tok[0], &v, NULL)) {
331                 return false;
332         }
333         ace->type = v;
334
335         /* ace flags */
336         if (!sddl_map_flags(ace_flags, tok[1], &v, NULL)) {
337                 return false;
338         }
339         ace->flags = v;
340
341         /* access mask */
342         ok = sddl_decode_access(tok[2], &ace->access_mask);
343         if (!ok) {
344                 return false;
345         }
346
347         /* object */
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)) {
352                         return false;
353                 }
354                 ace->object.object.flags |= SEC_ACE_OBJECT_TYPE_PRESENT;
355         }
356
357         /* inherit object */
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)) {
362                         return false;
363                 }
364                 ace->object.object.flags |= SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT;
365         }
366
367         /* trustee */
368         s = tok[5];
369         sid = sddl_decode_sid(mem_ctx, &s, domain_sid);
370         if (sid == NULL) {
371                 return false;
372         }
373         ace->trustee = *sid;
374         talloc_free(sid);
375
376         return true;
377 }
378
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 },
383         { NULL, 0 }
384 };
385
386 /*
387   decode an ACL
388 */
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)
392 {
393         const char *sddl = *sddlp;
394         struct security_acl *acl;
395         size_t len;
396
397         *flags = 0;
398
399         acl = talloc_zero(sd, struct security_acl);
400         if (acl == NULL) return NULL;
401         acl->revision = SECURITY_ACL_REVISION_ADS;
402
403         if (isupper(sddl[0]) && sddl[1] == ':') {
404                 /* its an empty ACL */
405                 return acl;
406         }
407
408         /* work out the ACL flags */
409         if (!sddl_map_flags(acl_flags, sddl, flags, &len)) {
410                 talloc_free(acl);
411                 return NULL;
412         }
413         sddl += len;
414
415         /* now the ACEs */
416         while (*sddl == '(') {
417                 char *astr;
418                 len = strcspn(sddl+1, ")");
419                 astr = talloc_strndup(acl, sddl+1, len);
420                 if (astr == NULL || sddl[len+1] != ')') {
421                         talloc_free(acl);
422                         return NULL;
423                 }
424                 acl->aces = talloc_realloc(acl, acl->aces, struct security_ace,
425                                            acl->num_aces+1);
426                 if (acl->aces == NULL) {
427                         talloc_free(acl);
428                         return NULL;
429                 }
430                 if (!sddl_decode_ace(acl->aces, &acl->aces[acl->num_aces],
431                                      astr, domain_sid)) {
432                         talloc_free(acl);
433                         return NULL;
434                 }
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;
441                         break;
442                 default:
443                         break;
444                 }
445                 talloc_free(astr);
446                 sddl += len+2;
447                 acl->num_aces++;
448         }
449
450         (*sddlp) = sddl;
451         return acl;
452 }
453
454 /*
455   decode a security descriptor in SDDL format
456 */
457 struct security_descriptor *sddl_decode(TALLOC_CTX *mem_ctx, const char *sddl,
458                                         const struct dom_sid *domain_sid)
459 {
460         struct security_descriptor *sd;
461         sd = talloc_zero(mem_ctx, struct security_descriptor);
462
463         sd->revision = SECURITY_DESCRIPTOR_REVISION_1;
464         sd->type     = SEC_DESC_SELF_RELATIVE;
465
466         while (*sddl) {
467                 uint32_t flags;
468                 char c = sddl[0];
469                 if (sddl[1] != ':') goto failed;
470
471                 sddl += 2;
472                 switch (c) {
473                 case 'D':
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;
478                         break;
479                 case 'S':
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;
486                         break;
487                 case 'O':
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;
491                         break;
492                 case 'G':
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;
496                         break;
497                 }
498         }
499
500         return sd;
501
502 failed:
503         DEBUG(2,("Badly formatted SDDL '%s'\n", sddl));
504         talloc_free(sd);
505         return NULL;
506 }
507
508 /*
509   turn a set of flags into a string
510 */
511 static char *sddl_flags_to_string(TALLOC_CTX *mem_ctx, const struct flag_map *map,
512                                   uint32_t flags, bool check_all)
513 {
514         int i;
515         char *s;
516
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);
521                 }
522         }
523
524         s = talloc_strdup(mem_ctx, "");
525
526         /* now by bits */
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;
532                 }
533         }
534
535         if (check_all && flags != 0) {
536                 goto failed;
537         }
538
539         return s;
540
541 failed:
542         talloc_free(s);
543         return NULL;
544 }
545
546 /*
547   encode a sid in SDDL format
548 */
549 static char *sddl_encode_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
550                              const struct dom_sid *domain_sid)
551 {
552         size_t i;
553         char *sidstr;
554
555         sidstr = dom_sid_string(mem_ctx, sid);
556         if (sidstr == NULL) return NULL;
557
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) {
561                         talloc_free(sidstr);
562                         return talloc_strdup(mem_ctx, sid_codes[i].code);
563                 }
564         }
565
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) {
571                                 talloc_free(sidstr);
572                                 return talloc_strdup(mem_ctx, sid_codes[i].code);
573                         }
574                 }
575         }
576
577         talloc_free(sidstr);
578
579         /* TODO: encode well known sids as two letter codes */
580         return dom_sid_string(mem_ctx, sid);
581 }
582
583
584 /*
585   encode an ACE in SDDL format
586 */
587 char *sddl_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
588                       const struct dom_sid *domain_sid)
589 {
590         char *sddl = NULL;
591         TALLOC_CTX *tmp_ctx;
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="";
595
596         tmp_ctx = talloc_new(mem_ctx);
597         if (tmp_ctx == NULL) {
598                 DEBUG(0, ("talloc_new failed\n"));
599                 return NULL;
600         }
601
602         sddl_type = sddl_flags_to_string(tmp_ctx, ace_types, ace->type, true);
603         if (sddl_type == NULL) {
604                 goto failed;
605         }
606
607         sddl_flags = sddl_flags_to_string(tmp_ctx, ace_flags, ace->flags,
608                                           true);
609         if (sddl_flags == NULL) {
610                 goto failed;
611         }
612
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",
617                                              ace->access_mask);
618                 if (sddl_mask == NULL) {
619                         goto failed;
620                 }
621         }
622
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;
628
629                 if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
630                         sddl_object = GUID_buf_string(
631                                 &object->type.type, &object_buf);
632                 }
633
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,
638                                 &iobject_buf);
639                 }
640         }
641
642         sddl_trustee = sddl_encode_sid(tmp_ctx, &ace->trustee, domain_sid);
643         if (sddl_trustee == NULL) {
644                 goto failed;
645         }
646
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);
650
651 failed:
652         talloc_free(tmp_ctx);
653         return sddl;
654 }
655
656 /*
657   encode an ACL in SDDL format
658 */
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)
661 {
662         char *sddl;
663         uint32_t i;
664
665         /* add any ACL flags */
666         sddl = sddl_flags_to_string(mem_ctx, acl_flags, flags, false);
667         if (sddl == NULL) goto failed;
668
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;
675                 talloc_free(ace);
676         }
677
678         return sddl;
679
680 failed:
681         talloc_free(sddl);
682         return NULL;
683 }
684
685
686 /*
687   encode a security descriptor to SDDL format
688 */
689 char *sddl_encode(TALLOC_CTX *mem_ctx, const struct security_descriptor *sd,
690                   const struct dom_sid *domain_sid)
691 {
692         char *sddl;
693         TALLOC_CTX *tmp_ctx;
694
695         /* start with a blank string */
696         sddl = talloc_strdup(mem_ctx, "");
697         if (sddl == NULL) goto failed;
698
699         tmp_ctx = talloc_new(mem_ctx);
700
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;
706         }
707
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;
713         }
714
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;
720         }
721
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;
727         }
728
729         talloc_free(tmp_ctx);
730         return sddl;
731
732 failed:
733         talloc_free(sddl);
734         return NULL;
735 }