diff options
Diffstat (limited to 'server/responder/common/responder_dp.c')
-rw-r--r-- | server/responder/common/responder_dp.c | 590 |
1 files changed, 0 insertions, 590 deletions
diff --git a/server/responder/common/responder_dp.c b/server/responder/common/responder_dp.c deleted file mode 100644 index 782befb1..00000000 --- a/server/responder/common/responder_dp.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - Authors: - Simo Sorce <ssorce@redhat.com> - Stephen Gallagher <sgallagh@redhat.com> - - Copyright (C) 2009 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 <sys/time.h> -#include <time.h> -#include "util/util.h" -#include "responder/common/responder_packet.h" -#include "responder/common/responder.h" -#include "providers/data_provider.h" -#include "sbus/sbus_client.h" - -hash_table_t *dp_requests = NULL; - -struct sss_dp_req; - -struct sss_dp_callback { - struct sss_dp_callback *prev; - struct sss_dp_callback *next; - - struct sss_dp_req *sdp_req; - - sss_dp_callback_t callback; - void *callback_ctx; -}; - -struct sss_dp_req { - struct tevent_context *ev; - DBusPendingCall *pending_reply; - - char *key; - - struct tevent_timer *tev; - struct sss_dp_callback *cb_list; - - dbus_uint16_t err_maj; - dbus_uint32_t err_min; - char *err_msg; -}; - -static int sss_dp_callback_destructor(void *ptr) -{ - struct sss_dp_callback *cb = talloc_get_type(ptr, struct sss_dp_callback); - - DLIST_REMOVE(cb->sdp_req->cb_list, cb); - - return EOK; -} - -static int sss_dp_req_destructor(void *ptr) -{ - struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req); - struct sss_dp_callback *cb, *next; - hash_key_t key; - - /* Cancel Dbus pending reply if still pending */ - if (sdp_req->pending_reply) { - dbus_pending_call_cancel(sdp_req->pending_reply); - sdp_req->pending_reply = NULL; - } - - /* Destroy the hash entry */ - key.type = HASH_KEY_STRING; - key.str = sdp_req->key; - int hret = hash_delete(dp_requests, &key); - if (hret != HASH_SUCCESS) { - /* This should never happen */ - DEBUG(0, ("Could not clear entry from request queue\n")); - } - - /* Free any remaining callback */ - if (sdp_req->err_maj == DP_ERR_OK) { - sdp_req->err_maj = DP_ERR_FATAL; - sdp_req->err_min = EIO; - sdp_req->err_msg = discard_const_p(char, "Internal Error"); - } - - cb = sdp_req->cb_list; - while (cb) { - cb->callback(sdp_req->err_maj, - sdp_req->err_min, - sdp_req->err_msg, - cb->callback_ctx); - next = cb->next; - talloc_free(cb); - cb = next; - } - - return 0; -} - -static void sdp_req_timeout(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval t, void *ptr) -{ - struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req); - - sdp_req->err_maj = DP_ERR_FATAL; - sdp_req->err_min = ETIMEDOUT; - sdp_req->err_msg = discard_const_p(char, "Timed out"); - - /* steal te on NULL because it will be freed as soon as the handler - * returns. Causing a double free if we don't, as te is allocated on - * sdp_req and we are just going to free it */ - talloc_steal(NULL, te); - - talloc_free(sdp_req); -} - -static int sss_dp_get_reply(DBusPendingCall *pending, - dbus_uint16_t *err_maj, - dbus_uint32_t *err_min, - char **err_msg); - -static void sss_dp_invoke_callback(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval t, void *ptr) -{ - struct sss_dp_req *sdp_req = talloc_get_type(ptr, struct sss_dp_req); - struct sss_dp_callback *cb; - struct timeval tv; - struct tevent_timer *tev; - - cb = sdp_req->cb_list; - /* Remove the callback from the list, the caller may free it, within the - * callback. */ - talloc_set_destructor((TALLOC_CTX *)cb, NULL); - DLIST_REMOVE(sdp_req->cb_list, cb); - - cb->callback(sdp_req->err_maj, - sdp_req->err_min, - sdp_req->err_msg, - cb->callback_ctx); - - /* Call the next callback if needed */ - if (sdp_req->cb_list != NULL) { - tv = tevent_timeval_current(); - tev = tevent_add_timer(sdp_req->ev, sdp_req, tv, - sss_dp_invoke_callback, sdp_req); - if (!te) { - /* Out of memory or other serious error */ - goto done; - } - - return; - } - - /* No more callbacks to invoke. Destroy the request */ -done: - /* steal te on NULL because it will be freed as soon as the handler - * returns. Causing a double free if we don't, as te is allocated on - * sdp_req and we are just going to free it */ - talloc_steal(NULL, te); - - talloc_zfree(sdp_req); -} - -static void sss_dp_send_acct_callback(DBusPendingCall *pending, void *ptr) -{ - int ret; - struct sss_dp_req *sdp_req; - struct sss_dp_callback *cb; - struct timeval tv; - struct tevent_timer *te; - - sdp_req = talloc_get_type(ptr, struct sss_dp_req); - - /* prevent trying to cancel a reply that we already received */ - sdp_req->pending_reply = NULL; - - ret = sss_dp_get_reply(pending, - &sdp_req->err_maj, - &sdp_req->err_min, - &sdp_req->err_msg); - if (ret != EOK) { - if (ret == ETIME) { - sdp_req->err_maj = DP_ERR_TIMEOUT; - sdp_req->err_min = ret; - sdp_req->err_msg = talloc_strdup(sdp_req, "Request timed out"); - } - else { - sdp_req->err_maj = DP_ERR_FATAL; - sdp_req->err_min = ret; - sdp_req->err_msg = - talloc_strdup(sdp_req, - "Failed to get reply from Data Provider"); - } - } - - /* Check whether we need to issue any callbacks */ - cb = sdp_req->cb_list; - if (sdp_req->cb_list == NULL) { - if (cb == NULL) { - /* No callbacks to invoke. Destroy the hash entry */ - talloc_zfree(sdp_req); - return; - } - } - - /* Queue up all callbacks */ - tv = tevent_timeval_current(); - te = tevent_add_timer(sdp_req->ev, sdp_req, tv, - sss_dp_invoke_callback, sdp_req); - if (!te) { - /* Out of memory or other serious error */ - goto error; - } - - return; - -error: - talloc_zfree(sdp_req); -} - -static int sss_dp_send_acct_req_create(struct resp_ctx *rctx, - TALLOC_CTX *callback_memctx, - const char *domain, - uint32_t be_type, - char *filter, - int timeout, - sss_dp_callback_t callback, - void *callback_ctx, - struct sss_dp_req **ndp); - -int sss_dp_send_acct_req(struct resp_ctx *rctx, TALLOC_CTX *callback_memctx, - sss_dp_callback_t callback, void *callback_ctx, - int timeout, const char *domain, - bool fast_reply, int type, - const char *opt_name, uint32_t opt_id) -{ - int ret, hret; - uint32_t be_type; - char *filter; - hash_key_t key; - hash_value_t value; - TALLOC_CTX *tmp_ctx; - struct timeval tv; - struct sss_dp_req *sdp_req = NULL; - struct sss_dp_callback *cb; - - /* either, or, not both */ - if (opt_name && opt_id) { - return EINVAL; - } - - if (!domain) { - return EINVAL; - } - - switch (type) { - case SSS_DP_USER: - be_type = BE_REQ_USER; - break; - case SSS_DP_GROUP: - be_type = BE_REQ_GROUP; - break; - case SSS_DP_INITGROUPS: - be_type = BE_REQ_INITGROUPS; - break; - default: - return EINVAL; - } - - if (fast_reply) { - be_type |= BE_REQ_FAST; - } - - if (dp_requests == NULL) { - /* Create a hash table to handle queued update requests */ - ret = hash_create(10, &dp_requests, NULL, NULL); - if (ret != HASH_SUCCESS) { - fprintf(stderr, "cannot create hash table (%s)\n", hash_error_string(ret)); - return EIO; - } - } - - tmp_ctx = talloc_new(NULL); - if (!tmp_ctx) { - return ENOMEM; - } - - key.type = HASH_KEY_STRING; - key.str = NULL; - - if (opt_name) { - filter = talloc_asprintf(tmp_ctx, "name=%s", opt_name); - key.str = talloc_asprintf(tmp_ctx, "%d%s@%s", type, opt_name, domain); - } else if (opt_id) { - filter = talloc_asprintf(tmp_ctx, "idnumber=%u", opt_id); - key.str = talloc_asprintf(tmp_ctx, "%d%d@%s", type, opt_id, domain); - } else { - filter = talloc_strdup(tmp_ctx, "name=*"); - key.str = talloc_asprintf(tmp_ctx, "%d*@%s", type, domain); - } - if (!filter || !key.str) { - talloc_zfree(tmp_ctx); - return ENOMEM; - } - - /* Check whether there's already a request in progress */ - hret = hash_lookup(dp_requests, &key, &value); - switch (hret) { - case HASH_SUCCESS: - /* Request already in progress - * Add an additional callback if needed and return - */ - DEBUG(2, ("Identical request in progress\n")); - - if (callback) { - /* We have a new request asking for a callback */ - sdp_req = talloc_get_type(value.ptr, struct sss_dp_req); - if (!sdp_req) { - DEBUG(0, ("Could not retrieve DP request context\n")); - ret = EIO; - goto done; - } - - cb = talloc_zero(callback_memctx, struct sss_dp_callback); - if (!cb) { - ret = ENOMEM; - goto done; - } - - cb->callback = callback; - cb->callback_ctx = callback_ctx; - cb->sdp_req = sdp_req; - - DLIST_ADD_END(sdp_req->cb_list, cb, struct sss_dp_callback *); - talloc_set_destructor((TALLOC_CTX *)cb, sss_dp_callback_destructor); - } - - ret = EOK; - break; - - case HASH_ERROR_KEY_NOT_FOUND: - /* No such request in progress - * Create a new request - */ - ret = sss_dp_send_acct_req_create(rctx, callback_memctx, domain, - be_type, filter, timeout, - callback, callback_ctx, - &sdp_req); - if (ret != EOK) { - goto done; - } - - value.type = HASH_VALUE_PTR; - value.ptr = sdp_req; - hret = hash_enter(dp_requests, &key, &value); - if (hret != HASH_SUCCESS) { - DEBUG(0, ("Could not store request query (%s)", - hash_error_string(hret))); - talloc_zfree(sdp_req); - ret = EIO; - goto done; - } - - sdp_req->key = talloc_strdup(sdp_req, key.str); - - tv = tevent_timeval_current_ofs(timeout, 0); - sdp_req->tev = tevent_add_timer(sdp_req->ev, sdp_req, tv, - sdp_req_timeout, sdp_req); - if (!sdp_req->tev) { - DEBUG(0, ("Out of Memory!?")); - talloc_zfree(sdp_req); - ret = ENOMEM; - goto done; - } - - talloc_set_destructor((TALLOC_CTX *)sdp_req, sss_dp_req_destructor); - - ret = EOK; - break; - - default: - DEBUG(0,("Could not query request list (%s)\n", - hash_error_string(hret))); - talloc_zfree(sdp_req); - ret = EIO; - } - -done: - talloc_zfree(tmp_ctx); - return ret; -} - -static int sss_dp_send_acct_req_create(struct resp_ctx *rctx, - TALLOC_CTX *callback_memctx, - const char *domain, - uint32_t be_type, - char *filter, - int timeout, - sss_dp_callback_t callback, - void *callback_ctx, - struct sss_dp_req **ndp) -{ - DBusConnection *dbus_conn; - DBusMessage *msg; - DBusPendingCall *pending_reply; - dbus_bool_t dbret; - struct sss_dp_callback *cb; - struct sss_dp_req *sdp_req; - uint32_t attrs = BE_ATTR_CORE; - struct be_conn *be_conn; - int ret; - - /* double check dp_ctx has actually been initialized. - * in some pathological cases it may happen that nss starts up before - * dp connection code is actually able to establish a connection. - */ - ret = sss_dp_get_domain_conn(rctx, domain, &be_conn); - if (ret != EOK) { - DEBUG(1, ("The Data Provider connection for %s is not available!" - " This maybe a bug, it shouldn't happen!\n", domain)); - return EIO; - } - dbus_conn = sbus_get_connection(be_conn->conn); - - /* create the message */ - msg = dbus_message_new_method_call(NULL, - DP_PATH, - DP_INTERFACE, - DP_METHOD_GETACCTINFO); - if (msg == NULL) { - DEBUG(0,("Out of memory?!\n")); - return ENOMEM; - } - - DEBUG(4, ("Sending request for [%s][%u][%d][%s]\n", - domain, be_type, attrs, filter)); - - dbret = dbus_message_append_args(msg, - DBUS_TYPE_UINT32, &be_type, - DBUS_TYPE_UINT32, &attrs, - DBUS_TYPE_STRING, &filter, - DBUS_TYPE_INVALID); - if (!dbret) { - DEBUG(1,("Failed to build message\n")); - return EIO; - } - - dbret = dbus_connection_send_with_reply(dbus_conn, msg, - &pending_reply, timeout); - if (!dbret || pending_reply == NULL) { - /* - * Critical Failure - * We can't communicate on this connection - * We'll drop it using the default destructor. - */ - DEBUG(0, ("D-BUS send failed.\n")); - dbus_message_unref(msg); - return EIO; - } - - sdp_req = talloc_zero(rctx, struct sss_dp_req); - if (!sdp_req) { - dbus_message_unref(msg); - return ENOMEM; - } - sdp_req->ev = rctx->ev; - sdp_req->pending_reply = pending_reply; - - if (callback) { - cb = talloc_zero(callback_memctx, struct sss_dp_callback); - if (!cb) { - dbus_message_unref(msg); - talloc_zfree(sdp_req); - return ENOMEM; - } - cb->callback = callback; - cb->callback_ctx = callback_ctx; - cb->sdp_req = sdp_req; - - DLIST_ADD(sdp_req->cb_list, cb); - talloc_set_destructor((TALLOC_CTX *)cb, sss_dp_callback_destructor); - } - - /* Set up the reply handler */ - dbret = dbus_pending_call_set_notify(pending_reply, - sss_dp_send_acct_callback, - sdp_req, NULL); - if (!dbret) { - DEBUG(0, ("Could not queue up pending request!")); - talloc_zfree(sdp_req); - dbus_pending_call_cancel(pending_reply); - dbus_message_unref(msg); - return EIO; - } - - dbus_message_unref(msg); - - *ndp = sdp_req; - - return EOK; -} - -static int sss_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")); - - /* FIXME: Destroy this connection ? */ - 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")); - /* FIXME: Destroy this connection ? */ - 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. - */ - - /* FIXME: Destroy this connection ? */ - err = EIO; - } - -done: - dbus_pending_call_unref(pending); - dbus_message_unref(reply); - - return err; -} - |