sudosrv_get_sudorules.c revision f6171b2bc954a367f316853ab71090eb213bdee3
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/*
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen Authors:
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen Pavel Březina <pbrezina@redhat.com>
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen Jakub Hrozek <jhrozek@redhat.com>
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen Copyright (C) 2011 Red Hat
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen This program is free software; you can redistribute it and/or modify
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen it under the terms of the GNU General Public License as published by
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen the Free Software Foundation; either version 3 of the License, or
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen (at your option) any later version.
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen This program is distributed in the hope that it will be useful,
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen GNU General Public License for more details.
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen You should have received a copy of the GNU General Public License
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen*/
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen#include <stdint.h>
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch#include <string.h>
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch#include <talloc.h>
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch#include "util/util.h"
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch#include "db/sysdb_sudo.h"
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch#include "responder/sudo/sudosrv_private.h"
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch
e28b88ee83b47dc2257140600f491482704c7b79Stephan Boschstatic errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx);
8bca5ef713f2916dbd60bb2b76e7cc06f4800d4dStephan Boschstatic errno_t sudosrv_get_rules(struct sudo_dom_ctx *dctx);
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch
8bca5ef713f2916dbd60bb2b76e7cc06f4800d4dStephan Boscherrno_t sudosrv_get_sudorules(struct sudo_dom_ctx *dctx)
8bca5ef713f2916dbd60bb2b76e7cc06f4800d4dStephan Bosch{
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch errno_t ret;
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch
e28b88ee83b47dc2257140600f491482704c7b79Stephan Bosch dctx->check_provider = true;
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen ret = sudosrv_get_user(dctx);
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen if (ret == EAGAIN) {
2f2244332687187931e9541e5ff312aa6c5aa705Timo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL,
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen ("Looking up the user info from Data Provider\n"));
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen return EAGAIN;
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen } else if (ret != EOK) {
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen DEBUG(SSSDBG_OP_FAILURE,
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen ("Error looking up user information [%d]: %s\n", ret, strerror(ret)));
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen return ret;
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen }
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen /* OK, got the user from cache. Try to get the rules. */
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen ret = sudosrv_get_rules(dctx);
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen if (ret == EAGAIN) {
2f2244332687187931e9541e5ff312aa6c5aa705Timo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL,
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen ("Looking up the sudo rules from Data Provider\n"));
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen return EAGAIN;
1384fac439fea3026b16a9d8d24954200e413bccTimo Sirainen } else if (ret != EOK) {
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen DEBUG(SSSDBG_OP_FAILURE,
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen ("Error looking up sudo rules [%d]: %s\n", ret, strerror(ret)));
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen return ret;
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen }
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen return EOK;
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen}
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainenstatic void sudosrv_dp_send_acct_req_done(struct tevent_req *req);
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainenstatic void sudosrv_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen const char *err_msg, void *ptr);
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainenstatic errno_t sudosrv_get_user(struct sudo_dom_ctx *dctx)
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen{
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen struct sss_domain_info *dom = dctx->domain;
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen struct sudo_cmd_ctx *cmd_ctx = dctx->cmd_ctx;
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen struct cli_ctx *cli_ctx = dctx->cmd_ctx->cli_ctx;
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen struct sysdb_ctx *sysdb;
27a33f6aaa3d02d88c020315ae613e0c4910e950Timo Sirainen time_t cache_expire = 0;
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi struct tevent_req *dpreq;
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen struct dp_callback_ctx *cb_ctx;
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen errno_t ret;
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen while (dom) {
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen /* if it is a domainless search, skip domains that require fully
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen * qualified names instead */
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen while (dom && cmd_ctx->check_next && dom->fqnames) {
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen dom = dom->next;
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen }
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen if (!dom) break;
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen
c3c07d6527ad28c8546cbbf84c257d178e23c184Timo Sirainen /* make sure to update the dctx if we changed domain */
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi dctx->domain = dom;
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi DEBUG(SSSDBG_FUNC_DATA, ("Requesting info about [%s@%s]\n",
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi cmd_ctx->username, dom->name));
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi ret = sysdb_get_ctx_from_list(cli_ctx->rctx->db_list,
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi dctx->domain, &sysdb);
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi if (ret != EOK) {
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi DEBUG(SSSDBG_CRIT_FAILURE,
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi ("sysdb context not found for this domain!\n"));
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi return EIO;
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi }
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi ret = sysdb_getpwnam(dctx, sysdb, cmd_ctx->username, &dctx->user);
9983cbb4cef92d68ffde87dcc91913cc2fed3da5Martti Rannanjärvi if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Failed to make request to our cache!\n"));
return EIO;
}
if (dctx->user->count > 1) {
DEBUG(SSSDBG_CRIT_FAILURE,
("getpwnam call returned more than one result !?!\n"));
return EIO;
}
if (dctx->user->count == 0 && !dctx->check_provider) {
/* if a multidomain search, try with next */
if (cmd_ctx->check_next) {
dctx->check_provider = true;
dom = dom->next;
if (dom) continue;
}
DEBUG(SSSDBG_MINOR_FAILURE, ("No results for getpwnam call\n"));
return ENOENT;
}
/* One result found, check cache expiry */
if (dctx->user->count == 1) {
cache_expire = ldb_msg_find_attr_as_uint64(dctx->user->msgs[0],
SYSDB_CACHE_EXPIRE, 0);
}
/* If cache miss and we haven't checked DP yet OR the entry is
* outdated, go to DP */
if ((dctx->user->count == 0 && dctx->check_provider) ||
cache_expire < time(NULL)) {
dpreq = sss_dp_get_account_send(cli_ctx, cli_ctx->rctx,
dom, false, SSS_DP_INITGROUPS,
cmd_ctx->username, 0, NULL);
if (!dpreq) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Out of memory sending data provider request\n"));
return ENOMEM;
}
cb_ctx = talloc_zero(cli_ctx, struct dp_callback_ctx);
if(!cb_ctx) {
talloc_zfree(dpreq);
return ENOMEM;
}
cb_ctx->callback = sudosrv_check_user_dp_callback;
cb_ctx->ptr = dctx;
cb_ctx->cctx = cli_ctx;
cb_ctx->mem_ctx = cli_ctx;
tevent_req_set_callback(dpreq, sudosrv_dp_send_acct_req_done, cb_ctx);
/* tell caller we are in an async call */
return EAGAIN;
}
DEBUG(SSSDBG_TRACE_FUNC, ("Returning info for user [%s@%s]\n",
cmd_ctx->username, dctx->domain->name));
return EOK;
}
return ENOENT;
}
static void sudosrv_dp_send_acct_req_done(struct tevent_req *req)
{
struct dp_callback_ctx *cb_ctx =
tevent_req_callback_data(req, struct dp_callback_ctx);
errno_t ret;
dbus_uint16_t err_maj;
dbus_uint32_t err_min;
char *err_msg;
ret = sss_dp_get_account_recv(cb_ctx->mem_ctx, req,
&err_maj, &err_min,
&err_msg);
talloc_zfree(req);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Fatal error, killing connection!\n"));
talloc_free(cb_ctx->cctx);
return;
}
cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
}
static void sudosrv_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
const char *err_msg, void *ptr)
{
errno_t ret;
struct sudo_dom_ctx *dctx = talloc_get_type(ptr, struct sudo_dom_ctx);
if (err_maj) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Unable to get information from Data Provider\n"
"Error: %u, %u, %s\n",
(unsigned int)err_maj, (unsigned int)err_min, err_msg));
}
DEBUG(SSSDBG_TRACE_INTERNAL,
("Data Provider returned, check the cache again\n"));
dctx->check_provider = false;
ret = sudosrv_get_user(dctx);
/* FIXME - set entry into cache so that we don't perform initgroups too often */
if (ret == EAGAIN) {
goto done;
} else if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Could not look up the user [%d]: %s\n",
ret, strerror(ret)));
sudosrv_cmd_done(dctx, EIO);
return;
}
DEBUG(SSSDBG_TRACE_INTERNAL, ("Looking up sudo rules..\n"));
ret = sudosrv_get_rules(dctx);
if (ret == EAGAIN) {
goto done;
} else if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Error getting sudo rules [%d]: %s\n",
ret, strerror(ret)));
sudosrv_cmd_done(dctx, EIO);
return;
}
done:
sudosrv_cmd_done(dctx, ret);
}
static errno_t sudosrv_get_sudorules_from_cache(struct sudo_dom_ctx *dctx);
static void
sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min,
const char *err_msg, void *ptr);
static void
sudosrv_dp_req_done(struct tevent_req *req);
static errno_t sudosrv_get_rules(struct sudo_dom_ctx *dctx)
{
struct tevent_req *dpreq;
struct sudo_cmd_ctx *cmd_ctx = dctx->cmd_ctx;
struct dp_callback_ctx *cb_ctx = NULL;
/* FIXME - cache logic will be here. For now, just refresh
* the cache unconditionally */
dpreq = sss_dp_get_sudoers_send(cmd_ctx->cli_ctx,
cmd_ctx->cli_ctx->rctx,
dctx->domain, false,
SSS_DP_SUDO,
cmd_ctx->username);
if (dpreq == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Cannot issue DP request.\n"));
return EIO;
}
cb_ctx = talloc_zero(dctx, struct dp_callback_ctx);
if (!cb_ctx) {
talloc_zfree(dpreq);
return ENOMEM;
}
cb_ctx->callback = sudosrv_get_sudorules_dp_callback;
cb_ctx->ptr = dctx;
cb_ctx->cctx = dctx->cmd_ctx->cli_ctx;
cb_ctx->mem_ctx = dctx;
tevent_req_set_callback(dpreq, sudosrv_dp_req_done, cb_ctx);
return EAGAIN;
}
static void
sudosrv_dp_req_done(struct tevent_req *req)
{
struct dp_callback_ctx *cb_ctx =
tevent_req_callback_data(req, struct dp_callback_ctx);
struct sudo_dom_ctx *dctx =
talloc_get_type(cb_ctx->ptr, struct sudo_dom_ctx);
errno_t ret;
dbus_uint16_t err_maj;
dbus_uint32_t err_min;
char *err_msg;
ret = sss_dp_get_sudoers_recv(cb_ctx->mem_ctx, req,
&err_maj, &err_min,
&err_msg);
talloc_free(req);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Fatal error, killing connection!\n"));
talloc_free(dctx->cmd_ctx->cli_ctx);
return;
}
cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
}
static void
sudosrv_get_sudorules_dp_callback(uint16_t err_maj, uint32_t err_min,
const char *err_msg, void *ptr)
{
struct sudo_dom_ctx *dctx =
talloc_get_type(ptr, struct sudo_dom_ctx);
errno_t ret;
if (err_maj) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Unable to get information from Data Provider\n"
"Error: %u, %u, %s\n"
"Will try to return what we have in cache\n",
(unsigned int)err_maj, (unsigned int)err_min, err_msg));
/* FIXME - cache or next domain? */
/* Loop to the next domain if possible */
if (dctx->domain->next && dctx->cmd_ctx->check_next) {
dctx->domain = dctx->domain->next;
dctx->check_provider = NEED_CHECK_PROVIDER(dctx->domain->provider);
}
}
DEBUG(SSSDBG_TRACE_INTERNAL, ("About to get sudo rules from cache\n"));
ret = sudosrv_get_sudorules_from_cache(dctx);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Failed to make a request to our cache [%d]: %s\n",
ret, strerror(ret)));
sudosrv_cmd_done(dctx, EIO);
return;
}
sudosrv_cmd_done(dctx, ret);
}
static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
const char *username,
uid_t uid,
char **groupnames,
struct sysdb_attrs ***_rules,
size_t *_count);
static errno_t sudosrv_get_sudorules_from_cache(struct sudo_dom_ctx *dctx)
{
TALLOC_CTX *tmp_ctx;
errno_t ret;
struct sysdb_ctx *sysdb;
struct cli_ctx *cli_ctx = dctx->cmd_ctx->cli_ctx;
uid_t uid;
char **groupnames;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) return ENOMEM;
ret = sysdb_get_ctx_from_list(cli_ctx->rctx->db_list,
dctx->domain, &sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("sysdb context not found for this domain!\n"));
ret = EIO;
goto done;
}
ret = sysdb_get_sudo_user_info(tmp_ctx, dctx->cmd_ctx->username,
sysdb, &uid, &groupnames);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Unable to retrieve user info [%d]: %s\n", strerror(ret)));
goto done;
}
ret = sudosrv_get_sudorules_query_cache(dctx, sysdb,
dctx->cmd_ctx->username,
uid, groupnames,
&dctx->res, &dctx->res_count);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Unable to retrieve sudo rules [%d]: %s\n", strerror(ret)));
goto done;
}
DEBUG(SSSDBG_TRACE_FUNC, ("Returning rules for [%s@%s]\n",
dctx->cmd_ctx->username, dctx->domain->name));
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
static errno_t
sort_sudo_rules(struct sysdb_attrs **rules, size_t count);
static errno_t sudosrv_get_sudorules_query_cache(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
const char *username,
uid_t uid,
char **groupnames,
struct sysdb_attrs ***_rules,
size_t *_count)
{
TALLOC_CTX *tmp_ctx;
char *filter;
errno_t ret;
size_t count;
struct sysdb_attrs **rules;
struct ldb_message **msgs;
unsigned int flags = SYSDB_SUDO_FILTER_NONE;
const char *attrs[] = { SYSDB_OBJECTCLASS
SYSDB_SUDO_CACHE_AT_OC,
SYSDB_SUDO_CACHE_AT_CN,
SYSDB_SUDO_CACHE_AT_USER,
SYSDB_SUDO_CACHE_AT_HOST,
SYSDB_SUDO_CACHE_AT_COMMAND,
SYSDB_SUDO_CACHE_AT_OPTION,
SYSDB_SUDO_CACHE_AT_RUNASUSER,
SYSDB_SUDO_CACHE_AT_RUNASGROUP,
SYSDB_SUDO_CACHE_AT_NOTBEFORE,
SYSDB_SUDO_CACHE_AT_NOTAFTER,
SYSDB_SUDO_CACHE_AT_ORDER,
NULL };
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) return ENOMEM;
flags = SYSDB_SUDO_FILTER_USERINFO
| SYSDB_SUDO_FILTER_INCLUDE_ALL
| SYSDB_SUDO_FILTER_INCLUDE_DFL;
ret = sysdb_get_sudo_filter(tmp_ctx, username, uid, groupnames,
flags, &filter);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Could not construct the search filter [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
DEBUG(SSSDBG_FUNC_DATA, ("Searching sysdb with [%s]\n", filter));
ret = sysdb_search_custom(tmp_ctx, sysdb, filter,
SUDORULE_SUBDIR, attrs,
&count, &msgs);
if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up SUDO rules"));
goto done;
} if (ret == ENOENT) {
*_rules = NULL;
*_count = 0;
ret = EOK;
goto done;
}
ret = sysdb_msg2attrs(tmp_ctx, count, msgs, &rules);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Could not convert ldb message to sysdb_attrs\n"));
goto done;
}
ret = sort_sudo_rules(rules, count);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
("Could not sort rules by sudoOrder\n"));
goto done;
}
*_rules = talloc_steal(mem_ctx, rules);
*_count = count;
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
static int
sudo_order_cmp_fn(const void *a, const void *b)
{
struct sysdb_attrs *r1, *r2;
uint32_t o1, o2;
int ret;
r1 = * (struct sysdb_attrs * const *) a;
r2 = * (struct sysdb_attrs * const *) b;
if (!r1 || !r2) {
DEBUG(SSSDBG_CRIT_FAILURE, ("BUG: Wrong data?\n"));
return 0;
}
ret = sysdb_attrs_get_uint32_t(r1, SYSDB_SUDO_CACHE_AT_ORDER, &o1);
if (ret == ENOENT) {
/* man sudoers-ldap: If the sudoOrder attribute is not present,
* a value of 0 is assumed */
o1 = 0;
} else if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Cannot get sudoOrder value\n"));
return 0;
}
ret = sysdb_attrs_get_uint32_t(r2, SYSDB_SUDO_CACHE_AT_ORDER, &o2);
if (ret == ENOENT) {
/* man sudoers-ldap: If the sudoOrder attribute is not present,
* a value of 0 is assumed */
o2 = 0;
} else if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Cannot get sudoOrder value\n"));
return 0;
}
if (o1 > o2) {
return 1;
} else if (o1 < o2) {
return -1;
}
return 0;
}
static errno_t
sort_sudo_rules(struct sysdb_attrs **rules, size_t count)
{
qsort(rules, count, sizeof(struct sysdb_attrs *),
sudo_order_cmp_fn);
return EOK;
}
char * sudosrv_get_sudorules_parse_query(TALLOC_CTX *mem_ctx,
const char *query_body,
int query_len)
{
/* empty string or not NULL terminated */
if (query_len < 2 || strnlen(query_body, query_len) == query_len) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Invalid query.\n"));
return NULL;
}
return talloc_strdup(mem_ctx, query_body);
}
/*
* Response format:
* <error_code(uint32_t)><num_entries(uint32_t)><rule1><rule2>...
* <ruleN> = <num_attrs(uint32_t)><attr1><attr2>...
* <attrN> = <name(char*)>\0<num_values(uint32_t)><value1(char*)>\0<value2(char*)>\0...
*
* if <error_code> is not SSS_SUDO_ERROR_OK, the rest of the data is skipped.
*/
int sudosrv_get_sudorules_build_response(TALLOC_CTX *mem_ctx,
uint32_t error,
int rules_num,
struct sysdb_attrs **rules,
uint8_t **_response_body,
size_t *_response_len)
{
uint8_t *response_body = NULL;
size_t response_len = 0;
TALLOC_CTX *tmp_ctx = NULL;
int i = 0;
int ret = EOK;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
return ENOMEM;
}
/* error code */
ret = sudosrv_response_append_uint32(tmp_ctx, error,
&response_body, &response_len);
if (ret != EOK) {
goto fail;
}
if (error != SSS_SUDO_ERROR_OK) {
goto done;
}
/* rules count */
ret = sudosrv_response_append_uint32(tmp_ctx, (uint32_t)rules_num,
&response_body, &response_len);
if (ret != EOK) {
goto fail;
}
/* rules */
for (i = 0; i < rules_num; i++) {
ret = sudosrv_response_append_rule(tmp_ctx, rules[i]->num, rules[i]->a,
&response_body, &response_len);
if (ret != EOK) {
goto fail;
}
}
done:
*_response_body = talloc_steal(mem_ctx, response_body);
*_response_len = response_len;
ret = EOK;
fail:
talloc_free(tmp_ctx);
return ret;
}