From efa6c1f75c4c18bcc148d6e7efd429c2d56499ad Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Mon, 28 Apr 2014 10:54:12 +0200 Subject: sss_sifp: add support for string dictionary https://fedorahosted.org/sssd/ticket/2254 Reviewed-by: Sumit Bose --- src/lib/sifp/sss_sifp.c | 6 ++ src/lib/sifp/sss_sifp.h | 16 +++ src/lib/sifp/sss_sifp_attrs.c | 24 +++++ src/lib/sifp/sss_sifp_parser.c | 197 ++++++++++++++++++++++++++++++++-- src/lib/sifp/sss_sifp_private.h | 4 +- src/lib/sifp/sss_simpleifp.exports | 1 + src/tests/cmocka/test_sss_sifp.c | 211 +++++++++++++++++++++++++++++++++++++ 7 files changed, 452 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/lib/sifp/sss_sifp.c b/src/lib/sifp/sss_sifp.c index 0bf29075e..7e8e7c6d6 100644 --- a/src/lib/sifp/sss_sifp.c +++ b/src/lib/sifp/sss_sifp.c @@ -370,6 +370,12 @@ sss_sifp_free_attrs(sss_sifp_ctx *ctx, } _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]); diff --git a/src/lib/sifp/sss_sifp.h b/src/lib/sifp/sss_sifp.h index 4c6712f5f..6f897135c 100644 --- a/src/lib/sifp/sss_sifp.h +++ b/src/lib/sifp/sss_sifp.h @@ -24,6 +24,7 @@ #include #include #include +#include /** * @defgroup sss_simpleifp Simple interface to SSSD InfoPipe responder. @@ -302,6 +303,21 @@ sss_sifp_find_attr_as_string(sss_sifp_attr **attrs, const char *name, const char **_value); +/** + * @brief Find attribute in list and return its value. + * + * The dictionary is stored in dhash table, the values + * are pointers to NULL-terminated string array. + * + * @param[in] attrs Attributes + * @param[in] name Name of the attribute to find + * @param[out] _value Output value + */ +sss_sifp_error +sss_sifp_find_attr_as_string_dict(sss_sifp_attr **attrs, + const char *name, + hash_table_t **_value); + /** * @brief Find attribute in list and return its values. * diff --git a/src/lib/sifp/sss_sifp_attrs.c b/src/lib/sifp/sss_sifp_attrs.c index 8e871b2e6..6d10c4611 100644 --- a/src/lib/sifp/sss_sifp_attrs.c +++ b/src/lib/sifp/sss_sifp_attrs.c @@ -158,6 +158,30 @@ sss_sifp_find_attr_as_string(sss_sifp_attr **attrs, return SSS_SIFP_OK; } +sss_sifp_error +sss_sifp_find_attr_as_string_dict(sss_sifp_attr **attrs, + const char *name, + hash_table_t **_value) +{ + sss_sifp_attr *attr = sss_sifp_find_attr(attrs, name); + + if (attr == NULL) { + return SSS_SIFP_ATTR_MISSING; + } + + if (attr->type != SSS_SIFP_ATTR_TYPE_STRING_DICT) { + return SSS_SIFP_INCORRECT_TYPE; + } + + if (attr->data.str_dict == NULL) { + return SSS_SIFP_ATTR_NULL; + } + + *_value = attr->data.str_dict; + + return SSS_SIFP_OK; +} + /** * @brief Find attribute in list and return its values. * diff --git a/src/lib/sifp/sss_sifp_parser.c b/src/lib/sifp/sss_sifp_parser.c index 1c1ff80c8..eaa57d8d5 100644 --- a/src/lib/sifp/sss_sifp_parser.c +++ b/src/lib/sifp/sss_sifp_parser.c @@ -20,6 +20,7 @@ #include #include +#include #include "lib/sifp/sss_sifp.h" #include "lib/sifp/sss_sifp_private.h" @@ -102,6 +103,149 @@ sss_sifp_get_array_length(DBusMessageIter *iter) return size; } +static void hash_delete_cb(hash_entry_t *item, + hash_destroy_enum type, + void *pvt) +{ + sss_sifp_ctx *ctx = (sss_sifp_ctx*)pvt; + char **values = (char**)(item->value.ptr); + int i; + + if (values == NULL) { + return; + } + + for (i = 0; values[i] != NULL; i++) { + _free(ctx, values[i]); + values[i] = NULL; + } + + _free(ctx, values); + item->value.ptr = NULL; +} + +static sss_sifp_error +sss_sifp_parse_dict(sss_sifp_ctx *ctx, + DBusMessageIter *iter, + hash_table_t *table) +{ + DBusMessageIter dict_iter; + DBusMessageIter array_iter; + sss_sifp_error ret; + hash_key_t table_key; + hash_value_t table_value; + const char *key = NULL; + const char *value = NULL; + char **values = NULL; + unsigned int i; + unsigned int num_values; + int hret; + + dbus_message_iter_recurse(iter, &dict_iter); + + /* get the key */ + check_dbus_arg(&dict_iter, DBUS_TYPE_STRING, ret, done); + dbus_message_iter_get_basic(&dict_iter, &key); + + table_key.type = HASH_KEY_STRING; + table_key.str = sss_sifp_strdup(ctx, key); + if (table_key.str == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + if (!dbus_message_iter_next(&dict_iter)) { + ret = SSS_SIFP_INTERNAL_ERROR; + goto done; + } + + /* now read the value */ + switch (dbus_message_iter_get_arg_type(&dict_iter)) { + case DBUS_TYPE_STRING: + dbus_message_iter_get_basic(&dict_iter, &value); + values = _alloc_zero(ctx, char *, 2); + if (values == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + values[0] = sss_sifp_strdup(ctx, value); + if (values[0] == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + values[1] = NULL; + + ret = SSS_SIFP_OK; + break; + case DBUS_TYPE_ARRAY: + num_values = sss_sifp_get_array_length(&dict_iter); + if (num_values == 0) { + values = NULL; + ret = SSS_SIFP_OK; + goto done; + } + + if (dbus_message_iter_get_element_type(&dict_iter) + != DBUS_TYPE_STRING) { + ret = SSS_SIFP_NOT_SUPPORTED; + goto done; + } + + dbus_message_iter_recurse(&dict_iter, &array_iter); + + values = _alloc_zero(ctx, char*, num_values + 1); + if (values == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + for (i = 0; i < num_values; i++) { + dbus_message_iter_get_basic(&array_iter, &value); + values[i] = sss_sifp_strdup(ctx, value); + if (values[i] == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + dbus_message_iter_next(&array_iter); + } + + ret = SSS_SIFP_OK; + break; + default: + ret = SSS_SIFP_NOT_SUPPORTED; + break; + } + + table_value.type = HASH_VALUE_PTR; + table_value.ptr = values; + + hret = hash_enter(table, &table_key, &table_value); + if (hret == HASH_ERROR_NO_MEMORY) { + ret = SSS_SIFP_OUT_OF_MEMORY; + } else if (hret != HASH_SUCCESS) { + ret = SSS_SIFP_INTERNAL_ERROR; + } + +done: + if (table_key.str != NULL) { + _free(ctx, table_key.str); + } + + if (ret != SSS_SIFP_OK) { + if (values != NULL) { + for (i = 0; values[i] != NULL; i++) { + _free(ctx, values[i]); + } + _free(ctx, values); + } + } + + return ret; +} + static sss_sifp_error sss_sifp_parse_basic(sss_sifp_ctx *ctx, DBusMessageIter *iter, @@ -178,6 +322,7 @@ sss_sifp_parse_array(sss_sifp_ctx *ctx, { DBusMessageIter array_iter; sss_sifp_error ret; + int hret; attr->num_values = sss_sifp_get_array_length(iter); dbus_message_iter_recurse(iter, &array_iter); @@ -244,6 +389,38 @@ sss_sifp_parse_array(sss_sifp_ctx *ctx, } } + ret = SSS_SIFP_OK; + break; + case DBUS_TYPE_DICT_ENTRY: + attr->type = SSS_SIFP_ATTR_TYPE_STRING_DICT; + if (attr->num_values == 0) { + attr->data.str_dict = NULL; + ret = SSS_SIFP_OK; + goto done; + } + + hret = hash_create_ex(10, &(attr->data.str_dict), 0, 0, 0, 0, + ctx->alloc_fn, ctx->free_fn, ctx->alloc_pvt, + hash_delete_cb, ctx); + if (hret != HASH_SUCCESS) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + for (i = 0; i < attr->num_values; i++) { + ret = sss_sifp_parse_dict(ctx, &array_iter, attr->data.str_dict); + if (ret != SSS_SIFP_OK) { + _free(ctx, attr->data.str_dict); + 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: @@ -252,13 +429,19 @@ sss_sifp_parse_array(sss_sifp_ctx *ctx, } 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]); + if (ret != SSS_SIFP_OK) { + if (attr->type == SSS_SIFP_ATTR_TYPE_STRING && attr->data.str != NULL) { + for (unsigned int i = 0; + attr->data.str[i] != NULL && i < attr->num_values; + i++) { + _free(ctx, attr->data.str[i]); + } + _free(ctx, attr->data.str); + } else if (attr->type == SSS_SIFP_ATTR_TYPE_STRING_DICT + && attr->data.str_dict != NULL) { + hash_destroy(attr->data.str_dict); + attr->data.str_dict = NULL; } - _free(ctx, attr->data.str); } return ret; @@ -283,6 +466,8 @@ sss_sifp_parse_variant(sss_sifp_ctx *ctx, } else { /* container types */ switch (type) { + /* case DBUS_TYPE_DICT_ENTRY may only be contained within an array + * in variant */ case DBUS_TYPE_ARRAY: ret = sss_sifp_parse_array(ctx, &variant_iter, attr);; break; diff --git a/src/lib/sifp/sss_sifp_private.h b/src/lib/sifp/sss_sifp_private.h index 0f21e4a97..b42d05146 100644 --- a/src/lib/sifp/sss_sifp_private.h +++ b/src/lib/sifp/sss_sifp_private.h @@ -53,7 +53,8 @@ enum sss_sifp_attr_type { SSS_SIFP_ATTR_TYPE_UINT32, SSS_SIFP_ATTR_TYPE_INT64, SSS_SIFP_ATTR_TYPE_UINT64, - SSS_SIFP_ATTR_TYPE_STRING + SSS_SIFP_ATTR_TYPE_STRING, + SSS_SIFP_ATTR_TYPE_STRING_DICT }; /** @@ -72,6 +73,7 @@ struct sss_sifp_attr { int64_t *int64; uint64_t *uint64; char **str; + hash_table_t *str_dict; } data; }; diff --git a/src/lib/sifp/sss_simpleifp.exports b/src/lib/sifp/sss_simpleifp.exports index 168d08fdd..921b49d58 100644 --- a/src/lib/sifp/sss_simpleifp.exports +++ b/src/lib/sifp/sss_simpleifp.exports @@ -23,6 +23,7 @@ SSS_SIMPLEIFP_0.0 { sss_sifp_find_attr_as_int64; sss_sifp_find_attr_as_uint64; sss_sifp_find_attr_as_string; + sss_sifp_find_attr_as_string_dict; sss_sifp_find_attr_as_bool_array; sss_sifp_find_attr_as_int16_array; sss_sifp_find_attr_as_uint16_array; diff --git a/src/tests/cmocka/test_sss_sifp.c b/src/tests/cmocka/test_sss_sifp.c index cddc1ab1b..4a5fd7265 100644 --- a/src/tests/cmocka/test_sss_sifp.c +++ b/src/tests/cmocka/test_sss_sifp.c @@ -595,6 +595,99 @@ void test_sss_sifp_parse_attr_object_path(void **state) assert_null(attrs); } +void test_sss_sifp_parse_attr_string_dict(void **state) +{ + sss_sifp_ctx *ctx = test_ctx.dbus_ctx; + DBusMessage *reply = test_ctx.reply; + DBusMessageIter iter; + DBusMessageIter var_iter; + DBusMessageIter array_iter; + DBusMessageIter dict_iter; + dbus_bool_t bret; + sss_sifp_error ret; + sss_sifp_attr **attrs = NULL; + const char *name = "test-attr"; + struct { + const char *key; + const char *value; + } data = {"key", "value"}; + hash_table_t *out; + hash_key_t key; + hash_value_t value; + char **values; + int hret; + + /* prepare message */ + dbus_message_iter_init_append(reply, &iter); + + bret = dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &var_iter); + assert_true(bret); + + bret = dbus_message_iter_open_container(&var_iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &array_iter); + assert_true(bret); + + bret = dbus_message_iter_open_container(&array_iter, + DBUS_TYPE_DICT_ENTRY, + NULL, &dict_iter); + assert_true(bret); + + bret = dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, + &data.key); + assert_true(bret); + + bret = dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, + &data.value); + assert_true(bret); + + bret = dbus_message_iter_close_container(&array_iter, &dict_iter); + assert_true(bret); + + bret = dbus_message_iter_close_container(&var_iter, &array_iter); + assert_true(bret); + + bret = dbus_message_iter_close_container(&iter, &var_iter); + assert_true(bret); + + ret = sss_sifp_parse_attr(ctx, name, reply, &attrs); + assert_int_equal(ret, SSS_SIFP_OK); + assert_non_null(attrs); + assert_non_null(attrs[0]); + assert_null(attrs[1]); + + assert_int_equal(attrs[0]->num_values, 1); + assert_int_equal(attrs[0]->type, SSS_SIFP_ATTR_TYPE_STRING_DICT); + assert_string_equal(attrs[0]->name, name); + + ret = sss_sifp_find_attr_as_string_dict(attrs, name, &out); + assert_int_equal(ret, SSS_SIFP_OK); + assert_int_equal(hash_count(out), 1); + + key.type = HASH_KEY_STRING; + key.str = discard_const(data.key); + hret = hash_lookup(out, &key, &value); + assert_int_equal(hret, HASH_SUCCESS); + assert_int_equal(value.type, HASH_VALUE_PTR); + assert_non_null(value.ptr); + values = value.ptr; + assert_non_null(values[0]); + assert_string_equal(values[0], data.value); + assert_null(values[1]); + + sss_sifp_free_attrs(ctx, &attrs); + assert_null(attrs); +} + void test_sss_sifp_parse_attr_bool_array(void **state) { sss_sifp_ctx *ctx = test_ctx.dbus_ctx; @@ -973,6 +1066,120 @@ void test_sss_sifp_parse_attr_object_path_array(void **state) assert_null(attrs); } +void test_sss_sifp_parse_attr_string_dict_array(void **state) +{ + return; + + sss_sifp_ctx *ctx = test_ctx.dbus_ctx; + DBusMessage *reply = test_ctx.reply; + DBusMessageIter iter; + DBusMessageIter var_iter; + DBusMessageIter array_iter; + DBusMessageIter dict_iter; + DBusMessageIter val_iter; + dbus_bool_t bret; + sss_sifp_error ret; + sss_sifp_attr **attrs = NULL; + const char *name = "test-attr"; + static struct { + const char *key; + const char *values[]; + } data = {"key", {"value1", "value2", "value3"}}; + unsigned int num_values = 3; + hash_table_t *out; + hash_key_t key; + hash_value_t value; + char **values; + unsigned int i; + int hret; + + /* prepare message */ + dbus_message_iter_init_append(reply, &iter); + + bret = dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + 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, + &var_iter); + assert_true(bret); + + bret = dbus_message_iter_open_container(&var_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, + &array_iter); + assert_true(bret); + + bret = dbus_message_iter_open_container(&array_iter, + DBUS_TYPE_DICT_ENTRY, + NULL, &dict_iter); + assert_true(bret); + + bret = dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, + &data.key); + assert_true(bret); + + bret = dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + &val_iter); + assert_true(bret); + + for (i = 0; i < num_values; i++) { + bret = dbus_message_iter_append_basic(&val_iter, DBUS_TYPE_STRING, + &data.values[i]); + assert_true(bret); + } + + bret = dbus_message_iter_close_container(&dict_iter, &val_iter); + assert_true(bret); + + bret = dbus_message_iter_close_container(&array_iter, &dict_iter); + assert_true(bret); + + bret = dbus_message_iter_close_container(&var_iter, &array_iter); + assert_true(bret); + + bret = dbus_message_iter_close_container(&iter, &var_iter); + assert_true(bret); + + ret = sss_sifp_parse_attr(ctx, name, reply, &attrs); + assert_int_equal(ret, SSS_SIFP_OK); + assert_non_null(attrs); + assert_non_null(attrs[0]); + assert_null(attrs[1]); + + assert_int_equal(attrs[0]->num_values, 1); + assert_int_equal(attrs[0]->type, SSS_SIFP_ATTR_TYPE_STRING_DICT); + assert_string_equal(attrs[0]->name, name); + + ret = sss_sifp_find_attr_as_string_dict(attrs, name, &out); + assert_int_equal(ret, SSS_SIFP_OK); + assert_int_equal(hash_count(out), 1); + + key.type = HASH_KEY_STRING; + key.str = discard_const(data.key); + hret = hash_lookup(out, &key, &value); + assert_int_equal(hret, HASH_SUCCESS); + assert_int_equal(value.type, HASH_VALUE_PTR); + assert_non_null(value.ptr); + values = value.ptr; + + for (i = 0; i < num_values; i++) { + assert_non_null(values[i]); + assert_string_equal(values[i], data.values[i]); + } + assert_null(values[i]); + + + sss_sifp_free_attrs(ctx, &attrs); + assert_null(attrs); +} + void test_sss_sifp_parse_attr_list(void **state) { sss_sifp_ctx *ctx = test_ctx.dbus_ctx; @@ -1494,6 +1701,8 @@ int main(int argc, const char *argv[]) test_setup, test_teardown_parser), unit_test_setup_teardown(test_sss_sifp_parse_attr_object_path, test_setup, test_teardown_parser), + unit_test_setup_teardown(test_sss_sifp_parse_attr_string_dict, + test_setup, test_teardown_parser), unit_test_setup_teardown(test_sss_sifp_parse_attr_bool_array, test_setup, test_teardown_parser), unit_test_setup_teardown(test_sss_sifp_parse_attr_int32_array, @@ -1508,6 +1717,8 @@ int main(int argc, const char *argv[]) test_setup, test_teardown_parser), unit_test_setup_teardown(test_sss_sifp_parse_attr_object_path_array, test_setup, test_teardown_parser), + unit_test_setup_teardown(test_sss_sifp_parse_attr_string_dict_array, + test_setup, test_teardown_parser), unit_test_setup_teardown(test_sss_sifp_parse_attr_list, test_setup, test_teardown_parser), unit_test_setup_teardown(test_sss_sifp_parse_attr_list_empty, -- cgit