diff options
Diffstat (limited to 'src/lib/sifp/sss_sifp_parser.c')
-rw-r--r-- | src/lib/sifp/sss_sifp_parser.c | 536 |
1 files changed, 536 insertions, 0 deletions
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 <pbrezina@redhat.com> + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include <dbus/dbus.h> +#include <string.h> + +#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; +} |