diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2013-01-19 15:17:42 +0100 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2013-01-21 15:55:48 +0100 |
commit | 2234d49c8a307ee4f11cc544c862a359f76b44ad (patch) | |
tree | 400a1825971ecca435f874d92aa535a96d2a3c9b /src | |
parent | 99b2c04e198e077708c5a08f2fdfa9574512a82c (diff) | |
download | sssd-2234d49c8a307ee4f11cc544c862a359f76b44ad.tar.gz sssd-2234d49c8a307ee4f11cc544c862a359f76b44ad.tar.bz2 sssd-2234d49c8a307ee4f11cc544c862a359f76b44ad.zip |
LDAP: Compare lists of DNs when saving autofs entries
https://fedorahosted.org/sssd/ticket/1758
The autofs entries do not have the key as an unique identifier, but
rather the full (key, value) tuple as some keys have a special meaning,
such as the direct mount key (/-) and may be present in a single map
multiple times.
Comparing the full DN that contains both the key and the value will
allow for working updates if either key or value changes.
Diffstat (limited to 'src')
-rw-r--r-- | src/db/sysdb_autofs.c | 27 | ||||
-rw-r--r-- | src/db/sysdb_autofs.h | 13 | ||||
-rw-r--r-- | src/providers/ldap/sdap_async_autofs.c | 281 |
3 files changed, 178 insertions, 143 deletions
diff --git a/src/db/sysdb_autofs.c b/src/db/sysdb_autofs.c index f8fe3925..cc44c350 100644 --- a/src/db/sysdb_autofs.c +++ b/src/db/sysdb_autofs.c @@ -78,6 +78,26 @@ done: return dn; } +char * +sysdb_autofsentry_strdn(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *map_name, + const char *entry_name, + const char *entry_value) +{ + struct ldb_dn *dn; + char *strdn; + + dn = sysdb_autofsentry_dn(mem_ctx, sysdb, domain, + map_name, entry_name, entry_value); + if (!dn) return NULL; + + strdn = talloc_strdup(mem_ctx, ldb_dn_get_linearized(dn)); + talloc_free(dn); + return strdn; +} + errno_t sysdb_save_autofsmap(struct sysdb_ctx *sysdb_ctx, struct sss_domain_info *domain, @@ -319,15 +339,12 @@ done: errno_t sysdb_del_autofsentry(struct sysdb_ctx *sysdb_ctx, - struct sss_domain_info *domain, - const char *map, - const char *key, - const char *value) + const char *entry_dn) { struct ldb_dn *dn; errno_t ret; - dn = sysdb_autofsentry_dn(sysdb_ctx, sysdb_ctx, domain, map, key, value); + dn = ldb_dn_new(NULL, sysdb_ctx_get_ldb(sysdb_ctx), entry_dn); if (!dn) { return ENOMEM; } diff --git a/src/db/sysdb_autofs.h b/src/db/sysdb_autofs.h index 0d130946..e3528ce4 100644 --- a/src/db/sysdb_autofs.h +++ b/src/db/sysdb_autofs.h @@ -65,10 +65,7 @@ sysdb_save_autofsentry(struct sysdb_ctx *sysdb_ctx, struct sysdb_attrs *attrs); errno_t sysdb_del_autofsentry(struct sysdb_ctx *sysdb_ctx, - struct sss_domain_info *domain, - const char *map, - const char *key, - const char *value); + const char *entry_dn); errno_t sysdb_autofs_entries_by_map(TALLOC_CTX *mem_ctx, @@ -89,4 +86,12 @@ errno_t sysdb_invalidate_autofs_maps(struct sysdb_ctx *sysdb, struct sss_domain_info *domain); +char * +sysdb_autofsentry_strdn(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *map_name, + const char *entry_name, + const char *entry_value); + #endif /* _SYSDB_AUTOFS_H_ */ diff --git a/src/providers/ldap/sdap_async_autofs.c b/src/providers/ldap/sdap_async_autofs.c index 6306991e..8e874d64 100644 --- a/src/providers/ldap/sdap_async_autofs.c +++ b/src/providers/ldap/sdap_async_autofs.c @@ -50,153 +50,138 @@ get_autofs_map_name(struct sysdb_attrs *map, struct sdap_options *opts) } static const char * -get_autofs_entry_key(struct sysdb_attrs *entry, struct sdap_options *opts) +get_autofs_entry_attr(struct sysdb_attrs *entry, struct sdap_options *opts, + enum sdap_autofs_entry_attrs attr) { errno_t ret; struct ldb_message_element *el; ret = sysdb_attrs_get_el(entry, - opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_KEY].sys_name, + opts->autofs_entry_map[attr].sys_name, &el); if (ret) return NULL; - if (el->num_values == 0) return NULL; + if (el->num_values != 1) { + DEBUG(SSSDBG_CRIT_FAILURE, + ("Expected one entry got %d\n", el->num_values)); + return NULL; + } return (const char *)el->values[0].data; } +static const char * +get_autofs_entry_key(struct sysdb_attrs *entry, struct sdap_options *opts) +{ + return get_autofs_entry_attr(entry, opts, SDAP_AT_AUTOFS_ENTRY_KEY); +} + +static const char * +get_autofs_entry_value(struct sysdb_attrs *entry, struct sdap_options *opts) +{ + return get_autofs_entry_attr(entry, opts, SDAP_AT_AUTOFS_ENTRY_VALUE); +} + static errno_t -mod_autofs_entry(struct sysdb_ctx *sysdb, +add_autofs_entry(struct sysdb_ctx *sysdb, struct sss_domain_info *domain, const char *map, struct sdap_options *opts, - struct sysdb_attrs *entry, - enum autofs_map_op mod_op) + struct sysdb_attrs *entry) { const char *key; const char *value; - struct ldb_message_element *el; - errno_t ret; key = get_autofs_entry_key(entry, opts); - if (!key) return EINVAL; - - ret = sysdb_attrs_get_el(entry, - opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_VALUE].sys_name, - &el); - if (ret) return ret; - if (el->num_values == 0) return EINVAL; - else value = (const char *)el->values[0].data; + if (!key) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not get autofs entry key\n")); + return EINVAL; + } - switch (mod_op) { - case AUTOFS_MAP_OP_ADD: - ret = sysdb_save_autofsentry(sysdb, domain, map, key, value, NULL); - break; - case AUTOFS_MAP_OP_DEL: - ret = sysdb_del_autofsentry(sysdb, domain, map, key, value); - break; + value = get_autofs_entry_value(entry, opts); + if (!value) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not get autofs entry value\n")); + return EINVAL; } - return ret; + return sysdb_save_autofsentry(sysdb, domain, map, key, value, NULL); } static errno_t -mod_autofs_entries(struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - struct sdap_options *opts, - const char *map, - char **mod_entries, - struct sysdb_attrs **entries, - size_t num_entries, - enum autofs_map_op mod_op) - +save_autofs_entries(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + struct sdap_options *opts, + const char *map, + char **add_dn_list, + hash_table_t *entry_hash) { - errno_t ret, tret; - const char *key; - bool in_transaction = false; - int i, j; + hash_key_t key; + hash_value_t value; + size_t i; + int hret; + errno_t ret; + struct sysdb_attrs *entry; - ret = sysdb_transaction_start(sysdb); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("Cannot start sysdb transaction [%d]: %s\n", - ret, strerror(ret))); - goto done; + if (!add_dn_list) { + return EOK; } - in_transaction = true; - /* Loop through entry names.. */ - for (i=0; mod_entries[i]; i++) { - for (j=0; j < num_entries; j++) { - /* get a pointer to sysdb_attrs of an entry that is not - * cached, skip names that are not in **entries - */ - key = get_autofs_entry_key(entries[j], opts); - if (!key) { - DEBUG(SSSDBG_MINOR_FAILURE, - ("An entry without name? Skipping\n")); - return EINVAL; - } - - if (strcmp(mod_entries[i], key)) { - continue; - } + for (i=0; add_dn_list[i]; i++) { + key.type = HASH_KEY_STRING; + key.str = (char *) add_dn_list[i]; - ret = mod_autofs_entry(sysdb, domain, map, opts, entries[j], mod_op); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - ("Cannot modify autofs entry [%d]: %s. Ignoring.\n", - ret, strerror(ret))); - continue; - } + hret = hash_lookup(entry_hash, &key, &value); + if (hret != HASH_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Cannot retrieve entry [%s] from hash\n", add_dn_list[i])); + continue; } - } - ret = sysdb_transaction_commit(sysdb); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("Cannot commit sysdb transaction [%d]: %s\n", - ret, strerror(ret))); - goto done; - } - in_transaction = false; + entry = talloc_get_type(value.ptr, struct sysdb_attrs); + if (!entry) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Cannot retrieve entry [%s] from ptr\n", add_dn_list[i])); + continue; + } - ret = EOK; -done: - if (in_transaction) { - tret = sysdb_transaction_cancel(sysdb); - if (tret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, - ("Cannot cancel sysdb transaction [%d]: %s\n", - ret, strerror(ret))); + DEBUG(SSSDBG_TRACE_FUNC, + ("Saving autofs entry [%s]\n", add_dn_list[i])); + ret = add_autofs_entry(sysdb, domain, map, opts, entry); + if (ret) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Cannot save entry [%s] to cache\n", add_dn_list[i])); + continue; } + + DEBUG(SSSDBG_TRACE_FUNC, ("Saved entry [%s]\n", add_dn_list[i])); } - return ret; -} -static errno_t -save_autofs_entries(struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, - struct sdap_options *opts, - const char *map, - char **add_entries, - struct sysdb_attrs **entries, - size_t num_entries) -{ - return mod_autofs_entries(sysdb, domain, opts, map, add_entries, - entries, num_entries, AUTOFS_MAP_OP_ADD); + DEBUG(SSSDBG_TRACE_INTERNAL, ("All entries saved\n")); + return EOK; } static errno_t del_autofs_entries(struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, struct sdap_options *opts, const char *map, - char **add_entries, - struct sysdb_attrs **entries, - size_t num_entries) + char **del_dn_list) { - return mod_autofs_entries(sysdb, domain, opts, map, add_entries, - entries, num_entries, AUTOFS_MAP_OP_DEL); + size_t i; + errno_t ret; + + for (i=0; del_dn_list[i]; i++) { + DEBUG(SSSDBG_TRACE_FUNC, + ("Removing autofs entry [%s]\n", del_dn_list[i])); + + ret = sysdb_del_autofsentry(sysdb, del_dn_list[i]); + if (ret) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Cannot delete entry %s\n", del_dn_list[i])); + continue; + } + } + + DEBUG(SSSDBG_TRACE_INTERNAL, ("All entries removed\n")); + return EOK; } static errno_t @@ -798,18 +783,25 @@ sdap_autofs_setautomntent_save(struct tevent_req *req) bool in_transaction = false; TALLOC_CTX *tmp_ctx; struct ldb_message **entries = NULL; - struct sysdb_attrs **entries_attrs; size_t count; + const char *key; const char *val; char **sysdb_entrylist; char **ldap_entrylist; char **add_entries; char **del_entries; - size_t i; + size_t i, j; + + hash_table_t *entry_hash; + hash_key_t hkey; + hash_value_t value; + int hret; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return ENOMEM; + DEBUG(SSSDBG_TRACE_LIBS, + ("Got %d map entries from LDAP\n", state->entries_count)); if (state->entries_count == 0) { /* No entries for this map in LDAP. * We need to ensure that there are no entries @@ -817,17 +809,51 @@ sdap_autofs_setautomntent_save(struct tevent_req *req) */ ldap_entrylist = NULL; } else { - ret = sysdb_attrs_to_list( - tmp_ctx, state->entries, - state->entries_count, - state->opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_KEY].sys_name, - &ldap_entrylist); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - ("sysdb_attrs_primary_name_list failed [%d]: %s\n", - ret, strerror(ret))); + ldap_entrylist = talloc_array(tmp_ctx, char *, + state->entries_count+1); + if (!ldap_entrylist) { + ret = ENOMEM; goto done; } + + ret = sss_hash_create(state, 32, &entry_hash); + if (ret) { + goto done; + } + + /* Get a list of the map members by DN */ + for (i=0, j=0; i < state->entries_count; i++) { + key = get_autofs_entry_key(state->entries[i], state->opts); + val = get_autofs_entry_value(state->entries[i], state->opts); + if (!key || !val) { + DEBUG(SSSDBG_MINOR_FAILURE, ("Malformed entry, skipping\n")); + continue; + } + + ldap_entrylist[j] = sysdb_autofsentry_strdn(ldap_entrylist, + state->sysdb, + state->dom, + state->mapname, + key, val); + if (!ldap_entrylist[j]) { + ret = ENOMEM; + goto done; + } + + hkey.type = HASH_KEY_STRING; + hkey.str = ldap_entrylist[j]; + value.type = HASH_VALUE_PTR; + value.ptr = state->entries[i]; + + hret = hash_enter(entry_hash, &hkey, &value); + if (hret != HASH_SUCCESS) { + ret = EIO; + goto done; + } + + j++; + } + ldap_entrylist[state->entries_count] = NULL; } ret = sysdb_autofs_entries_by_map(tmp_ctx, state->sysdb, @@ -840,6 +866,7 @@ sdap_autofs_setautomntent_save(struct tevent_req *req) goto done; } + DEBUG(SSSDBG_TRACE_LIBS, ("Got %d map entries from sysdb\n", count)); if (count == 0) { /* No map members for this map in sysdb currently */ sysdb_entrylist = NULL; @@ -850,16 +877,10 @@ sdap_autofs_setautomntent_save(struct tevent_req *req) goto done; } - /* Get a list of the map members by name only */ + /* Get a list of the map members by DN */ for (i=0; i < count; i++) { - val = ldb_msg_find_attr_as_string(entries[i], - SYSDB_AUTOFS_ENTRY_KEY, NULL); - if (!val) { - DEBUG(SSSDBG_MINOR_FAILURE, ("An entry with no value?\n")); - continue; - } - - sysdb_entrylist[i] = talloc_strdup(sysdb_entrylist, val); + sysdb_entrylist[i] = talloc_strdup(sysdb_entrylist, + ldb_dn_get_linearized(entries[i]->dn)); if (!sysdb_entrylist[i]) { ret = ENOMEM; goto done; @@ -897,7 +918,7 @@ sdap_autofs_setautomntent_save(struct tevent_req *req) if (add_entries && add_entries[0]) { ret = save_autofs_entries(state->sysdb, state->dom, state->opts, state->mapname, add_entries, - state->entries, state->entries_count); + entry_hash); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Cannot save autofs entries [%d]: %s\n", @@ -908,16 +929,8 @@ sdap_autofs_setautomntent_save(struct tevent_req *req) /* Delete entries that don't exist anymore */ if (del_entries && del_entries[0]) { - ret = sysdb_msg2attrs(tmp_ctx, count, entries, &entries_attrs); - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - ("sysdb_msg2attrs failed: [%d]: %s\n", ret, strerror(ret))); - goto done; - } - - ret = del_autofs_entries(state->sysdb, state->dom, state->opts, - state->mapname, del_entries, - entries_attrs, count); + ret = del_autofs_entries(state->sysdb, state->opts, + state->mapname, del_entries); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Cannot delete autofs entries [%d]: %s\n", |