From 91cf6f4c6069d6aff01aab171825e83a1a669e2f Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Sun, 18 May 2014 20:52:42 +0200 Subject: sss_sifp: implement API https://fedorahosted.org/sssd/ticket/2254 Reviewed-by: Sumit Bose --- src/lib/sifp/sss_sifp.c | 437 ++++++++++++++++++++++++++++++++ src/lib/sifp/sss_sifp_attrs.c | 259 +++++++++++++++++++ src/lib/sifp/sss_sifp_dbus.c | 192 ++++++++++++++ src/lib/sifp/sss_sifp_parser.c | 536 ++++++++++++++++++++++++++++++++++++++++ src/lib/sifp/sss_sifp_private.h | 115 +++++++++ src/lib/sifp/sss_sifp_utils.c | 117 +++++++++ 6 files changed, 1656 insertions(+) create mode 100644 src/lib/sifp/sss_sifp.c create mode 100644 src/lib/sifp/sss_sifp_attrs.c create mode 100644 src/lib/sifp/sss_sifp_dbus.c create mode 100644 src/lib/sifp/sss_sifp_parser.c create mode 100644 src/lib/sifp/sss_sifp_private.h create mode 100644 src/lib/sifp/sss_sifp_utils.c (limited to 'src/lib/sifp') diff --git a/src/lib/sifp/sss_sifp.c b/src/lib/sifp/sss_sifp.c new file mode 100644 index 000000000..0bf29075e --- /dev/null +++ b/src/lib/sifp/sss_sifp.c @@ -0,0 +1,437 @@ +/* + 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; + } + + 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; + *_ctx = ctx; + + 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; +} + +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; + } + _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; +} diff --git a/src/lib/sifp/sss_sifp_attrs.c b/src/lib/sifp/sss_sifp_attrs.c new file mode 100644 index 000000000..8e871b2e6 --- /dev/null +++ b/src/lib/sifp/sss_sifp_attrs.c @@ -0,0 +1,259 @@ +/* + 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 "lib/sifp/sss_sifp.h" +#include "lib/sifp/sss_sifp_private.h" + +#define GET_ATTR(attrs, name, rtype, field, out) do { \ + sss_sifp_attr *attr = sss_sifp_find_attr(attrs, name); \ + \ + if (attr == NULL) { \ + return SSS_SIFP_ATTR_MISSING; \ + } \ + \ + if (attr->type != rtype) { \ + return SSS_SIFP_INCORRECT_TYPE; \ + } \ + \ + if (attr->data.field == NULL) { \ + return SSS_SIFP_ATTR_NULL; \ + } \ + \ + out = attr->data.field[0]; \ +} while (0) + +#define GET_ATTR_ARRAY(attrs, name, rtype, field, out_num, out_val) do { \ + sss_sifp_attr *attr = sss_sifp_find_attr(attrs, name); \ + \ + if (attr == NULL) { \ + return SSS_SIFP_ATTR_MISSING; \ + } \ + \ + if (attr->type != rtype) { \ + return SSS_SIFP_INCORRECT_TYPE; \ + } \ + \ + if (attr->data.field == NULL) { \ + return SSS_SIFP_ATTR_NULL; \ + } \ + \ + out_num = attr->num_values; \ + out_val = attr->data.field; \ +} while (0) + +static sss_sifp_attr *sss_sifp_find_attr(sss_sifp_attr **attrs, + const char *name) +{ + int i; + + if (attrs == NULL || name == NULL) { + return NULL; + } + + for (i = 0; attrs[i] != NULL; i++) { + if (strcmp(attrs[i]->name, name) == 0) { + return attrs[i]; + } + } + + return NULL; +} + +sss_sifp_error +sss_sifp_find_attr_as_bool(sss_sifp_attr **attrs, + const char *name, + bool *_value) +{ + GET_ATTR(attrs, name, SSS_SIFP_ATTR_TYPE_BOOL, boolean, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_int16(sss_sifp_attr **attrs, + const char *name, + int16_t *_value) +{ + GET_ATTR(attrs, name, SSS_SIFP_ATTR_TYPE_INT16, int16, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_uint16(sss_sifp_attr **attrs, + const char *name, + uint16_t *_value) +{ + GET_ATTR(attrs, name, SSS_SIFP_ATTR_TYPE_UINT16, uint16, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_int32(sss_sifp_attr **attrs, + const char *name, + int32_t *_value) +{ + GET_ATTR(attrs, name, SSS_SIFP_ATTR_TYPE_INT32, int32, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_uint32(sss_sifp_attr **attrs, + const char *name, + uint32_t *_value) +{ + GET_ATTR(attrs, name, SSS_SIFP_ATTR_TYPE_UINT32, uint32, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_int64(sss_sifp_attr **attrs, + const char *name, + int64_t *_value) +{ + GET_ATTR(attrs, name, SSS_SIFP_ATTR_TYPE_INT64, int64, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_uint64(sss_sifp_attr **attrs, + const char *name, + uint64_t *_value) +{ + GET_ATTR(attrs, name, SSS_SIFP_ATTR_TYPE_UINT64, uint64, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_string(sss_sifp_attr **attrs, + const char *name, + const char **_value) +{ + const char *value = NULL; + + GET_ATTR(attrs, name, SSS_SIFP_ATTR_TYPE_STRING, str, value); + + if (value == NULL) { + return SSS_SIFP_ATTR_NULL; + } + + *_value = value; + return SSS_SIFP_OK; +} + +/** + * @brief Find attribute in list and return its values. + * + * @param[in] attrs Attributes + * @param[in] name Name of the attribute to find + * + * @return Attribute values or NULL if it is not found. + */ +sss_sifp_error +sss_sifp_find_attr_as_bool_array(sss_sifp_attr **attrs, + const char *name, + unsigned int *_num_values, + bool **_value) +{ + GET_ATTR_ARRAY(attrs, name, SSS_SIFP_ATTR_TYPE_BOOL, boolean, + *_num_values, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_int16_array(sss_sifp_attr **attrs, + const char *name, + unsigned int *_num_values, + int16_t **_value) +{ + GET_ATTR_ARRAY(attrs, name, SSS_SIFP_ATTR_TYPE_INT16, int16, + *_num_values, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_uint16_array(sss_sifp_attr **attrs, + const char *name, + unsigned int *_num_values, + uint16_t **_value) +{ + GET_ATTR_ARRAY(attrs, name, SSS_SIFP_ATTR_TYPE_UINT16, uint16, + *_num_values, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_int32_array(sss_sifp_attr **attrs, + const char *name, + unsigned int *_num_values, + int32_t **_value) +{ + GET_ATTR_ARRAY(attrs, name, SSS_SIFP_ATTR_TYPE_INT32, int32, + *_num_values, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_uint32_array(sss_sifp_attr **attrs, + const char *name, + unsigned int *_num_values, + uint32_t **_value) +{ + GET_ATTR_ARRAY(attrs, name, SSS_SIFP_ATTR_TYPE_UINT32, uint32, + *_num_values, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_int64_array(sss_sifp_attr **attrs, + const char *name, + unsigned int *_num_values, + int64_t **_value) +{ + GET_ATTR_ARRAY(attrs, name, SSS_SIFP_ATTR_TYPE_INT64, int64, + *_num_values, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_uint64_array(sss_sifp_attr **attrs, + const char *name, + unsigned int *_num_values, + uint64_t **_value) +{ + GET_ATTR_ARRAY(attrs, name, SSS_SIFP_ATTR_TYPE_UINT64, uint64, + *_num_values, *_value); + return SSS_SIFP_OK; +} + +sss_sifp_error +sss_sifp_find_attr_as_string_array(sss_sifp_attr **attrs, + const char *name, + unsigned int *_num_values, + const char * const **_value) +{ + char **value; + + GET_ATTR_ARRAY(attrs, name, SSS_SIFP_ATTR_TYPE_STRING, str, + *_num_values, value); + *_value = (const char * const *)value; + + return SSS_SIFP_OK; +} diff --git a/src/lib/sifp/sss_sifp_dbus.c b/src/lib/sifp/sss_sifp_dbus.c new file mode 100644 index 000000000..d9813718b --- /dev/null +++ b/src/lib/sifp/sss_sifp_dbus.c @@ -0,0 +1,192 @@ +/* + 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" + +static sss_sifp_error sss_sifp_ifp_call(sss_sifp_ctx *ctx, + const char *method, + int first_arg_type, + va_list ap, + DBusMessage **_reply) +{ + DBusMessage *msg = NULL; + sss_sifp_error ret; + + msg = sss_sifp_create_message(SSS_SIFP_PATH_IFP, SSS_SIFP_IFACE_IFP, method); + if (msg == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + if (first_arg_type != DBUS_TYPE_INVALID) { + dbus_message_append_args_valist(msg, first_arg_type, ap); + } + + ret = sss_sifp_send_message(ctx, msg, _reply); + +done: + if (msg != NULL) { + dbus_message_unref(msg); + } + + return ret; +} + +DBusMessage * +sss_sifp_create_message(const char *object_path, + const char *interface, + const char *method) +{ + return dbus_message_new_method_call(SSS_SIFP_IFP, object_path, + interface, method); +} + +sss_sifp_error +sss_sifp_send_message(sss_sifp_ctx *ctx, + DBusMessage *msg, + DBusMessage **_reply) +{ + return sss_sifp_send_message_ex(ctx, msg, 5000, _reply); +} + +sss_sifp_error +sss_sifp_send_message_ex(sss_sifp_ctx *ctx, + DBusMessage *msg, + int timeout, + DBusMessage **_reply) +{ + DBusMessage *reply = NULL; + DBusError dbus_error; + sss_sifp_error ret; + + if (ctx == NULL || msg == NULL) { + return SSS_SIFP_INVALID_ARGUMENT; + } + + dbus_error_init(&dbus_error); + + reply = dbus_connection_send_with_reply_and_block(ctx->conn, msg, + timeout, &dbus_error); + if (dbus_error_is_set(&dbus_error)) { + sss_sifp_set_io_error(ctx, &dbus_error); + ret = SSS_SIFP_IO_ERROR; + goto done; + } + + if (_reply == NULL) { + dbus_message_unref(reply); + } else { + *_reply = reply; + } + + ret = SSS_SIFP_OK; + +done: + dbus_error_free(&dbus_error); + return ret; +} + +sss_sifp_error +sss_sifp_invoke_list(sss_sifp_ctx *ctx, + const char *method, + char ***_object_paths, + int first_arg_type, + ...) +{ + DBusMessage *reply = NULL; + char *dbus_method = NULL; + sss_sifp_error ret; + va_list ap; + + if (ctx == NULL || method == NULL || _object_paths == NULL) { + return SSS_SIFP_INVALID_ARGUMENT; + } + + dbus_method = sss_sifp_strcat(ctx, "List", method); + if (dbus_method == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + va_start(ap, first_arg_type); + ret = sss_sifp_ifp_call(ctx, dbus_method, first_arg_type, ap, &reply); + va_end(ap); + if (ret != SSS_SIFP_OK) { + goto done; + } + + ret = sss_sifp_parse_object_path_list(ctx, reply, _object_paths); + +done: + sss_sifp_free_string(ctx, &dbus_method); + + if (reply != NULL) { + dbus_message_unref(reply); + } + + return ret; +} + +sss_sifp_error +sss_sifp_invoke_find(sss_sifp_ctx *ctx, + const char *method, + char **_object_path, + int first_arg_type, + ...) +{ + DBusMessage *reply = NULL; + char *dbus_method = NULL; + sss_sifp_error ret; + va_list ap; + + if (ctx == NULL || method == NULL || _object_path == NULL) { + return SSS_SIFP_INVALID_ARGUMENT; + } + + dbus_method = sss_sifp_strcat(ctx, "Find", method); + if (dbus_method == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + va_start(ap, first_arg_type); + ret = sss_sifp_ifp_call(ctx, dbus_method, first_arg_type, ap, &reply); + va_end(ap); + if (ret != SSS_SIFP_OK) { + goto done; + } + + ret = sss_sifp_parse_object_path(ctx, reply, _object_path); + +done: + sss_sifp_free_string(ctx, &dbus_method); + + if (reply != NULL) { + dbus_message_unref(reply); + } + + return ret; +} diff --git a/src/lib/sifp/sss_sifp_parser.c b/src/lib/sifp/sss_sifp_parser.c new file mode 100644 index 000000000..1c1ff80c8 --- /dev/null +++ b/src/lib/sifp/sss_sifp_parser.c @@ -0,0 +1,536 @@ +/* + 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 "lib/sifp/sss_sifp.h" +#include "lib/sifp/sss_sifp_private.h" + +#define check_dbus_arg(iter, type, ret, done) do { \ + if (dbus_message_iter_get_arg_type((iter)) != (type)) { \ + ret = SSS_SIFP_INTERNAL_ERROR; \ + goto done; \ + } \ +} while (0) + +#define parse_basic(ctx, iter, ret, attr_type, dbus_type, \ + data_type, field, done) \ +do { \ + dbus_type val; \ + dbus_message_iter_get_basic(iter, &val); \ + attr->type = attr_type; \ + attr->data.field = _alloc_zero(ctx, data_type, 1); \ + \ + if (attr->data.field == NULL) { \ + ret = SSS_SIFP_OUT_OF_MEMORY; \ + goto done; \ + } \ + \ + attr->data.field[0] = val; \ + attr->num_values = 1; \ + \ + ret = SSS_SIFP_OK; \ +} while (0) + +#define parse_array(ctx, iter, ret, attr_type, dbus_type, \ + data_type, field, done) \ +do { \ + dbus_type val; \ + unsigned int i; \ + \ + attr->type = attr_type; \ + if (attr->num_values == 0) { \ + attr->data.field = NULL; \ + ret = SSS_SIFP_OK; \ + goto done; \ + } \ + \ + attr->data.field = _alloc_zero(ctx, data_type, attr->num_values); \ + if (attr->data.field == NULL) { \ + ret = SSS_SIFP_OUT_OF_MEMORY; \ + goto done; \ + } \ + \ + for (i = 0; i < attr->num_values; i++) { \ + dbus_message_iter_get_basic(iter, &val); \ + attr->data.field[i] = val; \ + \ + if (!dbus_message_iter_next(iter) && i + 1 < attr->num_values) { \ + ret = SSS_SIFP_INTERNAL_ERROR; \ + goto done; \ + } \ + } \ + \ + ret = SSS_SIFP_OK; \ +} while (0) + +static unsigned int +sss_sifp_get_array_length(DBusMessageIter *iter) +{ + DBusMessageIter array_iter; + unsigned int size; + + dbus_message_iter_recurse(iter, &array_iter); + + if (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_INVALID) { + return 0; + } + + size = 0; + do { + size++; + } while (dbus_message_iter_next(&array_iter)); + + return size; +} + +static sss_sifp_error +sss_sifp_parse_basic(sss_sifp_ctx *ctx, + DBusMessageIter *iter, + sss_sifp_attr *attr) +{ + sss_sifp_error ret; + + switch (dbus_message_iter_get_arg_type(iter)) { + case DBUS_TYPE_BOOLEAN: + parse_basic(ctx, iter, ret, SSS_SIFP_ATTR_TYPE_BOOL, + dbus_bool_t, bool, boolean, done); + break; + case DBUS_TYPE_INT16: + parse_basic(ctx, iter, ret, SSS_SIFP_ATTR_TYPE_INT16, + int16_t, int16_t, int16, done); + break; + case DBUS_TYPE_UINT16: + parse_basic(ctx, iter, ret, SSS_SIFP_ATTR_TYPE_UINT16, + uint16_t, uint16_t, uint16, done); + break; + case DBUS_TYPE_INT32: + parse_basic(ctx, iter, ret, SSS_SIFP_ATTR_TYPE_INT32, + int32_t, int32_t, int32, done); + break; + case DBUS_TYPE_UINT32: + parse_basic(ctx, iter, ret, SSS_SIFP_ATTR_TYPE_UINT32, + uint32_t, uint32_t, uint32, done); + break; + case DBUS_TYPE_INT64: + parse_basic(ctx, iter, ret, SSS_SIFP_ATTR_TYPE_INT64, + int64_t, int64_t, int64, done); + break; + case DBUS_TYPE_UINT64: + parse_basic(ctx, iter, ret, SSS_SIFP_ATTR_TYPE_UINT64, + uint64_t, uint64_t, uint64, done); + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: ; + const char *val = NULL; + + dbus_message_iter_get_basic(iter, &val); + + attr->type = SSS_SIFP_ATTR_TYPE_STRING; + attr->data.str = _alloc_zero(ctx, char*, 1); + if (attr->data.str == NULL) { \ + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + attr->data.str[0] = sss_sifp_strdup(ctx, val); + if (attr->data.str[0] == NULL) { + _free(ctx, attr->data.str); + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + attr->num_values = 1; + + ret = SSS_SIFP_OK; + break; + default: + ret = SSS_SIFP_INVALID_ARGUMENT; + break; + } + +done: + return ret; +} + +static sss_sifp_error +sss_sifp_parse_array(sss_sifp_ctx *ctx, + DBusMessageIter *iter, + sss_sifp_attr *attr) +{ + DBusMessageIter array_iter; + sss_sifp_error ret; + + attr->num_values = sss_sifp_get_array_length(iter); + dbus_message_iter_recurse(iter, &array_iter); + + switch (dbus_message_iter_get_element_type(iter)) { + case DBUS_TYPE_BOOLEAN: + parse_array(ctx, &array_iter, ret, SSS_SIFP_ATTR_TYPE_BOOL, + dbus_bool_t, bool, boolean, done); + break; + case DBUS_TYPE_INT16: + parse_array(ctx, &array_iter, ret, SSS_SIFP_ATTR_TYPE_INT16, + int16_t, int16_t, int16, done); + break; + case DBUS_TYPE_UINT16: + parse_array(ctx, &array_iter, ret, SSS_SIFP_ATTR_TYPE_UINT16, + uint16_t, uint16_t, uint16, done); + break; + case DBUS_TYPE_INT32: + parse_array(ctx, &array_iter, ret, SSS_SIFP_ATTR_TYPE_INT32, + int32_t, int32_t, int32, done); + break; + case DBUS_TYPE_UINT32: + parse_array(ctx, &array_iter, ret, SSS_SIFP_ATTR_TYPE_UINT32, + uint32_t, uint32_t, uint32, done); + break; + case DBUS_TYPE_INT64: + parse_array(ctx, &array_iter, ret, SSS_SIFP_ATTR_TYPE_INT64, + int64_t, int64_t, int64, done); + break; + case DBUS_TYPE_UINT64: + parse_array(ctx, &array_iter, ret, SSS_SIFP_ATTR_TYPE_UINT64, + uint64_t, uint64_t, uint64, done); + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: ; + const char *val; + unsigned int i; + + attr->type = SSS_SIFP_ATTR_TYPE_STRING; + if (attr->num_values == 0) { + attr->data.str = NULL; + ret = SSS_SIFP_OK; + goto done; + } + + attr->data.str = _alloc_zero(ctx, char *, attr->num_values); + if (attr->data.str == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + for (i = 0; i < attr->num_values; i++) { + dbus_message_iter_get_basic(&array_iter, &val); + attr->data.str[i] = sss_sifp_strdup(ctx, val); + if (attr->data.str[i] == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + if (!dbus_message_iter_next(&array_iter) + && i + 1 < attr->num_values) { + ret = SSS_SIFP_INTERNAL_ERROR; + goto done; + } + } + + ret = SSS_SIFP_OK; + break; + default: + ret = SSS_SIFP_INVALID_ARGUMENT; + break; + } + +done: + if (ret != SSS_SIFP_OK && attr->type == SSS_SIFP_ATTR_TYPE_STRING + && attr->data.str != NULL) { + unsigned int i; + for (i = 0; attr->data.str[i] != NULL && i < attr->num_values; i++) { + _free(ctx, attr->data.str[i]); + } + _free(ctx, attr->data.str); + } + + return ret; +} + +static sss_sifp_error +sss_sifp_parse_variant(sss_sifp_ctx *ctx, + DBusMessageIter *iter, + sss_sifp_attr *attr) +{ + DBusMessageIter variant_iter; + sss_sifp_error ret; + int type; + + check_dbus_arg(iter, DBUS_TYPE_VARIANT, ret, done); + + dbus_message_iter_recurse(iter, &variant_iter); + + type = dbus_message_iter_get_arg_type(&variant_iter); + if (dbus_type_is_basic(type)) { + ret = sss_sifp_parse_basic(ctx, &variant_iter, attr); + } else { + /* container types */ + switch (type) { + case DBUS_TYPE_ARRAY: + ret = sss_sifp_parse_array(ctx, &variant_iter, attr);; + break; + default: + ret = SSS_SIFP_NOT_SUPPORTED; + break; + } + } + +done: + return ret; +} + +/** + * DBusMessage format: + * variant:value + * + * Iterator has to point to the variant but not inside the variant. + */ +static sss_sifp_error +sss_sifp_parse_single_attr(sss_sifp_ctx *ctx, + const char *name, + DBusMessageIter *iter, + sss_sifp_attr **_attr) +{ + sss_sifp_attr *attr = NULL; + sss_sifp_error ret; + + attr = _alloc_zero(ctx, sss_sifp_attr, 1); + if (attr == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + attr->name = sss_sifp_strdup(ctx, name); + if (attr->name == NULL) { + _free(ctx, attr); + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + ret = sss_sifp_parse_variant(ctx, iter, attr); + if (ret != SSS_SIFP_OK) { + _free(ctx, attr->name); + _free(ctx, attr); + } + + *_attr = attr; + +done: + return ret; +} + +/** + * DBusMessage format: + * variant:value + */ +sss_sifp_error +sss_sifp_parse_attr(sss_sifp_ctx *ctx, + const char *name, + DBusMessage *msg, + sss_sifp_attr ***_attrs) +{ + sss_sifp_attr **attrs = NULL; + DBusMessageIter iter; + sss_sifp_error ret; + + dbus_message_iter_init(msg, &iter); + + attrs = _alloc_zero(ctx, sss_sifp_attr *, 2); + if (attrs == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + ret = sss_sifp_parse_single_attr(ctx, name, &iter, &attrs[0]); + if (ret != SSS_SIFP_OK) { + goto done; + } + + *_attrs = attrs; + + ret = SSS_SIFP_OK; + +done: + if (ret != SSS_SIFP_OK) { + sss_sifp_free_attrs(ctx, &attrs); + } + + return ret; +} + +/** + * DBusMessage format: + * array of dict_entry(string:attr_name, variant:value) + */ +sss_sifp_error +sss_sifp_parse_attr_list(sss_sifp_ctx *ctx, + DBusMessage *msg, + sss_sifp_attr ***_attrs) +{ + DBusMessageIter iter; + DBusMessageIter array_iter; + DBusMessageIter dict_iter; + sss_sifp_attr **attrs = NULL; + const char *name = NULL; + unsigned int num_values; + sss_sifp_error ret; + unsigned int i; + + dbus_message_iter_init(msg, &iter); + + check_dbus_arg(&iter, DBUS_TYPE_ARRAY, ret, done); + + if (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { + ret = SSS_SIFP_INTERNAL_ERROR; + goto done; + } + + num_values = sss_sifp_get_array_length(&iter); + attrs = _alloc_zero(ctx, sss_sifp_attr *, num_values + 1); + if (attrs == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + dbus_message_iter_recurse(&iter, &array_iter); + + for (i = 0; i < num_values; i++) { + dbus_message_iter_recurse(&array_iter, &dict_iter); + + /* get the key */ + check_dbus_arg(&dict_iter, DBUS_TYPE_STRING, ret, done); + dbus_message_iter_get_basic(&dict_iter, &name); + + if (!dbus_message_iter_next(&dict_iter)) { + ret = SSS_SIFP_INTERNAL_ERROR; + goto done; + } + + /* now read the value */ + check_dbus_arg(&dict_iter, DBUS_TYPE_VARIANT, ret, done); + + ret = sss_sifp_parse_single_attr(ctx, name, &dict_iter, &attrs[i]); + if (ret != SSS_SIFP_OK) { + goto done; + } + + dbus_message_iter_next(&array_iter); + } + + *_attrs = attrs; + ret = SSS_SIFP_OK; + +done: + if (ret != SSS_SIFP_OK) { + sss_sifp_free_attrs(ctx, &attrs); + } + + return ret; +} + +sss_sifp_error +sss_sifp_parse_object_path(sss_sifp_ctx *ctx, + DBusMessage *msg, + char **_object_path) +{ + char *object_path = NULL; + const char *dbus_path = NULL; + DBusError dbus_error; + dbus_bool_t bret; + sss_sifp_error ret; + + dbus_error_init(&dbus_error); + + bret = dbus_message_get_args(msg, &dbus_error, + DBUS_TYPE_OBJECT_PATH, &dbus_path, + DBUS_TYPE_INVALID); + if (!bret) { + sss_sifp_set_io_error(ctx, &dbus_error); + ret = SSS_SIFP_IO_ERROR; + goto done; + } + + object_path = sss_sifp_strdup(ctx, dbus_path); + if (object_path == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + *_object_path = object_path; + ret = SSS_SIFP_OK; + +done: + dbus_error_free(&dbus_error); + + return ret; +} + +sss_sifp_error +sss_sifp_parse_object_path_list(sss_sifp_ctx *ctx, + DBusMessage *msg, + char ***_object_paths) +{ + char **object_paths = NULL; + char **dbus_paths = NULL; + int num_paths; + DBusError dbus_error; + dbus_bool_t bret; + sss_sifp_error ret; + int i; + + dbus_error_init(&dbus_error); + + bret = dbus_message_get_args(msg, &dbus_error, + DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, + &dbus_paths, &num_paths, + DBUS_TYPE_INVALID); + if (!bret) { + sss_sifp_set_io_error(ctx, &dbus_error); + ret = SSS_SIFP_IO_ERROR; + goto done; + } + + object_paths = _alloc_zero(ctx, char *, num_paths + 1); + if (object_paths == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + for (i = 0; i < num_paths; i++) { + object_paths[i] = sss_sifp_strdup(ctx, dbus_paths[i]); + if (object_paths[i] == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + } + + *_object_paths = object_paths; + ret = SSS_SIFP_OK; + +done: + dbus_error_free(&dbus_error); + dbus_free_string_array(dbus_paths); + + if (ret != SSS_SIFP_OK && object_paths != NULL) { + sss_sifp_free_string_array(ctx, &object_paths); + } + + return ret; +} diff --git a/src/lib/sifp/sss_sifp_private.h b/src/lib/sifp/sss_sifp_private.h new file mode 100644 index 000000000..0f21e4a97 --- /dev/null +++ b/src/lib/sifp/sss_sifp_private.h @@ -0,0 +1,115 @@ +/* + 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 . +*/ + +#ifndef SSS_SIFP_PRIVATE_H_ +#define SSS_SIFP_PRIVATE_H_ + +#define SSS_SIFP_PATH_IFP "/org/freedesktop/sssd/infopipe" + +#include +#include "lib/sifp/sss_sifp.h" + +void *sss_sifp_alloc_zero(sss_sifp_ctx *ctx, size_t size, size_t num); + +#define _alloc_zero(ctx, type, num) sss_sifp_alloc_zero(ctx, sizeof(type), num) + +#define _free(ctx, var) \ + do { \ + ctx->free_fn((var), ctx->alloc_pvt); \ + (var) = NULL; \ + } while (0) + +struct sss_sifp_ctx { + DBusConnection *conn; + sss_sifp_alloc_func *alloc_fn; + sss_sifp_free_func *free_fn; + void *alloc_pvt; + + DBusError *io_error; +}; + +enum sss_sifp_attr_type { + SSS_SIFP_ATTR_TYPE_BOOL, + SSS_SIFP_ATTR_TYPE_INT16, + SSS_SIFP_ATTR_TYPE_UINT16, + SSS_SIFP_ATTR_TYPE_INT32, + SSS_SIFP_ATTR_TYPE_UINT32, + SSS_SIFP_ATTR_TYPE_INT64, + SSS_SIFP_ATTR_TYPE_UINT64, + SSS_SIFP_ATTR_TYPE_STRING +}; + +/** + * D-Bus object attribute + */ +struct sss_sifp_attr { + char *name; + enum sss_sifp_attr_type type; + unsigned int num_values; + union { + bool *boolean; + int16_t *int16; + uint16_t *uint16; + int32_t *int32; + uint32_t *uint32; + int64_t *int64; + uint64_t *uint64; + char **str; + } data; +}; + +void +sss_sifp_set_io_error(sss_sifp_ctx *ctx, + DBusError *error); + +const char * +sss_sifp_get_iface_for_object(const char *object_path); + +char * +sss_sifp_strdup(sss_sifp_ctx *ctx, + const char *str); + +char * +sss_sifp_strcat(sss_sifp_ctx *ctx, + const char *str1, + const char *str2); + +sss_sifp_error +sss_sifp_parse_attr(sss_sifp_ctx *ctx, + const char *name, + DBusMessage *msg, + sss_sifp_attr ***_attrs); + +sss_sifp_error +sss_sifp_parse_attr_list(sss_sifp_ctx *ctx, + DBusMessage *msg, + sss_sifp_attr ***_attrs); + +sss_sifp_error +sss_sifp_parse_object_path(sss_sifp_ctx *ctx, + DBusMessage *msg, + char **_object_path); + +sss_sifp_error +sss_sifp_parse_object_path_list(sss_sifp_ctx *ctx, + DBusMessage *msg, + char ***_object_paths); + +#endif /* SSS_SIFP_PRIVATE_H_ */ diff --git a/src/lib/sifp/sss_sifp_utils.c b/src/lib/sifp/sss_sifp_utils.c new file mode 100644 index 000000000..29cde7ef5 --- /dev/null +++ b/src/lib/sifp/sss_sifp_utils.c @@ -0,0 +1,117 @@ +/* + 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 "lib/sifp/sss_sifp.h" +#include "lib/sifp/sss_sifp_private.h" + +void *sss_sifp_alloc_zero(sss_sifp_ctx *ctx, size_t size, size_t num) +{ + void *addr = ctx->alloc_fn(size * num, ctx->alloc_pvt); + + if (addr == NULL) { + return NULL; + } + + memset(addr, '\0', size * num); + + return addr; +} + +void sss_sifp_set_io_error(sss_sifp_ctx *ctx, DBusError *error) +{ + dbus_error_free(ctx->io_error); + dbus_error_init(ctx->io_error); + dbus_set_error(ctx->io_error, error->name, error->message); +} + +const char * +sss_sifp_get_iface_for_object(const char *object_path) +{ + int i; + const char *path; + static struct { + const char *path; + const char *iface; + } known_types[] = { + {SSS_SIFP_PATH_IFP "/Components/", SSS_SIFP_IFACE_COMPONENTS}, + {SSS_SIFP_PATH_IFP "/Domains/", SSS_SIFP_IFACE_DOMAINS}, + {SSS_SIFP_PATH_IFP "/Services/", SSS_SIFP_IFACE_SERVICES}, + {SSS_SIFP_PATH_IFP "/Users/", SSS_SIFP_IFACE_USERS}, + {SSS_SIFP_PATH_IFP "/Groups/", SSS_SIFP_IFACE_GROUPS}, + {NULL, NULL} + }; + + for (i = 0; known_types[i].path != NULL; i++) { + path = known_types[i].path; + if (strncmp(path, object_path, strlen(path)) == 0) { + return known_types[i].iface; + } + } + + return NULL; +} + +char * sss_sifp_strdup(sss_sifp_ctx *ctx, const char *str) +{ + char *result = NULL; + size_t str_len; + + if (str == NULL) { + return NULL; + } + + str_len = strlen(str); + result = _alloc_zero(ctx, char, str_len + 1); + if (result == NULL) { + return NULL; + } + + strncpy(result, str, str_len); + + return result; +} + +char * sss_sifp_strcat(sss_sifp_ctx *ctx, const char *str1, const char *str2) +{ + char *result = NULL; + + if (str1 == NULL) { + return sss_sifp_strdup(ctx, str2); + } + + if (str2 == NULL) { + return sss_sifp_strdup(ctx, str1); + } + + size_t len = strlen(str1) + strlen(str2) + 1; + + result = _alloc_zero(ctx, char, len); + if (result == NULL) { + return NULL; + } + + strcat(result, str1); + strcat(result, str2); + + return result; +} -- cgit