diff options
Diffstat (limited to 'src/sbus')
| -rw-r--r-- | src/sbus/sssd_dbus.h | 49 | ||||
| -rw-r--r-- | src/sbus/sssd_dbus_request.c | 106 |
2 files changed, 155 insertions, 0 deletions
diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h index ef728bd3..3bf70c8c 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 973089c4..c45f3a9f 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; +} |
