From 541ddde872b4bf37b6f63abef648bd5ffd6482c4 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 24 Apr 2015 09:22:14 -0700 Subject: [PATCH] smbcacls: Move print_ace and parse_ace to common file BUG: https://bugzilla.samba.org/show_bug.cgi?id=11237 Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison --- source3/include/util_sd.h | 4 + source3/lib/util_sd.c | 354 ++++++++++++++++++++++++++++++++++++++ source3/utils/smbcacls.c | 354 -------------------------------------- 3 files changed, 358 insertions(+), 354 deletions(-) diff --git a/source3/include/util_sd.h b/source3/include/util_sd.h index 7f21c643c24..1b22bb0853c 100644 --- a/source3/include/util_sd.h +++ b/source3/include/util_sd.h @@ -27,5 +27,9 @@ void SidToString(struct cli_state *cli, fstring str, const struct dom_sid *sid, bool numeric); bool StringToSid(struct cli_state *cli, struct dom_sid *sid, const char *str); +void print_ace(struct cli_state *cli, FILE *f, struct security_ace *ace, + bool numeric); +bool parse_ace(struct cli_state *cli, struct security_ace *ace, + const char *orig_str); #endif diff --git a/source3/lib/util_sd.c b/source3/lib/util_sd.c index 584d34aaf6f..616418af469 100644 --- a/source3/lib/util_sd.c +++ b/source3/lib/util_sd.c @@ -29,6 +29,31 @@ #include "rpc_client/cli_pipe.h" #include "rpc_client/cli_lsarpc.h" +/* These values discovered by inspection */ + +struct perm_value { + const char *perm; + uint32 mask; +}; + +static const struct perm_value special_values[] = { + { "R", SEC_RIGHTS_FILE_READ }, + { "W", SEC_RIGHTS_FILE_WRITE }, + { "X", SEC_RIGHTS_FILE_EXECUTE }, + { "D", SEC_STD_DELETE }, + { "P", SEC_STD_WRITE_DAC }, + { "O", SEC_STD_WRITE_OWNER }, + { NULL, 0 }, +}; + +static const struct perm_value standard_values[] = { + { "READ", SEC_RIGHTS_DIR_READ|SEC_DIR_TRAVERSE }, + { "CHANGE", SEC_RIGHTS_DIR_READ|SEC_STD_DELETE|\ + SEC_RIGHTS_DIR_WRITE|SEC_DIR_TRAVERSE }, + { "FULL", SEC_RIGHTS_DIR_ALL }, + { NULL, 0 }, +}; + /* Open cli connection and policy handle */ static NTSTATUS cli_lsa_lookup_sid(struct cli_state *cli, const struct dom_sid *sid, @@ -172,3 +197,332 @@ bool StringToSid(struct cli_state *cli, struct dom_sid *sid, const char *str) return NT_STATUS_IS_OK(cli_lsa_lookup_name(cli, str, &type, sid)); } + +static void print_ace_flags(FILE *f, uint8_t flags) +{ + char *str = talloc_strdup(NULL, ""); + + if (!str) { + goto out; + } + + if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) { + str = talloc_asprintf(str, "%s%s", + str, "OI|"); + if (!str) { + goto out; + } + } + if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) { + str = talloc_asprintf(str, "%s%s", + str, "CI|"); + if (!str) { + goto out; + } + } + if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { + str = talloc_asprintf(str, "%s%s", + str, "NP|"); + if (!str) { + goto out; + } + } + if (flags & SEC_ACE_FLAG_INHERIT_ONLY) { + str = talloc_asprintf(str, "%s%s", + str, "IO|"); + if (!str) { + goto out; + } + } + if (flags & SEC_ACE_FLAG_INHERITED_ACE) { + str = talloc_asprintf(str, "%s%s", + str, "I|"); + if (!str) { + goto out; + } + } + /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 ) + and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're + audit ace flags. */ + + if (str[strlen(str)-1] == '|') { + str[strlen(str)-1] = '\0'; + fprintf(f, "/%s/", str); + } else { + fprintf(f, "/0x%x/", flags); + } + TALLOC_FREE(str); + return; + + out: + fprintf(f, "/0x%x/", flags); +} + +/* print an ACE on a FILE, using either numeric or ascii representation */ +void print_ace(struct cli_state *cli, FILE *f, struct security_ace *ace, + bool numeric) +{ + const struct perm_value *v; + fstring sidstr; + int do_print = 0; + uint32 got_mask; + + SidToString(cli, sidstr, &ace->trustee, numeric); + + fprintf(f, "%s:", sidstr); + + if (numeric) { + fprintf(f, "%d/0x%x/0x%08x", + ace->type, ace->flags, ace->access_mask); + return; + } + + /* Ace type */ + + if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) { + fprintf(f, "ALLOWED"); + } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) { + fprintf(f, "DENIED"); + } else { + fprintf(f, "%d", ace->type); + } + + print_ace_flags(f, ace->flags); + + /* Standard permissions */ + + for (v = standard_values; v->perm; v++) { + if (ace->access_mask == v->mask) { + fprintf(f, "%s", v->perm); + return; + } + } + + /* Special permissions. Print out a hex value if we have + leftover bits in the mask. */ + + got_mask = ace->access_mask; + + again: + for (v = special_values; v->perm; v++) { + if ((ace->access_mask & v->mask) == v->mask) { + if (do_print) { + fprintf(f, "%s", v->perm); + } + got_mask &= ~v->mask; + } + } + + if (!do_print) { + if (got_mask != 0) { + fprintf(f, "0x%08x", ace->access_mask); + } else { + do_print = 1; + goto again; + } + } +} + +static bool parse_ace_flags(const char *str, unsigned int *pflags) +{ + const char *p = str; + *pflags = 0; + + while (*p) { + if (strnequal(p, "OI", 2)) { + *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT; + p += 2; + } else if (strnequal(p, "CI", 2)) { + *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT; + p += 2; + } else if (strnequal(p, "NP", 2)) { + *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT; + p += 2; + } else if (strnequal(p, "IO", 2)) { + *pflags |= SEC_ACE_FLAG_INHERIT_ONLY; + p += 2; + } else if (*p == 'I') { + *pflags |= SEC_ACE_FLAG_INHERITED_ACE; + p += 1; + } else if (*p) { + return false; + } + + switch (*p) { + case '|': + p++; + case '\0': + continue; + default: + return false; + } + } + return true; +} + +/* parse an ACE in the same format as print_ace() */ +bool parse_ace(struct cli_state *cli, struct security_ace *ace, + const char *orig_str) +{ + char *p; + const char *cp; + char *tok; + unsigned int atype = 0; + unsigned int aflags = 0; + unsigned int amask = 0; + struct dom_sid sid; + uint32_t mask; + const struct perm_value *v; + char *str = SMB_STRDUP(orig_str); + TALLOC_CTX *frame = talloc_stackframe(); + + if (!str) { + TALLOC_FREE(frame); + return False; + } + + ZERO_STRUCTP(ace); + p = strchr_m(str,':'); + if (!p) { + printf("ACE '%s': missing ':'.\n", orig_str); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + *p = '\0'; + p++; + /* Try to parse numeric form */ + + if (sscanf(p, "%u/%u/%u", &atype, &aflags, &amask) == 3 && + StringToSid(cli, &sid, str)) { + goto done; + } + + /* Try to parse text form */ + + if (!StringToSid(cli, &sid, str)) { + printf("ACE '%s': failed to convert '%s' to SID\n", + orig_str, str); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + + cp = p; + if (!next_token_talloc(frame, &cp, &tok, "/")) { + printf("ACE '%s': failed to find '/' character.\n", + orig_str); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + + if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { + atype = SEC_ACE_TYPE_ACCESS_ALLOWED; + } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) { + atype = SEC_ACE_TYPE_ACCESS_DENIED; + } else { + printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n", + orig_str, tok); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + + /* Only numeric form accepted for flags at present */ + + if (!next_token_talloc(frame, &cp, &tok, "/")) { + printf("ACE '%s': bad flags entry at '%s'\n", + orig_str, tok); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + + if (tok[0] < '0' || tok[0] > '9') { + if (!parse_ace_flags(tok, &aflags)) { + printf("ACE '%s': bad named flags entry at '%s'\n", + orig_str, tok); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + } else if (strnequal(tok, "0x", 2)) { + if (!sscanf(tok, "%x", &aflags)) { + printf("ACE '%s': bad hex flags entry at '%s'\n", + orig_str, tok); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + } else { + if (!sscanf(tok, "%u", &aflags)) { + printf("ACE '%s': bad integer flags entry at '%s'\n", + orig_str, tok); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + } + + if (!next_token_talloc(frame, &cp, &tok, "/")) { + printf("ACE '%s': missing / at '%s'\n", + orig_str, tok); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + + if (strncmp(tok, "0x", 2) == 0) { + if (sscanf(tok, "%u", &amask) != 1) { + printf("ACE '%s': bad hex number at '%s'\n", + orig_str, tok); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + goto done; + } + + for (v = standard_values; v->perm; v++) { + if (strcmp(tok, v->perm) == 0) { + amask = v->mask; + goto done; + } + } + + p = tok; + + while(*p) { + bool found = False; + + for (v = special_values; v->perm; v++) { + if (v->perm[0] == *p) { + amask |= v->mask; + found = True; + } + } + + if (!found) { + printf("ACE '%s': bad permission value at '%s'\n", + orig_str, p); + SAFE_FREE(str); + TALLOC_FREE(frame); + return False; + } + p++; + } + + if (*p) { + TALLOC_FREE(frame); + SAFE_FREE(str); + return False; + } + + done: + mask = amask; + init_sec_ace(ace, &sid, atype, mask, aflags); + TALLOC_FREE(frame); + SAFE_FREE(str); + return True; +} diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c index 778d30d4548..9081ebf70f1 100644 --- a/source3/utils/smbcacls.c +++ b/source3/utils/smbcacls.c @@ -47,31 +47,6 @@ enum acl_mode {SMB_ACL_SET, SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD }; enum chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP, REQUEST_INHERIT}; enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR}; -struct perm_value { - const char *perm; - uint32 mask; -}; - -/* These values discovered by inspection */ - -static const struct perm_value special_values[] = { - { "R", SEC_RIGHTS_FILE_READ }, - { "W", SEC_RIGHTS_FILE_WRITE }, - { "X", SEC_RIGHTS_FILE_EXECUTE }, - { "D", SEC_STD_DELETE }, - { "P", SEC_STD_WRITE_DAC }, - { "O", SEC_STD_WRITE_OWNER }, - { NULL, 0 }, -}; - -static const struct perm_value standard_values[] = { - { "READ", SEC_RIGHTS_DIR_READ|SEC_DIR_TRAVERSE }, - { "CHANGE", SEC_RIGHTS_DIR_READ|SEC_STD_DELETE|\ - SEC_RIGHTS_DIR_WRITE|SEC_DIR_TRAVERSE }, - { "FULL", SEC_RIGHTS_DIR_ALL }, - { NULL, 0 }, -}; - static NTSTATUS cli_lsa_lookup_domain_sid(struct cli_state *cli, struct dom_sid *sid) { @@ -147,335 +122,6 @@ static struct dom_sid *get_domain_sid(struct cli_state *cli) return sid; } -static void print_ace_flags(FILE *f, uint8_t flags) -{ - char *str = talloc_strdup(NULL, ""); - - if (!str) { - goto out; - } - - if (flags & SEC_ACE_FLAG_OBJECT_INHERIT) { - str = talloc_asprintf(str, "%s%s", - str, "OI|"); - if (!str) { - goto out; - } - } - if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT) { - str = talloc_asprintf(str, "%s%s", - str, "CI|"); - if (!str) { - goto out; - } - } - if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) { - str = talloc_asprintf(str, "%s%s", - str, "NP|"); - if (!str) { - goto out; - } - } - if (flags & SEC_ACE_FLAG_INHERIT_ONLY) { - str = talloc_asprintf(str, "%s%s", - str, "IO|"); - if (!str) { - goto out; - } - } - if (flags & SEC_ACE_FLAG_INHERITED_ACE) { - str = talloc_asprintf(str, "%s%s", - str, "I|"); - if (!str) { - goto out; - } - } - /* Ignore define SEC_ACE_FLAG_SUCCESSFUL_ACCESS ( 0x40 ) - and SEC_ACE_FLAG_FAILED_ACCESS ( 0x80 ) as they're - audit ace flags. */ - - if (str[strlen(str)-1] == '|') { - str[strlen(str)-1] = '\0'; - fprintf(f, "/%s/", str); - } else { - fprintf(f, "/0x%x/", flags); - } - TALLOC_FREE(str); - return; - - out: - fprintf(f, "/0x%x/", flags); -} - -/* print an ACE on a FILE, using either numeric or ascii representation */ -static void print_ace(struct cli_state *cli, FILE *f, struct security_ace *ace, - bool numeric) -{ - const struct perm_value *v; - fstring sidstr; - int do_print = 0; - uint32 got_mask; - - SidToString(cli, sidstr, &ace->trustee, numeric); - - fprintf(f, "%s:", sidstr); - - if (numeric) { - fprintf(f, "%d/0x%x/0x%08x", - ace->type, ace->flags, ace->access_mask); - return; - } - - /* Ace type */ - - if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) { - fprintf(f, "ALLOWED"); - } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) { - fprintf(f, "DENIED"); - } else { - fprintf(f, "%d", ace->type); - } - - print_ace_flags(f, ace->flags); - - /* Standard permissions */ - - for (v = standard_values; v->perm; v++) { - if (ace->access_mask == v->mask) { - fprintf(f, "%s", v->perm); - return; - } - } - - /* Special permissions. Print out a hex value if we have - leftover bits in the mask. */ - - got_mask = ace->access_mask; - - again: - for (v = special_values; v->perm; v++) { - if ((ace->access_mask & v->mask) == v->mask) { - if (do_print) { - fprintf(f, "%s", v->perm); - } - got_mask &= ~v->mask; - } - } - - if (!do_print) { - if (got_mask != 0) { - fprintf(f, "0x%08x", ace->access_mask); - } else { - do_print = 1; - goto again; - } - } -} - -static bool parse_ace_flags(const char *str, unsigned int *pflags) -{ - const char *p = str; - *pflags = 0; - - while (*p) { - if (strnequal(p, "OI", 2)) { - *pflags |= SEC_ACE_FLAG_OBJECT_INHERIT; - p += 2; - } else if (strnequal(p, "CI", 2)) { - *pflags |= SEC_ACE_FLAG_CONTAINER_INHERIT; - p += 2; - } else if (strnequal(p, "NP", 2)) { - *pflags |= SEC_ACE_FLAG_NO_PROPAGATE_INHERIT; - p += 2; - } else if (strnequal(p, "IO", 2)) { - *pflags |= SEC_ACE_FLAG_INHERIT_ONLY; - p += 2; - } else if (*p == 'I') { - *pflags |= SEC_ACE_FLAG_INHERITED_ACE; - p += 1; - } else if (*p) { - return false; - } - - switch (*p) { - case '|': - p++; - case '\0': - continue; - default: - return false; - } - } - return true; -} - -/* parse an ACE in the same format as print_ace() */ -static bool parse_ace(struct cli_state *cli, struct security_ace *ace, - const char *orig_str) -{ - char *p; - const char *cp; - char *tok; - unsigned int atype = 0; - unsigned int aflags = 0; - unsigned int amask = 0; - struct dom_sid sid; - uint32_t mask; - const struct perm_value *v; - char *str = SMB_STRDUP(orig_str); - TALLOC_CTX *frame = talloc_stackframe(); - - if (!str) { - TALLOC_FREE(frame); - return False; - } - - ZERO_STRUCTP(ace); - p = strchr_m(str,':'); - if (!p) { - printf("ACE '%s': missing ':'.\n", orig_str); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - *p = '\0'; - p++; - /* Try to parse numeric form */ - - if (sscanf(p, "%u/%u/%u", &atype, &aflags, &amask) == 3 && - StringToSid(cli, &sid, str)) { - goto done; - } - - /* Try to parse text form */ - - if (!StringToSid(cli, &sid, str)) { - printf("ACE '%s': failed to convert '%s' to SID\n", - orig_str, str); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - - cp = p; - if (!next_token_talloc(frame, &cp, &tok, "/")) { - printf("ACE '%s': failed to find '/' character.\n", - orig_str); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - - if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) { - atype = SEC_ACE_TYPE_ACCESS_ALLOWED; - } else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) { - atype = SEC_ACE_TYPE_ACCESS_DENIED; - } else { - printf("ACE '%s': missing 'ALLOWED' or 'DENIED' entry at '%s'\n", - orig_str, tok); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - - /* Only numeric form accepted for flags at present */ - - if (!next_token_talloc(frame, &cp, &tok, "/")) { - printf("ACE '%s': bad flags entry at '%s'\n", - orig_str, tok); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - - if (tok[0] < '0' || tok[0] > '9') { - if (!parse_ace_flags(tok, &aflags)) { - printf("ACE '%s': bad named flags entry at '%s'\n", - orig_str, tok); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - } else if (strnequal(tok, "0x", 2)) { - if (!sscanf(tok, "%x", &aflags)) { - printf("ACE '%s': bad hex flags entry at '%s'\n", - orig_str, tok); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - } else { - if (!sscanf(tok, "%u", &aflags)) { - printf("ACE '%s': bad integer flags entry at '%s'\n", - orig_str, tok); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - } - - if (!next_token_talloc(frame, &cp, &tok, "/")) { - printf("ACE '%s': missing / at '%s'\n", - orig_str, tok); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - - if (strncmp(tok, "0x", 2) == 0) { - if (sscanf(tok, "%u", &amask) != 1) { - printf("ACE '%s': bad hex number at '%s'\n", - orig_str, tok); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - goto done; - } - - for (v = standard_values; v->perm; v++) { - if (strcmp(tok, v->perm) == 0) { - amask = v->mask; - goto done; - } - } - - p = tok; - - while(*p) { - bool found = False; - - for (v = special_values; v->perm; v++) { - if (v->perm[0] == *p) { - amask |= v->mask; - found = True; - } - } - - if (!found) { - printf("ACE '%s': bad permission value at '%s'\n", - orig_str, p); - SAFE_FREE(str); - TALLOC_FREE(frame); - return False; - } - p++; - } - - if (*p) { - TALLOC_FREE(frame); - SAFE_FREE(str); - return False; - } - - done: - mask = amask; - init_sec_ace(ace, &sid, atype, mask, aflags); - TALLOC_FREE(frame); - SAFE_FREE(str); - return True; -} - /* add an ACE to a list of ACEs in a struct security_acl */ static bool add_ace(struct security_acl **the_acl, struct security_ace *ace) { -- 2.47.3