From 7c46a27d6a9193dbcd513020e7f19718452f5d9f Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Jun 23 2015 17:45:32 +0000 Subject: Improve matching against defined services We're seeing the dbus-python binding resolve our well-known name to a unique address and then sending requests to us using that. Because we compare the destination address in the request against the names of the multiple services we're supplying in order to route the message, that failed. If we don't match in that way, look for any service with an object that matches the requested path, and which supplies the requested method name, and interface if provided. If we can find one unambiguously, assume that service name. If that doesn't work well enough, we'll have to switch to opening and managing multiple connections to the bus, which would be more complicated. While we're in here, adjust the logic for cases where no interface name is provided, so that instead of assuming the first interface, try to look for one which supplies the requested method, again succeeding only when we find exactly one. --- diff --git a/src/oddjob_dbus.c b/src/oddjob_dbus.c index ec1d18c..8d18869 100644 --- a/src/oddjob_dbus.c +++ b/src/oddjob_dbus.c @@ -1,5 +1,5 @@ /* - Copyright 2005,2006,2007,2010,2012,2014 Red Hat, Inc. + Copyright 2005,2006,2007,2010,2012,2014,2015 Red Hat, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -595,6 +595,66 @@ oddjob_dbus_listener_reconnect_if_needed(struct oddjob_dbus_context *ctx) mainloop_reinit(ctx->conn); } +static struct oddjob_dbus_service * +guess_service(struct oddjob_dbus_context *ctx, const char *path, + const char *interface, const char *method) +{ + int i, j, k, l; + struct oddjob_dbus_service *srv, *matched = NULL; + struct oddjob_dbus_object *obj; + struct oddjob_dbus_interface *iface; + + for (i = 0; i < ctx->n_services; i++) { + srv = &ctx->services[i]; + for (j = 0; j < srv->n_objects; j++) { + if (fnmatch(srv->objects[j].path, path, + ODDJOB_OBJECT_FNMATCH_FLAGS) != 0) { + continue; + } + obj = &srv->objects[j]; + for (k = 0; k < obj->n_interfaces; k++) { + if ((interface != NULL) && + (strcmp(interface, obj->interfaces[k].interface) != 0)) { + continue; + } + iface = &obj->interfaces[k]; + for (l = 0; l < iface->n_methods; l++) { + if (strcmp(method, iface->methods[l].method) != 0) { + continue; + } + if ((matched != NULL) && (matched != srv)) { + return NULL; + } + matched = srv; + } + } + } + } + return matched; +} + +static struct oddjob_dbus_interface * +guess_interface(struct oddjob_dbus_object *obj, const char *method) +{ + int i, j; + struct oddjob_dbus_interface *iface, *match = NULL; + + /* Look for any interface containing the named method. */ + for (i = 0; i < obj->n_interfaces; i++) { + iface = &obj->interfaces[i]; + for (j = 0; j < iface->n_methods; j++) { + if (strcmp(iface->methods[j].method, method) == 0) { + if (match != NULL) { + /* No ambiguity allowed. */ + return NULL; + } + match = iface; + } + } + } + return match; +} + static DBusHandlerResult oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) { @@ -602,6 +662,7 @@ oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) struct oddjob_dbus_service *srv; struct oddjob_dbus_object *obj; struct oddjob_dbus_interface *interface; + struct oddjob_dbus_method *method; struct oddjob_dbus_message *msg; char n_args[LINE_MAX]; const char *sender_bus_name; @@ -653,7 +714,11 @@ oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) called_member = dbus_message_get_member(message); /* Check that the message is a method call. */ - if ((called_interface != NULL) && (called_member != NULL)) { + if ((called_service == NULL) || (called_path == NULL) || + (called_member == NULL)) { + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + if (called_interface != NULL) { if (!(dbus_message_is_method_call(message, called_interface, called_member))) { @@ -678,16 +743,21 @@ oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) } /* Get the called service name and find the service. */ - for (i = 0; (called_service != NULL) && (i < ctx->n_services); i++) { + for (i = 0; i < ctx->n_services; i++) { if (strcmp(ctx->services[i].name, called_service) == 0) { break; } } if (i >= ctx->n_services) { - oddjob_dbus_message_free(msg); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + srv = guess_service(ctx, called_path, called_interface, + called_member); + if (srv == NULL) { + oddjob_dbus_message_free(msg); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + } else { + srv = &ctx->services[i]; } - srv = &ctx->services[i]; /* Get the called object path and find the object. */ for (i = 0; (called_path != NULL) && (i < srv->n_objects); i++) { @@ -703,19 +773,28 @@ oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) called_path : ""); oddjob_dbus_message_free(msg); return DBUS_HANDLER_RESULT_HANDLED; + } else { + obj = &srv->objects[i]; } - obj = &srv->objects[i]; - /* Get the called interface and find the interface. */ - for (i = 0; - (called_interface != NULL) && (i < obj->n_interfaces); - i++) { - if (strcmp(obj->interfaces[i].interface, - called_interface) == 0) { - break; + /* Get the called interface, if there is one, and find the right + * interface. */ + if (called_interface == NULL) { + interface = guess_interface(obj, called_member); + } else { + for (i = 0; i < obj->n_interfaces; i++) { + if (strcmp(obj->interfaces[i].interface, + called_interface) == 0) { + break; + } + } + if (i >= obj->n_interfaces) { + interface = NULL; + } else { + interface = &obj->interfaces[i]; } } - if (i >= obj->n_interfaces) { + if (interface == NULL) { oddjob_dbus_send_message_response_error(msg, ODDJOB_ERROR_NO_INTERFACE, called_interface ? @@ -723,9 +802,8 @@ oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) oddjob_dbus_message_free(msg); return DBUS_HANDLER_RESULT_HANDLED; } - interface = &obj->interfaces[i]; - /* Search for the method. */ + /* Find the method in the interface. */ for (i = 0; (called_member != NULL) && (i < interface->n_methods); i++) { @@ -750,6 +828,8 @@ oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) called_member : ""); oddjob_dbus_message_free(msg); return DBUS_HANDLER_RESULT_HANDLED; + } else { + method = &interface->methods[i]; } /* Get the UID of the sending user and resolve it to a name. */ @@ -779,12 +859,11 @@ oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) } /* Check the number of arguments. */ - if (msg->n_args != interface->methods[i].n_arguments) { + if (msg->n_args != method->n_arguments) { snprintf(n_args, sizeof(n_args), "wrong number of arguments: " "expected %d, called with %d", - interface->methods[i].n_arguments, - msg->n_args); + method->n_arguments, msg->n_args); oddjob_dbus_send_message_response_error(msg, ODDJOB_ERROR_INVALID_CALL, n_args); @@ -793,15 +872,8 @@ oddjob_dbus_filter(DBusConnection *conn, DBusMessage *message, void *user_data) } /* Actually call the handler. */ - interface->methods[i].handler(ctx, - msg, - called_service, - called_path, - called_interface, - called_member, - pwd->pw_name, - uid, - interface->methods[i].data); + method->handler(ctx, msg, srv->name, called_path, interface->interface, + called_member, pwd->pw_name, uid, method->data); oddjob_dbus_message_free(msg); return DBUS_HANDLER_RESULT_HANDLED;