summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2011-12-16 13:29:16 +0100
committerStephen Gallagher <sgallagh@redhat.com>2011-12-16 14:46:18 -0500
commit2827b0d03f7b6bafa504d22a5d7ca39cbda048b3 (patch)
tree0681d8b030ec07d1a0f0ef523a131f406daad1e6
parente9eeb4302e0e426c6cc1a4e65b95a6f7066e80b9 (diff)
downloadsssd-2827b0d03f7b6bafa504d22a5d7ca39cbda048b3.tar.gz
sssd-2827b0d03f7b6bafa504d22a5d7ca39cbda048b3.tar.xz
sssd-2827b0d03f7b6bafa504d22a5d7ca39cbda048b3.zip
SUDO Integration - responder
-rw-r--r--Makefile.am17
-rw-r--r--src/confdb/confdb.h3
-rw-r--r--src/monitor/monitor.c2
-rw-r--r--src/responder/sudo/sudosrv.c194
-rw-r--r--src/responder/sudo/sudosrv_cmd.c227
-rw-r--r--src/responder/sudo/sudosrv_dp.c220
-rw-r--r--src/responder/sudo/sudosrv_get_sudorules.c113
-rw-r--r--src/responder/sudo/sudosrv_private.h109
-rw-r--r--src/responder/sudo/sudosrv_query.c178
-rw-r--r--src/sss_client/sss_cli.h3
10 files changed, 1065 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index ef92bf2d9..8bfa5a22d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -76,6 +76,9 @@ sssdlibexec_PROGRAMS = \
krb5_child \
ldap_child \
proxy_child
+if BUILD_SUDO
+sssdlibexec_PROGRAMS += sssd_sudo
+endif
if HAVE_CHECK
non_interactive_check_based_tests = \
@@ -310,6 +313,7 @@ dist_noinst_HEADERS = \
src/responder/nss/nsssrv_private.h \
src/responder/nss/nsssrv_netgroup.h \
src/responder/common/negcache.h \
+ src/responder/sudo/sudosrv_private.h \
src/sbus/sbus_client.h \
src/sbus/sssd_dbus.h \
src/sbus/sssd_dbus_private.h \
@@ -443,6 +447,19 @@ sssd_pam_LDADD = \
$(SSSD_LIBS) \
libsss_util.la
+if BUILD_SUDO
+sssd_sudo_SOURCES = \
+ src/responder/sudo/sudosrv.c \
+ src/responder/sudo/sudosrv_cmd.c \
+ src/responder/sudo/sudosrv_get_sudorules.c \
+ src/responder/sudo/sudosrv_query.c \
+ src/responder/sudo/sudosrv_dp.c \
+ $(SSSD_RESPONDER_OBJ)
+sssd_sudo_LDADD = \
+ $(SSSD_LIBS) \
+ libsss_util.la
+endif
+
sssd_be_SOURCES = \
src/providers/data_provider_be.c \
src/providers/data_provider_fo.c \
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 5b935c412..e3f8ba3c4 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -91,6 +91,9 @@
#define CONFDB_PAM_ID_TIMEOUT "pam_id_timeout"
#define CONFDB_PAM_PWD_EXPIRATION_WARNING "pam_pwd_expiration_warning"
+/* SUDO */
+#define CONFDB_SUDO_CONF_ENTRY "config/sudo"
+
/* Data Provider */
#define CONFDB_DP_CONF_ENTRY "config/dp"
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 61786ea5e..dc6f03d52 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -824,7 +824,7 @@ static int check_local_domain_unique(struct sss_domain_info *domains)
static char *check_services(char **services)
{
- const char *known_services[] = { "nss", "pam", NULL };
+ const char *known_services[] = { "nss", "pam", "sudo", NULL };
int i;
int ii;
diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c
new file mode 100644
index 000000000..841be43ef
--- /dev/null
+++ b/src/responder/sudo/sudosrv.c
@@ -0,0 +1,194 @@
+/*
+ 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 <popt.h>
+
+#include "util/util.h"
+#include "confdb/confdb.h"
+#include "monitor/monitor_interfaces.h"
+#include "responder/common/responder.h"
+#include "responder/sudo/sudosrv_private.h"
+#include "providers/data_provider.h"
+
+struct sbus_method monitor_sudo_methods[] = {
+ { MON_CLI_METHOD_PING, monitor_common_pong },
+ { MON_CLI_METHOD_RES_INIT, monitor_common_res_init },
+ { MON_CLI_METHOD_ROTATE, responder_logrotate },
+ { NULL, NULL }
+};
+
+struct sbus_interface monitor_sudo_interface = {
+ MONITOR_INTERFACE,
+ MONITOR_PATH,
+ SBUS_DEFAULT_VTABLE,
+ monitor_sudo_methods,
+ NULL
+};
+
+static struct sbus_method sudo_dp_methods[] = {
+ { NULL, NULL }
+};
+
+struct sbus_interface sudo_dp_interface = {
+ DP_INTERFACE,
+ DP_PATH,
+ SBUS_DEFAULT_VTABLE,
+ sudo_dp_methods,
+ NULL
+};
+
+static void sudo_dp_reconnect_init(struct sbus_connection *conn,
+ int status,
+ void *pvt)
+{
+ struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn);
+ int ret;
+
+ /* Did we reconnect successfully? */
+ if (status == SBUS_RECONNECT_SUCCESS) {
+ DEBUG(SSSDBG_TRACE_FUNC, ("Reconnected to the Data Provider.\n"));
+
+ /* Identify ourselves to the data provider */
+ ret = dp_common_send_id(be_conn->conn,
+ DATA_PROVIDER_VERSION,
+ "SUDO");
+ /* all fine */
+ if (ret == EOK) {
+ handle_requests_after_reconnect();
+ return;
+ }
+ }
+
+ /* Failed to reconnect */
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Could not reconnect to %s provider.\n",
+ be_conn->domain->name));
+}
+
+int sudo_process_init(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct confdb_ctx *cdb)
+{
+ struct sss_cmd_table *sudo_cmds;
+ struct sudo_ctx *sudo_ctx;
+ struct be_conn *iter;
+ int ret;
+ int max_retries;
+
+ sudo_ctx = talloc_zero(mem_ctx, struct sudo_ctx);
+ if (!sudo_ctx) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("fatal error initializing sudo_ctx\n"));
+ return ENOMEM;
+ }
+
+ sudo_cmds = get_sudo_cmds();
+ ret = sss_process_init(sudo_ctx, ev, cdb,
+ sudo_cmds,
+ SSS_SUDO_SOCKET_NAME, NULL,
+ CONFDB_SUDO_CONF_ENTRY,
+ SSS_SUDO_SBUS_SERVICE_NAME,
+ SSS_SUDO_SBUS_SERVICE_VERSION,
+ &monitor_sudo_interface,
+ "SUDO",
+ &sudo_dp_interface,
+ &sudo_ctx->rctx);
+ if (ret != EOK) {
+ return ret;
+ }
+ sudo_ctx->rctx->pvt_ctx = sudo_ctx;
+
+ /* Enable automatic reconnection to the Data Provider */
+ ret = confdb_get_int(sudo_ctx->rctx->cdb, sudo_ctx->rctx,
+ CONFDB_SUDO_CONF_ENTRY,
+ CONFDB_SERVICE_RECON_RETRIES,
+ 3, &max_retries);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ ("Failed to set up automatic reconnection\n"));
+ return ret;
+ }
+
+ for (iter = sudo_ctx->rctx->be_conns; iter; iter = iter->next) {
+ sbus_reconnect_init(iter->conn, max_retries,
+ sudo_dp_reconnect_init, iter);
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("SUDO Initialization complete\n"));
+
+ return EOK;
+}
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ poptContext pc;
+ struct main_context *main_ctx;
+ int ret;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ SSSD_MAIN_OPTS
+ POPT_TABLEEND
+ };
+
+ /* Set debug level to invalid value so we can deside if -d 0 was used. */
+ debug_level = SSSDBG_INVALID;
+
+ pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+ while((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ default:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+ }
+
+ poptFreeContext(pc);
+
+ CONVERT_AND_SET_DEBUG_LEVEL(debug_level);
+
+ /* set up things like debug, signals, daemonization, etc... */
+ debug_log_file = "sssd_sudo";
+
+ ret = server_setup("sssd[sudo]", 0, CONFDB_SUDO_CONF_ENTRY, &main_ctx);
+ if (ret != EOK) {
+ return 2;
+ }
+
+ ret = die_if_parent_died();
+ if (ret != EOK) {
+ /* This is not fatal, don't return */
+ DEBUG(SSSDBG_OP_FAILURE, ("Could not set up to exit "
+ "when parent process does\n"));
+ }
+
+ ret = sudo_process_init(main_ctx,
+ main_ctx->event_ctx,
+ main_ctx->confdb_ctx);
+ if (ret != EOK) {
+ return 3;
+ }
+
+ /* loop on main */
+ server_loop(main_ctx);
+
+ return 0;
+}
diff --git a/src/responder/sudo/sudosrv_cmd.c b/src/responder/sudo/sudosrv_cmd.c
new file mode 100644
index 000000000..72e608bd4
--- /dev/null
+++ b/src/responder/sudo/sudosrv_cmd.c
@@ -0,0 +1,227 @@
+/*
+ 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 <stdint.h>
+#include <errno.h>
+#include <talloc.h>
+
+#include "util/util.h"
+#include "responder/common/responder.h"
+#include "responder/common/responder_packet.h"
+#include "responder/sudo/sudosrv_private.h"
+
+static errno_t sudosrv_cmd_send_reply(struct sudo_cmd_ctx *cmd_ctx,
+ uint8_t *response_body,
+ size_t response_len)
+{
+ errno_t ret;
+ uint8_t *packet_body = NULL;
+ size_t packet_len = 0;
+ struct cli_ctx *cli_ctx = cmd_ctx->cli_ctx;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+ ret = sss_packet_new(cli_ctx->creq, 0,
+ sss_packet_get_cmd(cli_ctx->creq->in),
+ &cli_ctx->creq->out);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Unable to create a new packet [%d]; %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = sss_packet_grow(cli_ctx->creq->out, response_len);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Unable to create response: %s\n", strerror(ret)));
+ goto done;
+ }
+ sss_packet_get_body(cli_ctx->creq->out, &packet_body, &packet_len);
+ memcpy(packet_body, response_body, response_len);
+
+ sss_packet_set_error(cli_ctx->creq->out, EOK);
+ sss_cmd_done(cmd_ctx->cli_ctx, cmd_ctx);
+
+ ret = EOK;
+
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+static errno_t sudosrv_cmd_send_error(TALLOC_CTX *mem_ctx,
+ struct sudo_cmd_ctx *cmd_ctx,
+ uint32_t error)
+{
+ uint8_t *response_body = NULL;
+ size_t response_len = 0;
+ int ret = EOK;
+
+ ret = sudosrv_response_append_uint32(mem_ctx, error,
+ &response_body, &response_len);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ return sudosrv_cmd_send_reply(cmd_ctx, response_body, response_len);
+}
+
+errno_t sudosrv_cmd_done(struct sudo_dom_ctx *dctx, int ret)
+{
+ uint8_t *response_body = NULL;
+ size_t response_len = 0;
+
+ switch (ret) {
+ case EOK:
+ /* send result */
+ ret = sudosrv_get_sudorules_build_response(dctx->cmd_ctx, SSS_SUDO_ERROR_OK,
+ dctx->res_count, dctx->res,
+ &response_body, &response_len);
+ if (ret != EOK) {
+ return EFAULT;
+ }
+
+ ret = sudosrv_cmd_send_reply(dctx->cmd_ctx, response_body, response_len);
+ break;
+
+ case EAGAIN:
+ /* async processing, just return here */
+ return EOK;
+
+ case EFAULT:
+ /* very bad error */
+ return EFAULT;
+
+
+ /* case ENOENT:
+ * - means user not found
+ * - send error ENOENT
+ */
+
+ default:
+ /* send error */
+ ret = sudosrv_cmd_send_error(dctx->cmd_ctx, dctx->cmd_ctx, ret);
+ break;
+ }
+
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Fatal error, killing connection!\n"));
+ talloc_free(dctx->cmd_ctx->cli_ctx);
+ return EFAULT;
+ }
+
+ return EOK;
+}
+
+static int sudosrv_cmd_get_sudorules(struct cli_ctx *cli_ctx)
+{
+ char *rawname = NULL;
+ char *domname = NULL;
+ uint8_t *query_body = NULL;
+ size_t query_len = 0;
+ int ret = EOK;
+ struct sudo_cmd_ctx *cmd_ctx = NULL;
+ struct sudo_dom_ctx *dctx = NULL;
+
+ cmd_ctx = talloc_zero(cli_ctx, struct sudo_cmd_ctx);
+ if (!cmd_ctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cmd_ctx->cli_ctx = cli_ctx;
+
+ dctx = talloc_zero(cmd_ctx, struct sudo_dom_ctx);
+ if (!dctx) {
+ ret = ENOMEM;
+ goto done;
+ }
+ dctx->cmd_ctx = cmd_ctx;
+
+ /* get query */
+ sss_packet_get_body(cli_ctx->creq->in, &query_body, &query_len);
+ if (query_len <= 0 || query_body == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Query is empty\n"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ /* parse query */
+ rawname = sudosrv_get_sudorules_parse_query(cmd_ctx,
+ (const char*)query_body,
+ query_len);
+ if (rawname == NULL) {
+ ret = ENOMEM;
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("Unable to parse query: %s\n", strerror(ret)));
+ goto done;
+ }
+
+ domname = NULL;
+ ret = sss_parse_name(cmd_ctx, cli_ctx->rctx->names, rawname,
+ &domname, &cmd_ctx->username);
+ if (ret != EOK) {
+ DEBUG(2, ("Invalid name received [%s]\n", rawname));
+ ret = ENOENT;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_FUNC_DATA, ("Requesting sudo rules for [%s] from [%s]\n",
+ cmd_ctx->username, domname ? domname : "<ALL>"));
+
+ if (domname) {
+ dctx->domain = responder_get_domain(cli_ctx->rctx->domains, domname);
+ if (!dctx->domain) {
+ ret = ENOENT;
+ goto done;
+ }
+ } else {
+ /* this is a multidomain search */
+ dctx->domain = cli_ctx->rctx->domains;
+ cmd_ctx->check_next = true;
+ }
+
+ /* ok, find it ! */
+ ret = sudosrv_get_sudorules(dctx);
+
+done:
+ return sudosrv_cmd_done(dctx, ret);
+}
+
+struct cli_protocol_version *register_cli_protocol_version(void)
+{
+ static struct cli_protocol_version sudo_cli_protocol_version[] = {
+ {0, NULL, NULL}
+ };
+
+ return sudo_cli_protocol_version;
+}
+
+struct sss_cmd_table *get_sudo_cmds(void) {
+ static struct sss_cmd_table sudo_cmds[] = {
+ {SSS_GET_VERSION, sss_cmd_get_version},
+ {SSS_SUDO_GET_SUDORULES, sudosrv_cmd_get_sudorules},
+ {SSS_CLI_NULL, NULL}
+ };
+
+ return sudo_cmds;
+}
diff --git a/src/responder/sudo/sudosrv_dp.c b/src/responder/sudo/sudosrv_dp.c
new file mode 100644
index 000000000..0c621f5d5
--- /dev/null
+++ b/src/responder/sudo/sudosrv_dp.c
@@ -0,0 +1,220 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+ Jakub Hrozek <jhrozek@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 <talloc.h>
+#include <tevent.h>
+#include <dbus/dbus.h>
+#include "sbus/sssd_dbus.h"
+
+#include "util/util.h"
+#include "sbus/sbus_client.h"
+#include "providers/data_provider.h"
+#include "responder/common/responder.h"
+#include "responder/sudo/sudosrv_private.h"
+
+struct sudo_dp_refresh_state {
+ dbus_uint16_t err_maj;
+ dbus_uint32_t err_min;
+};
+
+/* FIXME -- need to keep track of a running request
+ * and just queue a callback
+ * OR reuse the common dp requests
+ */
+static void sudosrv_dp_process_reply(DBusPendingCall *pending, void *ptr);
+
+struct tevent_req * sudosrv_dp_refresh_send(struct resp_ctx *rctx,
+ struct sss_domain_info *dom,
+ const char *username)
+{
+ struct be_conn *be_conn;
+ struct sudo_dp_refresh_state *state;
+ DBusMessage *msg;
+ dbus_bool_t dbret;
+ int ret;
+ const int timeout = SSS_CLI_SOCKET_TIMEOUT / 2;
+ struct tevent_req *req;
+
+ /* Cache refresh requests need to be allocated on the responder context
+ * so that they don't go away if a client disconnects. The worst-
+ * case scenario here is that the cache is updated without any
+ * client expecting a response.
+ */
+ req = tevent_req_create(rctx, &state, struct sudo_dp_refresh_state);
+ if (!req) return NULL;
+
+ /* double check dp_ctx has actually been initialized.
+ * in some pathological cases it may happen that sudo starts up before
+ * dp connection code is actually able to establish a connection.
+ */
+ ret = sss_dp_get_domain_conn(rctx, dom->name, &be_conn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("The Data Provider connection for %s is not available! "
+ "This maybe a bug, it shouldn't happen!\n",
+ dom->name));
+ ret = EIO;
+ goto error;
+ }
+
+ msg = dbus_message_new_method_call(NULL,
+ DP_PATH,
+ DP_INTERFACE,
+ DP_METHOD_SUDOHANDLER);
+ if (msg == NULL) {
+ DEBUG(SSSDBG_FATAL_FAILURE, ("Out of memory?!\n"));
+ ret = ENOMEM;
+ goto error;
+ }
+
+ if (username != NULL) {
+ dbret = dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &username,
+ DBUS_TYPE_INVALID);
+ if (!dbret) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to generate dbus reply\n"));
+ ret = EIO;
+ goto error;
+ }
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, ("Sending SUDOers refresh request\n"));
+ ret = sbus_conn_send(be_conn->conn, msg,
+ timeout, sudosrv_dp_process_reply,
+ req, NULL);
+ dbus_message_unref(msg);
+
+ return req;
+
+error:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, rctx->ev);
+ return req;
+}
+
+static int sudosrv_dp_get_reply(DBusPendingCall *pending,
+ dbus_uint16_t *err_maj,
+ dbus_uint32_t *err_min,
+ char **err_msg)
+{
+ DBusMessage *reply;
+ DBusError dbus_error;
+ dbus_bool_t ret;
+ int type;
+ int err = EOK;
+
+ dbus_error_init(&dbus_error);
+
+ reply = dbus_pending_call_steal_reply(pending);
+ if (!reply) {
+ /* reply should never be null. This function shouldn't be called
+ * until reply is valid or timeout has occurred. If reply is NULL
+ * here, something is seriously wrong and we should bail out.
+ */
+ DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n"));
+
+ err = EIO;
+ goto done;
+ }
+
+ type = dbus_message_get_type(reply);
+ switch (type) {
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ ret = dbus_message_get_args(reply, &dbus_error,
+ DBUS_TYPE_UINT16, err_maj,
+ DBUS_TYPE_UINT32, err_min,
+ DBUS_TYPE_STRING, err_msg,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("Failed to parse message\n"));
+ if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
+ err = EIO;
+ goto done;
+ }
+
+ DEBUG(4, ("Got reply (%u, %u, %s) from Data Provider\n",
+ (unsigned int)*err_maj, (unsigned int)*err_min, *err_msg));
+
+ break;
+
+ case DBUS_MESSAGE_TYPE_ERROR:
+ if (strcmp(dbus_message_get_error_name(reply),
+ DBUS_ERROR_NO_REPLY) == 0) {
+ err = ETIME;
+ goto done;
+ }
+ DEBUG(0,("The Data Provider returned an error [%s]\n",
+ dbus_message_get_error_name(reply)));
+ /* Falling through to default intentionally*/
+ default:
+ /*
+ * Timeout or other error occurred or something
+ * unexpected happened.
+ * It doesn't matter which, because either way we
+ * know that this connection isn't trustworthy.
+ * We'll destroy it now.
+ */
+
+ err = EIO;
+ }
+
+done:
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(reply);
+
+ return err;
+}
+
+static void sudosrv_dp_process_reply(DBusPendingCall *pending, void *ptr)
+{
+ struct tevent_req *req;
+ errno_t ret;
+ char *err_msg;
+ struct sudo_dp_refresh_state *state;
+
+ req = talloc_get_type(ptr, struct tevent_req);
+ state = tevent_req_data(req, struct sudo_dp_refresh_state);
+
+ ret = sudosrv_dp_get_reply(pending, &state->err_maj, &state->err_min, &err_msg);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to get a reply from DP! "
+ "err_maj: %d err_min: %d err_msg: [%s]\n",
+ state->err_maj, state->err_min, err_msg ? err_msg : "none set"));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+errno_t sudosrv_dp_refresh_recv(struct tevent_req *req,
+ dbus_uint16_t *_err_maj,
+ dbus_uint32_t *_err_min)
+{
+ struct sudo_dp_refresh_state *state;
+ state = tevent_req_data(req, struct sudo_dp_refresh_state);
+
+ if (_err_maj) *_err_maj = state->err_maj;
+ if (_err_min) *_err_min = state->err_min;
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
diff --git a/src/responder/sudo/sudosrv_get_sudorules.c b/src/responder/sudo/sudosrv_get_sudorules.c
new file mode 100644
index 000000000..aa466c8bb
--- /dev/null
+++ b/src/responder/sudo/sudosrv_get_sudorules.c
@@ -0,0 +1,113 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+ Jakub Hrozek <jhrozek@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 <stdint.h>
+#include <string.h>
+#include <talloc.h>
+
+#include "util/util.h"
+#include "db/sysdb_sudo.h"
+#include "responder/sudo/sudosrv_private.h"
+
+errno_t sudosrv_get_sudorules(struct sudo_dom_ctx *dctx)
+{
+ dctx->res = NULL;
+ dctx->res_count = 0;
+
+ return EOK;
+}
+
+char * sudosrv_get_sudorules_parse_query(TALLOC_CTX *mem_ctx,
+ const char *query_body,
+ int query_len)
+{
+ if (query_len < 2 || ((query_len - 1) != strlen(query_body))) {
+ 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;
+}
diff --git a/src/responder/sudo/sudosrv_private.h b/src/responder/sudo/sudosrv_private.h
new file mode 100644
index 000000000..7401570cc
--- /dev/null
+++ b/src/responder/sudo/sudosrv_private.h
@@ -0,0 +1,109 @@
+/*
+ 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/>.
+*/
+
+#ifndef _SUDOSRV_PRIVATE_H_
+#define _SUDOSRV_PRIVATE_H_
+
+#include <stdint.h>
+#include <talloc.h>
+
+#include "src/db/sysdb.h"
+#include "responder/common/responder.h"
+
+#define SSS_SUDO_ERROR_OK 0
+#define SSS_SUDO_SBUS_SERVICE_VERSION 0x0001
+#define SSS_SUDO_SBUS_SERVICE_NAME "sudo"
+
+struct sudo_ctx {
+ struct resp_ctx *rctx;
+};
+
+struct sudo_cmd_ctx {
+ struct cli_ctx *cli_ctx;
+ char *username;
+ bool check_next;
+};
+
+struct sudo_dom_ctx {
+ struct sudo_cmd_ctx *cmd_ctx;
+ struct sss_domain_info *domain;
+ bool check_provider;
+
+ /* cache results */
+ struct ldb_result *user;
+ struct sysdb_attrs **res;
+ size_t res_count;
+};
+
+struct sudo_dp_request {
+ struct cli_ctx *cctx;
+ struct sss_domain_info *domain;
+};
+
+struct sss_cmd_table *get_sudo_cmds(void);
+
+errno_t sudosrv_cmd_done(struct sudo_dom_ctx *dctx, int ret);
+
+struct tevent_req * sudosrv_dp_refresh_send(struct resp_ctx *rctx,
+ struct sss_domain_info *dom,
+ const char *username);
+
+errno_t sudosrv_dp_refresh_recv(struct tevent_req *req,
+ dbus_uint16_t *_err_maj,
+ dbus_uint32_t *_err_min);
+
+errno_t sudosrv_get_sudorules(struct sudo_dom_ctx *dctx);
+
+char * sudosrv_get_sudorules_parse_query(TALLOC_CTX *mem_ctx,
+ const char *query_body,
+ int query_len);
+
+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);
+
+int sudosrv_response_append_string(TALLOC_CTX *mem_ctx,
+ const char *str,
+ size_t str_len,
+ uint8_t **_response_body,
+ size_t *_response_len);
+
+int sudosrv_response_append_uint32(TALLOC_CTX *mem_ctx,
+ uint32_t number,
+ uint8_t **_response_body,
+ size_t *_response_len);
+
+int sudosrv_response_append_rule(TALLOC_CTX *mem_ctx,
+ int attrs_num,
+ struct ldb_message_element *attrs,
+ uint8_t **_response_body,
+ size_t *_response_len);
+
+int sudosrv_response_append_attr(TALLOC_CTX *mem_ctx,
+ const char *name,
+ unsigned int values_num,
+ struct ldb_val *values,
+ uint8_t **_response_body,
+ size_t *_response_len);
+
+#endif /* _SUDOSRV_PRIVATE_H_ */
diff --git a/src/responder/sudo/sudosrv_query.c b/src/responder/sudo/sudosrv_query.c
new file mode 100644
index 000000000..8b98da6e8
--- /dev/null
+++ b/src/responder/sudo/sudosrv_query.c
@@ -0,0 +1,178 @@
+/*
+ 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 <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <talloc.h>
+
+#include "util/util.h"
+#include "responder/sudo/sudosrv_private.h"
+
+int sudosrv_response_append_string(TALLOC_CTX *mem_ctx,
+ const char *str,
+ size_t str_len,
+ uint8_t **_response_body,
+ size_t *_response_len)
+{
+ size_t response_len = *_response_len;
+ uint8_t *response_body = *_response_body;
+
+ response_body = talloc_realloc(mem_ctx, response_body, uint8_t,
+ response_len + (str_len * sizeof(char)));
+ if (response_body == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_realloc() failed\n"));
+ return ENOMEM;
+ }
+ memcpy(response_body + response_len, str, str_len);
+ response_len += str_len;
+
+ *_response_body = response_body;
+ *_response_len = response_len;
+
+ return EOK;
+}
+
+int sudosrv_response_append_uint32(TALLOC_CTX *mem_ctx,
+ uint32_t number,
+ uint8_t **_response_body,
+ size_t *_response_len)
+{
+ size_t response_len = *_response_len;
+ uint8_t *response_body = *_response_body;
+
+ response_body = talloc_realloc(mem_ctx, response_body, uint8_t,
+ response_len + sizeof(int));
+ if (response_body == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_realloc() failed\n"));
+ return ENOMEM;
+ }
+ SAFEALIGN_SET_UINT32(response_body + response_len, number, &response_len);
+
+ *_response_body = response_body;
+ *_response_len = response_len;
+
+ return EOK;
+}
+
+int sudosrv_response_append_rule(TALLOC_CTX *mem_ctx,
+ int attrs_num,
+ struct ldb_message_element *attrs,
+ uint8_t **_response_body,
+ size_t *_response_len)
+{
+ uint8_t *response_body = *_response_body;
+ size_t response_len = *_response_len;
+ 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;
+ }
+
+ /* attrs count */
+ ret = sudosrv_response_append_uint32(tmp_ctx, attrs_num,
+ &response_body, &response_len);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* attrs */
+ for (i = 0; i < attrs_num; i++) {
+ ret = sudosrv_response_append_attr(tmp_ctx, attrs[i].name,
+ attrs[i].num_values, attrs[i].values,
+ &response_body, &response_len);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ *_response_body = talloc_steal(mem_ctx, response_body);
+ *_response_len = response_len;
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sudosrv_response_append_attr(TALLOC_CTX *mem_ctx,
+ const char *name,
+ unsigned int values_num,
+ struct ldb_val *values,
+ uint8_t **_response_body,
+ size_t *_response_len)
+{
+ uint8_t *response_body = *_response_body;
+ size_t response_len = *_response_len;
+ 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;
+ }
+
+ /* attr name */
+ ret = sudosrv_response_append_string(tmp_ctx, name, strlen(name) + 1,
+ &response_body, &response_len);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* values count */
+ ret = sudosrv_response_append_uint32(tmp_ctx, values_num,
+ &response_body, &response_len);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* values */
+ for (i = 0; i < values_num; i++) {
+ if (strlen((char*)(values[i].data)) != values[i].length) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("value is not a string"));
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = sudosrv_response_append_string(tmp_ctx,
+ (const char*)values[i].data,
+ values[i].length + 1,
+ &response_body, &response_len);
+ if (ret != EOK) {
+ goto done;
+ }
+ }
+
+ *_response_body = talloc_steal(mem_ctx, response_body);
+ *_response_len = response_len;
+
+ ret = EOK;
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index 33e944166..f9bbda98e 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -144,6 +144,9 @@ enum sss_cli_command {
SSS_NSS_ENDSPENT = 0x00B5,
#endif
+/* SUDO */
+ SSS_SUDO_GET_SUDORULES = 0x00C1,
+
/* PAM related calls */
SSS_PAM_AUTHENTICATE = 0x00F1, /**< see pam_sm_authenticate(3) for
* details.