/* Authors: Pavel Březina Copyright (C) 2014 Red Hat SBUS: Interface introspection This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "config.h" #include #include #include "util/util.h" #include "sbus/sssd_dbus.h" #include "sbus/sssd_dbus_meta.h" #include "sbus/sssd_dbus_private.h" #include "sbus/sssd_dbus_invokers.h" static int sbus_invoke_get_basic(struct sbus_request *sbus_req, void *function_ptr, void *value_ptr, int dbus_type, DBusMessageIter *iter) { void (*handler_fn)(struct sbus_request *, void *, void *); dbus_bool_t value_bool; dbus_bool_t dbret; handler_fn = function_ptr; handler_fn(sbus_req, sbus_req->intf->handler_data, value_ptr); if (dbus_type == DBUS_TYPE_BOOLEAN) { /* Special case to convert bool into dbus_bool_t. */ value_bool = *((bool *) value_ptr); value_ptr = &value_bool; } dbret = dbus_message_iter_append_basic(iter, dbus_type, value_ptr); return dbret ? EOK : EIO; } static int sbus_invoke_get_string(struct sbus_request *sbus_req, void *function_ptr, const char *default_value, int dbus_type, DBusMessageIter *iter) { void (*handler_fn)(struct sbus_request *, void *, const char **); const char *value = NULL; dbus_bool_t dbret; handler_fn = function_ptr; handler_fn(sbus_req, sbus_req->intf->handler_data, &value); value = value == NULL ? default_value : value; dbret = dbus_message_iter_append_basic(iter, dbus_type, &value); return dbret ? EOK : EIO; } static int sbus_invoke_get_array(struct sbus_request *sbus_req, void *function_ptr, unsigned int item_size, int dbus_type, DBusMessageIter *iter) { void (*handler_fn)(struct sbus_request *, void *, void *, int *); const char array_type[2] = {dbus_type, '\0'}; DBusMessageIter array; dbus_bool_t dbret; uint8_t *values; void *addr; int num_values; int i; handler_fn = function_ptr; handler_fn(sbus_req, sbus_req->intf->handler_data, &values, &num_values); dbret = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, array_type, &array); if (!dbret) { return EIO; } for (i = 0; i < num_values; i++) { addr = values + i * item_size; dbret = dbus_message_iter_append_basic(&array, dbus_type, addr); if (!dbret) { return ENOMEM; } } dbret = dbus_message_iter_close_container(iter, &array); if (!dbret) { return EIO; } return EOK; } int sbus_invoke_get_y(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { uint8_t value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_BYTE, iter); } int sbus_invoke_get_b(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { bool value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_BOOLEAN, iter); } int sbus_invoke_get_n(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { int16_t value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_INT16, iter); } int sbus_invoke_get_q(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { uint16_t value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_UINT16, iter); } int sbus_invoke_get_i(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { int32_t value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_INT32, iter); } int sbus_invoke_get_u(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { uint32_t value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_UINT32, iter); } int sbus_invoke_get_x(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { int64_t value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_INT64, iter); } int sbus_invoke_get_t(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { uint64_t value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_UINT64, iter); } int sbus_invoke_get_d(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { double value; return sbus_invoke_get_basic(sbus_req, function_ptr, &value, DBUS_TYPE_DOUBLE, iter); } int sbus_invoke_get_s(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_string(sbus_req, function_ptr, "", DBUS_TYPE_STRING, iter); } int sbus_invoke_get_o(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_string(sbus_req, function_ptr, "/", DBUS_TYPE_OBJECT_PATH, iter); } int sbus_invoke_get_ay(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(uint8_t), DBUS_TYPE_BYTE, iter); } int sbus_invoke_get_an(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(int16_t), DBUS_TYPE_INT16, iter); } int sbus_invoke_get_aq(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(uint16_t), DBUS_TYPE_UINT16, iter); } int sbus_invoke_get_ai(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(int32_t), DBUS_TYPE_INT32, iter); } int sbus_invoke_get_au(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(uint32_t), DBUS_TYPE_UINT32, iter); } int sbus_invoke_get_ax(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(int64_t), DBUS_TYPE_INT64, iter); } int sbus_invoke_get_at(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(uint64_t), DBUS_TYPE_UINT64, iter); } int sbus_invoke_get_ad(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(double), DBUS_TYPE_DOUBLE, iter); } int sbus_invoke_get_as(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(const char *), DBUS_TYPE_STRING, iter); } int sbus_invoke_get_ao(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { return sbus_invoke_get_array(sbus_req, function_ptr, sizeof(const char *), DBUS_TYPE_OBJECT_PATH, iter); } int sbus_invoke_get_aDOsasDE(DBusMessageIter *iter, struct sbus_request *sbus_req, void *function_ptr) { void (*handler_fn)(struct sbus_request *, void *, hash_table_t **); DBusMessageIter it_array; DBusMessageIter it_dict; DBusMessageIter it_values; hash_table_t *table; struct hash_iter_context_t *table_iter = NULL; hash_entry_t *entry; const char **values; dbus_bool_t dbret; errno_t ret; int i; handler_fn = function_ptr; handler_fn(sbus_req, sbus_req->intf->handler_data, &table); dbret = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &it_array); if (!dbret) { ret = EIO; goto done; } /* iterate over keys */ if (table == NULL) { dbret = dbus_message_iter_close_container(iter, &it_array); if (!dbret) { ret = EIO; goto done; } ret = EOK; goto done; } table_iter = new_hash_iter_context(table); while ((entry = table_iter->next(table_iter)) != NULL) { if (entry->key.type != HASH_KEY_STRING || entry->key.str == NULL || entry->value.type != HASH_VALUE_PTR || entry->value.ptr == NULL) { continue; } dbret = dbus_message_iter_open_container(&it_array, DBUS_TYPE_DICT_ENTRY, NULL, &it_dict); if (!dbret) { ret = EIO; goto done; } /* append key as dict entry key */ dbret = dbus_message_iter_append_basic(&it_dict, DBUS_TYPE_STRING, &entry->key.str); if (!dbret) { ret = EIO; goto done; } /* iterate over values */ dbret = dbus_message_iter_open_container(&it_dict, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &it_values); if (!dbret) { ret = EIO; goto done; } values = entry->value.ptr; for (i = 0; values[i] != NULL; i++) { /* append value into array */ dbret = dbus_message_iter_append_basic(&it_values, DBUS_TYPE_STRING, &values[i]); if (!dbret) { ret = EIO; goto done; } } dbret = dbus_message_iter_close_container(&it_dict, &it_values); if (!dbret) { ret = EIO; goto done; } dbret = dbus_message_iter_close_container(&it_array, &it_dict); if (!dbret) { ret = EIO; goto done; } } dbret = dbus_message_iter_close_container(iter, &it_array); if (!dbret) { ret = EIO; goto done; } ret = EOK; done: talloc_free(table_iter); return ret; } void sbus_invoke_get(struct sbus_request *sbus_req, const char *type, sbus_get_invoker_fn invoker_fn, sbus_msg_handler_fn handler_fn) { DBusMessage *reply = NULL; DBusMessageIter iter; DBusMessageIter variant; dbus_bool_t dbret; errno_t ret; reply = dbus_message_new_method_return(sbus_req->message); if (reply == NULL) { ret = ENOMEM; goto fail; } dbus_message_iter_init_append(reply, &iter); dbret = dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, type, &variant); if (!dbret) { ret = ENOMEM; goto fail; } ret = invoker_fn(&variant, sbus_req, handler_fn); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Invoker error [%d]: %s\n", ret, sss_strerror(ret)); goto fail; } dbret = dbus_message_iter_close_container(&iter, &variant); if (!dbret) { ret = EIO; goto fail; } sbus_request_finish(sbus_req, reply); return; fail: DEBUG(SSSDBG_CRIT_FAILURE, "Unable to reply [%d]: %s\n", ret, sss_strerror(ret)); if (reply != NULL) { dbus_message_unref(reply); } sbus_request_finish(sbus_req, NULL); return; } void sbus_invoke_get_all(struct sbus_request *sbus_req) { const struct sbus_property_meta *props; sbus_msg_handler_fn *handler_fn; DBusMessage *reply = NULL; DBusMessageIter iter; DBusMessageIter array; DBusMessageIter dict; DBusMessageIter variant; dbus_bool_t dbret; errno_t ret; int i; reply = dbus_message_new_method_return(sbus_req->message); if (reply == NULL) { ret = ENOMEM; goto fail; } dbus_message_iter_init_append(reply, &iter); dbret = dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array); if (!dbret) { ret = ENOMEM; goto fail; } props = sbus_req->intf->vtable->meta->properties; if (props != NULL) { for (i = 0; props[i].name != NULL; i++) { dbret = dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict); if (!dbret) { ret = ENOMEM; goto fail; } /* key */ dbret = dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &props[i].name); if (!dbret) { ret = ENOMEM; goto fail; } /* value */ dbret = dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, props[i].type, &variant); if (!dbret) { ret = ENOMEM; goto fail; } handler_fn = VTABLE_FUNC(sbus_req->intf->vtable, props[i].vtable_offset_get); if (handler_fn == NULL) { ret = ERR_INTERNAL; goto fail; } ret = props[i].invoker_get(&variant, sbus_req, handler_fn); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Invoker error [%d]: %s\n", ret, sss_strerror(ret)); goto fail; } dbret = dbus_message_iter_close_container(&dict, &variant); if (!dbret) { ret = EIO; goto fail; } dbret = dbus_message_iter_close_container(&array, &dict); if (!dbret) { ret = EIO; goto fail; } } } dbret = dbus_message_iter_close_container(&iter, &array); if (!dbret) { ret = EIO; goto fail; } sbus_request_finish(sbus_req, reply); return; fail: DEBUG(SSSDBG_CRIT_FAILURE, "Unable to reply [%d]: %s\n", ret, sss_strerror(ret)); dbus_message_unref(reply); sbus_request_finish(sbus_req, NULL); return; }