summaryrefslogtreecommitdiffstats
path: root/src/sbus
diff options
context:
space:
mode:
authorStef Walter <stefw@redhat.com>2014-02-21 16:59:48 +0100
committerJakub Hrozek <jhrozek@redhat.com>2014-03-14 13:42:31 +0100
commit06b7bc8ca2e005ed510210d3b8dee16afbabbcc9 (patch)
tree8131673e499cced272643b379d1a754c064f76b2 /src/sbus
parentf5e47e1d65f80ffdb1893feab18583a74d661214 (diff)
downloadsssd-06b7bc8ca2e005ed510210d3b8dee16afbabbcc9.tar.gz
sssd-06b7bc8ca2e005ed510210d3b8dee16afbabbcc9.tar.xz
sssd-06b7bc8ca2e005ed510210d3b8dee16afbabbcc9.zip
sbus: Add the sbus_request_parse_or_finish() method
Some DBus types returned from dbus_message_get_args() require memory to be released when done. We automatically attach these to the talloc struct sbus_request memory context in this function. This accepts varargs similar to dbus_message_get_args(), which are rather awkward. However instead of reworking them completely, future generated marshalling code will replace most uses of these varargs. If parsing the dbus message fails, then it responds to the DBus caller with an appropriate error such as o.f.D.Error.InvalidArgs. In these cases (ie: when it returns FALSE) the sbus_request is finished. Migrated some, but not all, uses of dbus_message_get_args() to the new function. Some instances have uncommon semantics such as terminating the connection upon failure to parse a message. Reviewed-by: Jakub Hrozek <jhrozek@redhat.com> Reviewed-by: Pavel Březina <pbrezina@redhat.com> Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/sbus')
-rw-r--r--src/sbus/sssd_dbus.h49
-rw-r--r--src/sbus/sssd_dbus_request.c106
2 files changed, 155 insertions, 0 deletions
diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h
index ef728bd30..3bf70c8cc 100644
--- a/src/sbus/sssd_dbus.h
+++ b/src/sbus/sssd_dbus.h
@@ -252,4 +252,53 @@ int sbus_request_return_and_finish(struct sbus_request *dbus_req,
int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
const DBusError *error);
+/*
+ * Parse a DBus method call request.
+ *
+ * If parsing the method call message does not succeed, then an error is
+ * sent to the DBus caller and the request is finished. If this function
+ * returns false then @request is no longer valid.
+ *
+ * This also means if this method returns false within a handler, you should
+ * return EOK from the handler. The message has been handled, appropriate
+ * logs have been written, and everything should just move on.
+ *
+ * If the method call does not match the expected arguments, then a
+ * org.freedesktop.DBus.Error.InvalidArgs is returned to the caller as
+ * expected.
+ *
+ * The variable arguments are (unfortunately) formatted exactly the same
+ * as those of the dbus_message_get_args() function. Documented here:
+ *
+ * http://dbus.freedesktop.org/doc/api/html/group__DBusMessage.html
+ *
+ * Exception: You don't need to free string arrays returned by this
+ * function. They are automatically talloc parented to the request memory
+ * context and can be used until the request has been finished.
+ *
+ * Important: don't pass int or bool or such types as values to this
+ * function. That's not portable. Use actual dbus types. You must also pass
+ * pointers as the values:
+ *
+ * dbus_bool_t val1;
+ * dbus_int32_t val2;
+ * ret = sbus_request_parse_or_finish(request,
+ * DBUS_TYPE_BOOLEAN, &val1,
+ * DBUS_TYPE_INT32, &val2,
+ * DBUS_TYPE_INVALID);
+ *
+ * To pass arrays to this function, use the following syntax. Never
+ * pass actual C arrays with [] syntax to this function. The C standard is
+ * rather vague with C arrays and varargs, and it just plain doesn't work.
+ *
+ * int count; // yes, a plain int
+ * const char **array;
+ * ret = sbus_request_parse_or_finish(request,
+ * DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, &count,
+ * DBUS_TYPE_INVALID);
+ */
+bool sbus_request_parse_or_finish(struct sbus_request *request,
+ int first_arg_type,
+ ...);
+
#endif /* _SSSD_DBUS_H_*/
diff --git a/src/sbus/sssd_dbus_request.c b/src/sbus/sssd_dbus_request.c
index 973089c4b..c45f3a9fd 100644
--- a/src/sbus/sssd_dbus_request.c
+++ b/src/sbus/sssd_dbus_request.c
@@ -110,3 +110,109 @@ int sbus_request_fail_and_finish(struct sbus_request *dbus_req,
dbus_message_unref(reply);
return ret;
}
+
+struct array_arg {
+ char **dbus_array;
+};
+
+static int array_arg_destructor(struct array_arg *arg)
+{
+ dbus_free_string_array(arg->dbus_array);
+ return 0;
+}
+
+static bool
+parent_dbus_string_arrays(struct sbus_request *request, int first_arg_type,
+ va_list va)
+{
+ struct array_arg *array_arg;
+ int arg_type;
+ void **arg_ptr;
+
+ /*
+ * Here we iterate through the entire thing again and look for
+ * things we need to fix allocation for. Normally certain types
+ * returned from dbus_message_get_args() and friends require
+ * later freeing. We tie those to the talloc context here.
+ *
+ * The list of argument has already been validated by the previous
+ * dbus_message_get_args() call, so we can be cheap.
+ */
+
+ arg_type = first_arg_type;
+ while (arg_type != DBUS_TYPE_INVALID) {
+
+ if (arg_type == DBUS_TYPE_ARRAY) {
+ arg_type = va_arg(va, int); /* the array element type */
+ arg_ptr = va_arg(va, void **); /* the array elements */
+ va_arg(va, int *); /* the array length */
+
+ /* Arrays of these things need to be freed */
+ if (arg_type == DBUS_TYPE_STRING ||
+ arg_type == DBUS_TYPE_OBJECT_PATH ||
+ arg_type == DBUS_TYPE_SIGNATURE) {
+
+ array_arg = talloc_zero(request, struct array_arg);
+ if(array_arg == NULL) {
+ /* no kidding ... */
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory while trying not to leak memory\n");
+ return false;
+ }
+
+ array_arg->dbus_array = *arg_ptr;
+ talloc_set_destructor(array_arg, array_arg_destructor);
+ }
+
+ /* A non array argument */
+ } else {
+ arg_ptr = va_arg(va, void**);
+ }
+
+ /* The next type */
+ arg_type = va_arg(va, int);
+ }
+
+ return true;
+}
+
+bool
+sbus_request_parse_or_finish(struct sbus_request *request,
+ int first_arg_type,
+ ...)
+{
+ DBusError error = DBUS_ERROR_INIT;
+ bool ret = true;
+ va_list va2;
+ va_list va;
+
+ va_start(va, first_arg_type);
+ va_copy(va2, va);
+
+ if (dbus_message_get_args_valist(request->message, &error,
+ first_arg_type, va)) {
+ ret = parent_dbus_string_arrays (request, first_arg_type, va2);
+
+ } else {
+ /* Trying to send the error back to the caller in this case is a joke */
+ if (!dbus_error_is_set(&error) || dbus_error_has_name(&error, DBUS_ERROR_NO_MEMORY)) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory parsing DBus message\n");
+ sbus_request_finish(request, NULL);
+
+ /* Log other errors and send them back, this include o.f.d.InvalidArgs */
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE, "Couldn't parse DBus message %s.%s: %s\n",
+ dbus_message_get_interface(request->message),
+ dbus_message_get_member(request->message),
+ error.message);
+ sbus_request_fail_and_finish(request, &error);
+ }
+
+ dbus_error_free(&error);
+ ret = false;
+ }
+
+ va_end(va2);
+ va_end(va);
+
+ return ret;
+}