responder_dp.c revision b42b5d5aaf4da165582e73ad985fdff6e34e61e4
/*
Authors:
Simo Sorce <ssorce@redhat.com>
Stephen Gallagher <sgallagh@redhat.com>
Copyright (C) 2009 Red Hat
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 <time.h>
#include "responder/common/responder_packet.h"
#include "responder/common/responder.h"
#include "providers/data_provider.h"
#include "sbus/sbus_client.h"
struct sss_dp_req;
struct sss_dp_callback {
struct sss_dp_callback *prev;
struct sss_dp_callback *next;
struct tevent_req *req;
struct sss_dp_req *sdp_req;
};
struct sss_dp_req {
struct tevent_context *ev;
struct tevent_timer *tev;
struct sss_dp_callback *cb_list;
char *err_msg;
};
static int sss_dp_callback_destructor(void *ptr)
{
struct sss_dp_callback *cb =
return EOK;
}
static int sss_dp_req_destructor(void *ptr)
{
struct sss_dp_callback *cb;
struct sss_dp_req_state *state;
int hret;
/* Cancel Dbus pending reply if still pending */
if (sdp_req->pending_reply) {
}
/* If there are callbacks that haven't been invoked, return
* an error now.
*/
/* tevent_req_done/error will free cb */
/* Freeing the cb removes it from the cb_list.
* Therefore, the cb_list should now be pointing
* at a new callback. If it's not, it means the
* callback handler didn't free cb and may leak
* memory. Be paranoid and protect against this
* situation.
*/
("BUG: a callback did not free its request. "
"May leak memory\n"));
/* Skip to the next since a memory leak is non-fatal */
}
}
/* Destroy the hash entry */
if (hret != HASH_SUCCESS) {
/* This should never happen */
("BUG: Could not clear [%d:%d:%s] from request queue: [%s]\n",
return -1;
}
return 0;
}
{
int ret;
unsigned long count, i;
struct sss_dp_req *sdp_req;
if (!rctx->dp_request_table) {
return;
}
if (ret != HASH_SUCCESS) {
"not all request might be handled after reconnect.\n"));
return;
}
for (i=0; i<count; i++) {
}
}
char **err_msg)
{
int type;
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.
*/
("Severe error. A reply callback was called but no reply "
"was received and no timeout occurred\n"));
/* FIXME: Destroy this connection ? */
goto done;
}
switch (type) {
if (!ret) {
/* FIXME: Destroy this connection ? */
goto done;
}
("Got reply from Data Provider - "
"DP error code: %u errno: %u error message: %s\n",
break;
case DBUS_MESSAGE_TYPE_ERROR:
DBUS_ERROR_NO_REPLY) == 0) {
goto done;
}
DEBUG(0,("The Data Provider returned an error [%s]\n",
/* 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 ? */
}
done:
return err;
}
static struct tevent_req *
struct sss_domain_info *dom,
DBusMessage *msg);
static void
struct tevent_req *nreq)
{
int hret;
struct tevent_req *sidereq;
struct sss_dp_req *sdp_req;
struct sss_dp_callback *cb;
if (!tmp_ctx) {
return ENOMEM;
}
if (!key) {
goto fail;
}
goto fail;
}
/* Check the hash for existing references to this request */
switch (hret) {
case HASH_SUCCESS:
/* Request already in progress */
break;
case HASH_ERROR_KEY_NOT_FOUND:
/* No such request in progress
* Create a new request
*/
if (!msg) {
goto fail;
}
if (!sidereq) {
goto fail;
}
/* We should now be able to find the sdp_req in the hash table */
if (hret != HASH_SUCCESS) {
/* Something must have gone wrong with creating the request */
goto fail;
}
break;
default:
("Could not query request list (%s)\n",
goto fail;
}
/* Register this request for results */
if (!sdp_req) {
goto fail;
}
if (!cb) {
goto fail;
}
/* Add it to the list of requests to call */
struct sss_dp_callback *);
fail:
return ret;
}
static void
{
/* Nothing to do here. The callbacks have already been invoked */
}
struct tevent_req *sidereq,
char **err_msg)
{
struct sss_dp_req_state *state =
enum tevent_req_state TRROEstate;
if (TRROEstate == TEVENT_REQ_USER_ERROR) {
*dp_err = DP_ERR_FATAL;
} else {
return EIO;
}
}
return EOK;
}
/* Send a request to the data provider
* Once this function is called, the communication
* with the data provider will always run to
* completion. Freeing the returned tevent_req will
* cancel the notification of completion, but not
* the data provider action.
*/
struct sss_dp_account_info {
struct sss_domain_info *dom;
bool fast_reply;
enum sss_dp_acct_type type;
const char *opt_name;
const char *extra;
};
struct tevent_req *
struct sss_domain_info *dom,
bool fast_reply,
enum sss_dp_acct_type type,
const char *opt_name,
const char *extra)
{
struct tevent_req *req;
struct sss_dp_account_info *info;
struct sss_dp_req_state *state;
char *key;
if (!req) {
return NULL;
}
/* either, or, not both */
goto error;
}
if (!dom) {
goto error;
}
if (opt_name) {
if (extra) {
} else {
}
} else if (opt_id) {
if (extra) {
} else {
}
} else {
}
if (!key) {
goto error;
}
("Could not issue DP request [%d]: %s\n",
goto error;
}
return req;
return req;
}
static DBusMessage *
sss_dp_get_account_msg(void *pvt)
{
struct sss_dp_account_info *info;
char *filter;
case SSS_DP_USER:
break;
case SSS_DP_GROUP:
break;
case SSS_DP_INITGROUPS:
break;
case SSS_DP_NETGR:
break;
case SSS_DP_SERVICES:
break;
}
if (info->fast_reply) {
be_type |= BE_REQ_FAST;
}
} else {
}
} else {
}
} else {
}
if (!filter) {
return NULL;
}
return NULL;
}
/* create the message */
("Creating request for [%s][%u][%d][%s]\n",
if (!dbret) {
return NULL;
}
return msg;
}
struct tevent_req *req,
char **err_msg)
{
}
struct dp_internal_get_state {
struct sss_domain_info *dom;
struct sss_dp_req *sdp_req;
};
static struct tevent_req *
struct sss_domain_info *dom,
{
int hret;
struct tevent_req *req;
struct dp_internal_get_state *state;
/* Internal requests need to be allocated on the responder context
* so that they don't go away if a client disconnects. The worst-
* case scenario here is that the cache is updated without any
* client expecting a response.
*/
&state,
struct dp_internal_get_state);
goto error;
}
/* Copy the key to use when calling the destructor
* It needs to be a copy because the original request
* might be freed if it no longer cares about the reply.
*/
/* 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.
*/
("BUG: The Data Provider connection for %s is not available!",
goto error;
}
req,
/*
* Critical Failure
* We can't communicate on this connection
*/
("D-BUS send failed.\n"));
goto error;
}
/* Add this sdp_req to the hash table */
if (hret != HASH_SUCCESS) {
("Could not store request query (%s)\n",
goto error;
}
return req;
return req;
}
{
int ret;
struct tevent_req *req;
struct sss_dp_req *sdp_req;
struct sss_dp_callback *cb;
struct dp_internal_get_state *state;
struct sss_dp_req_state *cb_state;
/* prevent trying to cancel a reply that we already received */
}
else {
"Failed to get reply from Data Provider");
}
}
/* Check whether we need to issue any callbacks */
/* Don't bother checking for NULL. If it fails due to ENOMEM,
* we can't really handle it anyway.
*/
/* tevent_req_done/error will free cb */
} else {
}
/* Freeing the cb removes it from the cb_list.
* Therefore, the cb_list should now be pointing
* at a new callback. If it's not, it means the
* callback handler didn't free cb and may leak
* memory. Be paranoid and protect against this
* situation.
*/
("BUG: a callback did not free its request. "
"May leak memory\n"));
/* Skip to the next since a memory leak is non-fatal */
}
}
/* We're done with this request. Free the sdp_req
* This will clean up the hash table entry as well
*/
}