diff options
Diffstat (limited to 'src/sbus/sssd_dbus_request.c')
-rw-r--r-- | src/sbus/sssd_dbus_request.c | 106 |
1 files changed, 106 insertions, 0 deletions
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; +} |