From 0bb98b7700b1b61f5b0a20b93279d5c2c391007f Mon Sep 17 00:00:00 2001 From: Pavel Březina Date: Fri, 21 Mar 2014 13:12:37 +0100 Subject: sss_sifp: add shortcuts for common use cases https://fedorahosted.org/sssd/ticket/2254 Reviewed-by: Sumit Bose --- src/lib/sifp/sss_sifp.h | 56 ++++++++++++ src/lib/sifp/sss_sifp_common.c | 178 +++++++++++++++++++++++++++++++++++++ src/lib/sifp/sss_simpleifp.exports | 4 + src/tests/cmocka/test_sss_sifp.c | 168 ++++++++++++++++++++++++++++++++++ 4 files changed, 406 insertions(+) create mode 100644 src/lib/sifp/sss_sifp_common.c (limited to 'src') diff --git a/src/lib/sifp/sss_sifp.h b/src/lib/sifp/sss_sifp.h index 6f897135c..6b997951b 100644 --- a/src/lib/sifp/sss_sifp.h +++ b/src/lib/sifp/sss_sifp.h @@ -481,4 +481,60 @@ sss_sifp_free_string_array(sss_sifp_ctx *ctx, /** * @} */ + +/** + * @defgroup common Most common use cases of SSSD InfoPipe responder. + * @{ + */ + +/** + * @brief List names of available domains. + * + * @param[in] ctx sss_sifp context + * @param[out] _domains List of domain names + */ +sss_sifp_error +sss_sifp_list_domains(sss_sifp_ctx *ctx, + char ***_domains); + +/** + * @brief Fetch all information about domain by name. + * + * @param[in] ctx sss_sifp context + * @param[in] name Domain name + * @param[out] _domain Domain object + */ +sss_sifp_error +sss_sifp_fetch_domain_by_name(sss_sifp_ctx *ctx, + const char *name, + sss_sifp_object **_domain); + +/** + * @brief Fetch all information about user by uid. + * + * @param[in] ctx sss_sifp context + * @param[in] uid User ID + * @param[out] _user User object + */ +sss_sifp_error +sss_sifp_fetch_user_by_uid(sss_sifp_ctx *ctx, + uid_t uid, + sss_sifp_object **_user); + +/** + * @brief Fetch all information about user by name. + * + * @param[in] ctx sss_sifp context + * @param[in] name User name + * @param[out] _user User object + */ +sss_sifp_error +sss_sifp_fetch_user_by_name(sss_sifp_ctx *ctx, + const char *name, + sss_sifp_object **_user); + +/** + * @} + */ + #endif /* SSS_SIFP_H_ */ diff --git a/src/lib/sifp/sss_sifp_common.c b/src/lib/sifp/sss_sifp_common.c new file mode 100644 index 000000000..2acd6c5a5 --- /dev/null +++ b/src/lib/sifp/sss_sifp_common.c @@ -0,0 +1,178 @@ +/* + 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_dbus.h" +#include "lib/sifp/sss_sifp_private.h" + +#define SSS_SIFP_ATTR_NAME "name" + +static sss_sifp_error +sss_sifp_fetch_object_by_attr(sss_sifp_ctx *ctx, + const char *method, + int attr_type, + const void *attr, + sss_sifp_object **_object) +{ + sss_sifp_object *object = NULL; + char *object_path = NULL; + const char *interface = NULL; + sss_sifp_error ret; + + if (method == NULL || attr == NULL || attr_type == DBUS_TYPE_INVALID) { + return SSS_SIFP_INVALID_ARGUMENT; + } + + ret = sss_sifp_invoke_find(ctx, method, &object_path, + attr_type, attr, + DBUS_TYPE_INVALID); + if (ret != SSS_SIFP_OK) { + goto done; + } + + interface = sss_sifp_get_iface_for_object(object_path); + if (interface == NULL) { + return SSS_SIFP_INTERNAL_ERROR; + } + + ret = sss_sifp_fetch_object(ctx, object_path, interface, &object); + if (ret != SSS_SIFP_OK) { + goto done; + } + + *_object = object; + + ret = SSS_SIFP_OK; + +done: + sss_sifp_free_string(ctx, &object_path); + + return ret; +} + +static sss_sifp_error +sss_sifp_fetch_object_by_name(sss_sifp_ctx *ctx, + const char *method, + const char *name, + sss_sifp_object **_object) +{ + return sss_sifp_fetch_object_by_attr(ctx, method, DBUS_TYPE_STRING, &name, + _object); +} + +sss_sifp_error +sss_sifp_list_domains(sss_sifp_ctx *ctx, + char ***_domains) +{ + sss_sifp_attr **attrs = NULL; + char **object_paths = NULL; + char **domains = NULL; + const char *name = NULL; + unsigned int size; + unsigned int i; + sss_sifp_error ret; + + if (_domains == NULL) { + return SSS_SIFP_INVALID_ARGUMENT; + } + + ret = sss_sifp_invoke_list(ctx, "Domains", &object_paths, + DBUS_TYPE_INVALID); + if (ret != SSS_SIFP_OK) { + goto done; + } + + /* calculate number of paths acquired and allocate memory for domains */ + for (size = 0; object_paths[size] != NULL; size++); + + domains = _alloc_zero(ctx, char *, size + 1); + if (domains == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + /* fetch domain name */ + for (i = 0; i < size; i++) { + ret = sss_sifp_fetch_attr(ctx, object_paths[i], + SSS_SIFP_IFACE_DOMAINS, + SSS_SIFP_ATTR_NAME, &attrs); + if (ret != SSS_SIFP_OK) { + goto done; + } + + ret = sss_sifp_find_attr_as_string(attrs, SSS_SIFP_ATTR_NAME, &name); + if (ret != SSS_SIFP_OK) { + goto done; + } + + domains[i] = sss_sifp_strdup(ctx, name); + if (domains[i] == NULL) { + ret = SSS_SIFP_OUT_OF_MEMORY; + goto done; + } + + sss_sifp_free_attrs(ctx, &attrs); + } + + domains[i] = NULL; + + *_domains = domains; + + ret = SSS_SIFP_OK; + +done: + sss_sifp_free_attrs(ctx, &attrs); + sss_sifp_free_string_array(ctx, &object_paths); + + if (ret != SSS_SIFP_OK) { + sss_sifp_free_string_array(ctx, &domains); + } + + return ret; +} + +sss_sifp_error +sss_sifp_fetch_domain_by_name(sss_sifp_ctx *ctx, + const char *name, + sss_sifp_object **_domain) +{ + return sss_sifp_fetch_object_by_name(ctx, "DomainByName", name, _domain); +} + +sss_sifp_error +sss_sifp_fetch_user_by_uid(sss_sifp_ctx *ctx, + uid_t uid, + sss_sifp_object **_user) +{ + uint64_t _uid = uid; + + return sss_sifp_fetch_object_by_attr(ctx, "UserByID", + DBUS_TYPE_UINT64, &_uid, _user); +} + +sss_sifp_error +sss_sifp_fetch_user_by_name(sss_sifp_ctx *ctx, + const char *name, + sss_sifp_object **_user) +{ + return sss_sifp_fetch_object_by_name(ctx, "UserByName", name, _user); +} diff --git a/src/lib/sifp/sss_simpleifp.exports b/src/lib/sifp/sss_simpleifp.exports index 921b49d58..3d598fb28 100644 --- a/src/lib/sifp/sss_simpleifp.exports +++ b/src/lib/sifp/sss_simpleifp.exports @@ -37,6 +37,10 @@ SSS_SIMPLEIFP_0.0 { sss_sifp_free_object; sss_sifp_free_string; sss_sifp_free_string_array; + sss_sifp_list_domains; + sss_sifp_fetch_domain_by_name; + sss_sifp_fetch_user_by_uid; + sss_sifp_fetch_user_by_name; # everything else is local local: diff --git a/src/tests/cmocka/test_sss_sifp.c b/src/tests/cmocka/test_sss_sifp.c index 4a5fd7265..190dd7629 100644 --- a/src/tests/cmocka/test_sss_sifp.c +++ b/src/tests/cmocka/test_sss_sifp.c @@ -1648,6 +1648,170 @@ void test_sss_sifp_invoke_find_withargs(void **state) assert_null(path_out); } +void test_sss_sifp_list_domains(void **state) +{ + sss_sifp_ctx *ctx = test_ctx.dbus_ctx; + DBusMessage *msg_paths = NULL; + DBusMessage *msg_ldap = NULL; + DBusMessage *msg_ipa = NULL; + dbus_bool_t bret; + sss_sifp_error ret; + const char *in[] = {SSS_SIFP_PATH_IFP "/Domains/LDAP", + SSS_SIFP_PATH_IFP "/Domains/IPA"}; + const char **paths = in; + const char *names[] = {"LDAP", "IPA"}; + char **out = NULL; + int in_len = 2; + int i; + + msg_paths = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); + assert_non_null(msg_paths); + + msg_ldap = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); + assert_non_null(msg_ldap); + + msg_ipa = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); + assert_non_null(msg_ipa); + + /* prepare message */ + bret = dbus_message_append_args(msg_paths, DBUS_TYPE_ARRAY, + DBUS_TYPE_OBJECT_PATH, + &paths, in_len, + DBUS_TYPE_INVALID); + assert_true(bret); + + reply_variant_basic(msg_ldap, DBUS_TYPE_STRING_AS_STRING, &names[0]); + reply_variant_basic(msg_ipa, DBUS_TYPE_STRING_AS_STRING, &names[1]); + + will_return(__wrap_dbus_connection_send_with_reply_and_block, msg_paths); + will_return(__wrap_dbus_connection_send_with_reply_and_block, msg_ldap); + will_return(__wrap_dbus_connection_send_with_reply_and_block, msg_ipa); + + /* test */ + ret = sss_sifp_list_domains(ctx, &out); + assert_int_equal(ret, SSS_SIFP_OK); + assert_non_null(out); + + for (i = 0; i < in_len; i++) { + assert_non_null(out[i]); + assert_string_equal(out[i], names[i]); + } + + assert_null(out[i]); + + sss_sifp_free_string_array(ctx, &out); + assert_null(out); + + /* messages are unrefed in the library */ +} + +void test_sss_sifp_fetch_domain_by_name(void **state) +{ + sss_sifp_ctx *ctx = test_ctx.dbus_ctx; + DBusMessage *msg_path = NULL; + DBusMessage *msg_props = NULL; + DBusMessageIter iter; + DBusMessageIter array_iter; + DBusMessageIter dict_iter; + DBusMessageIter var_iter; + dbus_bool_t bret; + sss_sifp_error ret; + const char *in =SSS_SIFP_PATH_IFP "/Domains/LDAP"; + const char *name = "LDAP"; + const char *prop = NULL; + sss_sifp_object *out = NULL; + struct { + const char *name; + const char *value; + } props[] = {{"name", name}, {"a1", "a"}, {"a2", "b"}, {NULL, 0}}; + int i; + + + msg_path = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); + assert_non_null(msg_path); + + msg_props = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); + assert_non_null(msg_props); + + /* prepare message */ + bret = dbus_message_append_args(msg_path, DBUS_TYPE_OBJECT_PATH, &in, + DBUS_TYPE_INVALID); + assert_true(bret); + + dbus_message_iter_init_append(msg_props, &iter); + + bret = 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_iter); + assert_true(bret); + + for (i = 0; props[i].name != NULL; i++) { + 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, + &props[i].name); + assert_true(bret); + + bret = dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_VARIANT, + DBUS_TYPE_STRING_AS_STRING, + &var_iter); + assert_true(bret); + + bret = dbus_message_iter_append_basic(&var_iter, DBUS_TYPE_STRING, + &props[i].value); + assert_true(bret); + + bret = dbus_message_iter_close_container(&dict_iter, &var_iter); + assert_true(bret); + + bret = dbus_message_iter_close_container(&array_iter, &dict_iter); + assert_true(bret); + } + + bret = dbus_message_iter_close_container(&iter, &array_iter); + assert_true(bret); + + will_return(__wrap_dbus_connection_send_with_reply_and_block, msg_path); + will_return(__wrap_dbus_connection_send_with_reply_and_block, msg_props); + + /* test */ + ret = sss_sifp_fetch_domain_by_name(ctx, name, &out); + assert_int_equal(ret, SSS_SIFP_OK); + assert_non_null(out); + assert_non_null(out->attrs); + assert_non_null(out->name); + assert_non_null(out->object_path); + assert_non_null(out->interface); + + assert_string_equal(out->name, name); + assert_string_equal(out->object_path, in); + assert_string_equal(out->interface, SSS_SIFP_IFACE_DOMAINS); + + for (i = 0; props[i].name != NULL; i++) { + assert_non_null(out->attrs[i]); + assert_int_equal(out->attrs[i]->num_values, 1); + assert_int_equal(out->attrs[i]->type, SSS_SIFP_ATTR_TYPE_STRING); + assert_string_equal(out->attrs[i]->name, props[i].name); + + ret = sss_sifp_find_attr_as_string(out->attrs, props[i].name, &prop); + assert_int_equal(ret, SSS_SIFP_OK); + assert_string_equal(props[i].value, prop); + } + + assert_null(out->attrs[i]); + + sss_sifp_free_object(ctx, &out); + assert_null(out); + + /* messages are unrefed in the library */ +} + int main(int argc, const char *argv[]) { int rv; @@ -1738,6 +1902,10 @@ int main(int argc, const char *argv[]) test_setup, test_teardown_api), unit_test_setup_teardown(test_sss_sifp_invoke_find_withargs, test_setup, test_teardown_api), + unit_test_setup_teardown(test_sss_sifp_list_domains, + test_setup, test_teardown_api), + unit_test_setup_teardown(test_sss_sifp_fetch_domain_by_name, + test_setup, test_teardown_api), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ -- cgit