sdap_async_sudo.c revision 15ebeedaad83cc5dcf896cfcdea850227fdc46b5
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke/*
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke SSSD
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke Async LDAP Helper routines for sudo
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke Authors:
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke Pavel Březina <pbrezina@redhat.com>
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke Copyright (C) 2012 Red Hat
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke This program is free software; you can redistribute it and/or modify
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke it under the terms of the GNU General Public License as published by
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke the Free Software Foundation; either version 3 of the License, or
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke (at your option) any later version.
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke
cf04ba46b9eb495d334466e24e082e391055ca7bDominik Luecke This program is distributed in the hope that it will be useful,
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke but WITHOUT ANY WARRANTY; without even the implied warranty of
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke GNU General Public License for more details.
2af38fde95f93562f2124ec615fba0e509c8202eDominik Luecke
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke You should have received a copy of the GNU General Public License
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke along with this program. If not, see <http://www.gnu.org/licenses/>.
59917a4f0a6a20f5a20bcab1f2a0a0774db56807Dominik Luecke*/
59917a4f0a6a20f5a20bcab1f2a0a0774db56807Dominik Luecke
59917a4f0a6a20f5a20bcab1f2a0a0774db56807Dominik Luecke#include <errno.h>
59917a4f0a6a20f5a20bcab1f2a0a0774db56807Dominik Luecke#include <talloc.h>
59917a4f0a6a20f5a20bcab1f2a0a0774db56807Dominik Luecke#include <tevent.h>
59917a4f0a6a20f5a20bcab1f2a0a0774db56807Dominik Luecke
59917a4f0a6a20f5a20bcab1f2a0a0774db56807Dominik Luecke#include "providers/dp_backend.h"
59917a4f0a6a20f5a20bcab1f2a0a0774db56807Dominik Luecke#include "providers/ldap/ldap_common.h"
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke#include "providers/ldap/sdap.h"
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke#include "providers/ldap/sdap_async.h"
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke#include "providers/ldap/sdap_sudo.h"
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke#include "providers/ldap/sdap_sudo_cache.h"
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke#include "db/sysdb_sudo.h"
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Lueckestruct sdap_sudo_load_sudoers_state {
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke struct tevent_context *ev;
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke struct sdap_options *opts;
cf04ba46b9eb495d334466e24e082e391055ca7bDominik Luecke struct sdap_handle *sh;
ad270004874ce1d0697fb30d7309f180553bb315Christian Maeder
cf04ba46b9eb495d334466e24e082e391055ca7bDominik Luecke int timeout;
4df63f7187b1ba16cbe5c781db187a42f2f49579Dominik Luecke const char **attrs;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke const char *filter;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke size_t base_iter;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke struct sdap_search_base **search_bases;
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke struct sysdb_attrs **rules;
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke size_t num_rules;
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke};
f90884915ff10ae83f59e709c68824de834e64f5Dominik Luecke
f90884915ff10ae83f59e709c68824de834e64f5Dominik Lueckestatic errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req);
f90884915ff10ae83f59e709c68824de834e64f5Dominik Lueckestatic void sdap_sudo_load_sudoers_done(struct tevent_req *subreq);
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Lueckestatic struct tevent_req *
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Lueckesdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke struct tevent_context *ev,
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke struct sdap_options *opts,
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke struct sdap_handle *sh,
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke const char *ldap_filter)
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke{
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke struct tevent_req *req;
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke struct sdap_sudo_load_sudoers_state *state;
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke int ret;
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke req = tevent_req_create(mem_ctx, &state,
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke struct sdap_sudo_load_sudoers_state);
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke if (!req) {
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke return NULL;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke }
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke state->ev = ev;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke state->opts = opts;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke state->sh = sh;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke state->base_iter = 0;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke state->search_bases = opts->sdom->sudo_search_bases;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke state->filter = ldap_filter;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke state->timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT);
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke state->rules = NULL;
b72a390042c19e630cf221494b60c9df2a60d187Dominik Luecke state->num_rules = 0;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke if (state->search_bases == NULL) {
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke DEBUG(SSSDBG_CRIT_FAILURE,
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke "SUDOERS lookup request without a search base\n");
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke ret = EINVAL;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke goto immediately;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke }
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke /* create attrs from map */
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke ret = build_attrs_from_map(state, opts->sudorule_map, SDAP_OPTS_SUDO,
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke NULL, &state->attrs, NULL);
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke if (ret != EOK) {
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke goto immediately;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke }
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke /* begin search */
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke ret = sdap_sudo_load_sudoers_next_base(req);
0859769b65851f4c06d6d32fac084b0f4db56c94Christian Maeder if (ret == EAGAIN) {
0859769b65851f4c06d6d32fac084b0f4db56c94Christian Maeder /* asynchronous processing */
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke return req;
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke }
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke
08056875f5f633ef432598d5245ea41c112d2178Dominik Lueckeimmediately:
08056875f5f633ef432598d5245ea41c112d2178Dominik Luecke if (ret == EOK) {
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke tevent_req_done(req);
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke } else {
fcac596b16bb10f475066c323b9b1ca44db2b755Dominik Luecke tevent_req_error(req, ret);
0859769b65851f4c06d6d32fac084b0f4db56c94Christian Maeder }
4df63f7187b1ba16cbe5c781db187a42f2f49579Dominik Luecke tevent_req_post(req, ev);
4df63f7187b1ba16cbe5c781db187a42f2f49579Dominik Luecke
b694e4b3f771a2f32042c9c505dd698bde969558Dominik Luecke return req;
}
static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req)
{
struct sdap_sudo_load_sudoers_state *state;
struct sdap_search_base *base;
struct tevent_req *subreq;
char *filter;
state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
base = state->search_bases[state->base_iter];
if (base == NULL) {
return EOK;
}
/* Combine lookup and search base filters. */
filter = sdap_get_id_specific_filter(state, state->filter, base->filter);
if (filter == NULL) {
return ENOMEM;
}
DEBUG(SSSDBG_TRACE_FUNC, "Searching for sudo rules with base [%s]\n",
base->basedn);
subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
base->basedn, base->scope, filter,
state->attrs, state->opts->sudorule_map,
SDAP_OPTS_SUDO, state->timeout, true);
if (subreq == NULL) {
return ENOMEM;
}
tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_done, req);
state->base_iter++;
return EAGAIN;
}
static void sdap_sudo_load_sudoers_done(struct tevent_req *subreq)
{
struct tevent_req *req;
struct sdap_sudo_load_sudoers_state *state;
struct sdap_search_base *search_base;
struct sysdb_attrs **attrs = NULL;
size_t count;
int ret;
size_t i;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
search_base = state->search_bases[state->base_iter - 1];
DEBUG(SSSDBG_TRACE_FUNC, "Receiving sudo rules with base [%s]\n",
search_base->basedn);
ret = sdap_get_generic_recv(subreq, state, &count, &attrs);
talloc_zfree(subreq);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
/* Add rules to result. */
if (count > 0) {
state->rules = talloc_realloc(state, state->rules,
struct sysdb_attrs *,
state->num_rules + count);
if (state->rules == NULL) {
tevent_req_error(req, ENOMEM);
return;
}
for (i = 0; i < count; i++) {
state->rules[state->num_rules + i] = talloc_steal(state->rules,
attrs[i]);
}
state->num_rules += count;
}
/* Try next search base. */
ret = sdap_sudo_load_sudoers_next_base(req);
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
return;
}
static int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *num_rules,
struct sysdb_attrs ***rules)
{
struct sdap_sudo_load_sudoers_state *state;
state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
*num_rules = state->num_rules;
*rules = talloc_steal(mem_ctx, state->rules);
return EOK;
}
static int sdap_sudo_purge_sudoers(struct sss_domain_info *dom,
const char *filter,
struct sdap_attr_map *map,
size_t rules_count,
struct sysdb_attrs **rules)
{
const char *name;
size_t i;
errno_t ret;
if (filter == NULL) {
/* removes downloaded rules from the cache */
if (rules_count == 0 || rules == NULL) {
return EOK;
}
for (i = 0; i < rules_count; i++) {
ret = sysdb_attrs_get_string(rules[i],
map[SDAP_AT_SUDO_NAME].sys_name,
&name);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Failed to retrieve rule name: [%s]\n", strerror(ret));
continue;
}
ret = sysdb_sudo_purge_byname(dom, name);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Failed to delete rule %s: [%s]\n",
name, strerror(ret));
continue;
}
}
ret = EOK;
} else {
/* purge cache by provided filter */
ret = sysdb_sudo_purge_byfilter(dom, filter);
if (ret != EOK) {
goto done;
}
}
done:
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "failed to purge sudo rules [%d]: %s\n",
ret, strerror(ret));
}
return ret;
}
static int sdap_sudo_store_sudoers(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
struct sdap_options *opts,
size_t rules_count,
struct sysdb_attrs **rules,
int cache_timeout,
time_t now,
char **_usn)
{
errno_t ret;
/* Empty sudoers? Done. */
if (rules_count == 0 || rules == NULL) {
*_usn = NULL;
return EOK;
}
ret = sdap_save_native_sudorule_list(mem_ctx, domain,
opts->sudorule_map, rules,
rules_count, cache_timeout, now,
_usn);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "failed to save sudo rules [%d]: %s\n",
ret, strerror(ret));
return ret;
}
return EOK;
}
static void sdap_sudo_set_usn(struct sdap_server_opts *srv_opts, char *usn)
{
unsigned int usn_number;
char *endptr = NULL;
if (srv_opts == NULL) {
DEBUG(SSSDBG_TRACE_FUNC, "Bug: srv_opts is NULL\n");
return;
}
if (usn == NULL) {
/* If the USN value is unknown and we don't have max_sudo_value set
* (possibly first full refresh which did not find any rule) we will
* set zero so smart refresh can pick up. */
if (srv_opts->max_sudo_value == NULL) {
srv_opts->max_sudo_value = talloc_strdup(srv_opts, "0");
if (srv_opts->max_sudo_value == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
}
return;
}
DEBUG(SSSDBG_TRACE_FUNC, "Empty USN, ignoring\n");
return;
}
talloc_zfree(srv_opts->max_sudo_value);
srv_opts->max_sudo_value = talloc_steal(srv_opts, usn);
usn_number = strtoul(usn, &endptr, 10);
if ((endptr == NULL || (*endptr == '\0' && endptr != usn))
&& (usn_number > srv_opts->last_usn)) {
srv_opts->last_usn = usn_number;
}
DEBUG(SSSDBG_FUNC_DATA, "SUDO higher USN value: [%s]\n",
srv_opts->max_sudo_value);
}
static char *sdap_sudo_build_host_filter(TALLOC_CTX *mem_ctx,
struct sdap_attr_map *map,
char **hostnames,
char **ip_addr,
bool netgroups,
bool regexp)
{
TALLOC_CTX *tmp_ctx = NULL;
char *filter = NULL;
int i;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
return NULL;
}
filter = talloc_strdup(tmp_ctx, "(|");
if (filter == NULL) {
goto done;
}
/* sudoHost is not specified */
filter = talloc_asprintf_append_buffer(filter, "(!(%s=*))",
map[SDAP_AT_SUDO_HOST].name);
if (filter == NULL) {
goto done;
}
/* ALL */
filter = talloc_asprintf_append_buffer(filter, "(%s=ALL)",
map[SDAP_AT_SUDO_HOST].name);
if (filter == NULL) {
goto done;
}
/* hostnames */
if (hostnames != NULL) {
for (i = 0; hostnames[i] != NULL; i++) {
filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
map[SDAP_AT_SUDO_HOST].name,
hostnames[i]);
if (filter == NULL) {
goto done;
}
}
}
/* ip addresses and networks */
if (ip_addr != NULL) {
for (i = 0; ip_addr[i] != NULL; i++) {
filter = talloc_asprintf_append_buffer(filter, "(%s=%s)",
map[SDAP_AT_SUDO_HOST].name,
ip_addr[i]);
if (filter == NULL) {
goto done;
}
}
}
/* sudoHost contains netgroup - will be filtered more by sudo */
if (netgroups) {
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_get_id_specific_filter(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->srv_opts = id_ctx->srv_opts;
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");
/* 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;
time_t now;
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;
}
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 = sdap_sudo_purge_sudoers(state->domain, state->delete_filter,
state->opts->sudorule_map, rules_count, rules);
if (ret != EOK) {
goto done;
}
/* store rules */
now = time(NULL);
ret = sdap_sudo_store_sudoers(state, state->domain,
state->opts, rules_count, rules,
state->domain->sudo_timeout, now, &usn);
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 */
sdap_sudo_set_usn(state->srv_opts, usn);
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;
}