sdap_async_autofs.c revision 2234d49c8a307ee4f11cc544c862a359f76b44ad
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek/*
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek SSSD
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek Async LDAP Helper routines for autofs
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek Authors:
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek Jakub Hrozek <jhrozek@redhat.com>
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek Copyright (C) 2012 Red Hat
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek This program is free software; you can redistribute it and/or modify
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek it under the terms of the GNU General Public License as published by
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek the Free Software Foundation; either version 3 of the License, or
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek (at your option) any later version.
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek This program is distributed in the hope that it will be useful,
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek but WITHOUT ANY WARRANTY; without even the implied warranty of
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek GNU General Public License for more details.
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek You should have received a copy of the GNU General Public License
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek along with this program. If not, see <http://www.gnu.org/licenses/>.
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek*/
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek#include "util/util.h"
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek#include "db/sysdb.h"
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek#include "providers/ldap/sdap_async_private.h"
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek#include "db/sysdb_autofs.h"
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek#include "providers/ldap/ldap_common.h"
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozekenum autofs_map_op {
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek AUTOFS_MAP_OP_ADD,
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek AUTOFS_MAP_OP_DEL
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek};
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek
/* ====== Utility functions ====== */
static const char *
get_autofs_map_name(struct sysdb_attrs *map, struct sdap_options *opts)
{
errno_t ret;
struct ldb_message_element *el;
ret = sysdb_attrs_get_el(map,
opts->autofs_mobject_map[SDAP_AT_AUTOFS_MAP_NAME].sys_name,
&el);
if (ret) return NULL;
if (el->num_values == 0) return NULL;
return (const char *)el->values[0].data;
}
static const char *
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[attr].sys_name,
&el);
if (ret) 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
add_autofs_entry(struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
const char *map,
struct sdap_options *opts,
struct sysdb_attrs *entry)
{
const char *key;
const char *value;
key = get_autofs_entry_key(entry, opts);
if (!key) {
DEBUG(SSSDBG_OP_FAILURE, ("Could not get autofs entry key\n"));
return EINVAL;
}
value = get_autofs_entry_value(entry, opts);
if (!value) {
DEBUG(SSSDBG_OP_FAILURE, ("Could not get autofs entry value\n"));
return EINVAL;
}
return sysdb_save_autofsentry(sysdb, domain, map, key, value, NULL);
}
static errno_t
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)
{
hash_key_t key;
hash_value_t value;
size_t i;
int hret;
errno_t ret;
struct sysdb_attrs *entry;
if (!add_dn_list) {
return EOK;
}
for (i=0; add_dn_list[i]; i++) {
key.type = HASH_KEY_STRING;
key.str = (char *) add_dn_list[i];
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;
}
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;
}
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]));
}
DEBUG(SSSDBG_TRACE_INTERNAL, ("All entries saved\n"));
return EOK;
}
static errno_t
del_autofs_entries(struct sysdb_ctx *sysdb,
struct sdap_options *opts,
const char *map,
char **del_dn_list)
{
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
save_autofs_map(struct sysdb_ctx *sysdb,
struct sss_domain_info *dom,
struct sdap_options *opts,
struct sysdb_attrs *map)
{
const char *mapname;
errno_t ret;
time_t now;
mapname = get_autofs_map_name(map, opts);
if (!mapname) return EINVAL;
now = time(NULL);
ret = sysdb_save_autofsmap(sysdb, dom, mapname, mapname,
NULL, dom->autofsmap_timeout, now);
if (ret != EOK) {
return ret;
}
return EOK;
}
struct automntmaps_process_members_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
struct sss_domain_info *dom;
int timeout;
struct sysdb_ctx *sysdb;
const char *orig_dn;
char *base_filter;
char *filter;
const char **attrs;
size_t base_iter;
struct sdap_search_base **search_bases;
struct sysdb_attrs *map;
struct sysdb_attrs **entries;
size_t entries_count;
};
static void
automntmaps_process_members_done(struct tevent_req *subreq);
static errno_t
automntmaps_process_members_next_base(struct tevent_req *req);
static struct tevent_req *
automntmaps_process_members_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct sdap_options *opts,
struct sdap_handle *sh,
struct sss_domain_info *dom,
struct sdap_search_base **search_bases,
int timeout,
struct sysdb_ctx *sysdb,
struct sysdb_attrs *map)
{
errno_t ret;
struct tevent_req *req;
struct automntmaps_process_members_state *state;
req = tevent_req_create(mem_ctx, &state,
struct automntmaps_process_members_state);
if (!req) return NULL;
state->ev = ev;
state->opts = opts;
state->dom = dom;
state->sh = sh;
state->sysdb = sysdb;
state->timeout = timeout;
state->base_iter = 0;
state->map = map;
state->search_bases = search_bases;
state->base_filter = talloc_asprintf(state, "(&(%s=*)(objectclass=%s))",
opts->autofs_entry_map[SDAP_AT_AUTOFS_ENTRY_KEY].name,
opts->autofs_entry_map[SDAP_OC_AUTOFS_ENTRY].name);
if (!state->base_filter) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to build filter\n"));
ret = ENOMEM;
goto immediate;
}
ret = build_attrs_from_map(state, opts->autofs_entry_map,
SDAP_OPTS_AUTOFS_ENTRY, NULL,
&state->attrs, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to build attributes from map\n"));
ret = ENOMEM;
goto immediate;
}
ret = sysdb_attrs_get_string(state->map, SYSDB_ORIG_DN, &state->orig_dn);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get originalDN\n"));
goto immediate;
}
DEBUG(SSSDBG_TRACE_FUNC,
("Examining autofs map [%s]\n", state->orig_dn));
ret = automntmaps_process_members_next_base(req);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("search failed [%d]: %s\n", ret, strerror(ret)));
goto immediate;
}
return req;
immediate:
if (ret != EOK) {
tevent_req_error(req, ret);
} else {
tevent_req_done(req);
}
tevent_req_post(req, ev);
return req;
}
static errno_t
automntmaps_process_members_next_base(struct tevent_req *req)
{
struct tevent_req *subreq;
struct automntmaps_process_members_state *state =
tevent_req_data(req, struct automntmaps_process_members_state);
talloc_zfree(state->filter);
state->filter = sdap_get_id_specific_filter(state,
state->base_filter,
state->search_bases[state->base_iter]->filter);
if (!state->filter) {
return ENOMEM;
}
DEBUG(SSSDBG_TRACE_FUNC,
("Searching for automount map entries with base [%s]\n",
state->search_bases[state->base_iter]->basedn));
subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
state->orig_dn,
state->search_bases[state->base_iter]->scope,
state->filter, state->attrs,
state->opts->autofs_entry_map,
SDAP_OPTS_AUTOFS_ENTRY,
state->timeout, true);
if (!subreq) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot start search for entries\n"));
return EIO;
}
tevent_req_set_callback(subreq, automntmaps_process_members_done, req);
return EOK;
}
static void
automntmaps_process_members_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct automntmaps_process_members_state *state =
tevent_req_data(req, struct automntmaps_process_members_state);
errno_t ret;
struct sysdb_attrs **entries;
size_t entries_count, i;
ret = sdap_get_generic_recv(subreq, state,
&entries_count, &entries);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
return;
}
if (entries_count > 0) {
state->entries = talloc_realloc(state, state->entries,
struct sysdb_attrs *,
state->entries_count + entries_count + 1);
if (state->entries == NULL) {
tevent_req_error(req, ENOMEM);
return;
}
for (i=0; i < entries_count; i++) {
state->entries[state->entries_count + i] =
talloc_steal(state->entries, entries[i]);
}
state->entries_count += entries_count;
state->entries[state->entries_count] = NULL;
}
state->base_iter++;
if (state->search_bases[state->base_iter]) {
ret = automntmaps_process_members_next_base(req);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
}
DEBUG(SSSDBG_TRACE_INTERNAL, ("No more search bases to try\n"));
DEBUG(SSSDBG_TRACE_FUNC,
("Search for autofs entries, returned %d results.\n",
state->entries_count));
tevent_req_done(req);
return;
}
static errno_t
automntmaps_process_members_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *entries_count,
struct sysdb_attrs ***entries)
{
struct automntmaps_process_members_state *state;
state = tevent_req_data(req, struct automntmaps_process_members_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
if (entries_count) {
*entries_count = state->entries_count;
}
if (entries) {
*entries = talloc_steal(mem_ctx, state->entries);
}
return EOK;
}
struct sdap_get_automntmap_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
struct sss_domain_info *dom;
struct sysdb_ctx *sysdb;
const char **attrs;
const char *base_filter;
char *filter;
int timeout;
char *higher_timestamp;
struct sysdb_attrs **map;
size_t count;
struct sysdb_attrs **entries;
size_t entries_count;
size_t base_iter;
struct sdap_search_base **search_bases;
};
static errno_t
sdap_get_automntmap_next_base(struct tevent_req *req);
static void
sdap_get_automntmap_process(struct tevent_req *subreq);
static struct tevent_req *
sdap_get_automntmap_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct sss_domain_info *dom,
struct sysdb_ctx *sysdb,
struct sdap_options *opts,
struct sdap_search_base **search_bases,
struct sdap_handle *sh,
const char **attrs,
const char *filter,
int timeout)
{
errno_t ret;
struct tevent_req *req;
struct sdap_get_automntmap_state *state;
req = tevent_req_create(memctx, &state, struct sdap_get_automntmap_state);
if (!req) return NULL;
state->ev = ev;
state->opts = opts;
state->dom = dom;
state->sh = sh;
state->sysdb = sysdb;
state->attrs = attrs;
state->higher_timestamp = NULL;
state->map = NULL;
state->count = 0;
state->timeout = timeout;
state->base_filter = filter;
state->base_iter = 0;
state->search_bases = search_bases;
ret = sdap_get_automntmap_next_base(req);
if (ret != EOK) {
tevent_req_error(req, ret);
tevent_req_post(req, state->ev);
}
return req;
}
static errno_t
sdap_get_automntmap_next_base(struct tevent_req *req)
{
struct tevent_req *subreq;
struct sdap_get_automntmap_state *state;
state = tevent_req_data(req, struct sdap_get_automntmap_state);
talloc_zfree(state->filter);
state->filter = sdap_get_id_specific_filter(state,
state->base_filter,
state->search_bases[state->base_iter]->filter);
if (!state->filter) {
return ENOMEM;
}
DEBUG(SSSDBG_TRACE_FUNC,
("Searching for automount maps with base [%s]\n",
state->search_bases[state->base_iter]->basedn));
subreq = sdap_get_generic_send(
state, state->ev, state->opts, state->sh,
state->search_bases[state->base_iter]->basedn,
state->search_bases[state->base_iter]->scope,
state->filter, state->attrs,
state->opts->autofs_mobject_map, SDAP_OPTS_AUTOFS_MAP,
state->timeout,
false);
if (!subreq) {
return EIO;
}
tevent_req_set_callback(subreq, sdap_get_automntmap_process, req);
return EOK;
}
static void
sdap_get_automntmap_done(struct tevent_req *subreq);
static void
sdap_get_automntmap_process(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct sdap_get_automntmap_state *state = tevent_req_data(req,
struct sdap_get_automntmap_state);
errno_t ret;
ret = sdap_get_generic_recv(subreq, state,
&state->count, &state->map);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
return;
}
DEBUG(SSSDBG_TRACE_FUNC,
("Search for autofs maps, returned %d results.\n", state->count));
if (state->count == 0) {
/* No maps found in this search */
state->base_iter++;
if (state->search_bases[state->base_iter]) {
/* There are more search bases to try */
ret = sdap_get_automntmap_next_base(req);
if (ret != EOK) {
tevent_req_error(req, ENOENT);
}
return;
}
tevent_req_error(req, ENOENT);
return;
} else if (state->count > 1) {
DEBUG(SSSDBG_OP_FAILURE,
("The search yielded more than one autofs map\n"));
tevent_req_error(req, EIO);
return;
}
DEBUG(SSSDBG_TRACE_INTERNAL, ("Processing autofs maps\n"));
subreq = automntmaps_process_members_send(state, state->ev, state->opts,
state->sh, state->dom,
state->search_bases,
state->timeout, state->sysdb,
state->map[0]);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
}
tevent_req_set_callback(subreq, sdap_get_automntmap_done, req);
return;
}
static void
sdap_get_automntmap_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct sdap_get_automntmap_state *state = tevent_req_data(req,
struct sdap_get_automntmap_state);
errno_t ret;
ret = automntmaps_process_members_recv(subreq, state, &state->entries_count,
&state->entries);
talloc_zfree(subreq);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
DEBUG(SSSDBG_TRACE_FUNC, ("automount map members received\n"));
tevent_req_done(req);
return;
}
static errno_t
sdap_get_automntmap_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
struct sysdb_attrs **map,
size_t *entries_count,
struct sysdb_attrs ***entries)
{
struct sdap_get_automntmap_state *state = tevent_req_data(req,
struct sdap_get_automntmap_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
if (map) {
*map = talloc_steal(mem_ctx, state->map[0]);
}
if (entries_count) {
*entries_count = state->entries_count;
}
if (entries) {
*entries = talloc_steal(mem_ctx, state->entries);
}
return EOK;
}
struct sdap_autofs_setautomntent_state {
char *filter;
const char **attrs;
struct sdap_options *opts;
struct sdap_handle *sh;
struct sysdb_ctx *sysdb;
struct sdap_id_op *sdap_op;
struct sss_domain_info *dom;
const char *mapname;
struct sysdb_attrs *map;
struct sysdb_attrs **entries;
size_t entries_count;
int dp_error;
};
static void
sdap_autofs_setautomntent_done(struct tevent_req *subreq);
struct tevent_req *
sdap_autofs_setautomntent_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct sss_domain_info *dom,
struct sysdb_ctx *sysdb,
struct sdap_handle *sh,
struct sdap_id_op *op,
struct sdap_options *opts,
const char *mapname)
{
struct tevent_req *req;
struct tevent_req *subreq;
struct sdap_autofs_setautomntent_state *state;
char *clean_mapname;
errno_t ret;
req = tevent_req_create(memctx, &state,
struct sdap_autofs_setautomntent_state);
if (!req) return NULL;
if (!mapname) {
DEBUG(SSSDBG_CRIT_FAILURE, ("No map name given\n"));
ret = EINVAL;
goto fail;
}
state->sh = sh;
state->sysdb = sysdb;
state->opts = opts;
state->sdap_op = op;
state->dom = dom;
state->mapname = mapname;
ret = sss_filter_sanitize(state, mapname, &clean_mapname);
if (ret != EOK) {
goto fail;
}
state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
state->opts->autofs_mobject_map[SDAP_AT_AUTOFS_MAP_NAME].name,
clean_mapname,
state->opts->autofs_mobject_map[SDAP_OC_AUTOFS_MAP].name);
if (!state->filter) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to build filter\n"));
ret = ENOMEM;
goto fail;
}
talloc_free(clean_mapname);
ret = build_attrs_from_map(state, state->opts->autofs_mobject_map,
SDAP_OPTS_AUTOFS_MAP, NULL,
&state->attrs, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to build attributes from map\n"));
ret = ENOMEM;
goto fail;
}
subreq = sdap_get_automntmap_send(state, ev, dom,
sysdb, state->opts,
state->opts->autofs_search_bases,
state->sh,
state->attrs, state->filter,
dp_opt_get_int(state->opts->basic,
SDAP_SEARCH_TIMEOUT));
if (!subreq) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Out of memory\n"));
ret = ENOMEM;
goto fail;
}
tevent_req_set_callback(subreq, sdap_autofs_setautomntent_done, req);
return req;
fail:
tevent_req_error(req, ret);
tevent_req_post(req, ev);
return req;
}
static errno_t
sdap_autofs_setautomntent_save(struct tevent_req *req);
static void
sdap_autofs_setautomntent_done(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct sdap_autofs_setautomntent_state *state = tevent_req_data(req,
struct sdap_autofs_setautomntent_state);
ret = sdap_get_automntmap_recv(subreq, state, &state->map,
&state->entries_count, &state->entries);
talloc_zfree(subreq);
if (ret != EOK) {
if (ret == ENOENT) {
DEBUG(SSSDBG_MINOR_FAILURE, ("Could not find automount map\n"));
} else {
DEBUG(SSSDBG_OP_FAILURE,
("sdap_get_automntmap_recv failed [%d]: %s\n",
ret, strerror(ret)));
}
tevent_req_error(req, ret);
return;
}
ret = sdap_autofs_setautomntent_save(req);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Could not save automount map\n"));
tevent_req_error(req, ret);
return;
}
state->dp_error = DP_ERR_OK;
tevent_req_done(req);
return;
}
static errno_t
sdap_autofs_setautomntent_save(struct tevent_req *req)
{
struct sdap_autofs_setautomntent_state *state = tevent_req_data(req,
struct sdap_autofs_setautomntent_state);
errno_t ret, tret;
bool in_transaction = false;
TALLOC_CTX *tmp_ctx;
struct ldb_message **entries = NULL;
size_t count;
const char *key;
const char *val;
char **sysdb_entrylist;
char **ldap_entrylist;
char **add_entries;
char **del_entries;
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
* in the sysdb either.
*/
ldap_entrylist = NULL;
} else {
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,
state->dom, state->mapname,
&count, &entries);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_OP_FAILURE,
("cache lookup for the map failed [%d]: %s\n",
ret, strerror(ret)));
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;
} else {
sysdb_entrylist = talloc_array(state, char *, count+1);
if (!sysdb_entrylist) {
ret = ENOMEM;
goto done;
}
/* Get a list of the map members by DN */
for (i=0; i < count; i++) {
sysdb_entrylist[i] = talloc_strdup(sysdb_entrylist,
ldb_dn_get_linearized(entries[i]->dn));
if (!sysdb_entrylist[i]) {
ret = ENOMEM;
goto done;
}
}
sysdb_entrylist[count] = NULL;
}
/* Find the differences between the sysdb and LDAP lists
* Entries in the sysdb only must be removed.
*/
ret = diff_string_lists(tmp_ctx, ldap_entrylist, sysdb_entrylist,
&add_entries, &del_entries, NULL);
if (ret != EOK) goto done;
ret = sysdb_transaction_start(state->sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Cannot start sysdb transaction [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
in_transaction = true;
/* Save the map itself */
ret = save_autofs_map(state->sysdb, state->dom, state->opts, state->map);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Cannot save autofs map entry [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
/* Create entries that don't exist yet */
if (add_entries && add_entries[0]) {
ret = save_autofs_entries(state->sysdb, state->dom, state->opts,
state->mapname, add_entries,
entry_hash);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Cannot save autofs entries [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
}
/* Delete entries that don't exist anymore */
if (del_entries && del_entries[0]) {
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",
ret, strerror(ret)));
goto done;
}
}
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Cannot commit sysdb transaction [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
in_transaction = false;
ret = EOK;
done:
if (in_transaction) {
tret = sysdb_transaction_cancel(state->sysdb);
if (tret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Cannot cancel sysdb transaction [%d]: %s\n",
ret, strerror(ret)));
}
}
talloc_zfree(tmp_ctx);
return ret;
}
errno_t
sdap_autofs_setautomntent_recv(struct tevent_req *req)
{
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}