d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina Pavel Březina <pbrezina@redhat.com>
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina Copyright (C) 2016 Red Hat
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina This program is free software; you can redistribute it and/or modify
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina it under the terms of the GNU General Public License as published by
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina the Free Software Foundation; either version 3 of the License, or
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina (at your option) any later version.
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina This program is distributed in the hope that it will be useful,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina but WITHOUT ANY WARRANTY; without even the implied warranty of
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina GNU General Public License for more details.
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina You should have received a copy of the GNU General Public License
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina along with this program. If not, see <http://www.gnu.org/licenses/>.
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina#include "providers/data_provider/dp_private.h"
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* Active request list. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastatic bool check_data_type(const char *expected,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* If ptr is NULL we still return true since it is valid case. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Invalid %s data type provided. Expected [%s], "
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina "got [%s].\n", description, expected, talloc_get_name(ptr));
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina return false;
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastatic bool check_method_data(struct dp_method *method,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (!check_data_type(method->method_dtype, "method", method->method_data)) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina return false;
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (!check_data_type(method->request_dtype, "request", request_data)) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina return false;
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastatic int dp_req_destructor(struct dp_req *dp_req)
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DLIST_REMOVE(dp_req->provider->requests.active, dp_req);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (dp_req->provider->requests.num_active == 0) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Bug: there are no active requests!\n");
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, dp_req->name, "Request removed.");
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_TRACE_FUNC, "Number of active DP request: %u\n",
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastatic errno_t dp_attach_req(struct dp_req *dp_req,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* If we run out of numbers we simply overflow. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina dp_req->name = talloc_asprintf(dp_req, "%s #%u", name, dp_req->num);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* Attach this request to active request list. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina talloc_set_destructor(dp_req, dp_req_destructor);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_TRACE_FUNC, "Number of active DP request: %u\n",
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* We set output even for error to simplify code flow in the caller. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina ret = dp_attach_req(dp_req, provider, name, dp_flags);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create DP request "
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina "[%s] [%d]: %s\n", name, ret, sss_strerror(ret));
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* Now the request is created. We will return it even in case of error
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina * so we can get better debug messages. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina dp_req->domain = find_domain_by_name(be_ctx->domain, domainname, true);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Unknown domain: %s\n", domainname);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina ret = dp_find_method(provider, target, method, &dp_req->execute);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina ret = dp_req_new(mem_ctx, provider, dp_cli, domainname, name, target,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina method, dp_flags, request_data, req, &dp_req);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* DP request is already created. We will always return it to get nice
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina * debug messages. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* Check that provided data are of correct type. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (!check_method_data(dp_req->execute, dp_req->request_data)) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* Process data provider flags */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (dp_flags & DP_FAST_REPLY && be_is_offline(be_ctx)) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* File request */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina dp_params = talloc_zero(dp_req, struct dp_req_params);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina dp_req->handler_req = send_fn(dp_req, dp_req->execute->method_data,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastatic void dp_req_done(struct tevent_req *subreq);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastruct tevent_req *dp_req_send(TALLOC_CTX *mem_ctx,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina req = tevent_req_create(mem_ctx, &state, struct dp_req_state);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina ret = file_dp_request(state, provider, dp_cli, domain, name, target,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina method, dp_flags, request_data, req, &dp_req);
4a9c1047354dbe5a4ed41e5951ae623e3772e113René Genz /* An error occurred before request could be created. */
d46d59e78600aa72176df7217c94743b7e71881aJustin Stephenson PROBE(DP_REQ_SEND, domain, dp_req->name, target, method);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina request_name = talloc_strdup(mem_ctx, dp_req->name);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina state->output_data = talloc_zero_size(state, dp_req->execute->output_size);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina talloc_set_name_const(state->output_data, dp_req->execute->output_dtype);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina tevent_req_set_callback(dp_req->handler_req, dp_req_done, req);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastatic void dp_req_done(struct tevent_req *subreq)
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina req = tevent_req_callback_data(subreq, struct tevent_req);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina state = tevent_req_data(req, struct dp_req_state);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina ret = state->recv_fn(state->output_data, subreq, state->output_data);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* subreq is the same as dp_req->handler_req */
d46d59e78600aa72176df7217c94743b7e71881aJustin Stephenson PROBE(DP_REQ_DONE, state->dp_req->name, state->dp_req->target,
d46d59e78600aa72176df7217c94743b7e71881aJustin Stephenson state->dp_req->method, ret, sss_strerror(ret));
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->dp_req->name,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina "Request handler finished [%d]: %s", ret, sss_strerror(ret));
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina state = tevent_req_data(req, struct dp_req_state);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->dp_req->name,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina "Receiving request data.");
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* dp_req may be NULL in case we error when filing request */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina "Receiving data of prematurely interrupted request!\n");
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (!check_data_type(output_dtype, "output", state->output_data)) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina *_output_data = talloc_steal(mem_ctx, state->output_data);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastatic void dp_terminate_request(struct dp_req *dp_req)
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* This may occur when the handler already finished but the caller
a02a5ed51178b2cbede0396d66aed716b8898096René Genz * of dp request did not yet received data/free dp_req. We just
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina * return here. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina /* We will end the handler request and mark dp request as terminated. */
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DP_REQ_DEBUG(SSSDBG_TRACE_ALL, dp_req->name, "Terminating.");
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina tevent_req_error(dp_req->req, ERR_TERMINATED);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinastatic void dp_terminate_request_list(struct data_provider *provider,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (provider == NULL || provider->requests.active == NULL) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina for (cur = provider->requests.active; cur != NULL; cur = next) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (domain == NULL || strcmp(cur->domain->name, domain) == 0) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinavoid dp_terminate_active_requests(struct data_provider *provider)
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_TRACE_FUNC, "Terminating active data provider requests\n");
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinavoid dp_terminate_domain_requests(struct data_provider *provider,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_TRACE_FUNC, "Terminating active data provider requests "
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Bug: domain is NULL!\n");