From 3a8659c6641a8802416876c8716501806062c70d Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 28 Sep 2011 10:26:36 +0200 Subject: [PATCH 3/4] Store name aliases for users, groups --- src/providers/ldap/sdap_async.c | 89 ++++++++++++++++ src/providers/ldap/sdap_async.h | 7 ++ src/providers/ldap/sdap_async_accounts.c | 161 +++++++++++++++++++++++------- 3 files changed, 220 insertions(+), 37 deletions(-) diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c index a45adbe..3202f01 100644 --- a/src/providers/ldap/sdap_async.c +++ b/src/providers/ldap/sdap_async.c @@ -1071,3 +1071,92 @@ int sdap_get_generic_recv(struct tevent_req *req, return EOK; } +errno_t sdap_check_aliases(struct sysdb_ctx *sysdb, + struct sysdb_attrs *user_attrs, + struct sss_domain_info *dom, + struct sdap_options *opts, + bool steal_memberships) +{ + errno_t ret; + const char **aliases = NULL; + const char *name = NULL; + struct ldb_message *msg; + TALLOC_CTX *tmp_ctx = NULL; + char **parents; + uid_t alias_uid; + int i; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + ret = sysdb_attrs_primary_name(sysdb, user_attrs, + opts->user_map[SDAP_AT_USER_NAME].name, + &name); + if (ret != EOK) { + DEBUG(1, ("Could not get the primary name\n")); + goto done; + } + + ret = sysdb_attrs_get_aliases(tmp_ctx, user_attrs, name, &aliases); + if (ret != EOK) { + DEBUG(1, ("Failed to get the alias list\n")); + goto done; + } + + for (i = 0; aliases[i]; i++) { + /* In RFC2307 schema, another group might be referencing user + * using secondary name, so there might be fake users in the cache + * from a previous getgr call */ + ret = sysdb_search_user_by_name(tmp_ctx, sysdb, dom, + aliases[i], NULL, &msg); + if (ret && ret != ENOENT) { + DEBUG(1, ("Error searching the cache\n")); + goto done; + } else if (ret == ENOENT) { + DEBUG(9, ("No user with primary name same as alias %s\n", aliases[i])); + continue; + } + + alias_uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0); + if (alias_uid) { + DEBUG(1, ("Cache contains non-fake user with same name " + "as alias %s\n", aliases[i])); + ret = EIO; + goto done; + } + DEBUG(7, ("%s is a fake user\n", aliases[i])); + + if (steal_memberships) { + /* Get direct sysdb parents */ + ret = sysdb_get_direct_parents(tmp_ctx, sysdb, dom, + SYSDB_MEMBER_USER, + aliases[i], &parents); + if (ret) { + DEBUG(1, ("Could not get direct parents for %s: %d [%s]\n", + aliases[i], ret, strerror(ret))); + goto done; + } + + ret = sysdb_update_members(sysdb, dom, name, SYSDB_MEMBER_USER, + (const char *const *) parents, + NULL); + if (ret != EOK) { + DEBUG(1, ("Membership update failed [%d]: %s\n", + ret, strerror(ret))); + goto done; + } + } + + ret = sysdb_delete_user(tmp_ctx, sysdb, dom, aliases[i], alias_uid); + if (ret) { + DEBUG(1, ("Error deleting fake user %s\n", aliases[i])); + goto done; + } + } + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h index 84a23be..346940b 100644 --- a/src/providers/ldap/sdap_async.h +++ b/src/providers/ldap/sdap_async.h @@ -151,4 +151,11 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx, int sdap_get_generic_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, size_t *reply_count, struct sysdb_attrs ***reply_list); + +errno_t sdap_check_aliases(struct sysdb_ctx *sysdb, + struct sysdb_attrs *user_attrs, + struct sss_domain_info *dom, + struct sdap_options *opts, + bool steal_memberships); + #endif /* _SDAP_ASYNC_H_ */ diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c index 7871f18..fa77db6 100644 --- a/src/providers/ldap/sdap_async_accounts.c +++ b/src/providers/ldap/sdap_async_accounts.c @@ -55,6 +55,7 @@ static int sdap_save_user(TALLOC_CTX *memctx, char *usn_value = NULL; size_t c; char **missing = NULL; + const char **aliases = NULL; TALLOC_CTX *tmpctx = NULL; DEBUG(9, ("Save user\n")); @@ -281,6 +282,20 @@ static int sdap_save_user(TALLOC_CTX *memctx, } } + ret = sysdb_attrs_get_aliases(tmpctx, attrs, name, &aliases); + if (ret != EOK) { + DEBUG(1, ("Failed to get the alias list")); + goto fail; + } + + for (i = 0; aliases[i]; i++) { + ret = sysdb_attrs_add_string(user_attrs, SYSDB_NAME_ALIAS, + aliases[i]); + if (ret) { + goto fail; + } + } + /* Make sure that any attributes we requested from LDAP that we * did not receive are also removed from the sysdb */ @@ -366,6 +381,12 @@ static int sdap_save_users(TALLOC_CTX *memctx, DEBUG(9, ("User %d processed!\n", i)); } + ret = sdap_check_aliases(sysdb, users[i], dom, + opts, true); + if (ret) { + DEBUG(2, ("Failed to check aliases for user %d. Ignoring.\n", i)); + } + if (usn_value) { if (higher_usn) { if ((strlen(usn_value) > strlen(higher_usn)) || @@ -710,9 +731,11 @@ static int sdap_save_group(TALLOC_CTX *memctx, const char *name = NULL; gid_t gid; int ret; + int i; char *usn_value = NULL; TALLOC_CTX *tmpctx = NULL; bool posix_group; + const char **aliases = NULL; tmpctx = talloc_new(memctx); if (!tmpctx) { @@ -855,6 +878,20 @@ static int sdap_save_group(TALLOC_CTX *memctx, } } + ret = sysdb_attrs_get_aliases(tmpctx, attrs, name, &aliases); + if (ret != EOK) { + DEBUG(1, ("Failed to get the alias list\n")); + goto fail; + } + + for (i = 0; aliases[i]; i++) { + ret = sysdb_attrs_add_string(group_attrs, SYSDB_NAME_ALIAS, + aliases[i]); + if (ret) { + goto fail; + } + } + DEBUG(6, ("Storing info for group %s\n", name)); ret = sdap_store_group_with_gid(group_attrs, ctx, dom, @@ -1211,6 +1248,10 @@ sdap_process_missing_member_2307bis(struct tevent_req *req, int num_users); static int +sdap_add_group_member_2307(struct sdap_process_group_state *state, + const char *username); + +static int sdap_process_group_members_2307bis(struct tevent_req *req, struct sdap_process_group_state *state, struct ldb_message_element *memberel) @@ -1304,7 +1345,6 @@ sdap_process_group_members_2307(struct sdap_process_group_state *state, struct ldb_message *msg; bool in_transaction = false; char *member_name; - char *strdn; int ret; errno_t sret; int i; @@ -1319,23 +1359,17 @@ sdap_process_group_members_2307(struct sdap_process_group_state *state, state->dom, member_name, NULL, &msg); if (ret == EOK) { - strdn = sysdb_user_strdn(state->sysdb_dns->values, - state->dom->name, - member_name); - if (!strdn) { - ret = ENOMEM; + /* + * User already cached in sysdb. Remember the sysdb DN for later + * use by sdap_save_groups() + */ + DEBUG(7, ("Member already cached in sysdb: %s\n", member_name)); + + ret = sdap_add_group_member_2307(state, member_name); + if (ret != EOK) { + DEBUG(1, ("Could not add member %s into sysdb\n", member_name)); goto done; } - /* - * User already cached in sysdb. Remember the sysdb DN for later - * use by sdap_save_groups() - */ - DEBUG(7,("Member already cached in sysdb: %s\n", strdn)); - state->sysdb_dns->values[state->sysdb_dns->num_values].data = - (uint8_t *) strdn; - state->sysdb_dns->values[state->sysdb_dns->num_values].length = - strlen(strdn); - state->sysdb_dns->num_values++; } else if (ret == ENOENT) { /* The user is not in sysdb, need to add it */ DEBUG(7, ("member #%d (%s): not found in sysdb\n", @@ -1436,17 +1470,73 @@ sdap_process_missing_member_2307bis(struct tevent_req *req, } static int +sdap_add_group_member_2307(struct sdap_process_group_state *state, + const char *username) +{ + char *strdn; + + strdn = sysdb_user_strdn(state->sysdb_dns->values, + state->dom->name, username); + if (!strdn) { + return ENOMEM; + } + + state->sysdb_dns->values[state->sysdb_dns->num_values].data = + (uint8_t *) strdn; + state->sysdb_dns->values[state->sysdb_dns->num_values].length = + strlen(strdn); + state->sysdb_dns->num_values++; + + return EOK; +} + +static int sdap_process_missing_member_2307(struct sdap_process_group_state *state, - char *username, bool *in_transaction) + char *member_name, bool *in_transaction) { int ret, sret; - struct ldb_dn *dn; - char* dn_string; - - DEBUG(7, ("Adding a dummy entry\n")); + TALLOC_CTX *tmp_ctx; + const char *filter; + const char *username; + size_t count; + struct ldb_message **msgs = NULL; + static const char *attrs[] = { SYSDB_NAME, NULL }; if (!in_transaction) return EINVAL; + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) return ENOMEM; + + /* Check for the alias in the sysdb */ + filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME_ALIAS, member_name); + if (!filter) { + ret = ENOMEM; + goto fail; + } + + ret = sysdb_search_users(tmp_ctx, state->sysdb, state->dom, + filter, attrs, &count, &msgs); + if (ret == EOK && count > 0) { + /* Entry exists but the group references it with an alias. */ + + if (count != 1) { + DEBUG(1, ("More than one entry with this alias?\n")); + ret = EIO; + goto fail; + } + + /* fill username with primary name */ + username = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL); + goto done; + } else if (ret != EOK && ret != ENOENT) { + ret = EIO; + goto fail; + } + + username = member_name; + /* The entry really does not exist, add a fake entry */ + DEBUG(7, ("Adding a dummy entry\n")); + if (!*in_transaction) { ret = sysdb_transaction_start(state->sysdb); if (ret != EOK) { @@ -1468,27 +1558,17 @@ sdap_process_missing_member_2307(struct sdap_process_group_state *state, * Convert the just received DN into the corresponding sysdb DN * for saving into member attribute of the group */ - dn = sysdb_user_dn(state->sysdb, state, state->dom->name, - (char*) username); - if (!dn) { - ret = ENOMEM; - goto fail; - } - - dn_string = ldb_dn_alloc_linearized(state->sysdb_dns->values, dn); - if (!dn_string) { - ret = ENOMEM; +done: + ret = sdap_add_group_member_2307(state, username); + if (ret != EOK) { + DEBUG(1, ("Could not add group member %s\n", username)); goto fail; } - state->sysdb_dns->values[state->sysdb_dns->num_values].data = - (uint8_t *) dn_string; - state->sysdb_dns->values[state->sysdb_dns->num_values].length = - strlen(dn_string); - state->sysdb_dns->num_values++; - + talloc_free(tmp_ctx); return EOK; fail: + talloc_free(tmp_ctx); if (*in_transaction) { sret = sysdb_transaction_cancel(state->sysdb); if (sret == EOK) { @@ -3007,6 +3087,13 @@ static void sdap_get_initgr_user(struct tevent_req *subreq) switch (state->opts->schema_type) { case SDAP_SCHEMA_RFC2307: + ret = sdap_check_aliases(state->sysdb, state->orig_user, state->dom, + state->opts, false); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts, state->sysdb, state->dom, state->sh, dp_opt_get_string(state->opts->basic, -- 1.7.6.2