diff options
Diffstat (limited to 'libcli')
-rw-r--r-- | libcli/security/access_check.c | 144 | ||||
-rw-r--r-- | libcli/security/access_check.h | 27 | ||||
-rw-r--r-- | libcli/security/create_descriptor.c | 410 | ||||
-rw-r--r-- | libcli/security/dom_sid.c | 4 | ||||
-rw-r--r-- | libcli/security/dom_sid.h | 50 | ||||
-rw-r--r-- | libcli/security/object_tree.c | 121 | ||||
-rw-r--r-- | libcli/security/security.h | 4 | ||||
-rw-r--r-- | libcli/security/security_descriptor.h | 13 | ||||
-rw-r--r-- | libcli/security/util_sid.c | 371 | ||||
-rw-r--r-- | libcli/security/wscript_build | 4 |
10 files changed, 1139 insertions, 9 deletions
diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c index 081efe8711..e7c48cae08 100644 --- a/libcli/security/access_check.c +++ b/libcli/security/access_check.c @@ -250,3 +250,147 @@ done: return NT_STATUS_OK; } + + +static const struct GUID *get_ace_object_type(struct security_ace *ace) +{ + struct GUID *type; + + if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) + type = &ace->object.object.type.type; + else if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) + type = &ace->object.object.inherited_type.inherited_type; /* This doesn't look right. Is something wrong with the IDL? */ + else + type = NULL; + + return type; + +} + +/* modified access check for the purposes of DS security + * Lots of code duplication, it will ve united in just one + * function eventually */ + +NTSTATUS sec_access_check_ds(const struct security_descriptor *sd, + const struct security_token *token, + uint32_t access_desired, + uint32_t *access_granted, + struct object_tree *tree, + struct dom_sid *replace_sid) +{ + uint32_t i; + uint32_t bits_remaining; + struct object_tree *node; + const struct GUID *type; + struct dom_sid *ps_sid = dom_sid_parse_talloc(NULL, SID_NT_SELF); + + *access_granted = access_desired; + bits_remaining = access_desired; + + /* handle the maximum allowed flag */ + if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) { + access_desired |= access_check_max_allowed(sd, token); + access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED; + *access_granted = access_desired; + bits_remaining = access_desired & ~SEC_STD_DELETE; + } + + if (access_desired & SEC_FLAG_SYSTEM_SECURITY) { + if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) { + bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY; + } else { + return NT_STATUS_PRIVILEGE_NOT_HELD; + } + } + + /* a NULL dacl allows access */ + if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) { + *access_granted = access_desired; + return NT_STATUS_OK; + } + + /* the owner always gets SEC_STD_WRITE_DAC, SEC_STD_READ_CONTROL and SEC_STD_DELETE */ + if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE)) && + security_token_has_sid(token, sd->owner_sid)) { + bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE); + } + if ((bits_remaining & SEC_STD_DELETE) && + security_token_has_privilege(token, SEC_PRIV_RESTORE)) { + bits_remaining &= ~SEC_STD_DELETE; + } + + if (sd->dacl == NULL) { + goto done; + } + + /* check each ace in turn. */ + for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) { + struct dom_sid *trustee; + struct security_ace *ace = &sd->dacl->aces[i]; + + if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) { + continue; + } + if (dom_sid_equal(&ace->trustee, ps_sid) && replace_sid) { + trustee = replace_sid; + } + else + { + trustee = &ace->trustee; + } + if (!security_token_has_sid(token, trustee)) { + continue; + } + + switch (ace->type) { + case SEC_ACE_TYPE_ACCESS_ALLOWED: + if (tree) + object_tree_modify_access(tree, ace->access_mask); + + bits_remaining &= ~ace->access_mask; + break; + case SEC_ACE_TYPE_ACCESS_DENIED: + if (bits_remaining & ace->access_mask) { + return NT_STATUS_ACCESS_DENIED; + } + break; + case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: + case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: + /* check only in case we have provided a tree, + * the ACE has an object type and that type + * is in the tree */ + type = get_ace_object_type(ace); + + if (!tree) + continue; + + if (!type) + node = tree; + else + if (!(node = get_object_tree_by_GUID(tree, type))) + continue; + + if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) { + object_tree_modify_access(node, ace->access_mask); + if (node->remaining_access == 0) { + return NT_STATUS_OK; + } + } + else { + if (node->remaining_access & ace->access_mask){ + return NT_STATUS_ACCESS_DENIED; + } + } + break; + default: /* Other ACE types not handled/supported */ + break; + } + } + +done: + if (bits_remaining != 0) { + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} diff --git a/libcli/security/access_check.h b/libcli/security/access_check.h index 548e5a1437..700f981879 100644 --- a/libcli/security/access_check.h +++ b/libcli/security/access_check.h @@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "libcli/security/security_token.h" +#include "librpc/gen_ndr/security.h" /* Map generic access rights to object specific rights. This technique is used to give meaning to assigning read, write, execute and all access to @@ -51,3 +51,28 @@ NTSTATUS se_access_check(const struct security_descriptor *sd, const struct security_token *token, uint32_t access_desired, uint32_t *access_granted); + +/* modified access check for the purposes of DS security + * Lots of code duplication, it will ve united in just one + * function eventually */ + +NTSTATUS sec_access_check_ds(const struct security_descriptor *sd, + const struct security_token *token, + uint32_t access_desired, + uint32_t *access_granted, + struct object_tree *tree, + struct dom_sid *replace_sid); + +bool insert_in_object_tree(TALLOC_CTX *mem_ctx, + const struct GUID *guid, + uint32_t init_access, + struct object_tree **root, + struct object_tree **new_node); + +/* search by GUID */ +struct object_tree *get_object_tree_by_GUID(struct object_tree *root, + const struct GUID *guid); + +/* Change the granted access per each ACE */ +void object_tree_modify_access(struct object_tree *root, + uint32_t access); diff --git a/libcli/security/create_descriptor.c b/libcli/security/create_descriptor.c new file mode 100644 index 0000000000..bc3f42e1f2 --- /dev/null +++ b/libcli/security/create_descriptor.c @@ -0,0 +1,410 @@ +/* + Copyright (C) Nadezhda Ivanova 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Name: create_descriptor + * + * Component: routines for calculating and creating security descriptors + * as described in MS-DTYP 2.5.2.2 + * + * Description: + * + * + * Author: Nadezhda Ivanova + */ +#include "includes.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_security.h" + +/* Todos: + * build the security token dacl as follows: + * SYSTEM: GA, OWNER: GA, LOGIN_SID:GW|GE + * Need session id information for the login SID. Probably + * the best place for this is during token creation + * + * Implement SD Invariants + * ACE sorting rules + * LDAP_SERVER_SD_FLAGS_OID control + * ADTS 7.1.3.3 needs to be clarified + */ + +/* the mapping function for generic rights for DS.(GA,GR,GW,GX) + * The mapping function is passed as an argument to the + * descriptor calculating routine and depends on the security + * manager that calls the calculating routine. + * TODO: need similar mappings for the file system and + * registry security managers in order to make this code + * generic for all security managers + */ + +uint32_t map_generic_rights_ds(uint32_t access_mask) +{ + if (access_mask & SEC_GENERIC_ALL) { + access_mask |= SEC_ADS_GENERIC_ALL; + access_mask = ~SEC_GENERIC_ALL; + } + + if (access_mask & SEC_GENERIC_EXECUTE) { + access_mask |= SEC_ADS_GENERIC_EXECUTE; + access_mask = ~SEC_GENERIC_EXECUTE; + } + + if (access_mask & SEC_GENERIC_WRITE) { + access_mask |= SEC_ADS_GENERIC_WRITE; + access_mask &= ~SEC_GENERIC_WRITE; + } + + if (access_mask & SEC_GENERIC_READ) { + access_mask |= SEC_ADS_GENERIC_READ; + access_mask &= ~SEC_GENERIC_READ; + } + + return access_mask; +} + +/* Not sure what this has to be, +* and it does not seem to have any influence */ +static bool object_in_list(struct GUID *object_list, struct GUID *object) +{ + return true; +} + +static struct security_acl *calculate_inherited_from_parent(TALLOC_CTX *mem_ctx, + struct security_acl *acl, + bool is_container, + struct dom_sid *owner, + struct dom_sid *group, + struct GUID *object_list) +{ + uint32_t i; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct security_acl *tmp_acl = talloc_zero(mem_ctx, struct security_acl); + struct dom_sid *co, *cg; + if (!tmp_acl) { + return NULL; + } + + if (!acl) { + return NULL; + } + co = dom_sid_parse_talloc(tmp_ctx, SID_CREATOR_OWNER); + cg = dom_sid_parse_talloc(tmp_ctx, SID_CREATOR_GROUP); + + for (i=0; i < acl->num_aces; i++) { + struct security_ace *ace = &acl->aces[i]; + if ((ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) || + (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) { + tmp_acl->aces = talloc_realloc(tmp_acl, tmp_acl->aces, struct security_ace, + tmp_acl->num_aces+1); + if (tmp_acl->aces == NULL) { + talloc_free(tmp_ctx); + return NULL; + } + + tmp_acl->aces[tmp_acl->num_aces] = *ace; + tmp_acl->aces[tmp_acl->num_aces].flags |= SEC_ACE_FLAG_INHERITED_ACE; + + if (is_container && (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) + tmp_acl->aces[tmp_acl->num_aces].flags |= SEC_ACE_FLAG_INHERIT_ONLY; + + if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT || + ace->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT) { + if (!object_in_list(object_list, &ace->object.object.type.type)) { + tmp_acl->aces[tmp_acl->num_aces].flags |= SEC_ACE_FLAG_INHERIT_ONLY; + } + + } + tmp_acl->aces[tmp_acl->num_aces].access_mask = + map_generic_rights_ds(ace->access_mask); + tmp_acl->num_aces++; + if (is_container) { + if (!(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) && + ((dom_sid_equal(&ace->trustee, co) || dom_sid_equal(&ace->trustee, cg)))) { + tmp_acl->aces = talloc_realloc(tmp_acl, tmp_acl->aces, struct security_ace, + tmp_acl->num_aces+1); + if (tmp_acl->aces == NULL) { + talloc_free(tmp_ctx); + return NULL; + } + tmp_acl->aces[tmp_acl->num_aces] = *ace; + tmp_acl->aces[tmp_acl->num_aces].flags &= ~SEC_ACE_FLAG_INHERIT_ONLY; + tmp_acl->aces[tmp_acl->num_aces].flags |= SEC_ACE_FLAG_INHERITED_ACE; + if (dom_sid_equal(&tmp_acl->aces[tmp_acl->num_aces].trustee, co)) { + tmp_acl->aces[tmp_acl->num_aces].trustee = *owner; + } + if (dom_sid_equal(&tmp_acl->aces[tmp_acl->num_aces].trustee, cg)) { + tmp_acl->aces[tmp_acl->num_aces].trustee = *group; + } + tmp_acl->aces[tmp_acl->num_aces].flags &= ~SEC_ACE_FLAG_CONTAINER_INHERIT; + tmp_acl->aces[tmp_acl->num_aces].access_mask = + map_generic_rights_ds(ace->access_mask); + tmp_acl->num_aces++; + } + } + } + } + if (tmp_acl->num_aces == 0) { + return NULL; + } + if (acl) { + tmp_acl->revision = acl->revision; + } + return tmp_acl; +} + +static struct security_acl *process_user_acl(TALLOC_CTX *mem_ctx, + struct security_acl *acl, + bool is_container, + struct dom_sid *owner, + struct dom_sid *group, + struct GUID *object_list) +{ + uint32_t i; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct security_acl *tmp_acl = talloc_zero(tmp_ctx, struct security_acl); + struct security_acl *new_acl; + struct dom_sid *co, *cg; + + if (!acl) + return NULL; + + if (!tmp_acl) + return NULL; + + tmp_acl->revision = acl->revision; + DEBUG(6,(__location__ ": acl revision %u\n", acl->revision)); + + co = dom_sid_parse_talloc(tmp_ctx, SID_CREATOR_OWNER); + cg = dom_sid_parse_talloc(tmp_ctx, SID_CREATOR_GROUP); + + for (i=0; i < acl->num_aces; i++){ + struct security_ace *ace = &acl->aces[i]; + if (ace->flags & SEC_ACE_FLAG_INHERITED_ACE) + continue; + if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY && + !(ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT || + ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) + continue; + + tmp_acl->aces = talloc_realloc(tmp_acl, tmp_acl->aces, struct security_ace, + tmp_acl->num_aces+1); + tmp_acl->aces[tmp_acl->num_aces] = *ace; + if (dom_sid_equal(&(tmp_acl->aces[tmp_acl->num_aces].trustee), co)) { + tmp_acl->aces[tmp_acl->num_aces].trustee = *owner; + tmp_acl->aces[tmp_acl->num_aces].flags &= ~SEC_ACE_FLAG_CONTAINER_INHERIT; + } + if (dom_sid_equal(&(tmp_acl->aces[tmp_acl->num_aces].trustee), cg)) { + tmp_acl->aces[tmp_acl->num_aces].trustee = *group; + tmp_acl->aces[tmp_acl->num_aces].flags &= ~SEC_ACE_FLAG_CONTAINER_INHERIT; + } + tmp_acl->aces[tmp_acl->num_aces].access_mask = + map_generic_rights_ds(tmp_acl->aces[tmp_acl->num_aces].access_mask); + tmp_acl->num_aces++; + + if (!dom_sid_equal(&ace->trustee, co) && !dom_sid_equal(&ace->trustee, cg)) + continue; + + tmp_acl->aces = talloc_realloc(tmp_acl, tmp_acl->aces, struct security_ace, + tmp_acl->num_aces+1); + tmp_acl->aces[tmp_acl->num_aces] = *ace; + tmp_acl->aces[tmp_acl->num_aces].flags |= SEC_ACE_FLAG_INHERIT_ONLY; + tmp_acl->num_aces++; + } + new_acl = security_acl_dup(mem_ctx,tmp_acl); + + if (new_acl) + new_acl->revision = acl->revision; + + talloc_free(tmp_ctx); + return new_acl; +} + +static void cr_descr_log_descriptor(struct security_descriptor *sd, + const char *message, + int level) +{ + if (sd) { + DEBUG(level,("%s: %s\n", message, + ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_descriptor, + "", sd))); + } + else { + DEBUG(level,("%s: NULL\n", message)); + } +} + +static void cr_descr_log_acl(struct security_acl *acl, + const char *message, + int level) +{ + if (acl) { + DEBUG(level,("%s: %s\n", message, + ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_acl, + "", acl))); + } + else { + DEBUG(level,("%s: NULL\n", message)); + } +} + +static bool compute_acl(struct security_descriptor *parent_sd, + struct security_descriptor *creator_sd, + bool is_container, + uint32_t inherit_flags, + struct GUID *object_list, + uint32_t (*generic_map)(uint32_t access_mask), + struct security_token *token, + struct security_descriptor *new_sd) /* INOUT argument */ +{ + struct security_acl *user_dacl, *user_sacl, *inherited_dacl, *inherited_sacl; + int level = 10; + + if (!parent_sd || !(inherit_flags & SEC_DACL_AUTO_INHERIT)) { + inherited_dacl = NULL; + } else if (creator_sd && (creator_sd->type & SEC_DESC_DACL_PROTECTED)) { + inherited_dacl = NULL; + } else { + inherited_dacl = calculate_inherited_from_parent(new_sd, + parent_sd->dacl, + is_container, + new_sd->owner_sid, + new_sd->group_sid, + object_list); + } + + + if (!parent_sd || !(inherit_flags & SEC_SACL_AUTO_INHERIT)) { + inherited_sacl = NULL; + } else if (creator_sd && (creator_sd->type & SEC_DESC_SACL_PROTECTED)) { + inherited_sacl = NULL; + } else { + inherited_sacl = calculate_inherited_from_parent(new_sd, + parent_sd->sacl, + is_container, + new_sd->owner_sid, + new_sd->group_sid, + object_list); + } + + if (!creator_sd || (inherit_flags & SEC_DEFAULT_DESCRIPTOR)) { + user_dacl = NULL; + user_sacl = NULL; + } else { + user_dacl = process_user_acl(new_sd, + creator_sd->dacl, + is_container, + new_sd->owner_sid, + new_sd->group_sid, + object_list); + user_sacl = process_user_acl(new_sd, + creator_sd->sacl, + is_container, + new_sd->owner_sid, + new_sd->group_sid, + object_list); + } + cr_descr_log_descriptor(parent_sd, __location__"parent_sd", level); + cr_descr_log_descriptor(creator_sd,__location__ "creator_sd", level); + + new_sd->dacl = security_acl_concatenate(new_sd, user_dacl, inherited_dacl); + if (new_sd->dacl) { + new_sd->type |= SEC_DESC_DACL_PRESENT; + } + if (inherited_dacl) { + new_sd->type |= SEC_DESC_DACL_AUTO_INHERITED; + } + + new_sd->sacl = security_acl_concatenate(new_sd, user_sacl, inherited_sacl); + if (new_sd->sacl) { + new_sd->type |= SEC_DESC_SACL_PRESENT; + } + if (inherited_sacl) { + new_sd->type |= SEC_DESC_SACL_AUTO_INHERITED; + } + /* This is a hack to handle the fact that + * apprantly any AI flag provided by the user is preserved */ + if (creator_sd) + new_sd->type |= creator_sd->type; + cr_descr_log_descriptor(new_sd, __location__"final sd", level); + return true; +} + +struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx, + struct security_descriptor *parent_sd, + struct security_descriptor *creator_sd, + bool is_container, + struct GUID *object_list, + uint32_t inherit_flags, + struct security_token *token, + struct dom_sid *default_owner, /* valid only for DS, NULL for the other RSs */ + struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */ + uint32_t (*generic_map)(uint32_t access_mask)) +{ + struct security_descriptor *new_sd; + struct dom_sid *new_owner = NULL; + struct dom_sid *new_group = NULL; + + new_sd = security_descriptor_initialise(mem_ctx); + if (!new_sd) { + return NULL; + } + + if (!creator_sd || !creator_sd->owner_sid) { + if ((inherit_flags & SEC_OWNER_FROM_PARENT) && parent_sd) { + new_owner = parent_sd->owner_sid; + } else if (!default_owner) { + new_owner = &token->sids[PRIMARY_USER_SID_INDEX]; + } else { + new_owner = default_owner; + new_sd->type |= SEC_DESC_OWNER_DEFAULTED; + } + } else { + new_owner = creator_sd->owner_sid; + } + + if (!creator_sd || !creator_sd->group_sid){ + if ((inherit_flags & SEC_GROUP_FROM_PARENT) && parent_sd) { + new_group = parent_sd->group_sid; + } else if (!default_group && token->num_sids > PRIMARY_GROUP_SID_INDEX) { + new_group = &token->sids[PRIMARY_GROUP_SID_INDEX]; + } else if (!default_group) { + /* This will happen only for anonymous, which has no other groups */ + new_group = &token->sids[PRIMARY_USER_SID_INDEX]; + } else { + new_group = default_group; + new_sd->type |= SEC_DESC_GROUP_DEFAULTED; + } + } else { + new_group = creator_sd->group_sid; + } + + new_sd->owner_sid = talloc_memdup(new_sd, new_owner, sizeof(struct dom_sid)); + new_sd->group_sid = talloc_memdup(new_sd, new_group, sizeof(struct dom_sid)); + if (!new_sd->owner_sid || !new_sd->group_sid){ + talloc_free(new_sd); + return NULL; + } + + if (!compute_acl(parent_sd, creator_sd, + is_container, inherit_flags, object_list, + generic_map,token,new_sd)){ + talloc_free(new_sd); + return NULL; + } + + return new_sd; +} diff --git a/libcli/security/dom_sid.c b/libcli/security/dom_sid.c index f94d952b4d..217d7bb8d4 100644 --- a/libcli/security/dom_sid.c +++ b/libcli/security/dom_sid.c @@ -28,8 +28,8 @@ Compare the auth portion of two sids. *****************************************************************/ -static int dom_sid_compare_auth(const struct dom_sid *sid1, - const struct dom_sid *sid2) +int dom_sid_compare_auth(const struct dom_sid *sid1, + const struct dom_sid *sid2) { int i; diff --git a/libcli/security/dom_sid.h b/libcli/security/dom_sid.h index ac8669d725..8c60f761e4 100644 --- a/libcli/security/dom_sid.h +++ b/libcli/security/dom_sid.h @@ -25,10 +25,40 @@ #include "librpc/gen_ndr/security.h" +/* Some well-known SIDs */ +extern const struct dom_sid global_sid_World_Domain; +extern const struct dom_sid global_sid_World; +extern const struct dom_sid global_sid_Creator_Owner_Domain; +extern const struct dom_sid global_sid_NT_Authority; +extern const struct dom_sid global_sid_System; +extern const struct dom_sid global_sid_NULL; +extern const struct dom_sid global_sid_Authenticated_Users; +extern const struct dom_sid global_sid_Network; +extern const struct dom_sid global_sid_Creator_Owner; +extern const struct dom_sid global_sid_Creator_Group; +extern const struct dom_sid global_sid_Anonymous; +extern const struct dom_sid global_sid_Builtin; +extern const struct dom_sid global_sid_Builtin_Administrators; +extern const struct dom_sid global_sid_Builtin_Users; +extern const struct dom_sid global_sid_Builtin_Guests; +extern const struct dom_sid global_sid_Builtin_Power_Users; +extern const struct dom_sid global_sid_Builtin_Account_Operators; +extern const struct dom_sid global_sid_Builtin_Server_Operators; +extern const struct dom_sid global_sid_Builtin_Print_Operators; +extern const struct dom_sid global_sid_Builtin_Backup_Operators; +extern const struct dom_sid global_sid_Builtin_Replicator; +extern const struct dom_sid global_sid_Builtin_PreWin2kAccess; +extern const struct dom_sid global_sid_Unix_Users; +extern const struct dom_sid global_sid_Unix_Groups; + +int dom_sid_compare_auth(const struct dom_sid *sid1, + const struct dom_sid *sid2); int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2); int dom_sid_compare_domain(const struct dom_sid *sid1, const struct dom_sid *sid2); bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2); +bool sid_append_rid(struct dom_sid *sid, uint32_t rid); +bool string_to_sid(struct dom_sid *sidout, const char *sidstr); bool dom_sid_parse(const char *sidstr, struct dom_sid *ret); struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr); struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid); @@ -42,5 +72,25 @@ bool dom_sid_in_domain(const struct dom_sid *domain_sid, const struct dom_sid *sid); char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid); + +const char *sid_type_lookup(uint32_t sid_type); +const struct security_token *get_system_token(void); +bool sid_compose(struct dom_sid *dst, const struct dom_sid *domain_sid, uint32_t rid); +bool sid_split_rid(struct dom_sid *sid, uint32_t *rid); +bool sid_peek_rid(const struct dom_sid *sid, uint32_t *rid); +bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid *sid, uint32_t *rid); +void sid_copy(struct dom_sid *dst, const struct dom_sid *src); +bool sid_parse(const char *inbuf, size_t len, struct dom_sid *sid); +int sid_compare_domain(const struct dom_sid *sid1, const struct dom_sid *sid2); +bool sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2); +NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, + struct dom_sid **sids, uint32_t *num); +NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, + struct dom_sid **sids, uint32_t *num_sids); +void del_sid_from_array(const struct dom_sid *sid, struct dom_sid **sids, size_t *num); +bool add_rid_to_array_unique(TALLOC_CTX *mem_ctx, + uint32_t rid, uint32_t **pp_rids, size_t *p_num); +bool is_null_sid(const struct dom_sid *sid); + #endif /*_DOM_SID_H_*/ diff --git a/libcli/security/object_tree.c b/libcli/security/object_tree.c new file mode 100644 index 0000000000..7c7d644543 --- /dev/null +++ b/libcli/security/object_tree.c @@ -0,0 +1,121 @@ +/* + Unix SMB/CIFS implementation. + + security access checking routines + + Copyright (C) Nadezhda Ivanova 2009 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +/* + * Description: Contains data handler functions for + * the object tree that must be constructed to perform access checks. + * The object tree is an unbalanced tree of depth 3, indexed by + * object type guid. Perhaps a different data structure + * should be concidered later to improve performance + * + * Author: Nadezhda Ivanova + */ +#include "includes.h" +#include "libcli/security/security.h" +#include "librpc/ndr/libndr.h" + +/* Adds a new node to the object tree. If attributeSecurityGUID is not zero and + * has already been added to the tree, the new node is added as a child of that node + * In all other cases as a child of the root + */ + +bool insert_in_object_tree(TALLOC_CTX *mem_ctx, + const struct GUID *guid, + uint32_t init_access, + struct object_tree **root, + struct object_tree **new_node) +{ + if (!guid || GUID_all_zero(guid)){ + return true; + } + + if (!*root){ + *root = talloc_zero(mem_ctx, struct object_tree); + if (!*root) { + return false; + } + (*root)->guid = *guid; + *new_node = *root; + return true; + } + + if (!(*root)->children) { + (*root)->children = talloc_array(mem_ctx, struct object_tree, 1); + (*root)->children[0].guid = *guid; + (*root)->children[0].num_of_children = 0; + (*root)->children[0].children = NULL; + (*root)->num_of_children++; + (*root)->children[0].remaining_access = init_access; + *new_node = &((*root)->children[0]); + return true; + } + else { + int i; + for (i = 0; i < (*root)->num_of_children; i++) { + if (GUID_equal(&((*root)->children[i].guid), guid)) { + *new_node = &((*root)->children[i]); + return true; + } + } + (*root)->children = talloc_realloc(mem_ctx, (*root)->children, struct object_tree, + (*root)->num_of_children +1); + (*root)->children[(*root)->num_of_children].guid = *guid; + (*root)->children[(*root)->num_of_children].remaining_access = init_access; + *new_node = &((*root)->children[(*root)->num_of_children]); + (*root)->num_of_children++; + return true; + } + return true; +} + +/* search by GUID */ +struct object_tree *get_object_tree_by_GUID(struct object_tree *root, + const struct GUID *guid) +{ + struct object_tree *result = NULL; + int i; + + if (!root || GUID_equal(&root->guid, guid)) { + result = root; + return result; + } + else if (root->num_of_children > 0) { + for (i = 0; i < root->num_of_children; i++) { + if ((result = get_object_tree_by_GUID(&root->children[i], guid))) + break; + } + } + return result; +} + +/* Change the granted access per each ACE */ + +void object_tree_modify_access(struct object_tree *root, + uint32_t access) +{ + root->remaining_access &= ~access; + if (root->num_of_children > 0) { + int i; + for (i = 0; i < root->num_of_children; i++) { + object_tree_modify_access(&root->children[i], access); + } + } +} diff --git a/libcli/security/security.h b/libcli/security/security.h index f0e507231b..39ae3ec6cc 100644 --- a/libcli/security/security.h +++ b/libcli/security/security.h @@ -106,8 +106,4 @@ struct object_tree { #include "libcli/security/privileges.h" #include "libcli/security/access_check.h" -#if _SAMBA_BUILD_ >= 4 -#include "libcli/security/proto.h" -#endif - #endif diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h index bc5761ab6f..1c7f893ead 100644 --- a/libcli/security/security_descriptor.h +++ b/libcli/security/security_descriptor.h @@ -68,4 +68,17 @@ struct security_acl *security_acl_concatenate(TALLOC_CTX *mem_ctx, const struct security_acl *acl1, const struct security_acl *acl2); +uint32_t map_generic_rights_ds(uint32_t access_mask); + +struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx, + struct security_descriptor *parent_sd, + struct security_descriptor *creator_sd, + bool is_container, + struct GUID *object_list, + uint32_t inherit_flags, + struct security_token *token, + struct dom_sid *default_owner, /* valid only for DS, NULL for the other RSs */ + struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */ + uint32_t (*generic_map)(uint32_t access_mask)); + #endif /* __SECURITY_DESCRIPTOR_H__ */ diff --git a/libcli/security/util_sid.c b/libcli/security/util_sid.c new file mode 100644 index 0000000000..9ba28ebc75 --- /dev/null +++ b/libcli/security/util_sid.c @@ -0,0 +1,371 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Luke Kenneth Caseson Leighton 1998-1999 + Copyright (C) Jeremy Allison 1999 + Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Simo Sorce 2002 + Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005 + Copyright (C) Andrew Bartlett 2010 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "../librpc/gen_ndr/ndr_security.h" +#include "../librpc/gen_ndr/netlogon.h" +#include "../libcli/security/security.h" + +/* + * Some useful sids, more well known sids can be found at + * http://support.microsoft.com/kb/243330/EN-US/ + */ + + +const struct dom_sid global_sid_World_Domain = /* Everyone domain */ +{ 1, 0, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_World = /* Everyone */ +{ 1, 1, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Creator_Owner_Domain = /* Creator Owner domain */ +{ 1, 0, {0,0,0,0,0,3}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_NT_Authority = /* NT Authority */ +{ 1, 0, {0,0,0,0,0,5}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_System = /* System */ +{ 1, 1, {0,0,0,0,0,5}, {18,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_NULL = /* NULL sid */ +{ 1, 1, {0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Authenticated_Users = /* All authenticated rids */ +{ 1, 1, {0,0,0,0,0,5}, {11,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +#if 0 +/* for documentation */ +const struct dom_sid global_sid_Restriced = /* Restriced Code */ +{ 1, 1, {0,0,0,0,0,5}, {12,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +#endif +const struct dom_sid global_sid_Network = /* Network rids */ +{ 1, 1, {0,0,0,0,0,5}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + +const struct dom_sid global_sid_Creator_Owner = /* Creator Owner */ +{ 1, 1, {0,0,0,0,0,3}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Creator_Group = /* Creator Group */ +{ 1, 1, {0,0,0,0,0,3}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Anonymous = /* Anonymous login */ +{ 1, 1, {0,0,0,0,0,5}, {7,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Enterprise_DCs = /* Enterprise DCs */ +{ 1, 1, {0,0,0,0,0,5}, {9,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin = /* Local well-known domain */ +{ 1, 1, {0,0,0,0,0,5}, {32,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Administrators = /* Builtin administrators */ +{ 1, 2, {0,0,0,0,0,5}, {32,544,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Users = /* Builtin users */ +{ 1, 2, {0,0,0,0,0,5}, {32,545,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Guests = /* Builtin guest users */ +{ 1, 2, {0,0,0,0,0,5}, {32,546,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Power_Users = /* Builtin power users */ +{ 1, 2, {0,0,0,0,0,5}, {32,547,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Account_Operators = /* Builtin account operators */ +{ 1, 2, {0,0,0,0,0,5}, {32,548,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Server_Operators = /* Builtin server operators */ +{ 1, 2, {0,0,0,0,0,5}, {32,549,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Print_Operators = /* Builtin print operators */ +{ 1, 2, {0,0,0,0,0,5}, {32,550,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Backup_Operators = /* Builtin backup operators */ +{ 1, 2, {0,0,0,0,0,5}, {32,551,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_Replicator = /* Builtin replicator */ +{ 1, 2, {0,0,0,0,0,5}, {32,552,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Builtin_PreWin2kAccess = /* Builtin pre win2k access */ +{ 1, 2, {0,0,0,0,0,5}, {32,554,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + +const struct dom_sid global_sid_Unix_Users = /* Unmapped Unix users */ +{ 1, 1, {0,0,0,0,0,22}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +const struct dom_sid global_sid_Unix_Groups = /* Unmapped Unix groups */ +{ 1, 1, {0,0,0,0,0,22}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + +/* Unused, left here for documentary purposes */ +#if 0 +#define SECURITY_NULL_SID_AUTHORITY 0 +#define SECURITY_WORLD_SID_AUTHORITY 1 +#define SECURITY_LOCAL_SID_AUTHORITY 2 +#define SECURITY_CREATOR_SID_AUTHORITY 3 +#define SECURITY_NT_AUTHORITY 5 +#endif + +static struct dom_sid system_sid_array[1] = +{ { 1, 1, {0,0,0,0,0,5}, {18,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} }; +static const struct security_token system_token = { + .num_sids = ARRAY_SIZE(system_sid_array), + .sids = system_sid_array, + .privilege_mask = SE_ALL_PRIVS +}; + +/**************************************************************************** + Lookup string names for SID types. +****************************************************************************/ + +static const struct { + enum lsa_SidType sid_type; + const char *string; +} sid_name_type[] = { + {SID_NAME_USE_NONE, "None"}, + {SID_NAME_USER, "User"}, + {SID_NAME_DOM_GRP, "Domain Group"}, + {SID_NAME_DOMAIN, "Domain"}, + {SID_NAME_ALIAS, "Local Group"}, + {SID_NAME_WKN_GRP, "Well-known Group"}, + {SID_NAME_DELETED, "Deleted Account"}, + {SID_NAME_INVALID, "Invalid Account"}, + {SID_NAME_UNKNOWN, "UNKNOWN"}, + {SID_NAME_COMPUTER, "Computer"}, + + {(enum lsa_SidType)0, NULL} +}; + +const char *sid_type_lookup(uint32_t sid_type) +{ + int i = 0; + + /* Look through list */ + while(sid_name_type[i].sid_type != 0) { + if (sid_name_type[i].sid_type == sid_type) + return sid_name_type[i].string; + i++; + } + + /* Default return */ + return "SID *TYPE* is INVALID"; +} + +/************************************************************************** + Create the SYSTEM token. +***************************************************************************/ + +const struct security_token *get_system_token(void) +{ + return &system_token; +} + +bool sid_compose(struct dom_sid *dst, const struct dom_sid *domain_sid, uint32_t rid) +{ + sid_copy(dst, domain_sid); + return sid_append_rid(dst, rid); +} + +/***************************************************************** + Removes the last rid from the end of a sid +*****************************************************************/ + +bool sid_split_rid(struct dom_sid *sid, uint32_t *rid) +{ + if (sid->num_auths > 0) { + sid->num_auths--; + *rid = sid->sub_auths[sid->num_auths]; + return true; + } + return false; +} + +/***************************************************************** + Return the last rid from the end of a sid +*****************************************************************/ + +bool sid_peek_rid(const struct dom_sid *sid, uint32_t *rid) +{ + if (!sid || !rid) + return false; + + if (sid->num_auths > 0) { + *rid = sid->sub_auths[sid->num_auths - 1]; + return true; + } + return false; +} + +/***************************************************************** + Return the last rid from the end of a sid + and check the sid against the exp_dom_sid +*****************************************************************/ + +bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid *sid, uint32_t *rid) +{ + if (!exp_dom_sid || !sid || !rid) + return false; + + if (sid->num_auths != (exp_dom_sid->num_auths+1)) { + return false; + } + + if (sid_compare_domain(exp_dom_sid, sid)!=0){ + *rid=(-1); + return false; + } + + return sid_peek_rid(sid, rid); +} + +/***************************************************************** + Copies a sid +*****************************************************************/ + +void sid_copy(struct dom_sid *dst, const struct dom_sid *src) +{ + int i; + + ZERO_STRUCTP(dst); + + dst->sid_rev_num = src->sid_rev_num; + dst->num_auths = src->num_auths; + + memcpy(&dst->id_auth[0], &src->id_auth[0], sizeof(src->id_auth)); + + for (i = 0; i < src->num_auths; i++) + dst->sub_auths[i] = src->sub_auths[i]; +} + +/***************************************************************** + Parse a on-the-wire SID to a struct dom_sid. +*****************************************************************/ + +bool sid_parse(const char *inbuf, size_t len, struct dom_sid *sid) +{ + enum ndr_err_code ndr_err; + DATA_BLOB in = data_blob_const(inbuf, len); + ndr_err = ndr_pull_struct_blob_all(&in, NULL, sid, + (ndr_pull_flags_fn_t)ndr_pull_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return false; + } + return true; +} + +/***************************************************************** + See if 2 SIDs are in the same domain + this just compares the leading sub-auths +*****************************************************************/ + +int sid_compare_domain(const struct dom_sid *sid1, const struct dom_sid *sid2) +{ + int n, i; + + n = MIN(sid1->num_auths, sid2->num_auths); + + for (i = n-1; i >= 0; --i) + if (sid1->sub_auths[i] != sid2->sub_auths[i]) + return sid1->sub_auths[i] - sid2->sub_auths[i]; + + return dom_sid_compare_auth(sid1, sid2); +} + +/***************************************************************** + Compare two sids. +*****************************************************************/ + +bool sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2) +{ + return dom_sid_compare(sid1, sid2) == 0; +} + +/******************************************************************** + Add SID to an array SIDs +********************************************************************/ + +NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, + struct dom_sid **sids, uint32_t *num) +{ + *sids = talloc_realloc(mem_ctx, *sids, struct dom_sid, + (*num)+1); + if (*sids == NULL) { + *num = 0; + return NT_STATUS_NO_MEMORY; + } + + sid_copy(&((*sids)[*num]), sid); + *num += 1; + + return NT_STATUS_OK; +} + + +/******************************************************************** + Add SID to an array SIDs ensuring that it is not already there +********************************************************************/ + +NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const struct dom_sid *sid, + struct dom_sid **sids, uint32_t *num_sids) +{ + size_t i; + + for (i=0; i<(*num_sids); i++) { + if (dom_sid_compare(sid, &(*sids)[i]) == 0) + return NT_STATUS_OK; + } + + return add_sid_to_array(mem_ctx, sid, sids, num_sids); +} + +/******************************************************************** + Remove SID from an array +********************************************************************/ + +void del_sid_from_array(const struct dom_sid *sid, struct dom_sid **sids, size_t *num) +{ + struct dom_sid *sid_list = *sids; + size_t i; + + for ( i=0; i<*num; i++ ) { + + /* if we find the SID, then decrement the count + and break out of the loop */ + + if ( sid_equal(sid, &sid_list[i]) ) { + *num -= 1; + break; + } + } + + /* This loop will copy the remainder of the array + if i < num of sids ni the array */ + + for ( ; i<*num; i++ ) + sid_copy( &sid_list[i], &sid_list[i+1] ); + + return; +} + +bool add_rid_to_array_unique(TALLOC_CTX *mem_ctx, + uint32_t rid, uint32_t **pp_rids, size_t *p_num) +{ + size_t i; + + for (i=0; i<*p_num; i++) { + if ((*pp_rids)[i] == rid) + return true; + } + + *pp_rids = talloc_realloc(mem_ctx, *pp_rids, uint32_t, *p_num+1); + + if (*pp_rids == NULL) { + *p_num = 0; + return false; + } + + (*pp_rids)[*p_num] = rid; + *p_num += 1; + return true; +} + +bool is_null_sid(const struct dom_sid *sid) +{ + static const struct dom_sid null_sid = {0}; + return sid_equal(sid, &null_sid); +} diff --git a/libcli/security/wscript_build b/libcli/security/wscript_build index 5dac9019fb..aaaf8d8372 100644 --- a/libcli/security/wscript_build +++ b/libcli/security/wscript_build @@ -1,8 +1,8 @@ #!/usr/bin/env python -bld.SAMBA_SUBSYSTEM('LIBSECURITY_COMMON', - source='dom_sid.c display_sec.c secace.c secacl.c security_descriptor.c sddl.c privileges.c security_token.c', +bld.SAMBA_SUBSYSTEM('LIBSECURITY', + source='dom_sid.c display_sec.c secace.c secacl.c security_descriptor.c sddl.c privileges.c security_token.c access_check.c object_tree.c create_descriptor.c util_sid.c', deps='talloc LIBNDR' ) |