/* Authors: Pavel Březina Copyright (C) 2014 Red Hat 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 #include #include #include "lib/sifp/sss_sifp.h" #include "lib/sifp/sss_sifp_dbus.h" #include "lib/sifp/sss_sifp_private.h" #define DBUS_IFACE_PROP "org.freedesktop.DBus.Properties" static void * default_alloc(size_t size, void *pvt) { return malloc(size); } static void default_free(void *ptr, void *pvt) { free(ptr); } static DBusMessage * sss_sifp_create_prop_msg(const char *object_path, const char *method) { return sss_sifp_create_message(object_path, DBUS_IFACE_PROP, method); } sss_sifp_error sss_sifp_init(sss_sifp_ctx **_ctx) { return sss_sifp_init_ex(NULL, default_alloc, default_free, _ctx); } sss_sifp_error sss_sifp_init_ex(void *alloc_pvt, sss_sifp_alloc_func *alloc_func, sss_sifp_free_func *free_func, sss_sifp_ctx **_ctx) { sss_sifp_ctx *ctx = NULL; DBusConnection *conn = NULL; DBusError dbus_error; sss_sifp_error ret; if (_ctx == NULL || alloc_func == NULL || free_func == NULL) { return SSS_SIFP_INVALID_ARGUMENT; } dbus_error_init(&dbus_error); ctx = alloc_func(sizeof(sss_sifp_ctx), alloc_pvt); if (ctx == NULL) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } ctx->conn = NULL; ctx->alloc_fn = alloc_func; ctx->free_fn = free_func; ctx->alloc_pvt = alloc_pvt; ctx->io_error = alloc_func(sizeof(DBusError), alloc_pvt); if (ctx->io_error == NULL) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } *_ctx = ctx; dbus_error_init(ctx->io_error); conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error); if (dbus_error_is_set(&dbus_error)) { sss_sifp_set_io_error(ctx, &dbus_error); ret = SSS_SIFP_IO_ERROR; goto done; } ctx->conn = conn; ret = SSS_SIFP_OK; done: if (ret != SSS_SIFP_OK) { sss_sifp_free(&ctx); } dbus_error_free(&dbus_error); return ret; } const char * sss_sifp_get_last_io_error_name(sss_sifp_ctx *ctx) { if (ctx == NULL) { return "Invalid sss_sifp context"; } if (!dbus_error_is_set(ctx->io_error)) { return NULL; } return ctx->io_error->name; } const char * sss_sifp_get_last_io_error_message(sss_sifp_ctx *ctx) { if (ctx == NULL) { return "Invalid sss_sifp context"; } if (!dbus_error_is_set(ctx->io_error)) { return NULL; } return ctx->io_error->message; } const char * sss_sifp_strerr(sss_sifp_error error) { switch (error) { case SSS_SIFP_OK: return "Success"; case SSS_SIFP_OUT_OF_MEMORY: return "Out of memory"; case SSS_SIFP_INVALID_ARGUMENT: return "Invalid argument"; case SSS_SIFP_IO_ERROR: return "Communication error"; case SSS_SIFP_INTERNAL_ERROR: return "Internal error"; case SSS_SIFP_NOT_SUPPORTED: return "Not supported"; case SSS_SIFP_ATTR_MISSING: return "Attribute does not exist"; case SSS_SIFP_ATTR_NULL: return "Attribute does not have any value set"; case SSS_SIFP_INCORRECT_TYPE: return "Incorrect type"; case SSS_SIFP_ERROR_SENTINEL: return "Invalid error code"; } return "Invalid error code"; } sss_sifp_error sss_sifp_fetch_attr(sss_sifp_ctx *ctx, const char *object_path, const char *interface, const char *name, sss_sifp_attr ***_attrs) { DBusMessage *msg = NULL; DBusMessage *reply = NULL; dbus_bool_t bret; sss_sifp_error ret; if (ctx == NULL || object_path == NULL || interface == NULL || name == NULL || _attrs == NULL) { return SSS_SIFP_INVALID_ARGUMENT; } /* Message format: * In: string:interface * In: string:attribute * Out: variant(misc:value) */ msg = sss_sifp_create_prop_msg(object_path, "Get"); if (msg == NULL) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } bret = dbus_message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); if (!bret) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } ret = sss_sifp_send_message(ctx, msg, &reply); if (ret != SSS_SIFP_OK) { goto done; } ret = sss_sifp_parse_attr(ctx, name, reply, _attrs); done: if (msg != NULL) { dbus_message_unref(msg); } if (reply != NULL) { dbus_message_unref(reply); } return ret; } sss_sifp_error sss_sifp_fetch_all_attrs(sss_sifp_ctx *ctx, const char *object_path, const char *interface, sss_sifp_attr ***_attrs) { DBusMessage *msg = NULL; DBusMessage *reply = NULL; dbus_bool_t bret; sss_sifp_error ret; if (ctx == NULL || object_path == NULL || interface == NULL || _attrs == NULL) { return SSS_SIFP_INVALID_ARGUMENT; } msg = sss_sifp_create_prop_msg(object_path, "GetAll"); if (msg == NULL) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } bret = dbus_message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID); if (!bret) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } ret = sss_sifp_send_message(ctx, msg, &reply); if (ret != SSS_SIFP_OK) { goto done; } ret = sss_sifp_parse_attr_list(ctx, reply, _attrs); done: if (msg != NULL) { dbus_message_unref(msg); } if (reply != NULL) { dbus_message_unref(reply); } return ret; } sss_sifp_error sss_sifp_fetch_object(sss_sifp_ctx *ctx, const char *object_path, const char *interface, sss_sifp_object **_object) { sss_sifp_object *object = NULL; sss_sifp_attr **attrs = NULL; const char *name = NULL; sss_sifp_error ret; if (ctx == NULL || object_path == NULL || interface == NULL || _object == NULL) { return SSS_SIFP_INVALID_ARGUMENT; } ret = sss_sifp_fetch_all_attrs(ctx, object_path, interface, &attrs); if (ret != SSS_SIFP_OK) { goto done; } ret = sss_sifp_find_attr_as_string(attrs, "name", &name); if (ret != SSS_SIFP_OK) { goto done; } object = _alloc_zero(ctx, sss_sifp_object, 1); if (object == NULL) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } object->attrs = attrs; object->name = sss_sifp_strdup(ctx, name); if (object->name == NULL) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } object->object_path = sss_sifp_strdup(ctx, object_path); if (object->object_path == NULL) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } object->interface = sss_sifp_strdup(ctx, interface); if (object->interface == NULL) { ret = SSS_SIFP_OUT_OF_MEMORY; goto done; } *_object = object; ret = SSS_SIFP_OK; done: if (ret != SSS_SIFP_OK) { sss_sifp_free_object(ctx, &object); } return ret; } void sss_sifp_free(sss_sifp_ctx **_ctx) { sss_sifp_ctx *ctx = NULL; if (_ctx == NULL || *_ctx == NULL) { return; } ctx = *_ctx; if (ctx->conn != NULL) { dbus_connection_unref(ctx->conn); } if (ctx->io_error != NULL) { dbus_error_free(ctx->io_error); _free(ctx, ctx->io_error); } _free(ctx, ctx); *_ctx = NULL; return; } void sss_sifp_free_attrs(sss_sifp_ctx *ctx, sss_sifp_attr ***_attrs) { sss_sifp_attr **attrs = NULL; unsigned int i, j; if (_attrs == NULL || *_attrs == NULL) { return; } attrs = *_attrs; for (i = 0; attrs[i] != NULL; i++) { switch (attrs[i]->type) { case SSS_SIFP_ATTR_TYPE_BOOL: _free(ctx, attrs[i]->data.boolean); break; case SSS_SIFP_ATTR_TYPE_INT16: _free(ctx, attrs[i]->data.int16); break; case SSS_SIFP_ATTR_TYPE_UINT16: _free(ctx, attrs[i]->data.uint16); break; case SSS_SIFP_ATTR_TYPE_INT32: _free(ctx, attrs[i]->data.int32); break; case SSS_SIFP_ATTR_TYPE_UINT32: _free(ctx, attrs[i]->data.uint32); break; case SSS_SIFP_ATTR_TYPE_INT64: _free(ctx, attrs[i]->data.int64); break; case SSS_SIFP_ATTR_TYPE_UINT64: _free(ctx, attrs[i]->data.uint64); break; case SSS_SIFP_ATTR_TYPE_STRING: for (j = 0; j < attrs[i]->num_values; j++) { _free(ctx, attrs[i]->data.str[j]); } _free(ctx, attrs[i]->data.str); break; case SSS_SIFP_ATTR_TYPE_STRING_DICT: if (attrs[i]->data.str_dict != NULL) { hash_destroy(attrs[i]->data.str_dict); } attrs[i]->data.str_dict = NULL; break; } _free(ctx, attrs[i]->name); _free(ctx, attrs[i]); } _free(ctx, attrs); *_attrs = NULL; } void sss_sifp_free_object(sss_sifp_ctx *ctx, sss_sifp_object **_object) { sss_sifp_object *object = NULL; if (_object == NULL || *_object == NULL) { return; } object = *_object; sss_sifp_free_attrs(ctx, &object->attrs); _free(ctx, object->object_path); _free(ctx, object->interface); _free(ctx, object->name); _free(ctx, object); *_object = NULL; } void sss_sifp_free_string(sss_sifp_ctx *ctx, char **_str) { if (_str == NULL || *_str == NULL) { return; } _free(ctx, *_str); *_str = NULL; } void sss_sifp_free_string_array(sss_sifp_ctx *ctx, char ***_str_array) { char **str_array = NULL; int i; if (_str_array == NULL || *_str_array == NULL) { return; } str_array = *_str_array; for (i = 0; str_array[i] != NULL; i++) { _free(ctx, str_array[i]); } _free(ctx, str_array); *_str_array = NULL; }