From 8dfec3305cc1babeb5d822dc806c0f5dede7da46 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 2 Dec 2005 03:16:42 +0000 Subject: r12005: added a SDDL (Security Descriptor Description Language) parser. Not all flags are covered yet, and object aces aren't done yet. This is needed for ACL support in ldb, as the default security descriptor for each object class is given by the defaultSecurityDescriptor attribute in the schema, which is stored in SDDL format (This used to be commit dbdeecea01a8b362a9a525a3689cb03662a86776) --- source4/libcli/security/config.mk | 1 + source4/libcli/security/sddl.c | 315 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 source4/libcli/security/sddl.c (limited to 'source4') diff --git a/source4/libcli/security/config.mk b/source4/libcli/security/config.mk index d7492038d3..7faecaf5f2 100644 --- a/source4/libcli/security/config.mk +++ b/source4/libcli/security/config.mk @@ -22,6 +22,7 @@ ADD_OBJ_FILES = security_token.o \ dom_sid.o \ access_check.o \ privilege.o \ + sddl.o \ ../../librpc/ndr/ndr_sec.o REQUIRED_SUBSYSTEMS = LIB_SECURITY_NDR # End SUBSYSTEM LIB_SECURITY diff --git a/source4/libcli/security/sddl.c b/source4/libcli/security/sddl.c new file mode 100644 index 0000000000..17df393de4 --- /dev/null +++ b/source4/libcli/security/sddl.c @@ -0,0 +1,315 @@ +/* + Unix SMB/CIFS implementation. + + security descriptor description language functions + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "system/iconv.h" +#include "librpc/gen_ndr/ndr_security.h" + +struct flag_map { + const char *name; + uint32_t flag; +}; + +/* + map a series of letter codes into a uint32_t +*/ +static BOOL sddl_map_flags(const struct flag_map *map, const char *str, + uint32_t *flags, size_t *len) +{ + if (len) *len = 0; + *flags = 0; + while (str[0] && isupper(str[0])) { + int i; + for (i=0;map[i].name;i++) { + size_t l = strlen(map[i].name); + if (strncmp(map[i].name, str, l) == 0) { + *flags |= map[i].flag; + str += l; + if (len) *len += l; + break; + } + } + if (map[i].name == NULL) { + DEBUG(2, ("Unknown flag - %s\n", str)); + return False; + } + } + return True; +} + +/* + a mapping between the 2 letter SID codes and sid strings +*/ +static const struct { + const char *code; + const char *sid; +} sid_codes[] = { + { "AO", SID_BUILTIN_ACCOUNT_OPERATORS }, +}; + +/* + decode a SID + It can either be a special 2 letter code, or in S-* format +*/ +static struct dom_sid *sddl_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp) +{ + const char *sddl = (*sddlp); + int i; + + /* see if its in the numeric format */ + if (strncmp(sddl, "S-", 2) == 0) { + size_t len = strspn(sddl+2, "-0123456789"); + (*sddlp) += len+2; + return dom_sid_parse_talloc(mem_ctx, sddl); + } + + /* now check for one of the special codes */ + for (i=0;itype = v; + + /* ace flags */ + if (!sddl_map_flags(ace_flags, tok[1], &v, NULL)) { + return False; + } + ace->flags = v; + + /* access mask */ + if (strncmp(tok[2], "0x", 2) == 0) { + ace->access_mask = strtol(tok[2], NULL, 16); + } else { + if (!sddl_map_flags(ace_access_mask, tok[2], &v, NULL)) { + return False; + } + ace->access_mask = v; + } + + /* object */ + if (tok[3][0] != 0) { + /* TODO: add object parsing ... */ + return False; + } + + /* inherit object */ + if (tok[4][0] != 0) { + /* TODO: add object parsing ... */ + return False; + } + + /* trustee */ + s = tok[5]; + sid = sddl_decode_sid(mem_ctx, &s); + if (sid == NULL) { + return False; + } + ace->trustee = *sid; + talloc_steal(mem_ctx, sid->sub_auths); + talloc_free(sid); + + return True; +} + +static const struct flag_map acl_flags[] = { + { "P", SEC_DESC_DACL_PROTECTED }, + { "AR", SEC_DESC_DACL_AUTO_INHERIT_REQ }, + { "AI", SEC_DESC_DACL_AUTO_INHERITED }, + { NULL, 0 } +}; + +/* + decode an ACL +*/ +static struct security_acl *sddl_decode_acl(struct security_descriptor *sd, + const char **sddlp, uint32_t *flags) +{ + const char *sddl = *sddlp; + struct security_acl *acl; + size_t len; + + acl = talloc_zero(sd, struct security_acl); + if (acl == NULL) return NULL; + acl->revision = SECURITY_ACL_REVISION_NT4; + + /* work out the ACL flags */ + if (!sddl_map_flags(acl_flags, sddl, flags, &len)) { + talloc_free(acl); + return NULL; + } + sddl += len; + + /* now the ACEs */ + while (*sddl == '(') { + len = strcspn(sddl+1, ")"); + char *astr = talloc_strndup(acl, sddl+1, len); + if (astr == NULL || sddl[len+1] != ')') { + talloc_free(acl); + return NULL; + } + acl->aces = talloc_realloc(acl, acl->aces, struct security_ace, + acl->num_aces+1); + if (acl->aces == NULL) { + talloc_free(acl); + return NULL; + } + if (!sddl_decode_ace(acl->aces, &acl->aces[acl->num_aces], astr)) { + talloc_free(acl); + return NULL; + } + talloc_free(astr); + sddl += len+2; + acl->num_aces++; + } + + (*sddlp) = sddl; + return acl; +} + +/* + decode a security descriptor in SDDL format +*/ +struct security_descriptor *sddl_decode(TALLOC_CTX *mem_ctx, const char *sddl) +{ + struct security_descriptor *sd; + sd = talloc_zero(mem_ctx, struct security_descriptor); + + sd->revision = SECURITY_DESCRIPTOR_REVISION_1; + sd->type = SEC_DESC_SELF_RELATIVE; + + while (*sddl) { + uint32_t flags; + char c = sddl[0]; + if (sddl[1] != ':') goto failed; + + sddl += 2; + switch (c) { + case 'D': + if (sd->dacl != NULL) goto failed; + sd->dacl = sddl_decode_acl(sd, &sddl, &flags); + if (sd->dacl == NULL) goto failed; + sd->type |= flags | SEC_DESC_DACL_PRESENT; + break; + case 'S': + if (sd->sacl != NULL) goto failed; + sd->sacl = sddl_decode_acl(sd, &sddl, &flags); + if (sd->sacl == NULL) goto failed; + /* this relies on the SEC_DESC_SACL_* flags being + 1 bit shifted from the SEC_DESC_DACL_* flags */ + sd->type |= (flags<<1) | SEC_DESC_SACL_PRESENT; + break; + case 'O': + if (sd->owner_sid != NULL) goto failed; + sd->owner_sid = sddl_decode_sid(sd, &sddl); + if (sd->owner_sid == NULL) goto failed; + break; + case 'G': + if (sd->group_sid != NULL) goto failed; + sd->group_sid = sddl_decode_sid(sd, &sddl); + if (sd->group_sid == NULL) goto failed; + break; + } + } + + return sd; + +failed: + DEBUG(2,("Badly formatted SDDL '%s'\n", sddl)); + talloc_free(sd); + return NULL; +} -- cgit