diff options
author | Christof Schmitt <cs@samba.org> | 2015-04-24 09:22:14 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2015-04-25 00:04:24 +0200 |
commit | 541ddde872b4bf37b6f63abef648bd5ffd6482c4 (patch) | |
tree | 5bcdeababd7bbffddbbcc94f15bbbaf1c214ee8b /source3/lib | |
parent | a519b3e6c6e4c57863e02975ff2cc8b36c34ea6f (diff) | |
download | samba-541ddde872b4bf37b6f63abef648bd5ffd6482c4.tar.gz |
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 <cs@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/util_sd.c | 354 |
1 files changed, 354 insertions, 0 deletions
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; +} |