summaryrefslogtreecommitdiffstats
path: root/server/providers/data_provider.c
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2009-01-06 18:23:59 -0500
committerSimo Sorce <idra@samba.org>2009-01-06 18:23:59 -0500
commit5aa5391dcd8a7d593757c0af3a765bbce1ce2138 (patch)
tree6fe184bed37e97e72e9dfd59739aef0785e29fd8 /server/providers/data_provider.c
parentc1f2536bac22d17ab658050f0cacb0528b01a87f (diff)
downloadsssd-5aa5391dcd8a7d593757c0af3a765bbce1ce2138.tar.gz
sssd-5aa5391dcd8a7d593757c0af3a765bbce1ce2138.tar.xz
sssd-5aa5391dcd8a7d593757c0af3a765bbce1ce2138.zip
Add more infrastructure to data provider to dispatch requests (still untested).
Add helper functions to connect to the data provider. Add some plumbing to the ldap provider (still untested).
Diffstat (limited to 'server/providers/data_provider.c')
-rw-r--r--server/providers/data_provider.c343
1 files changed, 334 insertions, 9 deletions
diff --git a/server/providers/data_provider.c b/server/providers/data_provider.c
index 823054ab7..645c14250 100644
--- a/server/providers/data_provider.c
+++ b/server/providers/data_provider.c
@@ -57,7 +57,6 @@ struct dp_ctx {
struct dp_client {
struct dp_ctx *dpctx;
struct sbus_conn_ctx *conn_ctx;
- const char *domain;
};
struct dp_backend {
@@ -83,13 +82,30 @@ static int service_identity(DBusMessage *message, void *data, DBusMessage **r);
static int service_pong(DBusMessage *message, void *data, DBusMessage **r);
struct sbus_method mon_sbus_methods[] = {
- {SERVICE_METHOD_IDENTITY, service_identity},
- {SERVICE_METHOD_PING, service_pong},
- {NULL, NULL}
+ { SERVICE_METHOD_IDENTITY, service_identity },
+ { SERVICE_METHOD_PING, service_pong },
+ { NULL, NULL }
};
+static int dp_get_account_info(DBusMessage *message, void *data, DBusMessage **r);
+
struct sbus_method dp_sbus_methods[] = {
- {NULL, NULL}
+ { DP_SRV_METHOD_GETACCTINFO, dp_get_account_info },
+ { NULL, NULL }
+};
+
+struct dp_request {
+ /* reply message to send when request is done */
+ DBusMessage *reply;
+ /* frontend client that made the request */
+ struct dp_client *src_cli;
+
+ int pending_replies;
+};
+
+struct dp_be_request {
+ struct dp_request *req;
+ struct dp_client *be_cli;
};
static int service_identity(DBusMessage *message, void *data, DBusMessage **r)
@@ -193,6 +209,7 @@ static int dp_db_init(struct dp_ctx *dpctx)
static void be_identity_check(DBusPendingCall *pending, void *data);
static void be_online_check(DBusPendingCall *pending, void *data);
+static void be_got_account_info(DBusPendingCall *pending, void *data);
static int dbus_dp_init(struct sbus_conn_ctx *conn_ctx, void *data)
{
@@ -280,7 +297,7 @@ static void be_identity_check(DBusPendingCall *pending, void *data)
* until reply is valid or timeout has occurred. If reply is NULL
* here, something is seriously wrong and we should bail out.
*/
- DEBUG(0, ("Serious error. A reply callback was called but no reply was received and no timeout occurred\n"));
+ DEBUG(0, ("Severe error. A reply callback was called but no reply was received and no timeout occurred\n"));
/* Destroy this connection */
sbus_disconnect(dpcli->conn_ctx);
@@ -382,6 +399,314 @@ static void be_online_check(DBusPendingCall *pending, void *data)
return;
}
+static void be_got_account_info(DBusPendingCall *pending, void *data)
+{
+ struct dp_be_request *bereq;
+ DBusMessage *reply;
+ DBusConnection *conn;
+ DBusError dbus_error;
+ dbus_uint16_t cli_err_maj;
+ dbus_uint32_t cli_err_min;
+ char *cli_err_msg;
+ dbus_bool_t ret;
+ int type;
+
+ bereq = talloc_get_type(data, struct dp_be_request);
+ 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"));
+
+ /* Destroy this connection */
+ sbus_disconnect(bereq->be_cli->conn_ctx);
+ 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, &cli_err_maj,
+ DBUS_TYPE_UINT32, &cli_err_min,
+ DBUS_TYPE_STRING, &cli_err_msg,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("be_identity_check failed, to parse message, killing connection\n"));
+ sbus_disconnect(bereq->be_cli->conn_ctx);
+ goto done;
+ }
+
+ /* Set up the destructor for this service */
+ break;
+
+ case DBUS_MESSAGE_TYPE_ERROR:
+ DEBUG(0,("getAccountInfo returned an error [%s], closing connection.\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.
+ */
+ sbus_disconnect(bereq->be_cli->conn_ctx);
+ }
+
+ /* TODO: handle errors !! */
+ if (bereq->req->pending_replies > 1) {
+ bereq->req->pending_replies--;
+ talloc_free(bereq);
+ } else {
+ conn = sbus_get_connection(bereq->be_cli->conn_ctx);
+ ret = dbus_message_append_args(bereq->req->reply,
+ DBUS_TYPE_UINT16, 0,
+ DBUS_TYPE_UINT32, 0,
+ DBUS_TYPE_STRING, "Success",
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1, ("Failed to build reply ... frontend will wait for timeout ...\n"));
+ talloc_free(bereq->req);
+ goto done;
+ }
+
+ /* finally send it */
+ dbus_connection_send(conn, bereq->req->reply, NULL);
+ dbus_message_unref(bereq->req->reply);
+ talloc_free(bereq->req);
+ }
+
+done:
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(reply);
+}
+
+static int dp_send_acct_req(struct dp_be_request *bereq,
+ uint32_t type, char *attrs, char *filter)
+{
+ DBusMessage *msg;
+ DBusPendingCall *pending_reply;
+ DBusConnection *conn;
+ DBusError dbus_error;
+ dbus_bool_t ret;
+
+ conn = sbus_get_connection(bereq->be_cli->conn_ctx);
+ dbus_error_init(&dbus_error);
+
+ /* create the message */
+ msg = dbus_message_new_method_call(NULL,
+ DP_CLI_PATH,
+ DP_CLI_INTERFACE,
+ DP_CLI_METHOD_GETACCTINFO);
+ if (msg == NULL) {
+ DEBUG(0,("Out of memory?!\n"));
+ return ENOMEM;
+ }
+
+ ret = dbus_message_append_args(msg,
+ DBUS_TYPE_UINT32, &type,
+ DBUS_TYPE_STRING, &attrs,
+ DBUS_TYPE_STRING, &filter,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("Failed to build message\n"));
+ return EIO;
+ }
+
+ ret = dbus_connection_send_with_reply(conn, msg, &pending_reply,
+ -1 /* TODO: set timeout */);
+ if (!ret) {
+ /*
+ * 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;
+ }
+
+ /* Set up the reply handler */
+ dbus_pending_call_set_notify(pending_reply, be_got_account_info,
+ bereq, NULL);
+ dbus_message_unref(msg);
+
+ return EOK;
+}
+
+static int dp_get_account_info(DBusMessage *message, void *data, DBusMessage **r)
+{
+ struct sbus_message_handler_ctx *smh_ctx;
+ struct dp_client *dpcli;
+ struct dp_be_request *bereq;
+ struct dp_request *dpreq = NULL;
+ struct dp_backend *dpbe;
+ DBusMessage *reply;
+ DBusError dbus_error;
+ dbus_bool_t dbret;
+ void *user_data;
+ uint32_t type;
+ char *domain, *attrs, *filter;
+ const char *errmsg = NULL;
+ int dpret = 0, ret = 0;
+
+ if (!data) return EINVAL;
+ smh_ctx = talloc_get_type(data, struct sbus_message_handler_ctx);
+ if (!smh_ctx) return EINVAL;
+ user_data = sbus_conn_get_private_data(smh_ctx->conn_ctx);
+ if (!user_data) return EINVAL;
+ dpcli = talloc_get_type(user_data, struct dp_client);
+ if (!dpcli) return EINVAL;
+
+ dbus_error_init(&dbus_error);
+
+ ret = dbus_message_get_args(message, &dbus_error,
+ DBUS_TYPE_STRING, &domain,
+ DBUS_TYPE_UINT32, &type,
+ DBUS_TYPE_STRING, &attrs,
+ DBUS_TYPE_STRING, &filter,
+ DBUS_TYPE_INVALID);
+ if (!ret) {
+ DEBUG(1,("Failed, to parse message!\n"));
+ return EIO;
+ }
+
+ reply = dbus_message_new_method_return(message);
+
+ /* search for domain */
+ if (!domain) {
+ dpret = DP_ERR_FATAL;
+ errmsg = "Invalid Domain";
+ ret = EINVAL;
+ goto respond;
+ }
+
+ /* nothing to do for local */
+ if (strcasecmp(domain, "LOCAL") == 0) {
+ dpret = DP_ERR_OK;
+ errmsg = "Success";
+ ret = EOK;
+ goto respond;
+ }
+
+ /* all domains, fire off a request for each backend */
+ if (strcmp(domain, "*") == 0) {
+ dpreq = talloc(dpcli->dpctx, struct dp_request);
+ if (!dpreq) {
+ dpret = DP_ERR_FATAL;
+ errmsg = "Out of memory";
+ ret = ENOMEM;
+ goto respond;
+ }
+
+ dpreq->reply = reply;
+ dpreq->src_cli = dpcli;
+ dpreq->pending_replies = 0;
+
+ /* now fire off requests */
+ dpbe = dpcli->dpctx->be_list;
+ while (dpbe) {
+ bereq = talloc(dpreq, struct dp_be_request);
+ if (!bereq) {
+ DEBUG(1, ("Out of memory while sending requests\n"));
+ dpbe = dpbe->next;
+ continue;
+ }
+ bereq->req = dpreq;
+ bereq->be_cli = dpbe->dpcli;
+ ret = dp_send_acct_req(bereq, type, attrs, filter);
+ if (ret != EOK) {
+ DEBUG(2,("Failed to dispatch request to %s", dpbe->domain));
+ dpbe = dpbe->next;
+ continue;
+ }
+ dpreq->pending_replies++;
+ dpbe = dpbe->next;
+ }
+
+ if (dpreq->pending_replies == 0) {
+ dpret = DP_ERR_FATAL;
+ errmsg = "Unable to contact backends";
+ ret = EIO;
+ talloc_free(dpreq);
+ goto respond;
+ }
+
+ return EOK;
+ }
+
+ dpbe = dpcli->dpctx->be_list;
+ while (dpbe) {
+ if (strcasecmp(dpbe->domain, domain) == 0) {
+ break;
+ }
+
+ dpbe = dpbe->next;
+ }
+
+ if (dpbe) {
+ dpreq = talloc(dpcli->dpctx, struct dp_request);
+ if (!dpreq) {
+ DEBUG(1, ("Out of memory while sending request\n"));
+ dpret = DP_ERR_FATAL;
+ errmsg = "Out of memory";
+ ret = ENOMEM;
+ goto respond;
+ }
+
+ dpreq->reply = reply;
+ dpreq->src_cli = dpcli;
+ dpreq->pending_replies = 1;
+
+ bereq = talloc(dpreq, struct dp_be_request);
+ if (!bereq) {
+ DEBUG(1, ("Out of memory while sending request\n"));
+ dpret = DP_ERR_FATAL;
+ errmsg = "Out of memory";
+ ret = ENOMEM;
+ talloc_free(dpreq);
+ goto respond;
+ }
+ bereq->req = dpreq;
+ bereq->be_cli = dpbe->dpcli;
+
+ ret = dp_send_acct_req(bereq, type, attrs, filter);
+ if (ret != EOK) {
+ DEBUG(2,("Failed to dispatch request to %s", dpbe->domain));
+ dpret = DP_ERR_FATAL;
+ errmsg = "Dispatch Failed";
+ talloc_free(dpreq);
+ goto respond;
+ }
+
+ } else {
+
+ dpret = DP_ERR_FATAL;
+ errmsg = "Invalid Domain";
+ ret = EINVAL;
+ goto respond;
+ }
+
+ return EOK;
+
+respond:
+ dbret = dbus_message_append_args(reply,
+ DBUS_TYPE_UINT16, dpret,
+ DBUS_TYPE_UINT32, ret,
+ DBUS_TYPE_STRING, errmsg,
+ DBUS_TYPE_INVALID);
+ if (!dbret) return EIO;
+
+ *r = reply;
+ return EOK;
+}
+
static int dp_backend_destructor(void *ctx)
{
struct dp_backend *dpbe = talloc_get_type(ctx, struct dp_backend);
@@ -466,9 +791,9 @@ done:
return ret;
}
-int dp_process_init(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
- struct confdb_ctx *cdb)
+static int dp_process_init(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ struct confdb_ctx *cdb)
{
struct dp_ctx *dpctx;
int ret;