summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2008-10-31 15:51:08 -0400
committerSimo Sorce <idra@samba.org>2008-11-03 10:12:29 -0500
commit0396ffe802dc32dc48c9d0ac3b22efc8217a98b3 (patch)
treec81f44d0e5383f039c6e74682fa9290bc812bdd8
parent913d0433c4d70b90051727972c070af770166940 (diff)
downloadsssd-0396ffe802dc32dc48c9d0ac3b22efc8217a98b3.tar.gz
sssd-0396ffe802dc32dc48c9d0ac3b22efc8217a98b3.tar.bz2
sssd-0396ffe802dc32dc48c9d0ac3b22efc8217a98b3.zip
Moved method handling into sssd_dbus_connection.c. Added support for handling multiple D-BUS paths in a connection. Added support for per-connection method setup. Added support for per-connection specialized destructors. Added mandatory getIdentity call for all services connecting to the monitor. If they do not present an identity (expose the getIdentity method and respond with name and version), they are dropped immediately. Other minor fixes.
-rw-r--r--server/Makefile.in2
-rw-r--r--server/dbus/sssd_dbus.h49
-rw-r--r--server/dbus/sssd_dbus_connection.c313
-rw-r--r--server/dbus/sssd_dbus_private.h7
-rw-r--r--server/dbus/sssd_dbus_server.c152
-rw-r--r--server/dbus/tests/test_client.c96
-rw-r--r--server/monitor.c109
-rw-r--r--server/util/debug.c2
8 files changed, 557 insertions, 173 deletions
diff --git a/server/Makefile.in b/server/Makefile.in
index f2d2c69f..dcab55fe 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -75,7 +75,7 @@ dirs:
@mkdir -p $(DIRS)
clean::
- rm -f *.o */*.o
+ rm -f *.o */*.o */*/*.o
rm -f $(BINS)
distclean:: clean
diff --git a/server/dbus/sssd_dbus.h b/server/dbus/sssd_dbus.h
index 547aaad2..2b8a7787 100644
--- a/server/dbus/sssd_dbus.h
+++ b/server/dbus/sssd_dbus.h
@@ -21,10 +21,26 @@
#ifndef _SSSD_DBUS_H_
#define _SSSD_DBUS_H_
-
+struct dbus_connection_toplevel_context;
typedef int (*sssd_dbus_msg_handler_fn)(DBusMessage *msg, void *data,
DBusMessage **reply);
+/*
+ * sssd_dbus_connection_destructor_fn
+ * Function to be called when a connection is finalized
+ */
+typedef int (*sssd_dbus_connection_destructor_fn)(
+ void *ctx);
+
+/*
+ * sssd_dbus_server_connection_init_fn
+ * Set up function for connection-specific activities
+ * This function should define the sssd_dbus_connection_destructor_fn
+ * for this connection at a minimum
+ */
+typedef int (*sssd_dbus_server_connection_init_fn)(
+ struct dbus_connection_toplevel_context *dct_ctx);
+
extern int connection_type_slot;
enum {
@@ -37,17 +53,36 @@ struct sssd_dbus_method {
sssd_dbus_msg_handler_fn fn;
};
-struct sssd_dbus_ctx {
- struct event_context *ev;
- char *name;
+struct sssd_dbus_method_ctx {
+ struct sssd_dbus_method_ctx *prev, *next;
+ /*struct event_context *ev;*/
+ char *interface;
char *path;
+
+ /* If a non-default message_handler is desired, set it in this
+ * object before calling dbus_connection_add_method_ctx()
+ * Otherwise it will default to message_handler() in
+ * sssd_dbus_connection.c
+ */
+ DBusObjectPathMessageFunction message_handler;
struct sssd_dbus_method *methods;
};
/* Server Functions */
-int sssd_new_dbus_server(struct sssd_dbus_ctx *ctx, const char *address);
+int sssd_new_dbus_server(struct event_context *ev, struct sssd_dbus_method_ctx *ctx, const char *address, sssd_dbus_server_connection_init_fn init_fn);
/* Connection Functions */
-int sssd_new_dbus_connection(struct sssd_dbus_ctx *ctx, const char *address,
- DBusConnection **connection);
+int sssd_new_dbus_connection(TALLOC_CTX *ctx, struct event_context *ev, const char *address,
+ struct dbus_connection_toplevel_context **dct_ctx,
+ sssd_dbus_connection_destructor_fn destructor);
+
+void sssd_dbus_connection_set_destructor(struct dbus_connection_toplevel_context *dct_ctx,
+ sssd_dbus_connection_destructor_fn destructor);
+int default_connection_destructor(void *ctx);
+
+DBusConnection *sssd_get_dbus_connection(struct dbus_connection_toplevel_context *dct_ctx);
+void sssd_dbus_disconnect (struct dbus_connection_toplevel_context *dct_ctx);
+void sssd_connection_set_private_data(struct dbus_connection_toplevel_context *dct_ctx, void *private);
+int dbus_connection_add_method_ctx(struct dbus_connection_toplevel_context *dct_ctx, struct sssd_dbus_method_ctx *method_ctx);
+
#endif /* _SSSD_DBUS_H_*/
diff --git a/server/dbus/sssd_dbus_connection.c b/server/dbus/sssd_dbus_connection.c
index 0033ab87..e9289e04 100644
--- a/server/dbus/sssd_dbus_connection.c
+++ b/server/dbus/sssd_dbus_connection.c
@@ -5,14 +5,17 @@
#include "dbus/sssd_dbus.h"
#include "dbus/sssd_dbus_private.h"
-dbus_int32_t connection_type_slot = -1;
-dbus_int32_t connection_destructor_slot = -1;
-
/* Types */
+struct dbus_ctx_list;
+
struct dbus_connection_toplevel_context {
DBusConnection *conn;
struct event_context *ev;
- /*sssd_dbus_connection_destructor_fn destructor;*/
+ int connection_type;
+ int disconnect;
+ struct sssd_dbus_method_ctx *method_ctx_list;
+ sssd_dbus_connection_destructor_fn destructor;
+ void *private; /* Private data for this connection */
};
struct dbus_connection_watch_context {
@@ -28,34 +31,35 @@ struct dbus_connection_timeout_context {
struct dbus_connection_toplevel_context *top;
};
+static int method_list_contains_path(struct sssd_dbus_method_ctx *list, struct sssd_dbus_method_ctx *method);
+static void sssd_unregister_object_paths(struct dbus_connection_toplevel_context *dct_ctx);
+
static void do_dispatch(struct event_context *ev,
struct timed_event *te,
struct timeval tv, void *data)
{
struct timed_event *new_event;
+ struct dbus_connection_toplevel_context *dct_ctx;
DBusConnection *conn;
- int connection_type;
int ret;
- conn = (DBusConnection *)data;
+ if (data == NULL) {
+ return;
+ }
- if(!dbus_connection_get_is_connected(conn)) {
- DEBUG(0,("Connection is not open for dispatching.\n"));
- connection_type = *(int *)(dbus_connection_get_data(conn, connection_type_slot));
- if (connection_type == DBUS_CONNECTION_TYPE_PRIVATE) {
- /* Private connections must be closed explicitly */
- dbus_connection_close(conn);
- dbus_connection_unref(conn);
- } else if (connection_type == DBUS_CONNECTION_TYPE_SHARED) {
- /* Shared connections are destroyed when their last reference is removed */
- dbus_connection_unref(conn);
- }
- else {
- /* Critical Error! */
- DEBUG(0,("Critical Error, connection_type is neither shared nor private!\n"))
- }
- dbus_connection_set_data(conn,connection_type_slot, NULL, NULL);
+ dct_ctx = talloc_get_type(data, struct dbus_connection_toplevel_context);
+ conn = dct_ctx->conn;
+ DEBUG(3, ("conn: %lX\n", conn));
+
+ if((dct_ctx->disconnect) || (!dbus_connection_get_is_connected(conn))) {
+ DEBUG(0,("Connection is not open for dispatching.\n"));
+ /*
+ * Free the connection object.
+ * This will invoke the destructor for the connection
+ */
+ talloc_free(dct_ctx);
+ dct_ctx = NULL;
return;
}
@@ -73,7 +77,7 @@ static void do_dispatch(struct event_context *ev,
*/
ret = dbus_connection_get_dispatch_status(conn);
if (ret != DBUS_DISPATCH_COMPLETE) {
- new_event = event_add_timed(ev, ev, tv, do_dispatch, conn);
+ new_event = event_add_timed(ev, ev, tv, do_dispatch, dct_ctx);
if (new_event == NULL) {
DEBUG(0,("Could not add dispatch event!\n"));
@@ -248,7 +252,7 @@ static void dbus_connection_wakeup_main(void *data) {
/* D-BUS calls this function when it is time to do a dispatch */
te = event_add_timed(dct_ctx->ev, dct_ctx->ev,
- tv, do_dispatch, dct_ctx->conn);
+ tv, do_dispatch, dct_ctx);
if (te == NULL) {
DEBUG(0,("Could not add dispatch event!\n"));
exit(1);
@@ -260,15 +264,30 @@ static void dbus_connection_wakeup_main(void *data) {
* Set up a D-BUS connection to use the libevents mainloop
* for handling file descriptor and timed events
*/
-int sssd_add_dbus_connection(struct sssd_dbus_ctx *ctx,
- DBusConnection *dbus_conn)
+int sssd_add_dbus_connection(TALLOC_CTX *ctx,
+ struct event_context *ev,
+ DBusConnection *dbus_conn,
+ struct dbus_connection_toplevel_context **dct_ctx,
+ int connection_type)
{
- struct dbus_connection_toplevel_context *dt_ctx;
dbus_bool_t dbret;
+ struct dbus_connection_toplevel_context *dt_ctx;
+ DEBUG(0,("Adding connection %lX\n", dbus_conn));
dt_ctx = talloc_zero(ctx, struct dbus_connection_toplevel_context);
- dt_ctx->ev = ctx->ev;
+ dt_ctx->ev = ev;
dt_ctx->conn = dbus_conn;
+ dt_ctx->connection_type = connection_type;
+ dt_ctx->disconnect = 0;
+ /* This will be replaced on the first call to dbus_connection_add_method_ctx() */
+ dt_ctx->method_ctx_list = NULL;
+
+ /*
+ * Set the default destructor
+ * Connections can override this with
+ * sssd_dbus_connection_set_destructor
+ */
+ sssd_dbus_connection_set_destructor(dt_ctx, NULL);
/* Set up DBusWatch functions */
dbret = dbus_connection_set_watch_functions(dt_ctx->conn,
@@ -297,6 +316,8 @@ int sssd_add_dbus_connection(struct sssd_dbus_ctx *ctx,
dbus_connection_set_wakeup_main_function(dt_ctx->conn,
dbus_connection_wakeup_main,
dt_ctx, NULL);
+
+ /* Set up any method_contexts passed in */
/* Attempt to dispatch immediately in case of opportunistic
* services connecting before the handlers were all up.
@@ -305,15 +326,21 @@ int sssd_add_dbus_connection(struct sssd_dbus_ctx *ctx,
*/
dbus_connection_wakeup_main(dt_ctx);
+ /* Return the new toplevel object */
+ *dct_ctx = dt_ctx;
+
return EOK;
}
-int sssd_new_dbus_connection(struct sssd_dbus_ctx *ctx, const char *address,
- DBusConnection **connection)
+/*int sssd_new_dbus_connection(struct sssd_dbus_method_ctx *ctx, const char *address,
+ DBusConnection **connection,
+ sssd_dbus_connection_destructor_fn destructor)*/
+int sssd_new_dbus_connection(TALLOC_CTX *ctx, struct event_context *ev, const char *address,
+ struct dbus_connection_toplevel_context **dct_ctx,
+ sssd_dbus_connection_destructor_fn destructor)
{
DBusConnection *dbus_conn;
DBusError dbus_error;
- int connection_type;
int ret;
dbus_error_init(&dbus_error);
@@ -326,20 +353,224 @@ int sssd_new_dbus_connection(struct sssd_dbus_ctx *ctx, const char *address,
return EIO;
}
- /* Allocate or increase the reference count of connection_type_slot */
- if (!dbus_connection_allocate_data_slot(&connection_type_slot)) {
- return ENOMEM;
+ ret = sssd_add_dbus_connection(ctx, ev, dbus_conn, dct_ctx, DBUS_CONNECTION_TYPE_SHARED);
+ if (ret != EOK) {
+ /* FIXME: release resources */
+ }
+
+ dbus_connection_set_exit_on_disconnect((*dct_ctx)->conn, FALSE);
+
+ /* Set connection destructor */
+ sssd_dbus_connection_set_destructor(*dct_ctx, destructor);
+
+ return ret;
+}
+
+/*
+ * sssd_dbus_connection_set_destructor
+ * Configures a callback to clean up this connection when it
+ * is finalized.
+ * @param dct_ctx The dbus_connection_toplevel_context created
+ * when this connection was established
+ * @param destructor The destructor function that should be
+ * called when the connection is finalized. If passed NULL,
+ * this will reset the connection to the default destructor.
+ */
+void sssd_dbus_connection_set_destructor(struct dbus_connection_toplevel_context *dct_ctx,
+ sssd_dbus_connection_destructor_fn destructor) {
+ if (!dct_ctx) {
+ return;
}
+
+ dct_ctx->destructor = destructor;
+ /* TODO: Should we try to handle the talloc_destructor too? */
+}
- connection_type = DBUS_CONNECTION_TYPE_SHARED;
- dbus_connection_set_data(dbus_conn, connection_type_slot, &connection_type, NULL);
+int default_connection_destructor(void *ctx) {
+ struct dbus_connection_toplevel_context *dct_ctx;
+ dct_ctx = talloc_get_type(ctx, struct dbus_connection_toplevel_context);
+
+ DEBUG(3, ("Invoking default destructor on connection %lX\n", dct_ctx->conn));
+ if (dct_ctx->connection_type == DBUS_CONNECTION_TYPE_PRIVATE) {
+ /* Private connections must be closed explicitly */
+ dbus_connection_close(dct_ctx->conn);
+ } else if (dct_ctx->connection_type == DBUS_CONNECTION_TYPE_SHARED) {
+ /* Shared connections are destroyed when their last reference is removed */
+ }
+ else {
+ /* Critical Error! */
+ DEBUG(0,("Critical Error, connection_type is neither shared nor private!\n"));
+ return -1;
+ }
+
+ /* Remove object path */
+
+
+
+ dbus_connection_unref(dct_ctx->conn);
+ return 0;
+}
- ret = sssd_add_dbus_connection(ctx, dbus_conn);
- if (ret == EOK) {
- *connection = dbus_conn;
+/*
+ * sssd_get_dbus_connection
+ * Utility function to retreive the DBusConnection object
+ * from a dbus_connection_toplevel_context
+ */
+DBusConnection *sssd_get_dbus_connection(struct dbus_connection_toplevel_context *dct_ctx) {
+ return dct_ctx->conn;
+}
+
+void sssd_dbus_disconnect (struct dbus_connection_toplevel_context *dct_ctx) {
+ if (dct_ctx == NULL) {
+ return;
+ }
+
+ DEBUG(2,("Disconnecting %lX\n", dct_ctx->conn));
+ dbus_connection_ref(dct_ctx->conn);
+ dct_ctx->disconnect = 1;
+
+ /* Invoke the custom destructor, if it exists */
+ if(dct_ctx->destructor) {
+ dct_ctx->destructor(dct_ctx);
+ }
+
+ /* Unregister object paths */
+ sssd_unregister_object_paths(dct_ctx);
+
+ /* Disable watch functions */
+ dbus_connection_set_watch_functions(dct_ctx->conn,
+ NULL, NULL, NULL,
+ NULL, NULL);
+ /* Disable timeout functions */
+ dbus_connection_set_timeout_functions(dct_ctx->conn,
+ NULL, NULL, NULL,
+ NULL, NULL);
+
+ /* Disable dispatch status function */
+ dbus_connection_set_dispatch_status_function(dct_ctx->conn, NULL, NULL, NULL);
+
+ /* Disable wakeup main function */
+ dbus_connection_set_wakeup_main_function(dct_ctx->conn, NULL, NULL, NULL);
+
+ /* Finalize the connection */
+ default_connection_destructor(dct_ctx);
+ dbus_connection_unref(dct_ctx->conn);
+ DEBUG(2,("Disconnected %lX\n", dct_ctx->conn));
+}
+
+/* messsage_handler
+ * Receive messages and process them
+ */
+static DBusHandlerResult message_handler(DBusConnection *conn,
+ DBusMessage *message,
+ void *user_data)
+{
+ struct sssd_dbus_method_ctx *ctx;
+ const char *method;
+ const char *path;
+ const char *msg_interface;
+ DBusMessage *reply = NULL;
+ int i, ret;
+
+ ctx = talloc_get_type(user_data, struct sssd_dbus_method_ctx);
+
+ method = dbus_message_get_member(message);
+ path = dbus_message_get_path(message);
+ msg_interface = dbus_message_get_interface(message);
+
+ if (!method || !path || !msg_interface)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ /* Validate the method interface */
+ if (strcmp(msg_interface, ctx->interface) != 0)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ /* Validate the D-BUS path */
+ if (strcmp(path, ctx->path) == 0) {
+ for (i = 0; ctx->methods[i].method != NULL; i++) {
+ if (strcmp(method, ctx->methods[i].method) == 0) {
+ ret = ctx->methods[i].fn(message, ctx, &reply);
+ /* FIXME: check error */
+ break;
+ }
+ }
+ /* FIXME: check if we didn't find any matching method */
+ }
+
+ DEBUG(2, ("Method %s complete. Reply %sneeded.\n", method, reply?"":"not "));
+
+ if (reply) {
+ dbus_connection_send(conn, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+ return reply ? DBUS_HANDLER_RESULT_HANDLED :
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+/* Adds a new D-BUS path message handler to the connection
+ * Note: this must be a unique path.
+ */
+int dbus_connection_add_method_ctx(struct dbus_connection_toplevel_context *dct_ctx, struct sssd_dbus_method_ctx *method_ctx) {
+ DBusObjectPathVTable *connection_vtable;
+ dbus_bool_t dbret;
+ if (!method_ctx) {
+ return EINVAL;
+ }
+
+ if (method_list_contains_path(dct_ctx->method_ctx_list, method_ctx)) {
+ return EINVAL;
+ }
+
+ DLIST_ADD(dct_ctx->method_ctx_list, method_ctx);
+
+ /* Set up the vtable for the object path */
+ connection_vtable = talloc_zero(dct_ctx, DBusObjectPathVTable);
+ if (method_ctx->message_handler) {
+ connection_vtable->message_function = method_ctx->message_handler;
} else {
- /* FIXME: release resources */
+ connection_vtable->message_function = message_handler;
}
+
+ dbret = dbus_connection_register_object_path(dct_ctx->conn, method_ctx->path, connection_vtable, method_ctx);
+ if (!dbret) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
- return ret;
+static int method_list_contains_path(struct sssd_dbus_method_ctx *list, struct sssd_dbus_method_ctx *method) {
+ struct sssd_dbus_method_ctx *iter;
+
+ if (!list || !method) {
+ return 0; /* FALSE */
+ }
+
+ iter = list;
+ while (iter != NULL) {
+ if (strcmp(iter->path, method->path) == 0)
+ return 1; /* TRUE */
+
+ iter = iter->next;
+ }
+
+ return 0; /* FALSE */
+}
+
+static void sssd_unregister_object_paths(struct dbus_connection_toplevel_context *dct_ctx) {
+ struct sssd_dbus_method_ctx *iter = dct_ctx->method_ctx_list;
+ struct sssd_dbus_method_ctx *purge;
+
+ while(iter != NULL) {
+ dbus_connection_unregister_object_path(dct_ctx->conn, iter->path);
+ DLIST_REMOVE(dct_ctx->method_ctx_list, iter);
+ purge = iter;
+ iter = iter->next;
+ talloc_free(purge);
+ }
+}
+
+void sssd_connection_set_private_data(struct dbus_connection_toplevel_context *dct_ctx, void *private) {
+ dct_ctx->private = private;
}
diff --git a/server/dbus/sssd_dbus_private.h b/server/dbus/sssd_dbus_private.h
index ae3540bd..ea1b719b 100644
--- a/server/dbus/sssd_dbus_private.h
+++ b/server/dbus/sssd_dbus_private.h
@@ -1,8 +1,11 @@
#ifndef _SSSD_DBUS_PRIVATE_H_
#define _SSSD_DBUS_PRIVATE_H_
-int sssd_add_dbus_connection(struct sssd_dbus_ctx *ctx,
- DBusConnection *dbus_conn);
+int sssd_add_dbus_connection(TALLOC_CTX *ctx,
+ struct event_context *ev,
+ DBusConnection *dbus_conn,
+ struct dbus_connection_toplevel_context **dct_ctx,
+ int connection_type);
struct timeval _dbus_timeout_get_interval_tv(int interval);
void remove_watch(DBusWatch *watch, void *data);
diff --git a/server/dbus/sssd_dbus_server.c b/server/dbus/sssd_dbus_server.c
index ebf5a611..8bdccf8e 100644
--- a/server/dbus/sssd_dbus_server.c
+++ b/server/dbus/sssd_dbus_server.c
@@ -28,9 +28,18 @@
/* Types */
struct dbus_server_toplevel_context {
DBusServer *server;
- /* talloc context to manage the server object memory*/
- DBusServer **server_talloc;
- struct sssd_dbus_ctx *sd_ctx;
+ /*
+ * sd_ctx here describes the object path that will be
+ * presented to all clients of this server. Additional
+ * connection-specific paths can be specified by the
+ * init_fn, which is called every time a new connection
+ * is established.
+ * There should only be one global object path (for
+ * simplicity's sake)
+ */
+ struct event_context *ev;
+ struct sssd_dbus_method_ctx *sd_ctx;
+ sssd_dbus_server_connection_init_fn init_fn;
};
struct dbus_server_watch_context {
@@ -105,7 +114,7 @@ static dbus_bool_t add_server_watch(DBusWatch *watch, void *data)
}
DEBUG(2,("%lX: %d, %d=%s\n", watch, svw_ctx->fd, event_flags, event_flags==EVENT_FD_READ?"READ":"WRITE"));
- svw_ctx->fde = event_add_fd(dt_ctx->sd_ctx->ev, svw_ctx, svw_ctx->fd,
+ svw_ctx->fde = event_add_fd(dt_ctx->ev, svw_ctx, svw_ctx->fd,
event_flags, dbus_server_read_write_handler,
svw_ctx);
@@ -159,7 +168,7 @@ static dbus_bool_t add_server_timeout(DBusTimeout *timeout, void *data)
tv = _dbus_timeout_get_interval_tv(dbus_timeout_get_interval(timeout));
- svt_ctx->te = event_add_timed(dt_ctx->sd_ctx->ev, svt_ctx, tv,
+ svt_ctx->te = event_add_timed(dt_ctx->ev, svt_ctx, tv,
dbus_server_timeout_handler, svt_ctx);
/* Save the event to the watch object so it can be removed later */
@@ -182,54 +191,6 @@ static void toggle_server_timeout(DBusTimeout *timeout, void *data)
}
}
-/* messsage_handler
- * Receive messages and process them
- */
-static DBusHandlerResult message_handler(DBusConnection *conn,
- DBusMessage *message,
- void *user_data)
-{
- struct sssd_dbus_ctx *ctx;
- const char *method;
- const char *path;
- const char *msg_interface;
- DBusMessage *reply = NULL;
- int i, ret;
-
- ctx = talloc_get_type(user_data, struct sssd_dbus_ctx);
-
- method = dbus_message_get_member(message);
- path = dbus_message_get_path(message);
- msg_interface = dbus_message_get_interface(message);
-
- if (!method || !path || !msg_interface)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- /* Validate the method interface */
- if (strcmp(msg_interface, ctx->name) != 0)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- /* Validate the D-BUS path */
- if (strcmp(path, ctx->path) == 0) {
- for (i = 0; ctx->methods[i].method != NULL; i++) {
- if (strcmp(method, ctx->methods[i].method) == 0) {
- ret = ctx->methods[i].fn(message, ctx, &reply);
- /* FIXME: check error */
- break;
- }
- }
- /* FIXME: check if we didn't find any matching method */
- }
-
- if (reply) {
- dbus_connection_send(conn, reply, NULL);
- dbus_message_unref(reply);
- }
-
- return reply ? DBUS_HANDLER_RESULT_HANDLED :
- DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
/*
* new_connection_callback
* Actions to be run upon each new client connection
@@ -241,41 +202,45 @@ static void new_connection_callback(DBusServer *server, DBusConnection *conn,
void *data)
{
struct dbus_server_toplevel_context *dst_ctx;
- DBusObjectPathVTable *monitor_vtable;
- int *connection_type;
+ struct dbus_connection_toplevel_context *dct_ctx;
+ struct sssd_dbus_method_ctx *iter;
+
+ /*DBusObjectPathVTable *connection_vtable;*/
int ret;
-
+ DEBUG(0,("Entering.\n"));
dst_ctx = talloc_get_type(data,struct dbus_server_toplevel_context);
-
- if (!dbus_connection_allocate_data_slot(&connection_type_slot)) {
- dbus_connection_close(conn);
+ if(dst_ctx == NULL) {
return;
}
- connection_type = talloc(dst_ctx, int);
- *connection_type = DBUS_CONNECTION_TYPE_PRIVATE;
- dbus_connection_set_data(conn, connection_type_slot, connection_type, talloc_free);
-
- ret = sssd_add_dbus_connection(dst_ctx->sd_ctx, conn);
+ DEBUG(0,("Adding connection %lX.\n", conn));
+ ret = sssd_add_dbus_connection(dst_ctx, dst_ctx->ev, conn, &dct_ctx, DBUS_CONNECTION_TYPE_PRIVATE);
if (ret != 0) {
dbus_connection_close(conn);
DEBUG(0,("Closing connection (failed setup)"));
return;
}
-
+
dbus_connection_ref(conn);
DEBUG(3,("Got a connection\n"));
- monitor_vtable = talloc_zero(dst_ctx, DBusObjectPathVTable);
-
- DEBUG (3,("Initializing D-BUS methods.\n"));
- monitor_vtable->message_function = message_handler;
-
- dbus_connection_register_object_path(conn, dst_ctx->sd_ctx->path,
- monitor_vtable, dst_ctx->sd_ctx);
-
- DEBUG(3,("D-BUS method initialization complete.\n"));
+ /* Set up global methods */
+ iter = dst_ctx->sd_ctx;
+ while (iter != NULL) {
+ dbus_connection_add_method_ctx(dct_ctx, iter);
+ iter = iter->next;
+ }
+
+ /*
+ * Initialize connection-specific features
+ * This may set a more detailed destructor, but
+ * the default destructor will always be chained
+ * to handle connection cleanup.
+ * This function (or its callbacks) should also
+ * set up connection-specific methods.
+ */
+ dst_ctx->init_fn(dct_ctx);
}
/*
@@ -283,9 +248,9 @@ static void new_connection_callback(DBusServer *server, DBusConnection *conn,
* Set up a D-BUS server, integrate with the event loop
* for handling file descriptor and timed events
*/
-int sssd_new_dbus_server(struct sssd_dbus_ctx *ctx, const char *address)
+int sssd_new_dbus_server(struct event_context *ev, struct sssd_dbus_method_ctx *ctx, const char *address, sssd_dbus_server_connection_init_fn init_fn)
{
- struct dbus_server_toplevel_context *dt_ctx;
+ struct dbus_server_toplevel_context *dst_ctx;
DBusServer *dbus_server;
DBusServer **dbus_server_talloc;
DBusError dbus_error;
@@ -299,47 +264,46 @@ int sssd_new_dbus_server(struct sssd_dbus_ctx *ctx, const char *address)
dbus_error.name, dbus_error.message));
return EIO;
}
- dbus_server_talloc = talloc_takeover(ctx, dbus_server, dbus_server_destructor);
DEBUG(2, ("D-BUS Server listening on %s\n",
dbus_server_get_address(dbus_server)));
- dt_ctx = talloc_zero(ctx, struct dbus_server_toplevel_context);
- if (!dt_ctx) {
- talloc_free(dbus_server_talloc);
+ dst_ctx = talloc_zero(ev, struct dbus_server_toplevel_context);
+ if (!dst_ctx) {
return ENOMEM;
}
- dt_ctx->server_talloc = dbus_server_talloc;
- dt_ctx->server = *dbus_server_talloc;
- dt_ctx->sd_ctx = ctx;
+
+ dbus_server_talloc = talloc_takeover(ctx, dbus_server, dbus_server_destructor);
+ dst_ctx->ev = ev;
+ dst_ctx->server = dbus_server;
+ dst_ctx->sd_ctx = ctx;
+ dst_ctx->init_fn = init_fn;
/* Set up D-BUS new connection handler */
- dbus_server_set_new_connection_function(dt_ctx->server,
+ dbus_server_set_new_connection_function(dst_ctx->server,
new_connection_callback,
- dt_ctx, NULL);
+ dst_ctx, NULL);
/* Set up DBusWatch functions */
- dbret = dbus_server_set_watch_functions(dt_ctx->server, add_server_watch,
+ dbret = dbus_server_set_watch_functions(dst_ctx->server, add_server_watch,
remove_watch, toggle_server_watch,
- dt_ctx, NULL);
+ dst_ctx, NULL);
if (!dbret) {
DEBUG(0, ("Error setting up D-BUS server watch functions"));
- talloc_free(dt_ctx->server_talloc);
- dt_ctx->server = NULL;
+ talloc_free(dst_ctx);
return EIO;
}
/* Set up DBusTimeout functions */
- dbret = dbus_server_set_timeout_functions(dt_ctx->server,
+ dbret = dbus_server_set_timeout_functions(dst_ctx->server,
add_server_timeout,
remove_timeout,
toggle_server_timeout,
- dt_ctx, NULL);
+ dst_ctx, NULL);
if (!dbret) {
DEBUG(0,("Error setting up D-BUS server timeout functions"));
- dbus_server_set_watch_functions(dt_ctx->server, NULL, NULL, NULL, NULL, NULL);
- talloc_free(dt_ctx->server_talloc);
- dt_ctx->server = NULL;
+ dbus_server_set_watch_functions(dst_ctx->server, NULL, NULL, NULL, NULL, NULL);
+ talloc_free(dst_ctx);
return EIO;
}
diff --git a/server/dbus/tests/test_client.c b/server/dbus/tests/test_client.c
index 30401991..daf80db9 100644
--- a/server/dbus/tests/test_client.c
+++ b/server/dbus/tests/test_client.c
@@ -9,14 +9,32 @@
/* TODO: get this value from LDB */
#define DBUS_ADDRESS "unix:path=/var/lib/sss/pipes/private/dbus"
+/* Identity */
+#define TEST_CLIENT_NAME "testclient"
+#define TEST_CLIENT_VERSION 1
+
/* Monitor Interface */
#define MONITOR_DBUS_INTERFACE "org.freeipa.sssd.monitor"
#define MONITOR_DBUS_PATH "/org/freeipa/sssd/monitor"
#define MONITOR_METHOD_VERSION "getVersion"
+/* Service Interface */
+#define SERVICE_PATH "/org/freeipa/sssd/service"
+#define SERVICE_INTERFACE "org.freeipa.sssd.service"
+#define SERVICE_METHOD_IDENTITY "getIdentity"
+
struct test_cli_ctx {
- struct sssd_dbus_ctx *sd_ctx;
- DBusConnection *conn;
+ struct sssd_dbus_method_ctx *sd_ctx;
+ /*DBusConnection *conn;*/
+ struct event_context *ev;
+ struct dbus_connection_toplevel_context *dct_ctx;
+};
+
+static int provide_identity(DBusMessage *message, void *data, DBusMessage **r);
+
+struct sssd_dbus_method monitor_service_methods [] = {
+ {SERVICE_METHOD_IDENTITY, provide_identity},
+ {NULL, NULL}
};
static void request_version_timed(struct test_cli_ctx *ctx);
@@ -55,9 +73,16 @@ static void print_version(DBusPendingCall *pending, void *data)
}
break;
case DBUS_MESSAGE_TYPE_ERROR:
+
+ if (strcmp(DBUS_ERROR_NO_REPLY, dbus_message_get_error_name(reply))==0) {
+ DEBUG(0, ("Received error. Timeout"));
+ }
+ else {
+ DEBUG(0, ("Received error. Not a timeout: %s", dbus_message_get_error_name(reply)));
+ }
break;
default:
- DEBUG(0, ("Received unexpected message"));
+ DEBUG(0, ("Received unexpected message\n"));
exit(4);
}
}
@@ -67,7 +92,7 @@ static void test_timed_handler(struct event_context *ev,
struct timeval tv, void *data)
{
struct test_cli_ctx *test_ctx;
- struct sssd_dbus_ctx *ctx;
+ struct sssd_dbus_method_ctx *ctx;
DBusPendingCall *pending_reply;
DBusMessage *vmsg;
DBusError error;
@@ -81,10 +106,10 @@ static void test_timed_handler(struct event_context *ev,
dbus_error_init(&error);
vmsg = dbus_message_new_method_call(NULL,
- ctx->path, ctx->name,
+ ctx->path, ctx->interface,
MONITOR_METHOD_VERSION);
- dbret = dbus_connection_send_with_reply(test_ctx->conn, vmsg,
+ dbret = dbus_connection_send_with_reply(sssd_get_dbus_connection(test_ctx->dct_ctx), vmsg,
&pending_reply, -1);
if (!dbret) {
/* Critical failure */
@@ -107,7 +132,7 @@ static void request_version_timed(struct test_cli_ctx *ctx)
gettimeofday(&tv, NULL);
tv.tv_sec += 5;
tv.tv_usec = 0;
- te = event_add_timed(ctx->sd_ctx->ev, ctx, tv, test_timed_handler, ctx);
+ te = event_add_timed(ctx->ev, ctx, tv, test_timed_handler, ctx);
if (te == NULL) {
DEBUG(0, ("failed to add event!\n"));
exit(1);
@@ -117,9 +142,9 @@ static void request_version_timed(struct test_cli_ctx *ctx)
int main (int argc, const char *argv[])
{
struct event_context *event_ctx;
- struct sssd_dbus_ctx *ctx;
+ struct sssd_dbus_method_ctx *ctx;
struct test_cli_ctx *test_ctx;
- DBusConnection *dbus_conn;
+ struct sssd_dbus_method_ctx *service_methods;
int ret;
event_ctx = event_context_init(talloc_autofree_context());
@@ -128,38 +153,46 @@ int main (int argc, const char *argv[])
exit(1);
}
- ctx = talloc_zero(event_ctx, struct sssd_dbus_ctx);
+ ctx = talloc_zero(event_ctx, struct sssd_dbus_method_ctx);
if (!ctx) {
printf("Out of memory!?\n");
exit(1);
}
- ctx->ev = event_ctx;
- ctx->name = talloc_strdup(ctx, MONITOR_DBUS_INTERFACE);
+
+ test_ctx = talloc(event_ctx, struct test_cli_ctx);
+ if (!test_ctx) {
+ printf("Out of memory!?\n");
+ exit(1);
+ }
+
+ test_ctx->ev = event_ctx;
+ ctx->interface = talloc_strdup(ctx, MONITOR_DBUS_INTERFACE);
ctx->path = talloc_strdup(ctx, MONITOR_DBUS_PATH);
- if (!ctx->name || !ctx->path) {
+ if (!ctx->interface || !ctx->path) {
printf("Out of memory!?\n");
exit(1);
}
- ret = sssd_new_dbus_connection(ctx, DBUS_ADDRESS, &dbus_conn);
+ ret = sssd_new_dbus_connection(test_ctx, test_ctx->ev, DBUS_ADDRESS, &(test_ctx->dct_ctx), NULL);
if (ret != EOK) {
exit(1);
}
- test_ctx = talloc(ctx, struct test_cli_ctx);
- if (!test_ctx) {
- printf("Out of memory!?\n");
- exit(1);
- }
test_ctx->sd_ctx = ctx;
- test_ctx->conn = dbus_conn;
- dbus_connection_set_exit_on_disconnect(dbus_conn, TRUE);
+ dbus_connection_set_exit_on_disconnect(sssd_get_dbus_connection(test_ctx->dct_ctx), TRUE);
/* Set up a timed event to request the server version every
* five seconds and print it to the screen.
*/
request_version_timed(test_ctx);
+
+ /* Set up handler for service methods */
+ service_methods = talloc_zero(test_ctx, struct sssd_dbus_method_ctx);
+ service_methods->interface = talloc_strdup(service_methods, SERVICE_INTERFACE);
+ service_methods->path = talloc_strdup(service_methods, SERVICE_PATH);
+ service_methods->methods = monitor_service_methods;
+ dbus_connection_add_method_ctx(test_ctx->dct_ctx, service_methods);
/* Enter the main loop (and hopefully never return) */
event_loop_wait(event_ctx);
@@ -167,3 +200,24 @@ int main (int argc, const char *argv[])
talloc_free(event_ctx);
return EXIT_SUCCESS;
}
+
+static int provide_identity(DBusMessage *message, void *data, DBusMessage **r) {
+ const char *name = TEST_CLIENT_NAME;
+ dbus_uint16_t version = TEST_CLIENT_VERSION;
+
+ DBusMessage *reply;
+ dbus_bool_t ret;
+
+ reply = dbus_message_new_method_return(message);
+ ret = dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_UINT16, &version,
+ DBUS_TYPE_INVALID);
+
+ if (!ret) {
+ return EIO;
+ }
+
+ *r = reply;
+ return EOK;
+}
diff --git a/server/monitor.c b/server/monitor.c
index 7a877cdd..cf628754 100644
--- a/server/monitor.c
+++ b/server/monitor.c
@@ -31,6 +31,10 @@
#include "dbus/dbus.h"
#include "dbus/sssd_dbus.h"
+/* TODO: Get these values from LDB */
+#define SERVICE_PATH "/org/freeipa/sssd/service"
+#define SERVICE_INTERFACE "org.freeipa.sssd.service"
+#define SERVICE_METHOD_IDENTITY "getIdentity"
/* TODO: get this value from LDB */
#define DBUS_ADDRESS "unix:path=/var/lib/sss/pipes/private/dbus"
@@ -49,6 +53,9 @@ struct mt_srv {
int restarts;
};
+static int dbus_service_init(struct dbus_connection_toplevel_context *dct_ctx);
+static void identity_check(DBusPendingCall *pending, void *data);
+
/* dbus_get_monitor_version
* Return the monitor version over D-BUS */
static int dbus_get_monitor_version(DBusMessage *message,
@@ -80,17 +87,17 @@ struct sssd_dbus_method monitor_methods[] = {
* Set up the monitor service as a D-BUS Server */
static int monitor_dbus_init(struct mt_ctx *ctx)
{
- struct sssd_dbus_ctx *sd_ctx;
+ struct sssd_dbus_method_ctx *sd_ctx;
int ret;
- sd_ctx = talloc(ctx, struct sssd_dbus_ctx);
+ sd_ctx = talloc_zero(ctx, struct sssd_dbus_method_ctx);
if (!sd_ctx) {
return ENOMEM;
}
- sd_ctx->ev = ctx->ev;
- sd_ctx->name = talloc_strdup(sd_ctx, MONITOR_DBUS_INTERFACE);
- if (!sd_ctx->name) {
+ /* Set up globally-available D-BUS methods */
+ sd_ctx->interface = talloc_strdup(sd_ctx, MONITOR_DBUS_INTERFACE);
+ if (!sd_ctx->interface) {
talloc_free(sd_ctx);
return ENOMEM;
}
@@ -100,8 +107,9 @@ static int monitor_dbus_init(struct mt_ctx *ctx)
return ENOMEM;
}
sd_ctx->methods = monitor_methods;
+ sd_ctx->message_handler = NULL; /* Use the default message_handler */
- ret = sssd_new_dbus_server(sd_ctx, DBUS_ADDRESS);
+ ret = sssd_new_dbus_server(ctx->ev, sd_ctx, DBUS_ADDRESS, dbus_service_init);
return ret;
}
@@ -234,3 +242,92 @@ int start_monitor(TALLOC_CTX *mem_ctx,
return EOK;
}
+/*
+ * dbus_service_init
+ * This function should initiate a query to the newly connected
+ * service to discover the service's identity (invoke the getIdentity
+ * method on the new client). The reply callback for this request
+ * should set the connection destructor appropriately.
+ */
+static int dbus_service_init(struct dbus_connection_toplevel_context *dct_ctx) {
+ DBusMessage *msg;
+ DBusPendingCall *pending_reply;
+ DBusConnection *conn;
+ DBusError dbus_error;
+ dbus_bool_t dbret;
+
+ DEBUG(0,("Initializing D-BUS Service"));
+ conn = sssd_get_dbus_connection(dct_ctx);
+ dbus_error_init(&dbus_error);
+
+ /*
+ * Set up identity request
+ * This should be a well-known path and method
+ * for all services
+ */
+ msg = dbus_message_new_method_call(NULL,
+ SERVICE_PATH,
+ SERVICE_INTERFACE,
+ SERVICE_METHOD_IDENTITY);
+ dbret = dbus_connection_send_with_reply(conn, msg, &pending_reply, -1);
+ if (!dbret) {
+ /*
+ * Critical Failure
+ * We can't communicate on this connection
+ * We'll drop it using the default destructor.
+ */
+ DEBUG(0, ("D-BUS send failed.\n"));
+ talloc_free(dct_ctx);
+ }
+
+ /* Set up the reply handler */
+ dbus_pending_call_set_notify(pending_reply, identity_check, dct_ctx, NULL);
+ dbus_message_unref(msg);
+
+ return EOK;
+}
+
+static void identity_check(DBusPendingCall *pending, void *data) {
+ struct dbus_connection_toplevel_context *dct_ctx;
+ DBusMessage *reply;
+ DBusError dbus_error;
+ int type;
+
+ dct_ctx = talloc_get_type(data, struct dbus_connection_toplevel_context);
+ 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, ("Serious error. A reply callback was called but no reply was received and no timeout occurred\n"));
+
+ /* Destroy this connection */
+ sssd_dbus_disconnect(dct_ctx);
+ return;
+ }
+
+ type = dbus_message_get_type(reply);
+ switch (type) {
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ /* Got the service name and version */
+ /* Extract the name and version from the message */
+ /* Set up the destructor for this service */
+ break;
+ case DBUS_MESSAGE_TYPE_ERROR:
+ DEBUG(0,("getIdentity 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.
+ */
+ sssd_dbus_disconnect(dct_ctx);
+ break;
+ }
+}
diff --git a/server/util/debug.c b/server/util/debug.c
index 0814bb7b..403ec8d2 100644
--- a/server/util/debug.c
+++ b/server/util/debug.c
@@ -3,7 +3,7 @@
#include <stdarg.h>
#include <stdlib.h>
-int debug_level = 2;
+int debug_level = 3;
void debug_fn(const char *format, ...)
{