>From ec775ea676ac3cae20d75a33c9b9edff88020121 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 6 Jan 2014 15:27:44 +0100 Subject: [PATCH 6/9] IFP: Add utility functions Adds a number of utility functions, most importanly ifp_req_create(). The ifp_req is a structure that will be passed along with the ifp request and would provide easy access to both the sbus_request data and per-responder data, like the ifp_ctx. Also includes a utility function to split a path prefix from a full path and add a ldb_element into a dictionary. These will be reused later. --- Makefile.am | 23 ++++- src/responder/ifp/ifp_private.h | 14 +++ src/responder/ifp/ifpsrv_util.c | 135 ++++++++++++++++++++++++++ src/tests/cmocka/test_ifp.c | 210 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 src/responder/ifp/ifpsrv_util.c create mode 100644 src/tests/cmocka/test_ifp.c diff --git a/Makefile.am b/Makefile.am index 56d8e1df648822a1fe8b3ca5fc8995f3c78a8566..785e8479c99a7b48b26b12b62010467d8926c06e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -176,7 +176,12 @@ if HAVE_CMOCKA dp_opt_tests \ responder-get-domains-tests \ test_search_bases -endif + +if BUILD_IFP +non_interactive_cmocka_based_tests += ifp_tests +endif # BUILD_IFP + +endif # HAVE_CMOCKA check_PROGRAMS = \ stress-tests \ @@ -818,6 +823,7 @@ sssd_ifp_SOURCES = \ src/responder/ifp/ifpsrv_cmd.c \ src/responder/ifp/ifp_iface_generated.c \ src/responder/ifp/ifp_iface_generated.h \ + src/responder/ifp/ifpsrv_util.c \ $(SSSD_UTIL_OBJ) \ $(SSSD_RESPONDER_OBJ) sssd_ifp_CFLAGS = \ @@ -1676,8 +1682,23 @@ dp_opt_tests_LDADD = \ $(SSSD_INTERNAL_LTLIBS) \ libsss_test_common.la +if BUILD_IFP +ifp_tests_SOURCES = \ + $(TEST_MOCK_RESP_OBJ) \ + src/tests/cmocka/test_ifp.c \ + src/responder/ifp/ifpsrv_cmd.c \ + src/responder/ifp/ifpsrv_util.c +ifp_tests_CFLAGS = \ + $(AM_CFLAGS) +ifp_tests_LDADD = \ + $(CMOCKA_LIBS) \ + $(SSSD_LIBS) \ + $(SSSD_INTERNAL_LTLIBS) \ + libsss_test_common.la endif +endif # HAVE_CMOCKA + noinst_PROGRAMS = pam_test_client if BUILD_SUDO noinst_PROGRAMS += sss_sudo_cli diff --git a/src/responder/ifp/ifp_private.h b/src/responder/ifp/ifp_private.h index b97cb8a7d9e55f550a3eda0e9acc034329d4ba17..472d10441bf2c6f8b89d9b459cdca116cdb2a2b6 100644 --- a/src/responder/ifp/ifp_private.h +++ b/src/responder/ifp/ifp_private.h @@ -46,4 +46,18 @@ struct ifp_ctx { * It will be removed later */ int ifp_ping(struct sbus_request *dbus_req, void *data); +/* == Utility functions == */ +struct ifp_req { + struct sbus_request *dbus_req; + struct ifp_ctx *ifp_ctx; +}; + +errno_t ifp_req_create(struct sbus_request *dbus_req, + struct ifp_ctx *ifp_ctx, + struct ifp_req **_ifp_req); + +const char *ifp_path_strip_prefix(const char *path, const char *prefix); +errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict, + struct ldb_message_element *el); + #endif /* _IFPSRV_PRIVATE_H_ */ diff --git a/src/responder/ifp/ifpsrv_util.c b/src/responder/ifp/ifpsrv_util.c new file mode 100644 index 0000000000000000000000000000000000000000..e16d36279d0b156ee00ba03eded14e36881b3903 --- /dev/null +++ b/src/responder/ifp/ifpsrv_util.c @@ -0,0 +1,135 @@ +/* + Authors: + Jakub Hrozek + Stephen Gallagher + + Copyright (C) 2013 Red Hat + + InfoPipe responder: Utility functions + + 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 "db/sysdb.h" +#include "responder/ifp/ifp_private.h" + +errno_t ifp_req_create(struct sbus_request *dbus_req, + struct ifp_ctx *ifp_ctx, + struct ifp_req **_ifp_req) +{ + struct ifp_req *ireq = NULL; + + if (ifp_ctx->sysbus == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Responder not connected to sysbus!\n"); + return EINVAL; + } + + ireq = talloc_zero(dbus_req, struct ifp_req); + if (ireq == NULL) { + return ENOMEM; + } + + ireq->ifp_ctx = ifp_ctx; + ireq->dbus_req = dbus_req; + + *_ifp_req = ireq; + return EOK; +} + +const char *ifp_path_strip_prefix(const char *path, const char *prefix) +{ + if (strncmp(path, prefix, strlen(prefix)) == 0) { + return path + strlen(prefix); + } + + return NULL; +} + +errno_t ifp_add_ldb_el_to_dict(DBusMessageIter *iter_dict, + struct ldb_message_element *el) +{ + DBusMessageIter iter_dict_entry; + DBusMessageIter iter_dict_val; + DBusMessageIter iter_array; + dbus_bool_t dbret; + unsigned int i; + + if (el == NULL) { + return EINVAL; + } + + dbret = dbus_message_iter_open_container(iter_dict, + DBUS_TYPE_DICT_ENTRY, NULL, + &iter_dict_entry); + if (!dbret) { + return ENOMEM; + } + + /* Start by appending the key */ + dbret = dbus_message_iter_append_basic(&iter_dict_entry, + DBUS_TYPE_STRING, &(el->name)); + if (!dbret) { + return ENOMEM; + } + + dbret = dbus_message_iter_open_container(&iter_dict_entry, + DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_STRING_AS_STRING, + &iter_dict_val); + if (!dbret) { + return ENOMEM; + } + + /* Open container for values */ + dbret = dbus_message_iter_open_container(&iter_dict_val, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, + &iter_array); + if (!dbret) { + return ENOMEM; + } + + /* Now add all the values */ + for (i = 0; i < el->num_values; i++) { + DEBUG(SSSDBG_TRACE_FUNC, "element [%s] has value [%s]\n", + el->name, (const char *) el->values[i].data); + + dbret = dbus_message_iter_append_basic(&iter_array, + DBUS_TYPE_STRING, + &(el->values[i].data)); + if (!dbret) { + return ENOMEM; + } + } + + dbret = dbus_message_iter_close_container(&iter_dict_val, + &iter_array); + if (!dbret) { + return ENOMEM; + } + + dbret = dbus_message_iter_close_container(&iter_dict_entry, + &iter_dict_val); + if (!dbret) { + return ENOMEM; + } + + dbret = dbus_message_iter_close_container(iter_dict, + &iter_dict_entry); + if (!dbret) { + return ENOMEM; + } + + return EOK; +} diff --git a/src/tests/cmocka/test_ifp.c b/src/tests/cmocka/test_ifp.c new file mode 100644 index 0000000000000000000000000000000000000000..161f8ffe4732a3dc0ca0ef675760e3fe001fbf05 --- /dev/null +++ b/src/tests/cmocka/test_ifp.c @@ -0,0 +1,210 @@ +/* + Authors: + Jakub Hrozek + + Copyright (C) 2013 Red Hat + + SSSD tests: InfoPipe responder + + 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 "db/sysdb.h" +#include "tests/cmocka/common_mock.h" +#include "responder/ifp/ifp_private.h" +#include "sbus/sssd_dbus_private.h" + +static struct ifp_ctx * +mock_ifp_ctx(TALLOC_CTX *mem_ctx) +{ + struct ifp_ctx *ifp_ctx; + + ifp_ctx = talloc_zero(mem_ctx, struct ifp_ctx); + assert_non_null(ifp_ctx); + + ifp_ctx->sysbus = talloc_zero(ifp_ctx, struct sysbus_ctx); + assert_non_null(ifp_ctx->sysbus); + + ifp_ctx->sysbus->conn = talloc_zero(ifp_ctx, struct sbus_connection); + assert_non_null(ifp_ctx->sysbus->conn); + + return ifp_ctx; +} + +static struct sbus_request * +mock_sbus_request(TALLOC_CTX *mem_ctx) +{ + struct sbus_request *sr; + + sr = talloc_zero(mem_ctx, struct sbus_request); + assert_non_null(sr); + + sr->conn = talloc_zero(sr, struct sbus_connection); + assert_non_null(sr->conn); + + sr->message = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL); + assert_non_null(sr->message); + dbus_message_set_serial(sr->message, 1); + + return sr; +} + +void ifp_test_req_create(void **state) +{ + struct ifp_req *ireq; + struct sbus_request *sr; + struct ifp_ctx *ifp_ctx; + errno_t ret; + + assert_true(leak_check_setup()); + + ifp_ctx = mock_ifp_ctx(global_talloc_context); + assert_non_null(ifp_ctx); + check_leaks_push(ifp_ctx); + + sr = mock_sbus_request(ifp_ctx); + assert_non_null(sr); + check_leaks_push(sr); + + ret = ifp_req_create(sr, ifp_ctx, &ireq); + assert_int_equal(ret, EOK); + talloc_free(ireq); + + assert_true(check_leaks_pop(sr) == true); + talloc_free(sr); + + assert_true(check_leaks_pop(ifp_ctx) == true); + talloc_free(ifp_ctx); + + assert_true(leak_check_teardown()); +} + +void test_path_prefix(void **state) +{ + const char *prefix = "foo"; + + assert_non_null(ifp_path_strip_prefix("foobar", prefix)); + assert_null(ifp_path_strip_prefix("notfoo", prefix)); +} + +void test_el_to_dict(void **state) +{ + static struct sbus_request *sr; + dbus_bool_t dbret; + DBusMessageIter iter; + DBusMessageIter iter_dict; + struct ldb_message_element *el; + errno_t ret; + char *attr_name; + char *attr_val; + + sr = mock_sbus_request(global_talloc_context); + assert_non_null(sr); + + el = talloc(sr, struct ldb_message_element); + assert_non_null(el); + el->name = "numbers"; + el->values = talloc_array(el, struct ldb_val, 2); + assert_non_null(el->values); + el->num_values = 2; + el->values[0].data = (uint8_t *) discard_const("one"); + el->values[0].length = strlen("one") + 1; + el->values[1].data = (uint8_t *) discard_const("two"); + el->values[1].length = strlen("two") + 1; + + dbus_message_iter_init_append(sr->message, &iter); + dbret = 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, + &iter_dict); + assert_true(dbret == TRUE); + + ret = ifp_add_ldb_el_to_dict(&iter_dict, el); + assert_int_equal(ret, EOK); + + dbret = dbus_message_iter_close_container(&iter, &iter_dict); + assert_true(dbret == TRUE); + + /* Test the reply contains what we expect */ + dbus_message_iter_init(sr->message, &iter); + assert_int_equal(dbus_message_iter_get_arg_type(&iter), + DBUS_TYPE_ARRAY); + dbus_message_iter_recurse(&iter, &iter); + assert_int_equal(dbus_message_iter_get_arg_type(&iter), + DBUS_TYPE_DICT_ENTRY); + + dbus_message_iter_recurse(&iter, &iter_dict); + dbus_message_iter_get_basic(&iter_dict, &attr_name); + assert_string_equal(attr_name, "numbers"); + + dbus_message_iter_next(&iter_dict); + assert_int_equal(dbus_message_iter_get_arg_type(&iter_dict), + DBUS_TYPE_VARIANT); + dbus_message_iter_recurse(&iter_dict, &iter_dict); + assert_int_equal(dbus_message_iter_get_arg_type(&iter_dict), + DBUS_TYPE_ARRAY); + + dbus_message_iter_recurse(&iter_dict, &iter_dict); + dbus_message_iter_get_basic(&iter_dict, &attr_val); + assert_string_equal(attr_val, "one"); + assert_true(dbus_message_iter_next(&iter_dict)); + dbus_message_iter_get_basic(&iter_dict, &attr_val); + assert_string_equal(attr_val, "two"); + assert_false(dbus_message_iter_next(&iter_dict)); +} + +int main(int argc, const char *argv[]) +{ + poptContext pc; + int opt; + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_DEBUG_OPTS + POPT_TABLEEND + }; + + const UnitTest tests[] = { + unit_test(ifp_test_req_create), + unit_test(test_path_prefix), + unit_test(test_el_to_dict), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ + debug_level = SSSDBG_INVALID; + + pc = poptGetContext(argv[0], argc, argv, long_options, 0); + while((opt = poptGetNextOpt(pc)) != -1) { + switch(opt) { + default: + fprintf(stderr, "\nInvalid option %s: %s\n\n", + poptBadOption(pc, 0), poptStrerror(opt)); + poptPrintUsage(pc, stderr, 0); + return 1; + } + } + poptFreeContext(pc); + + DEBUG_INIT(debug_level); + + /* Even though normally the tests should clean up after themselves + * they might not after a failed run. Remove the old db to be sure */ + tests_set_cwd(); + + return run_tests(tests); +} -- 1.9.0