diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/Makefile.in | 2 | ||||
-rw-r--r-- | server/dbus/sssd_dbus.h | 49 | ||||
-rw-r--r-- | server/dbus/sssd_dbus_connection.c | 313 | ||||
-rw-r--r-- | server/dbus/sssd_dbus_private.h | 7 | ||||
-rw-r--r-- | server/dbus/sssd_dbus_server.c | 152 | ||||
-rw-r--r-- | server/dbus/tests/test_client.c | 96 | ||||
-rw-r--r-- | server/monitor.c | 109 | ||||
-rw-r--r-- | server/util/debug.c | 2 |
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, ...) { |