summaryrefslogtreecommitdiffstats
path: root/src/providers/data_provider
diff options
context:
space:
mode:
authorPavel Březina <pbrezina@redhat.com>2016-03-29 12:38:25 +0200
committerJakub Hrozek <jhrozek@redhat.com>2016-06-20 14:48:47 +0200
commitdea636af4d1902a081ee891f1b19ee2f8729d759 (patch)
treea4d66ceb2b32ddf3b69bee1f1e2412568eae655e /src/providers/data_provider
parent62370340092503baeaf6587d7ffe4fe25bd9582d (diff)
downloadsssd-dea636af4d1902a081ee891f1b19ee2f8729d759.tar.gz
sssd-dea636af4d1902a081ee891f1b19ee2f8729d759.tar.xz
sssd-dea636af4d1902a081ee891f1b19ee2f8729d759.zip
DP: Switch to new interface
Reviewed-by: Sumit Bose <sbose@redhat.com> Reviewed-by: Jakub Hrozek <jhrozek@redhat.com> Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/providers/data_provider')
-rw-r--r--src/providers/data_provider/dp_custom_data.h30
-rw-r--r--src/providers/data_provider/dp_iface.c12
-rw-r--r--src/providers/data_provider/dp_iface.h28
-rw-r--r--src/providers/data_provider/dp_target_auth.c302
-rw-r--r--src/providers/data_provider/dp_target_autofs.c55
-rw-r--r--src/providers/data_provider/dp_target_hostid.c63
-rw-r--r--src/providers/data_provider/dp_target_id.c311
-rw-r--r--src/providers/data_provider/dp_target_subdomains.c50
-rw-r--r--src/providers/data_provider/dp_target_sudo.c199
9 files changed, 1044 insertions, 6 deletions
diff --git a/src/providers/data_provider/dp_custom_data.h b/src/providers/data_provider/dp_custom_data.h
index 298f91de4..decc0f4e8 100644
--- a/src/providers/data_provider/dp_custom_data.h
+++ b/src/providers/data_provider/dp_custom_data.h
@@ -25,6 +25,36 @@
/* Request handler private data. */
+struct dp_sudo_data {
+ uint32_t type;
+ char **rules;
+};
+
+struct dp_hostid_data {
+ const char *name;
+ const char *alias;
+};
+
+struct dp_autofs_data {
+ const char *mapname;
+};
+
+struct dp_subdomains_data {
+ const char *domain_hint;
+};
+
+/* TODO rename be_acct_req to dp_id_data to be consistent
+ This can be done after the original code is removed.
+struct dp_id_data {
+ uint32_t entry_type;
+ uint32_t attr_type;
+ uint32_t filter_type;
+ const char *filter_value;
+ const char *extra_value;
+ const char *domain;
+};
+*/
+
/* Reply private data. */
struct dp_reply_std {
diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c
index 5eaf7e2a3..6a6ca6769 100644
--- a/src/providers/data_provider/dp_iface.c
+++ b/src/providers/data_provider/dp_iface.c
@@ -28,12 +28,12 @@
struct iface_dp iface_dp = {
{&iface_dp_meta, 0},
- .pamHandler = NULL,
- .sudoHandler = NULL,
- .autofsHandler = NULL,
- .hostHandler = NULL,
- .getDomains = NULL,
- .getAccountInfo = NULL
+ .pamHandler = dp_pam_handler,
+ .sudoHandler = dp_sudo_handler,
+ .autofsHandler = dp_autofs_handler,
+ .hostHandler = dp_host_handler,
+ .getDomains = dp_subdomains_handler,
+ .getAccountInfo = dp_get_account_info_handler
};
static struct sbus_iface_map dp_map[] = {
diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h
index 2991bf7aa..eeef220e3 100644
--- a/src/providers/data_provider/dp_iface.h
+++ b/src/providers/data_provider/dp_iface.h
@@ -31,4 +31,32 @@
errno_t dp_register_sbus_interface(struct sbus_connection *conn,
struct dp_client *pvt);
+errno_t dp_get_account_info_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ uint32_t entry_type,
+ uint32_t attr_type,
+ const char *filter,
+ const char *domain,
+ const char *extra);
+
+errno_t dp_pam_handler(struct sbus_request *sbus_req, void *dp_cli);
+
+errno_t dp_sudo_handler(struct sbus_request *sbus_req, void *dp_cli);
+
+errno_t dp_host_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ const char *name,
+ const char *alias);
+
+errno_t dp_autofs_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ const char *mapname);
+
+errno_t dp_subdomains_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ const char *domain_hint);
+
#endif /* DP_IFACE_H_ */
diff --git a/src/providers/data_provider/dp_target_auth.c b/src/providers/data_provider/dp_target_auth.c
new file mode 100644
index 000000000..78c4cce7e
--- /dev/null
+++ b/src/providers/data_provider/dp_target_auth.c
@@ -0,0 +1,302 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+#include "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+static void dp_pam_reply(struct sbus_request *sbus_req,
+ const char *request_name,
+ struct pam_data *pd)
+{
+ DBusMessage *reply;
+ dbus_bool_t dbret;
+
+ DP_REQ_DEBUG(SSSDBG_TRACE_LIBS, request_name,
+ "Sending result [%d][%s]", pd->pam_status, pd->domain);
+
+ reply = dbus_message_new_method_return(sbus_req->message);
+ if (reply == NULL) {
+ DP_REQ_DEBUG(SSSDBG_TRACE_LIBS, request_name,
+ "Unable to acquire reply message");
+ return;
+ }
+
+ dbret = dp_pack_pam_response(reply, pd);
+ if (!dbret) {
+ DP_REQ_DEBUG(SSSDBG_TRACE_LIBS, request_name,
+ "Unable to generate reply message");
+ dbus_message_unref(reply);
+ return;
+ }
+
+ sbus_request_finish(sbus_req, reply);
+ dbus_message_unref(reply);
+ return;
+}
+
+static errno_t pam_data_create(TALLOC_CTX *mem_ctx,
+ struct sbus_request *sbus_req,
+ struct be_ctx *be_ctx,
+ struct pam_data **_pd)
+{
+ DBusError dbus_error;
+ struct pam_data *pd;
+ bool bret;
+
+ dbus_error_init(&dbus_error);
+ bret = dp_unpack_pam_request(sbus_req->message, mem_ctx, &pd, &dbus_error);
+ if (bret == false) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse message!\n");
+ return EINVAL;
+ }
+
+ pd->pam_status = PAM_SYSTEM_ERR;
+ if (pd->domain == NULL) {
+ pd->domain = talloc_strdup(pd, be_ctx->domain->name);
+ if (pd->domain == NULL) {
+ talloc_free(pd);
+ return ENOMEM;
+ }
+ }
+
+ *_pd = pd;
+
+ return EOK;
+}
+
+static void choose_target(struct data_provider *provider,
+ struct pam_data *pd,
+ enum dp_targets *_target,
+ enum dp_methods *_method,
+ const char **_req_name)
+{
+ enum dp_targets target;
+ enum dp_methods method;
+ const char *name;
+
+ switch (pd->cmd) {
+ case SSS_PAM_AUTHENTICATE:
+ target = DPT_AUTH;
+ method = DPM_AUTH_HANDLER;
+ name = "PAM Authenticate";
+ break;
+ case SSS_PAM_PREAUTH:
+ target = DPT_AUTH;
+ method = DPM_AUTH_HANDLER;
+ name = "PAM Preauth";
+ break;
+ case SSS_PAM_ACCT_MGMT:
+ target = DPT_ACCESS;
+ method = DPM_ACCESS_HANDLER;
+ name = "PAM Account";
+ break;
+ case SSS_PAM_CHAUTHTOK_PRELIM:
+ target = DPT_CHPASS;
+ method = DPM_AUTH_HANDLER;
+ name = "PAM Chpass 1st";
+ break;
+ case SSS_PAM_CHAUTHTOK:
+ target = DPT_CHPASS;
+ method = DPM_AUTH_HANDLER;
+ name = "PAM Chpass 2nd";
+ break;
+ case SSS_PAM_OPEN_SESSION:
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ name = "PAM Open Session";
+ pd->pam_status = PAM_SUCCESS;
+ break;
+ case SSS_PAM_SETCRED:
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ name = "PAM Set Credentials";
+ pd->pam_status = PAM_SUCCESS;
+ break;
+ case SSS_PAM_CLOSE_SESSION:
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ name = "PAM Close Session";
+ pd->pam_status = PAM_SUCCESS;
+ break;
+ default:
+ DEBUG(SSSDBG_TRACE_LIBS, "Unsupported PAM command [%d].\n",
+ pd->cmd);
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ name = "PAM Unsupported";
+ pd->pam_status = PAM_MODULE_UNKNOWN;
+ break;
+ }
+
+ /* Check that target is configured. */
+ if (target != DP_TARGET_SENTINEL
+ && !dp_target_enabled(provider, NULL, target)) {
+ target = DP_TARGET_SENTINEL;
+ method = DP_METHOD_SENTINEL;
+ pd->pam_status = PAM_MODULE_UNKNOWN;
+ }
+
+ *_target = target;
+ *_method = method;
+ *_req_name = name;
+}
+
+struct dp_pam_handler_state {
+ struct data_provider *provider;
+ struct dp_client *dp_cli;
+ struct sbus_request *sbus_req;
+ const char *request_name;
+};
+
+void dp_pam_handler_step_done(struct tevent_req *req);
+void dp_pam_handler_selinux_done(struct tevent_req *req);
+
+errno_t dp_pam_handler(struct sbus_request *sbus_req, void *sbus_data)
+{
+ struct dp_pam_handler_state *state;
+ struct data_provider *provider;
+ struct pam_data *pd = NULL;
+ struct dp_client *dp_cli;
+ enum dp_targets target;
+ enum dp_methods method;
+ const char *req_name;
+ struct tevent_req *req;
+ errno_t ret;
+
+ dp_cli = talloc_get_type(sbus_data, struct dp_client);
+ provider = dp_client_provider(dp_cli);
+
+ state = talloc_zero(sbus_req, struct dp_pam_handler_state);
+ if (state == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = pam_data_create(state, sbus_req, provider->be_ctx, &pd);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ state->provider = provider;
+ state->dp_cli = dp_cli;
+ state->sbus_req = sbus_req;
+
+ DEBUG(SSSDBG_CONF_SETTINGS, "Got request with the following data\n");
+ DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
+
+ choose_target(provider, pd, &target, &method, &req_name);
+ if (target == DP_TARGET_SENTINEL) {
+ /* Just send the result. Pam data are freed with this call. */
+ dp_pam_reply(sbus_req, req_name, pd);
+ return EOK;
+ }
+
+ req = dp_req_send(state, provider, dp_cli, pd->domain, req_name,
+ target, method, 0, pd, &state->request_name);
+ if (req == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(req, dp_pam_handler_step_done, state);
+
+done:
+ if (ret != EOK) {
+ talloc_free(pd);
+ }
+
+ return ret;
+}
+
+static bool should_invoke_selinux(struct data_provider *provider,
+ struct pam_data *pd)
+{
+ if (!dp_method_enabled(provider, DPT_SELINUX, DPM_SELINUX_HANDLER)) {
+ return false;
+ }
+
+ if (pd->cmd == SSS_PAM_ACCT_MGMT && pd->pam_status == PAM_SUCCESS) {
+ return true;
+ }
+
+ return false;
+}
+
+void dp_pam_handler_step_done(struct tevent_req *req)
+{
+ struct dp_pam_handler_state *state;
+ struct pam_data *pd;
+ errno_t ret;
+
+ state = tevent_req_callback_data(req, struct dp_pam_handler_state);
+
+ ret = dp_req_recv(state, req, struct pam_data *, &pd);
+ talloc_zfree(req);
+ if (ret != EOK) {
+ dp_req_reply_error(state->sbus_req, state->request_name, ret);
+ return;
+ }
+
+ if (!should_invoke_selinux(state->provider, pd)) {
+ /* State and request related data are freed with sbus_req. */
+ dp_pam_reply(state->sbus_req, state->request_name, pd);
+ return;
+ }
+
+ req = dp_req_send(state, state->provider, state->dp_cli, pd->domain,
+ "PAM SELinux", DPT_SELINUX, DPM_SELINUX_HANDLER,
+ 0, pd, NULL);
+ if (req == NULL) {
+ DP_REQ_DEBUG(SSSDBG_CRIT_FAILURE, state->request_name,
+ "Unable to process SELinux, killing request...");
+ talloc_free(state->sbus_req);
+ return;
+ }
+
+ tevent_req_set_callback(req, dp_pam_handler_selinux_done, state);
+}
+
+void dp_pam_handler_selinux_done(struct tevent_req *req)
+{
+ struct dp_pam_handler_state *state;
+ struct pam_data *pd;
+ errno_t ret;
+
+ state = tevent_req_callback_data(req, struct dp_pam_handler_state);
+
+ ret = dp_req_recv(state, req, struct pam_data *, &pd);
+ talloc_zfree(req);
+ if (ret != EOK) {
+ dp_req_reply_error(state->sbus_req, state->request_name, ret);
+ return;
+ }
+
+ /* State and request related data are freed with sbus_req. */
+ dp_pam_reply(state->sbus_req, state->request_name, pd);
+ return;
+}
diff --git a/src/providers/data_provider/dp_target_autofs.c b/src/providers/data_provider/dp_target_autofs.c
new file mode 100644
index 000000000..13b12f5dd
--- /dev/null
+++ b/src/providers/data_provider/dp_target_autofs.c
@@ -0,0 +1,55 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+errno_t dp_autofs_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ const char *mapname)
+{
+ struct dp_autofs_data *data;
+ const char *key;
+
+ if (mapname == NULL) {
+ return EINVAL;
+ }
+
+ data = talloc_zero(sbus_req, struct dp_autofs_data);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ data->mapname = mapname;
+ key = mapname;
+
+ dp_req_with_reply(dp_cli, NULL, "AutoFS", key, sbus_req, DPT_AUTOFS,
+ DPM_AUTOFS_HANDLER, dp_flags, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ return EOK;
+}
diff --git a/src/providers/data_provider/dp_target_hostid.c b/src/providers/data_provider/dp_target_hostid.c
new file mode 100644
index 000000000..a47601f0b
--- /dev/null
+++ b/src/providers/data_provider/dp_target_hostid.c
@@ -0,0 +1,63 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+errno_t dp_host_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ const char *name,
+ const char *alias)
+{
+ struct dp_hostid_data *data;
+ const char *key;
+
+ if (name == NULL) {
+ return EINVAL;
+ }
+
+ data = talloc_zero(sbus_req, struct dp_hostid_data);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ data->name = name;
+ data->alias = alias[0] == '\0' ? NULL : alias;
+
+ key = talloc_asprintf(data, "%s:%s", name,
+ (data->alias == NULL ? "(null)" : data->alias));
+ if (key == NULL) {
+ talloc_free(data);
+ return ENOMEM;
+ }
+
+ dp_req_with_reply(dp_cli, NULL, "HostID", key, sbus_req, DPT_HOSTID,
+ DPM_HOSTID_HANDLER, dp_flags, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ return EOK;
+}
diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
new file mode 100644
index 000000000..855bcd895
--- /dev/null
+++ b/src/providers/data_provider/dp_target_id.c
@@ -0,0 +1,311 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+#define FILTER_TYPE(str, type) {str "=", sizeof(str "=") - 1, type}
+
+static bool check_attr_type(uint32_t attr_type)
+{
+ switch (attr_type) {
+ case BE_ATTR_CORE:
+ case BE_ATTR_MEM:
+ case BE_ATTR_ALL:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+static bool check_and_parse_filter(struct be_acct_req *data,
+ const char *filter,
+ const char *extra)
+{
+ /* We will use sizeof() to determine the length of a string so we don't
+ * call strlen over and over again with each request. Not a bottleneck,
+ * but unnecessary and simple to avoid. */
+ static struct {
+ const char *name;
+ size_t lenght;
+ uint32_t type;
+ } types[] = {FILTER_TYPE("name", BE_FILTER_NAME),
+ FILTER_TYPE("idnumber", BE_FILTER_IDNUM),
+ FILTER_TYPE(DP_SEC_ID, BE_FILTER_SECID),
+ FILTER_TYPE(DP_CERT, BE_FILTER_CERT),
+ FILTER_TYPE(DP_WILDCARD, BE_FILTER_WILDCARD),
+ {0, 0, 0}};
+ int i;
+
+ if (filter == NULL) {
+ return false;
+ }
+
+ for (i = 0; types[i].name != NULL; i++) {
+ if (strncmp(filter, types[i].name, types[i].lenght) == 0) {
+ data->filter_type = types[i].type;
+ data->filter_value = discard_const(&filter[types[i].lenght]); /* todo remove discard const */
+ data->extra_value = discard_const(extra); /* todo remove discard const */
+ return true;
+ }
+ }
+
+ if (strcmp(filter, ENUM_INDICATOR) == 0) {
+ data->filter_type = BE_FILTER_ENUM;
+ data->filter_value = NULL;
+ data->extra_value = NULL;
+ return true;
+ }
+
+ return false;
+}
+
+struct dp_initgr_ctx {
+ const char *username;
+ const char *domain;
+ uint32_t gnum;
+ uint32_t *groups;
+};
+
+static struct dp_initgr_ctx *create_initgr_ctx(TALLOC_CTX *mem_ctx,
+ const char *domain,
+ struct ldb_result *res)
+{
+ struct dp_initgr_ctx *ctx;
+ const char *username;
+ unsigned int i;
+ errno_t ret;
+
+ ctx = talloc_zero(mem_ctx, struct dp_initgr_ctx);
+ if (ctx == NULL) {
+ return NULL;
+ }
+
+ username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
+ if (username == NULL) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ ctx->username = talloc_strdup(ctx, username);
+ if (ctx->username == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ctx->domain = talloc_strdup(ctx, domain);
+ if (ctx->domain == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ctx->groups = talloc_array(mem_ctx, uint32_t, res->count);
+ if (ctx->groups == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* The first GID is the primary so it might be duplicated
+ * later in the list. */
+ for (ctx->gnum = 0, i = 0; i < res->count; i++) {
+ ctx->groups[ctx->gnum] = ldb_msg_find_attr_as_uint(res->msgs[i],
+ SYSDB_GIDNUM, 0);
+ /* If 0 it may be a non-posix group, so we skip it. */
+ if (ctx->groups[ctx->gnum] != 0) {
+ ctx->gnum++;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+static void dp_req_initgr_pp(const char *req_name,
+ struct data_provider *provider,
+ struct dp_initgr_ctx *ctx,
+ struct dp_reply_std *reply)
+{
+ struct dp_client *dp_cli;
+ DBusMessage *msg;
+ dbus_bool_t dbret;
+ int num;
+
+ dp_cli = provider->clients[DPC_NSS];
+ if (dp_cli == NULL) {
+ return;
+ }
+
+ msg = dbus_message_new_method_call(NULL,
+ DP_PATH,
+ DATA_PROVIDER_REV_IFACE,
+ DATA_PROVIDER_REV_IFACE_INITGRCHECK);
+ if (msg == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
+ return;
+ }
+
+ num = ctx->gnum;
+ dbret = dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &ctx->username,
+ DBUS_TYPE_STRING, &ctx->domain,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ &ctx->groups, num,
+ DBUS_TYPE_INVALID);
+ if (!dbret) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
+ dbus_message_unref(msg);
+ return;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Ordering NSS responder to update memory cache\n");
+
+ sbus_conn_send_reply(dp_client_conn(dp_cli), msg);
+ dbus_message_unref(msg);
+
+ return;
+}
+
+static errno_t dp_initgroups(struct sbus_request *sbus_req,
+ struct dp_client *dp_cli,
+ const char *key,
+ uint32_t dp_flags,
+ struct be_acct_req *data)
+{
+ struct be_ctx *be_ctx;
+ struct data_provider *provider;
+ struct sss_domain_info *domain;
+ struct dp_initgr_ctx *ctx;
+ struct ldb_result *res;
+ errno_t ret;
+
+ provider = dp_client_provider(dp_cli);
+ be_ctx = provider->be_ctx;
+
+ if (data->domain == NULL) {
+ domain = be_ctx->domain;
+ } else {
+ domain = find_domain_by_name(be_ctx->domain, data->domain, true);
+ if (domain == NULL) {
+ return ERR_DOMAIN_NOT_FOUND;
+ }
+ }
+
+ ret = sysdb_initgroups(sbus_req, domain, data->filter_value, &res);
+ if (ret == ENOENT || (ret == EOK && res->count == 0)) {
+ /* There is no point in concacting NSS responder. Proceed as usual. */
+ return EAGAIN;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get initgroups [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ctx = create_initgr_ctx(sbus_req, data->domain, res);
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dp_req_with_reply_pp(dp_cli, data->domain, "Initgroups", key,
+ sbus_req, DPT_ID, DPM_ACCOUNT_HANDLER, dp_flags, data,
+ dp_req_initgr_pp, ctx, struct dp_initgr_ctx,
+ dp_req_reply_std, struct dp_reply_std);
+
+ ret = EOK;
+
+done:
+ talloc_free(res);
+ return ret;
+}
+
+errno_t dp_get_account_info_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ uint32_t dp_flags,
+ uint32_t entry_type,
+ uint32_t attr_type,
+ const char *filter,
+ const char *domain,
+ const char *extra)
+{
+ struct be_acct_req *data;
+ const char *key;
+ errno_t ret;
+
+ if (!check_attr_type(attr_type)) {
+ return EINVAL;
+ }
+
+ data = talloc_zero(sbus_req, struct be_acct_req);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ data->entry_type = entry_type;
+ data->attr_type = attr_type;
+ data->domain = discard_const(domain); /* todo remove discard const */
+
+ if (!check_and_parse_filter(data, filter, extra)) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ key = talloc_asprintf(data, "%u:%u:%s:%s:%s", data->entry_type,
+ data->attr_type, extra, domain, filter);
+ if (key == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if ((data->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) {
+ ret = dp_initgroups(sbus_req, dp_cli, key, dp_flags, data);
+ if (ret != EAGAIN) {
+ goto done;
+ }
+ }
+
+ dp_req_with_reply(dp_cli, domain, "Account", key,
+ sbus_req, DPT_ID, DPM_ACCOUNT_HANDLER, dp_flags, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(data);
+ }
+
+ return ret;
+}
diff --git a/src/providers/data_provider/dp_target_subdomains.c b/src/providers/data_provider/dp_target_subdomains.c
new file mode 100644
index 000000000..85e37f063
--- /dev/null
+++ b/src/providers/data_provider/dp_target_subdomains.c
@@ -0,0 +1,50 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+errno_t dp_subdomains_handler(struct sbus_request *sbus_req,
+ void *dp_cli,
+ const char *domain_hint)
+{
+ struct dp_subdomains_data *data;
+ const char *key;
+
+ data = talloc_zero(sbus_req, struct dp_subdomains_data);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ data->domain_hint = domain_hint;
+ key = domain_hint[0] == '\0' ? "<ALL>" : domain_hint;
+
+ dp_req_with_reply(dp_cli, NULL, "Subdomains", key, sbus_req,
+ DPT_SUBDOMAINS, DPM_DOMAINS_HANDLER, 0, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ return EOK;
+}
diff --git a/src/providers/data_provider/dp_target_sudo.c b/src/providers/data_provider/dp_target_sudo.c
new file mode 100644
index 000000000..37add97fe
--- /dev/null
+++ b/src/providers/data_provider/dp_target_sudo.c
@@ -0,0 +1,199 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2016 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 "sbus/sssd_dbus.h"
+#include "providers/data_provider/dp_private.h"
+#include "providers/data_provider/dp_iface.h"
+#include "providers/backend.h"
+#include "util/util.h"
+
+static errno_t dp_sudo_parse_message(TALLOC_CTX *mem_ctx,
+ DBusMessage *msg,
+ uint32_t *_dp_flags,
+ uint32_t *_sudo_type,
+ char ***_rules)
+{
+ DBusError error;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ uint32_t dp_flags;
+ uint32_t sudo_type;
+ uint32_t num_rules;
+ const char *rule;
+ char **rules = NULL;
+ uint32_t i;
+ errno_t ret;
+
+ dbus_error_init(&error);
+ dbus_message_iter_init(msg, &iter);
+
+ /* get dp flags */
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&iter, &dp_flags);
+ dbus_message_iter_next(&iter); /* step behind the request type */
+
+ /* get type of the request */
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&iter, &sudo_type);
+ dbus_message_iter_next(&iter); /* step behind the request type */
+
+ /* get additional arguments according to the request type */
+ switch (sudo_type) {
+ case BE_REQ_SUDO_FULL:
+ /* no arguments required */
+ break;
+ case BE_REQ_SUDO_RULES:
+ /* additional arguments:
+ * rules_num
+ * rules[rules_num]
+ */
+ /* read rules_num */
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&iter, &num_rules);
+
+ rules = talloc_zero_array(mem_ctx, char *, num_rules + 1);
+ if (rules == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array() failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_recurse(&iter, &array_iter);
+
+ /* read the rules */
+ for (i = 0; i < num_rules; i++) {
+ if (dbus_message_iter_get_arg_type(&array_iter)
+ != DBUS_TYPE_STRING) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed, to parse the message!\n");
+ ret = EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&array_iter, &rule);
+ rules[i] = talloc_strdup(rules, rule);
+ if (rules[i] == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dbus_message_iter_next(&array_iter);
+ }
+
+ rules[num_rules] = NULL;
+
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request type %d\n", sudo_type);
+ return EINVAL;
+ }
+
+ *_dp_flags = dp_flags;
+ *_sudo_type = sudo_type;
+ *_rules = rules;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(rules);
+ }
+
+ return ret;
+}
+
+static const char *dp_sudo_get_key(uint32_t type)
+{
+ switch (type) {
+ case BE_REQ_SUDO_FULL:
+ return "full-refresh";
+ case BE_REQ_SUDO_RULES:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static const char *dp_sudo_get_name(uint32_t type)
+{
+ switch (type) {
+ case BE_REQ_SUDO_FULL:
+ return "SUDO Full Refresh";
+ case BE_REQ_SUDO_RULES:
+ return "SUDO Rules Refresh";
+ }
+
+ return NULL;
+}
+
+errno_t dp_sudo_handler(struct sbus_request *sbus_req, void *dp_cli)
+{
+ struct dp_sudo_data *data;
+ uint32_t dp_flags;
+ const char *key;
+ const char *name;
+ errno_t ret;
+
+ data = talloc_zero(sbus_req, struct dp_sudo_data);
+ if (data == NULL) {
+ return ENOMEM;
+ }
+
+ ret = dp_sudo_parse_message(data, sbus_req->message, &dp_flags,
+ &data->type, &data->rules);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ key = dp_sudo_get_key(data->type);
+ name = dp_sudo_get_name(data->type);
+
+ dp_req_with_reply(dp_cli, NULL, name, key, sbus_req, DPT_SUDO,
+ DPM_SUDO_HANDLER, dp_flags, data,
+ dp_req_reply_std, struct dp_reply_std);
+
+ return EOK;
+}