summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-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 f2d2c69fb..dcab55fe5 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 547aaad29..2b8a77878 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 0033ab87c..e9289e041 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 ae3540bd5..ea1b719bd 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 ebf5a6118..8bdccf8ea 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 30401991d..daf80db97 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 7a877cdda..cf628754b 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 0814bb7b6..403ec8d2d 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, ...)
{