/* Authors: Pavel Březina 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 . */ #include #include #include #include "util/util.h" #include "providers/backend.h" #include "providers/ldap/sdap_async.h" #include "providers/ldap/ldap_common.h" struct sdap_online_check_state { struct sdap_id_ctx *id_ctx; struct be_ctx *be_ctx; }; static void sdap_online_check_connect_done(struct tevent_req *subreq); static void sdap_online_check_reinit_done(struct tevent_req *subreq); static struct tevent_req *sdap_online_check_send(TALLOC_CTX *mem_ctx, struct sdap_id_ctx *id_ctx) { struct sdap_online_check_state *state; struct tevent_req *subreq; struct tevent_req *req; struct be_ctx *be_ctx; errno_t ret; req = tevent_req_create(mem_ctx, &state, struct sdap_online_check_state); if (req == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); return NULL; } state->id_ctx = id_ctx; state->be_ctx = be_ctx = id_ctx->be; subreq = sdap_cli_connect_send(state, be_ctx->ev, id_ctx->opts, be_ctx, id_ctx->conn->service, false, CON_TLS_DFL, false); if (subreq == NULL) { ret = ENOMEM; goto immediately; } tevent_req_set_callback(subreq, sdap_online_check_connect_done, req); return req; immediately: if (ret == EOK) { tevent_req_done(req); } else { tevent_req_error(req, ret); } tevent_req_post(req, be_ctx->ev); return req; } static void sdap_online_check_connect_done(struct tevent_req *subreq) { struct sdap_online_check_state *state; struct sdap_server_opts *srv_opts; struct sdap_id_ctx *id_ctx; struct tevent_req *req; bool can_retry; bool reinit = false; errno_t ret; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct sdap_online_check_state); id_ctx = state->id_ctx; ret = sdap_cli_connect_recv(subreq, state, &can_retry, NULL, &srv_opts); talloc_zfree(subreq); if (ret != EOK) { if (can_retry == false) { ret = ERR_OFFLINE; } goto done; } else { if (id_ctx->srv_opts == NULL) { srv_opts->max_user_value = 0; srv_opts->max_group_value = 0; srv_opts->max_service_value = 0; srv_opts->max_sudo_value = 0; } else if (strcmp(srv_opts->server_id, id_ctx->srv_opts->server_id) == 0 && srv_opts->supports_usn && id_ctx->srv_opts->last_usn > srv_opts->last_usn) { id_ctx->srv_opts->max_user_value = 0; id_ctx->srv_opts->max_group_value = 0; id_ctx->srv_opts->max_service_value = 0; id_ctx->srv_opts->max_sudo_value = 0; id_ctx->srv_opts->last_usn = srv_opts->last_usn; reinit = true; } sdap_steal_server_opts(id_ctx, &srv_opts); } if (reinit) { DEBUG(SSSDBG_TRACE_FUNC, "Server reinitialization detected. " "Cleaning cache.\n"); subreq = sdap_reinit_cleanup_send(state, state->be_ctx, id_ctx); if (subreq == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to perform reinitialization " "clean up.\n"); /* not fatal */ goto done; } tevent_req_set_callback(subreq, sdap_online_check_reinit_done, req); return; } ret = EOK; done: if (ret != EOK) { tevent_req_error(req, ret); return; } tevent_req_done(req); } static void sdap_online_check_reinit_done(struct tevent_req *subreq) { struct tevent_req *req; errno_t ret; req = tevent_req_callback_data(subreq, struct tevent_req); ret = sdap_reinit_cleanup_recv(subreq); talloc_zfree(subreq); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to perform reinitialization " "clean up [%d]: %s\n", ret, strerror(ret)); /* not fatal */ } else { DEBUG(SSSDBG_TRACE_FUNC, "Reinitialization clean up completed\n"); } tevent_req_done(req); } static errno_t sdap_online_check_recv(struct tevent_req *req) { TEVENT_REQ_RETURN_ON_ERROR(req); return EOK; } struct sdap_online_check_handler_state { struct dp_reply_std reply; }; static void sdap_online_check_handler_done(struct tevent_req *subreq); struct tevent_req * sdap_online_check_handler_send(TALLOC_CTX *mem_ctx, struct sdap_id_ctx *id_ctx, void *data, struct dp_req_params *params) { struct sdap_online_check_handler_state *state; struct tevent_req *subreq; struct tevent_req *req; errno_t ret; req = tevent_req_create(mem_ctx, &state, struct sdap_online_check_handler_state); if (req == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n"); return NULL; } subreq = sdap_online_check_send(state, id_ctx); if (subreq == NULL) { ret = ENOMEM; goto immediately; } tevent_req_set_callback(subreq, sdap_online_check_handler_done, req); return req; immediately: dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); /* TODO For backward compatibility we always return EOK to DP now. */ tevent_req_done(req); tevent_req_post(req, params->ev); return req; } static void sdap_online_check_handler_done(struct tevent_req *subreq) { struct sdap_online_check_handler_state *state; struct tevent_req *req; errno_t ret; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct sdap_online_check_handler_state); ret = sdap_online_check_recv(subreq); talloc_zfree(subreq); /* TODO For backward compatibility we always return EOK to DP now. */ dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL); tevent_req_done(req); } errno_t sdap_online_check_handler_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, struct dp_reply_std *data) { struct sdap_online_check_handler_state *state = NULL; state = tevent_req_data(req, struct sdap_online_check_handler_state); TEVENT_REQ_RETURN_ON_ERROR(req); *data = state->reply; return EOK; }