sdap_sudo.c revision ca4b7b92738f3dd463914e3de5757cd98d37a983
/*
Authors:
Pavel Březina <pbrezina@redhat.com>
Copyright (C) 2011 Red Hat
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <string.h>
#include <tevent.h>
#include "providers/dp_backend.h"
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap.h"
#include "providers/ldap/sdap_async.h"
#include "providers/ldap/sdap_sudo.h"
#include "providers/ldap/sdap_sudo_cache.h"
#include "providers/ldap/sdap_sudo_timer.h"
#include "db/sysdb_sudo.h"
static void
sdap_sudo_shutdown(struct be_req *req)
{
sdap_handler_done(req, DP_ERR_OK, EOK, NULL);
}
struct bet_ops sdap_sudo_ops = {
.handler = sdap_sudo_handler,
.finalize = sdap_sudo_shutdown
};
int sdap_sudo_setup_tasks(struct sdap_id_ctx *id_ctx);
int sdap_sudo_init(struct be_ctx *be_ctx,
struct sdap_id_ctx *id_ctx,
struct bet_ops **ops,
void **pvt_data)
{
int ret;
DEBUG(SSSDBG_TRACE_INTERNAL, ("Initializing sudo LDAP back end\n"));
*ops = &sdap_sudo_ops;
*pvt_data = id_ctx;
ret = ldap_get_sudo_options(id_ctx, be_ctx->cdb,
be_ctx->conf_path, id_ctx->opts);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Cannot get SUDO options [%d]: %s\n",
ret, strerror(ret)));
return ret;
}
ret = sdap_sudo_setup_tasks(id_ctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("SUDO setup failed [%d]: %s\n",
ret, strerror(ret)));
return ret;
}
return EOK;
}
int sdap_sudo_setup_tasks(struct sdap_id_ctx *id_ctx)
{
struct sdap_sudo_refresh_ctx *refresh_ctx = NULL;
struct timeval tv;
int ret = EOK;
bool refreshed = false;
bool refresh_enabled = dp_opt_get_bool(id_ctx->opts->basic,
SDAP_SUDO_REFRESH_ENABLED);
/* set up periodical update of sudo rules */
if (refresh_enabled) {
refresh_ctx = sdap_sudo_refresh_ctx_init(id_ctx, id_ctx->be, id_ctx,
id_ctx->opts,
tevent_timeval_zero());
if (refresh_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
("sdap_sudo_refresh_ctx_init() failed!\n"));
return ENOMEM;
}
/* If this is the first startup, we need to kick off
* an refresh immediately, to close a window where
* clients requesting sudo information won't get an
* immediate reply with no entries
*/
ret = sysdb_sudo_get_refreshed(id_ctx->be->sysdb, &refreshed);
if (ret != EOK) {
return ret;
}
if (refreshed) {
/* At least one update has previously run,
* so clients will get cached data. We will delay
* starting to enumerate by 10s so we don't slow
* down the startup process if this is happening
* during system boot.
*/
tv = tevent_timeval_current_ofs(10, 0);
DEBUG(SSSDBG_FUNC_DATA, ("Delaying first refresh of SUDO rules "
"for 10 seconds\n"));
} else {
/* This is our first startup. Schedule the
* update to start immediately once we
* enter the mainloop.
*/
tv = tevent_timeval_current();
}
ret = sdap_sudo_refresh_set_timer(refresh_ctx, tv);
if (ret != EOK) {
talloc_free(refresh_ctx);
return ret;
}
}
return EOK;
}
struct sdap_sudo_load_sudoers_state {
struct tevent_context *ev;
struct sdap_sudo_ctx *sudo_ctx;
struct sdap_options *opts;
struct sdap_handle *sh;
struct sysdb_attrs **ldap_rules; /* search result will be stored here */
size_t ldap_rules_count; /* search result will be stored here */
const char **attrs;
const char *filter;
size_t base_iter;
struct sdap_search_base **search_bases;
int timeout;
};
struct sdap_sudo_refresh_state {
struct be_ctx *be_ctx;
struct be_sudo_req *sudo_req;
struct sdap_options *opts;
struct sdap_id_op *sdap_op;
struct sdap_id_conn_cache *sdap_conn_cache;
int dp_error;
int error;
};
static int sdap_sudo_connect(struct tevent_req *req);
static void sdap_sudo_connect_done(struct tevent_req *subreq);
static struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_sudo_req *sudo_req,
struct sdap_options *opts,
struct sdap_handle *sh);
static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req);
static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq);
static int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *rules_count,
struct sysdb_attrs ***rules);
static void sdap_sudo_load_sudoers_done(struct tevent_req *req);
static int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx,
struct sss_domain_info *domain,
struct be_sudo_req *sudo_req);
static int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
struct sdap_options *opts,
size_t rules_count,
struct sysdb_attrs **rules);
static const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx,
struct sdap_attr_map *map,
struct be_sudo_req *sudo_req);
static const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx,
struct sdap_attr_map *map,
const char *username,
uid_t uid,
char **groups);
static void sdap_sudo_reply(struct tevent_req *req)
{
struct be_req *be_req = NULL;
int dp_error;
int error;
int ret;
be_req = tevent_req_callback_data(req, struct be_req);
ret = sdap_sudo_refresh_recv(req, &dp_error, &error);
talloc_zfree(req);
if (ret != EOK) {
sdap_handler_done(be_req, DP_ERR_FATAL, ret, strerror(ret));
return;
}
sdap_handler_done(be_req, dp_error, error, strerror(error));
}
void sdap_sudo_handler(struct be_req *be_req)
{
struct tevent_req *req = NULL;
struct be_sudo_req *sudo_req = NULL;
struct sdap_id_ctx *id_ctx = NULL;
int ret = EOK;
id_ctx = talloc_get_type(be_req->be_ctx->bet_info[BET_SUDO].pvt_bet_data,
struct sdap_id_ctx);
sudo_req = talloc_get_type(be_req->req_data, struct be_sudo_req);
/* get user info */
if (sudo_req->username != NULL) {
ret = sysdb_get_sudo_user_info(sudo_req, sudo_req->username,
id_ctx->be->sysdb,
&sudo_req->uid, &sudo_req->groups);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to get uid and groups of %s\n",
sudo_req->username));
goto fail;
}
} else {
sudo_req->uid = 0;
sudo_req->groups = NULL;
}
req = sdap_sudo_refresh_send(be_req, id_ctx->be, sudo_req, id_ctx->opts,
id_ctx->conn_cache);
if (req == NULL) {
ret = ENOMEM;
goto fail;
}
tevent_req_set_callback(req, sdap_sudo_reply, be_req);
return;
fail:
sdap_handler_done(be_req, DP_ERR_FATAL, ret, NULL);
}
struct tevent_req *sdap_sudo_refresh_send(TALLOC_CTX *mem_ctx,
struct be_ctx *be_ctx,
struct be_sudo_req *sudo_req,
struct sdap_options *opts,
struct sdap_id_conn_cache *conn_cache)
{
struct tevent_req *req = NULL;
struct sdap_sudo_refresh_state *state = NULL;
int ret;
req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_refresh_state);
if (!req) {
return NULL;
}
state->be_ctx = be_ctx;
state->sudo_req = sudo_req;
state->opts = opts;
state->sdap_op = NULL;
state->sdap_conn_cache = conn_cache;
state->dp_error = DP_ERR_OK;
state->error = EOK;
switch (sudo_req->type) {
case BE_REQ_SUDO_ALL:
DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: <ALL>\n"));
break;
case BE_REQ_SUDO_DEFAULTS:
DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh of cn=defaults\n"));
break;
case BE_REQ_SUDO_USER:
DEBUG(SSSDBG_TRACE_FUNC, ("Requested refresh for: %s\n",
sudo_req->username));
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
ret = EINVAL;
goto immediately;
}
ret = sdap_sudo_connect(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, be_ctx->ev);
return req;
}
int sdap_sudo_refresh_recv(struct tevent_req *req,
int *dp_error,
int *error)
{
struct sdap_sudo_refresh_state *state = NULL;
state = tevent_req_data(req, struct sdap_sudo_refresh_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
*dp_error = state->dp_error;
*error = state->error;
return EOK;
}
int sdap_sudo_connect(struct tevent_req *req)
{
struct tevent_req *subreq = NULL;
struct sdap_sudo_refresh_state *state = NULL;
int ret;
state = tevent_req_data(req, struct sdap_sudo_refresh_state);
if (be_is_offline(state->be_ctx)) {
state->dp_error = DP_ERR_OFFLINE;
state->error = EAGAIN;
return EOK;
}
if (state->sdap_op == NULL) {
state->sdap_op = sdap_id_op_create(state, state->sdap_conn_cache);
if (state->sdap_op == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_id_op_create() failed\n"));
state->dp_error = DP_ERR_FATAL;
state->error = EIO;
return EIO;
}
}
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)));
talloc_zfree(state->sdap_op);
state->dp_error = DP_ERR_FATAL;
state->error = ret;
return ret;
}
tevent_req_set_callback(subreq, sdap_sudo_connect_done, req);
return EAGAIN;
}
void sdap_sudo_connect_done(struct tevent_req *subreq)
{
struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */
struct sdap_sudo_refresh_state *state = NULL;
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 (dp_error == DP_ERR_OFFLINE) {
talloc_zfree(state->sdap_op);
state->dp_error = DP_ERR_OFFLINE;
state->error = EAGAIN;
tevent_req_done(req);
return;
} else if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("SUDO LDAP connection failed - %s\n", strerror(ret)));
goto fail;
}
DEBUG(SSSDBG_TRACE_FUNC, ("SUDO LDAP connection successful\n"));
subreq = sdap_sudo_load_sudoers_send(state, state->be_ctx->ev,
state->sudo_req, state->opts,
sdap_id_op_handle(state->sdap_op));
if (subreq == NULL) {
ret = EFAULT;
goto fail;
}
tevent_req_set_callback(subreq, sdap_sudo_load_sudoers_done, req);
return;
fail:
state->dp_error = DP_ERR_FATAL;
state->error = ret;
tevent_req_error(req, ret);
}
struct tevent_req * sdap_sudo_load_sudoers_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct be_sudo_req *sudo_req,
struct sdap_options *opts,
struct sdap_handle *sh)
{
struct tevent_req *req = NULL;
struct sdap_sudo_load_sudoers_state *state = NULL;
int ret;
req = tevent_req_create(mem_ctx, &state, struct sdap_sudo_load_sudoers_state);
if (!req) {
return NULL;
}
state->ev = ev;
state->opts = opts;
state->sh = sh;
state->base_iter = 0;
state->search_bases = opts->sudo_search_bases;
state->timeout = dp_opt_get_int(opts->basic, SDAP_SEARCH_TIMEOUT);
state->ldap_rules = NULL;
state->ldap_rules_count = 0;
if (!state->search_bases) {
DEBUG(SSSDBG_CRIT_FAILURE,
("SUDOERS lookup request without a search base\n"));
ret = EINVAL;
goto done;
}
/* create filter */
state->filter = sdap_sudo_build_filter(state, opts->sudorule_map, sudo_req);
if (state->filter == NULL) {
goto fail;
}
/* create attrs from map */
ret = build_attrs_from_map(state, opts->sudorule_map, SDAP_OPTS_SUDO,
&state->attrs, NULL);
if (ret != EOK) {
goto fail;
}
/* begin search */
ret = sdap_sudo_load_sudoers_next_base(req);
done:
if (ret != EOK) {
tevent_req_error(req, ret);
tevent_req_post(req, ev);
}
return req;
fail:
talloc_zfree(req);
return NULL;
}
static errno_t sdap_sudo_load_sudoers_next_base(struct tevent_req *req)
{
struct tevent_req *subreq = NULL;
struct sdap_sudo_load_sudoers_state *state = NULL;
struct sdap_search_base *search_base = NULL;
char *filter = NULL;
state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
search_base = state->search_bases[state->base_iter];
if (search_base == NULL) {
/* should not happen */
DEBUG(SSSDBG_CRIT_FAILURE, ("search_base is null\n"));
return EFAULT;
}
/* create filter */
filter = sdap_get_id_specific_filter(state, state->filter,
search_base->filter);
if (filter == NULL) {
return ENOMEM;
}
/* send request */
DEBUG(SSSDBG_TRACE_FUNC,
("Searching for sudo rules with base [%s]\n",
search_base->basedn));
subreq = sdap_get_generic_send(state,
state->ev,
state->opts,
state->sh,
search_base->basedn,
search_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_process, req);
return EOK;
}
static void sdap_sudo_load_sudoers_process(struct tevent_req *subreq)
{
struct tevent_req *req = NULL;
struct sdap_sudo_load_sudoers_state *state = NULL;
struct sdap_search_base *search_base = NULL;
struct sysdb_attrs **attrs = NULL;
size_t count;
int ret;
int 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];
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) {
tevent_req_error(req, ret);
return;
}
/* add rules to result */
if (count > 0) {
state->ldap_rules = talloc_realloc(state, state->ldap_rules,
struct sysdb_attrs *,
state->ldap_rules_count + count);
if (state->ldap_rules == NULL) {
tevent_req_error(req, ENOMEM);
return;
}
for (i = 0; i < count; i++) {
state->ldap_rules[state->ldap_rules_count + i] = talloc_steal(
state->ldap_rules, attrs[i]);
}
state->ldap_rules_count += count;
}
/* go to next base */
state->base_iter++;
if (state->search_bases[state->base_iter]) {
ret = sdap_sudo_load_sudoers_next_base(req);
if (ret != EOK) {
tevent_req_error(req, ret);
}
return;
}
/* we are done */
tevent_req_done(req);
}
int sdap_sudo_load_sudoers_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx,
size_t *rules_count,
struct sysdb_attrs ***rules)
{
struct sdap_sudo_load_sudoers_state *state = NULL;
state = tevent_req_data(req, struct sdap_sudo_load_sudoers_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
*rules_count = state->ldap_rules_count;
*rules = talloc_steal(mem_ctx, state->ldap_rules);
return EOK;
}
void sdap_sudo_load_sudoers_done(struct tevent_req *subreq)
{
struct tevent_req *req = NULL; /* req from sdap_sudo_refresh_send() */
struct sdap_sudo_refresh_state *state = NULL;
struct sysdb_attrs **rules = NULL;
size_t rules_count;
int ret;
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);
if (ret != EOK) {
goto done;
}
DEBUG(SSSDBG_TRACE_FUNC, ("Received %d rules\n", rules_count));
/* purge cache */
ret = sdap_sudo_purge_sudoers(state->be_ctx->sysdb, state->be_ctx->domain,
state->sudo_req);
if (ret != EOK) {
goto done;
}
/* store rules */
ret = sdap_sudo_store_sudoers(state->be_ctx->sysdb, state->opts,
rules_count, rules);
if (ret != EOK) {
goto done;
}
DEBUG(SSSDBG_TRACE_FUNC, ("Sudoers is successfuly stored in cache\n"));
ret = EOK;
done:
state->error = ret;
if (ret == EOK) {
state->dp_error = DP_ERR_OK;
tevent_req_done(req);
} else {
state->dp_error = DP_ERR_FATAL;
tevent_req_error(req, ret);
}
}
int sdap_sudo_purge_sudoers(struct sysdb_ctx *sysdb_ctx,
struct sss_domain_info *domain,
struct be_sudo_req *sudo_req)
{
TALLOC_CTX *tmp_ctx;
char *filter = NULL;
char **sudouser = NULL;
int ret = EOK;
errno_t sret;
bool in_transaction = false;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
return ENOMEM;
}
ret = sysdb_transaction_start(sysdb_ctx);
if (ret != EOK) {
goto done;
}
in_transaction = true;
switch (sudo_req->type) {
case BE_REQ_SUDO_ALL:
DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of all rules\n"));
ret = sysdb_sudo_purge_all(sysdb_ctx);
break;
case BE_REQ_SUDO_DEFAULTS:
DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of default options\n"));
ret = sysdb_sudo_purge_byname(sysdb_ctx, SDAP_SUDO_DEFAULTS);
break;
case BE_REQ_SUDO_USER:
DEBUG(SSSDBG_TRACE_FUNC, ("Purging SUDOers cache of user's [%s] rules\n",
sudo_req->username));
/* netgroups */
ret = sysdb_get_sudo_filter(tmp_ctx, NULL, 0, NULL,
SYSDB_SUDO_FILTER_NGRS, &filter);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create filter to purge "
"SUDOers cache [%d]: %s\n", ret, strerror(ret)));
goto done;
}
ret = sysdb_sudo_purge_byfilter(sysdb_ctx, filter);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache "
"(netgroups) [%d]: %s\n", ret, strerror(ret)));
goto done;
}
/* user, uid, groups */
sudouser = sysdb_sudo_build_sudouser(tmp_ctx, sudo_req->username,
sudo_req->uid, sudo_req->groups,
true);
if (sudouser == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to create sudoUser to purge "
"SUDOers cache [%d]: %s\n", ret, strerror(ret)));
goto done;
}
ret = sysdb_sudo_purge_bysudouser(sysdb_ctx, sudouser);
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
return EINVAL;
}
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to purge SUDOers cache [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
ret = sysdb_transaction_commit(sysdb_ctx);
if (ret == EOK) {
in_transaction = false;
}
done:
if (in_transaction) {
sret = sysdb_transaction_cancel(sysdb_ctx);
if (sret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n"));
}
}
talloc_free(tmp_ctx);
return ret;
}
int sdap_sudo_store_sudoers(struct sysdb_ctx *sysdb_ctx,
struct sdap_options *opts,
size_t rules_count,
struct sysdb_attrs **rules)
{
errno_t ret;
/* Empty sudoers? Done. */
if (rules_count == 0 || rules == NULL) {
return EOK;
}
ret = sdap_save_native_sudorule_list(sysdb_ctx, opts->sudorule_map,
rules, rules_count);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("failed to save sudo rules [%d]: %s\n",
ret, strerror(ret)));
return ret;
}
return EOK;
}
const char *sdap_sudo_build_filter(TALLOC_CTX *mem_ctx,
struct sdap_attr_map *map,
struct be_sudo_req *sudo_req)
{
switch (sudo_req->type) {
case BE_REQ_SUDO_ALL:
return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_ALL,
map[SDAP_OC_SUDORULE].name);
break;
case BE_REQ_SUDO_DEFAULTS:
return talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_DEFAULTS,
map[SDAP_OC_SUDORULE].name,
map[SDAP_AT_SUDO_NAME].name,
SDAP_SUDO_DEFAULTS); /* FIXME: add option for this */
break;
case BE_REQ_SUDO_USER:
return sdap_sudo_build_user_filter(mem_ctx, map, sudo_req->username,
sudo_req->uid, sudo_req->groups);
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid request type %d\n", sudo_req->type));
return NULL;
}
}
/* alway update cn=defaults and sudoUser=ALL */
const char *sdap_sudo_build_user_filter(TALLOC_CTX *mem_ctx,
struct sdap_attr_map *map,
const char *username,
uid_t uid,
char **groups)
{
char *filter = NULL;
char *output = NULL;
char *sanitized = NULL;
char **group = NULL;
int ret;
/* user name */
ret = sss_filter_sanitize(filter, username, &sanitized);
if (ret != EOK) {
goto fail;
}
filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_USERNAME,
map[SDAP_AT_SUDO_USER].name,
sanitized);
if (filter == NULL) {
goto fail;
}
/* user uid */
filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_UID,
map[SDAP_AT_SUDO_USER].name,
uid);
if (filter == NULL) {
goto fail;
}
/* groups */
if (groups != NULL) {
for (group = groups; *group != NULL; group++) {
ret = sss_filter_sanitize(filter, *group, &sanitized);
if (ret != EOK) {
goto fail;
}
filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_GROUP,
map[SDAP_AT_SUDO_USER].name,
sanitized);
if (filter == NULL) {
goto fail;
}
}
}
/* netgroups */
/*
* FIXME: load only netgroups user is member of
* FIXME: add option to disable this filter
*/
filter = talloc_asprintf_append(filter, SDAP_SUDO_FILTER_NETGROUP,
map[SDAP_AT_SUDO_USER].name,
"*");
if (filter == NULL) {
goto fail;
}
output = talloc_asprintf(mem_ctx, SDAP_SUDO_FILTER_USER,
map[SDAP_OC_SUDORULE].name,
map[SDAP_AT_SUDO_NAME].name,
SDAP_SUDO_DEFAULTS, /* FIXME: add option for this */
map[SDAP_AT_SUDO_USER].name,
filter);
talloc_free(filter);
return output;
fail:
talloc_free(filter);
return NULL;
}