diff options
| author | Pavel Březina <pbrezina@redhat.com> | 2016-03-29 12:38:25 +0200 |
|---|---|---|
| committer | Jakub Hrozek <jhrozek@redhat.com> | 2016-06-20 14:48:47 +0200 |
| commit | dea636af4d1902a081ee891f1b19ee2f8729d759 (patch) | |
| tree | a4d66ceb2b32ddf3b69bee1f1e2412568eae655e /src/providers/data_provider | |
| parent | 62370340092503baeaf6587d7ffe4fe25bd9582d (diff) | |
| download | sssd-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.h | 30 | ||||
| -rw-r--r-- | src/providers/data_provider/dp_iface.c | 12 | ||||
| -rw-r--r-- | src/providers/data_provider/dp_iface.h | 28 | ||||
| -rw-r--r-- | src/providers/data_provider/dp_target_auth.c | 302 | ||||
| -rw-r--r-- | src/providers/data_provider/dp_target_autofs.c | 55 | ||||
| -rw-r--r-- | src/providers/data_provider/dp_target_hostid.c | 63 | ||||
| -rw-r--r-- | src/providers/data_provider/dp_target_id.c | 311 | ||||
| -rw-r--r-- | src/providers/data_provider/dp_target_subdomains.c | 50 | ||||
| -rw-r--r-- | src/providers/data_provider/dp_target_sudo.c | 199 |
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; +} |
