sdap_async_sudo.c revision cad751beaa12e34e15565bc413442b1e80ac0c29
e1e8390280254f7f0580d701e583f670643d4f3fnilgun/*
e1e8390280254f7f0580d701e583f670643d4f3fnilgun SSSD
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun Async LDAP Helper routines for sudo
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun Authors:
e1e8390280254f7f0580d701e583f670643d4f3fnilgun Pavel Březina <pbrezina@redhat.com>
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc
e1e8390280254f7f0580d701e583f670643d4f3fnilgun Copyright (C) 2012 Red Hat
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen This program is free software; you can redistribute it and/or modify
2e545ce2450a9953665f701bb05350f0d3f26275nd it under the terms of the GNU General Public License as published by
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen the Free Software Foundation; either version 3 of the License, or
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen (at your option) any later version.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun This program is distributed in the hope that it will be useful,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun but WITHOUT ANY WARRANTY; without even the implied warranty of
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3f08db06526d6901aa08c110b5bc7dde6bc39905nd GNU General Public License for more details.
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun You should have received a copy of the GNU General Public License
e1e8390280254f7f0580d701e583f670643d4f3fnilgun along with this program. If not, see <http://www.gnu.org/licenses/>.
3f08db06526d6901aa08c110b5bc7dde6bc39905nd*/
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include <errno.h>
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include <talloc.h>
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include <tevent.h>
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include "providers/dp_backend.h"
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung#include "providers/ldap/ldap_common.h"
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include "providers/ldap/sdap.h"
f0fa55ff14fa0bf8fd72d989f6625de6dc3260c8igalic#include "providers/ldap/sdap_ops.h"
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include "providers/ldap/sdap_sudo.h"
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include "providers/ldap/sdap_sudo_shared.h"
e1e8390280254f7f0580d701e583f670643d4f3fnilgun#include "db/sysdb_sudo.h"
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstruct sdap_sudo_load_sudoers_state {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct sysdb_attrs **rules;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun size_t num_rules;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun};
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic void sdap_sudo_load_sudoers_done(struct tevent_req *subreq);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic struct tevent_req *
e1e8390280254f7f0580d701e583f670643d4f3fnilgunsdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct tevent_context *ev,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct sdap_options *opts,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct sdap_handle *sh,
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun const char *ldap_filter)
e1e8390280254f7f0580d701e583f670643d4f3fnilgun{
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct tevent_req *req;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct tevent_req *subreq;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct sdap_sudo_load_sudoers_state *state;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct sdap_search_base **sb;
2704de98885368683621b01c8f8f4e4b01557611takashi int ret;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun req = tevent_req_create(mem_ctx, &state,
b9f522ae1c0ed2bf3fc4444245bf28b2e2449a65nd struct sdap_sudo_load_sudoers_state);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun if (!req) {
c38e2a97e43fc69b22f6b03c6d2f60e3bd705f89sf return NULL;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun }
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun state->rules = NULL;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun state->num_rules = 0;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun sb = opts->sdom->sudo_search_bases;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun if (sb == NULL) {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun DEBUG(SSSDBG_CRIT_FAILURE,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun "SUDOERS lookup request without a search base\n");
e1e8390280254f7f0580d701e583f670643d4f3fnilgun ret = EINVAL;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun goto immediately;
2704de98885368683621b01c8f8f4e4b01557611takashi }
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun DEBUG(SSSDBG_TRACE_FUNC, "About to fetch sudo rules\n");
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun subreq = sdap_search_bases_send(state, ev, opts, sh, sb,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun opts->sudorule_map, true, 0,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun ldap_filter, NULL);
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun if (subreq == NULL) {
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun ret = ENOMEM;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh goto immediately;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun }
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_done, req);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun ret = EOK;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgunimmediately:
e1e8390280254f7f0580d701e583f670643d4f3fnilgun if (ret != EOK) {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun tevent_req_error(req, ret);
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun tevent_req_post(req, ev);
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun }
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun return req;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun}
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic void sdap_sudo_load_sudoers_done(struct tevent_req *subreq)
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun{
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct tevent_req *req;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct sdap_sudo_load_sudoers_state *state;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun errno_t ret;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun req = tevent_req_callback_data(subreq, struct tevent_req);
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun ret = sdap_search_bases_recv(subreq, state, &state->num_rules,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun &state->rules);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun talloc_zfree(subreq);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun if (ret != EOK) {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun tevent_req_error(req, ret);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun return;
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun }
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun DEBUG(SSSDBG_IMPORTANT_INFO, "Received %zu sudo rules\n",
e1e8390280254f7f0580d701e583f670643d4f3fnilgun state->num_rules);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun tevent_req_done(req);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun return;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun}
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgunstatic int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun TALLOC_CTX *mem_ctx,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun size_t *num_rules,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct sysdb_attrs ***rules)
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun{
e1e8390280254f7f0580d701e583f670643d4f3fnilgun struct sdap_sudo_load_sudoers_state *state;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun TEVENT_REQ_RETURN_ON_ERROR(req);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun *num_rules = state->num_rules;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun *rules = talloc_steal(mem_ctx, state->rules);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun return EOK;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun}
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgunstatic char *sdap_sudo_build_host_filter(TALLOC_CTX *mem_ctx,
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun struct sdap_attr_map *map,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun char **hostnames,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun char **ip_addr,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun bool netgroups,
e1e8390280254f7f0580d701e583f670643d4f3fnilgun bool regexp)
e1e8390280254f7f0580d701e583f670643d4f3fnilgun{
e1e8390280254f7f0580d701e583f670643d4f3fnilgun TALLOC_CTX *tmp_ctx = NULL;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun char *filter = NULL;
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun int i;
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun tmp_ctx = talloc_new(NULL);
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun if (tmp_ctx == NULL) {
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
2704de98885368683621b01c8f8f4e4b01557611takashi return NULL;
2704de98885368683621b01c8f8f4e4b01557611takashi }
2704de98885368683621b01c8f8f4e4b01557611takashi
2704de98885368683621b01c8f8f4e4b01557611takashi filter = talloc_strdup(tmp_ctx, "(|");
2704de98885368683621b01c8f8f4e4b01557611takashi if (filter == NULL) {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun goto done;
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun }
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun /* sudoHost is not specified */
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun filter = talloc_asprintf_append_buffer(filter, "(!(%s=*))",
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun map[SDAP_AT_SUDO_HOST].name);
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun if (filter == NULL) {
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun goto done;
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun }
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun /* ALL */
e0cfea1f5d38eeaa8fdf7c197c3c1eb31148e191nilgun filter = talloc_asprintf_append_buffer(filter, "(%s=ALL)",
e1e8390280254f7f0580d701e583f670643d4f3fnilgun map[SDAP_AT_SUDO_HOST].name);
e1e8390280254f7f0580d701e583f670643d4f3fnilgun if (filter == NULL) {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun goto done;
e1e8390280254f7f0580d701e583f670643d4f3fnilgun }
e1e8390280254f7f0580d701e583f670643d4f3fnilgun
e1e8390280254f7f0580d701e583f670643d4f3fnilgun /* hostnames */
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung if (hostnames != NULL) {
727872d18412fc021f03969b8641810d8896820bhumbedooh for (i = 0; hostnames[i] != NULL; i++) {
0d0ba3a410038e179b695446bb149cce6264e0abnd filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
727872d18412fc021f03969b8641810d8896820bhumbedooh map[SDAP_AT_SUDO_HOST].name,
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh hostnames[i]);
0d0ba3a410038e179b695446bb149cce6264e0abnd if (filter == NULL) {
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh goto done;
727872d18412fc021f03969b8641810d8896820bhumbedooh }
0d0ba3a410038e179b695446bb149cce6264e0abnd }
0d0ba3a410038e179b695446bb149cce6264e0abnd }
0d0ba3a410038e179b695446bb149cce6264e0abnd
ac082aefa89416cbdc9a1836eaf3bed9698201c8humbedooh /* ip addresses and networks */
0d0ba3a410038e179b695446bb149cce6264e0abnd if (ip_addr != NULL) {
0d0ba3a410038e179b695446bb149cce6264e0abnd for (i = 0; ip_addr[i] != NULL; i++) {
0d0ba3a410038e179b695446bb149cce6264e0abnd filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
727872d18412fc021f03969b8641810d8896820bhumbedooh map[SDAP_AT_SUDO_HOST].name,
0d0ba3a410038e179b695446bb149cce6264e0abnd ip_addr[i]);
0d0ba3a410038e179b695446bb149cce6264e0abnd if (filter == NULL) {
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh goto done;
205f749042ed530040a4f0080dbcb47ceae8a374rjung }
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen }
0d0ba3a410038e179b695446bb149cce6264e0abnd }
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd /* sudoHost contains netgroup - will be filtered more by sudo */
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd if (netgroups) {
e1e8390280254f7f0580d701e583f670643d4f3fnilgun filter = talloc_asprintf_append_buffer(filter, SDAP_SUDO_FILTER_NETGROUP,
map[SDAP_AT_SUDO_HOST].name,
"*");
if (filter == NULL) {
goto done;
}
}
/* sudoHost contains regexp - will be filtered more by sudo */
/* from sudo match.c :
* #define has_meta(s) (strpbrk(s, "\\?*[]") != NULL)
*/
if (regexp) {
filter = talloc_asprintf_append_buffer(filter,
"(|(%s=*\\\\*)(%s=*?*)(%s=*\\2A*)"
"(%s=*[*]*))",
map[SDAP_AT_SUDO_HOST].name,
map[SDAP_AT_SUDO_HOST].name,
map[SDAP_AT_SUDO_HOST].name,
map[SDAP_AT_SUDO_HOST].name);
if (filter == NULL) {
goto done;
}
}
filter = talloc_strdup_append_buffer(filter, ")");
if (filter == NULL) {
goto done;
}
talloc_steal(mem_ctx, filter);
done:
talloc_free(tmp_ctx);
return filter;
}
static char *sdap_sudo_get_filter(TALLOC_CTX *mem_ctx,
struct sdap_attr_map *map,
struct sdap_sudo_ctx *sudo_ctx,
const char *rule_filter)
{
TALLOC_CTX *tmp_ctx = NULL;
char *host_filter = NULL;
char *filter = NULL;
if (!sudo_ctx->use_host_filter) {
return talloc_strdup(mem_ctx, rule_filter);
}
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
return NULL;
}
host_filter = sdap_sudo_build_host_filter(tmp_ctx, map,
sudo_ctx->hostnames,
sudo_ctx->ip_addr,
sudo_ctx->include_netgroups,
sudo_ctx->include_regexp);
if (host_filter == NULL) {
goto done;
}
filter = sdap_combine_filters(tmp_ctx, rule_filter, host_filter);
if (filter == NULL) {
goto done;
}
talloc_steal(mem_ctx, filter);
done:
talloc_free(tmp_ctx);
return filter;
}
struct sdap_sudo_refresh_state {
struct sdap_sudo_ctx *sudo_ctx;
struct tevent_context *ev;
struct sdap_server_opts *srv_opts;
struct sdap_options *opts;
struct sdap_id_op *sdap_op;
struct sysdb_ctx *sysdb;
struct sss_domain_info *domain;
const char *search_filter;
const char *delete_filter;
int dp_error;
size_t num_rules;
};
static errno_t sdap_sudo_refresh_retry(struct tevent_req *req);
static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq);
static void sdap_sudo_refresh_hostinfo_done(struct tevent_req *subreq);
static errno_t sdap_sudo_refresh_sudoers(struct tevent_req *req);
static void sdap_sudo_refresh_done(struct tevent_req *subreq);
struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx,
struct sdap_sudo_ctx *sudo_ctx,
const char *search_filter,
const char *delete_filter)
{
struct tevent_req *req;
struct sdap_sudo_refresh_state *state;
struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx;
int ret;
req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_refresh_state);
if (!req) {
return NULL;
}
/* if we don't have a search filter, this request is meaningless */
if (search_filter == NULL) {
ret = EINVAL;
goto immediately;
}
state->sudo_ctx = sudo_ctx;
state->ev = id_ctx->be->ev;
state->opts = id_ctx->opts;
state->domain = id_ctx->be->domain;
state->sysdb = id_ctx->be->domain->sysdb;
state->dp_error = DP_ERR_FATAL;
state->sdap_op = sdap_id_op_create(state, id_ctx->conn->conn_cache);
if (!state->sdap_op) {
DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create() failed\n");
ret = ENOMEM;
goto immediately;
}
state->search_filter = talloc_strdup(state, search_filter);
if (state->search_filter == NULL) {
ret = ENOMEM;
goto immediately;
}
state->delete_filter = talloc_strdup(state, delete_filter);
if (delete_filter != NULL && state->delete_filter == NULL) {
ret = ENOMEM;
goto immediately;
}
ret = sdap_sudo_refresh_retry(req);
if (ret == EAGAIN) {
/* asynchronous processing */
return req;
}
immediately:
if (ret == EOK) {
tevent_req_done(req);
} else {
tevent_req_error(req, ret);
}
tevent_req_post(req, id_ctx->be->ev);
return req;
}
static errno_t sdap_sudo_refresh_retry(struct tevent_req *req)
{
struct sdap_sudo_refresh_state *state;
struct tevent_req *subreq;
int ret;
state = tevent_req_data(req, struct sdap_sudo_refresh_state);
subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
if (subreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "sdap_id_op_connect_send() failed: "
"%d(%s)\n", ret, strerror(ret));
return ret;
}
tevent_req_set_callback(subreq, sdap_sudo_refresh_connect_done, req);
return EAGAIN;
}
static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct sdap_sudo_refresh_state *state;
int dp_error;
int ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct sdap_sudo_refresh_state);
ret = sdap_id_op_connect_recv(subreq, &dp_error);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "SUDO LDAP connection failed "
"[%d]: %s\n", ret, strerror(ret));
state->dp_error = dp_error;
tevent_req_error(req, ret);
return;
}
DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n");
/* Obtain srv_opts here in case of first connection. */
state->srv_opts = state->sudo_ctx->id_ctx->srv_opts;
/* Renew host information if needed. */
if (state->sudo_ctx->run_hostinfo) {
subreq = sdap_sudo_get_hostinfo_send(state, state->opts,
state->sudo_ctx->id_ctx->be);
if (subreq == NULL) {
state->dp_error = DP_ERR_FATAL;
tevent_req_error(req, ENOMEM);
return;
}
tevent_req_set_callback(subreq, sdap_sudo_refresh_hostinfo_done, req);
state->sudo_ctx->run_hostinfo = false;
return;
}
ret = sdap_sudo_refresh_sudoers(req);
if (ret != EAGAIN) {
state->dp_error = DP_ERR_FATAL;
tevent_req_error(req, ret);
}
}
static void sdap_sudo_refresh_hostinfo_done(struct tevent_req *subreq)
{
struct sdap_sudo_ctx *sudo_ctx;
struct sdap_sudo_refresh_state *state;
struct tevent_req *req;
errno_t ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct sdap_sudo_refresh_state);
sudo_ctx = state->sudo_ctx;
ret = sdap_sudo_get_hostinfo_recv(sudo_ctx, subreq, &sudo_ctx->hostnames,
&sudo_ctx->ip_addr);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve host information, "
"host filter will be disabled [%d]: %s\n",
ret, sss_strerror(ret));
sudo_ctx->use_host_filter = false;
} else {
sudo_ctx->use_host_filter = true;
}
ret = sdap_sudo_refresh_sudoers(req);
if (ret != EAGAIN) {
state->dp_error = DP_ERR_FATAL;
tevent_req_error(req, ret);
}
}
static errno_t sdap_sudo_refresh_sudoers(struct tevent_req *req)
{
struct sdap_sudo_refresh_state *state;
struct tevent_req *subreq;
char *filter;
state = tevent_req_data(req, struct sdap_sudo_refresh_state);
/* We are connected. Host information may have changed during transition
* from offline to online state. At this point we can combine search
* and host filter. */
filter = sdap_sudo_get_filter(state, state->opts->sudorule_map,
state->sudo_ctx, state->search_filter);
if (filter == NULL) {
return ENOMEM;
}
subreq = sdap_sudo_load_sudoers_send(state, state->ev,
state->opts,
sdap_id_op_handle(state->sdap_op),
filter);
if (subreq == NULL) {
talloc_free(filter);
return ENOMEM;
}
tevent_req_set_callback(subreq, sdap_sudo_refresh_done, req);
return EAGAIN;
}
static void sdap_sudo_refresh_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct sdap_sudo_refresh_state *state;
struct sysdb_attrs **rules = NULL;
size_t rules_count = 0;
char *usn = NULL;
int dp_error;
int ret;
errno_t sret;
bool in_transaction = false;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct sdap_sudo_refresh_state);
ret = sdap_sudo_load_sudoers_recv(subreq, state, &rules_count, &rules);
talloc_zfree(subreq);
ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
if (dp_error == DP_ERR_OK && ret != EOK) {
/* retry */
ret = sdap_sudo_refresh_retry(req);
if (ret != EOK) {
tevent_req_error(req, ret);
}
return;
} else if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
DEBUG(SSSDBG_TRACE_FUNC, "Received %zu rules\n", rules_count);
/* start transaction */
ret = sysdb_transaction_start(state->sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
goto done;
}
in_transaction = true;
/* purge cache */
ret = sysdb_sudo_purge(state->domain, state->delete_filter,
rules, rules_count);
if (ret != EOK) {
goto done;
}
/* store rules */
ret = sysdb_sudo_store(state->domain, rules, rules_count);
if (ret != EOK) {
goto done;
}
/* commit transaction */
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
goto done;
}
in_transaction = false;
DEBUG(SSSDBG_TRACE_FUNC, "Sudoers is successfuly stored in cache\n");
/* remember new usn */
ret = sysdb_get_highest_usn(state, rules, rules_count, &usn);
if (ret == EOK) {
sdap_sudo_set_usn(state->srv_opts, usn);
} else {
DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get highest USN [%d]: %s\n",
ret, sss_strerror(ret));
}
ret = EOK;
state->num_rules = rules_count;
done:
if (in_transaction) {
sret = sysdb_transaction_cancel(state->sysdb);
if (sret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Could not cancel transaction\n");
}
}
state->dp_error = dp_error;
if (ret == EOK) {
tevent_req_done(req);
} else {
tevent_req_error(req, ret);
}
}
int sdap_sudo_refresh_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
int *dp_error,
size_t *num_rules)
{
struct sdap_sudo_refresh_state *state;
state = tevent_req_data(req, struct sdap_sudo_refresh_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
*dp_error = state->dp_error;
if (num_rules != NULL) {
*num_rules = state->num_rules;
}
return EOK;
}