/* Authors: Jakub Hrozek Copyright (C) 2013 Red Hat SSSD tests: Common utilities for tests that exercise domains 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 /* Including private header makes sure we can initialize test domains. */ #include "db/sysdb_private.h" #include "tests/common.h" static errno_t mock_confdb(TALLOC_CTX *mem_ctx, const char *tests_path, const char *cdb_file, struct confdb_ctx **_cdb) { TALLOC_CTX *tmp_ctx = NULL; struct confdb_ctx *cdb = NULL; char *cdb_path = NULL; errno_t ret; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); return ENOMEM; } cdb_path = talloc_asprintf(tmp_ctx, "%s/%s", tests_path, cdb_file); if (cdb_path == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed\n"); ret = ENOMEM; goto done; } /* connect to the confdb */ ret = confdb_init(tmp_ctx, &cdb, cdb_path); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "confdb_init failed: %d\n", ret); goto done; } *_cdb = talloc_steal(mem_ctx, cdb); ret = EOK; done: talloc_free(tmp_ctx); return ret; } static errno_t mock_confdb_domain(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, const char *db_path, const char *name, const char *id_provider, struct sss_test_conf_param *params, char **_cdb_path) { TALLOC_CTX *tmp_ctx = NULL; const char *val[2] = {NULL, NULL}; char *cdb_path = NULL; char **array = NULL; char *list = NULL; bool exists = false; errno_t ret; int i; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); return ENOMEM; } /* get current domain list */ ret = confdb_get_string(cdb, tmp_ctx, "config/sssd", "domains", NULL, &list); if (ret != EOK) { goto done; } /* check if the domain is already in */ if (list != NULL) { ret = split_on_separator(tmp_ctx, list, ',', true, true, &array, NULL); if (ret != EOK) { goto done; } for (i = 0; array[i] != NULL; i++) { if (strcmp(array[i], name) == 0) { exists = true; break; } } } /* add domain to the list of enabled domains */ if (!exists) { if (list == NULL) { list = talloc_strdup(tmp_ctx, name); } else { list = talloc_asprintf_append(list, ", %s", name); } if (list == NULL) { ret = ENOMEM; goto done; } val[0] = list; ret = confdb_add_param(cdb, true, "config/sssd", "domains", val); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to change domain list [%d]: %s\n", ret, sss_strerror(ret)); goto done; } } /* create domain section */ cdb_path = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL, name); if (cdb_path == NULL) { ret = ENOMEM; goto done; } val[0] = id_provider; ret = confdb_add_param(cdb, true, cdb_path, "id_provider", val); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add id_provider [%d]: %s\n", ret, sss_strerror(ret)); goto done; } if (params != NULL) { for (i = 0; params[i].key != NULL; i++) { val[0] = params[i].value; ret = confdb_add_param(cdb, true, cdb_path, params[i].key, val); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add parameter %s [%d]: " "%s\n", params[i].key, ret, sss_strerror(ret)); goto done; } } } if (_cdb_path != NULL) { *_cdb_path = talloc_steal(mem_ctx, cdb_path); } ret = EOK; done: talloc_free(tmp_ctx); return ret; } void reset_ldb_errstrings(struct sss_domain_info *dom) { ldb_reset_err_string(sysdb_ctx_get_ldb(dom->sysdb)); if (dom->sysdb->ldb_ts) { ldb_reset_err_string(dom->sysdb->ldb_ts); } } static errno_t mock_domain(TALLOC_CTX *mem_ctx, struct confdb_ctx *cdb, const char *db_path, const char *name, struct sss_domain_info **_domain) { struct sss_domain_info *domain = NULL; errno_t ret; /* initialize sysdb */ ret = sssd_domain_init(mem_ctx, cdb, name, db_path, &domain); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "sssd_domain_init() of %s failed " "[%d]: %s\n", name, ret, sss_strerror(ret)); goto done; } reset_ldb_errstrings(domain); /* init with an AD-style regex to be able to test flat name */ ret = sss_names_init_from_args(domain, "(((?P[^\\\\]+)\\\\(?P.+$))|" \ "((?P[^@]+)@(?P.+$))|" \ "(^(?P[^@\\\\]+)$))", "%1$s@%2$s", &domain->names); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "cannot create names context\n"); goto done; } if (_domain != NULL) { *_domain = domain; } ret = EOK; done: if (ret != EOK) { talloc_free(domain); } return ret; } struct sss_test_ctx * create_multidom_test_ctx(TALLOC_CTX *mem_ctx, const char *tests_path, const char *cdb_file, const char **domains, const char *id_provider, struct sss_test_conf_param *params) { struct sss_domain_info *domain = NULL; struct sss_test_ctx *test_ctx = NULL; char *cdb_path = NULL; errno_t ret; int i; test_ctx = create_ev_test_ctx(mem_ctx); if (test_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "create_ev_test_ctx() failed\n"); goto fail; } ret = mock_confdb(test_ctx, tests_path, cdb_file, &test_ctx->confdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize confdb [%d]: %s\n", ret, sss_strerror(ret)); goto fail; } /* create confdb objects for the domains */ for (i = 0; domains[i] != NULL; i++) { ret = mock_confdb_domain(test_ctx, test_ctx->confdb, tests_path, domains[i], id_provider, params, (cdb_path == NULL ? &cdb_path : NULL)); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize confdb domain " "[%d]: %s\n", ret, sss_strerror(ret)); goto fail; } } /* initialize domain list and sysdb of the domains */ for (i = 0; domains[i] != NULL; i++) { ret = mock_domain(test_ctx, test_ctx->confdb, tests_path, domains[i], (domain == NULL ? &domain : NULL)); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add new domain [%d]: %s\n", ret, sss_strerror(ret)); goto fail; } } /* the first domain we obtained is already head of the complete list */ test_ctx->dom = domain; /* set data from the first domain */ test_ctx->sysdb = test_ctx->dom->sysdb; test_ctx->nctx = test_ctx->dom->names; test_ctx->conf_dom_path = cdb_path; return test_ctx; fail: talloc_free(test_ctx); return NULL; } struct sss_test_ctx * create_dom_test_ctx(TALLOC_CTX *mem_ctx, const char *tests_path, const char *confdb_path, const char *domain_name, const char *id_provider, struct sss_test_conf_param *params) { const char *domains[] = {domain_name, NULL}; return create_multidom_test_ctx(mem_ctx, tests_path, confdb_path, domains, id_provider, params); } void test_multidom_suite_cleanup(const char *tests_path, const char *cdb_file, const char **domains) { TALLOC_CTX *tmp_ctx = NULL; char *cdb_path = NULL; char *sysdb_path = NULL; char *sysdb_ts_path = NULL; errno_t ret; int i; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); return; } if (cdb_file != NULL) { cdb_path = talloc_asprintf(tmp_ctx, "%s/%s", tests_path, cdb_file); if (cdb_path == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not contruct cdb path\n"); goto done; } errno = 0; ret = unlink(cdb_path); if (ret != 0 && errno != ENOENT) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "Could not delete the test config " "ldb file [%d]: (%s)\n", ret, sss_strerror(ret)); } } if (domains != NULL) { for (i = 0; domains[i] != NULL; i++) { if (strcmp(domains[i], LOCAL_SYSDB_FILE) == 0) { /* local domain */ ret = sysdb_get_db_file(tmp_ctx, "local", domains[i], tests_path, &sysdb_path, &sysdb_ts_path); if (ret != EOK) { goto done; } } else { /* The mocked database doesn't really care about its provider type, just * distinguishes between a local and non-local databases */ ret = sysdb_get_db_file(tmp_ctx, "fake_nonlocal", domains[i], tests_path, &sysdb_path, &sysdb_ts_path); if (ret != EOK) { goto done; } } if (sysdb_path == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct sysdb path\n"); goto done; } errno = 0; ret = unlink(sysdb_path); if (ret != 0 && errno != ENOENT) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "Could not delete the test domain " "ldb file [%d]: (%s)\n", ret, sss_strerror(ret)); } if (sysdb_ts_path) { errno = 0; ret = unlink(sysdb_ts_path); if (ret != 0 && errno != ENOENT) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "Could not delete the test domain " "ldb timestamp file [%d]: (%s)\n", ret, sss_strerror(ret)); } } talloc_zfree(sysdb_path); } } errno = 0; ret = rmdir(tests_path); if (ret != 0 && errno != ENOENT) { ret = errno; DEBUG(SSSDBG_CRIT_FAILURE, "Could not delete the test dir (%d) (%s)\n", ret, sss_strerror(ret)); } done: talloc_free(tmp_ctx); } void test_dom_suite_cleanup(const char *tests_path, const char *cdb_file, const char *domain) { const char *domains[] = {domain, NULL}; test_multidom_suite_cleanup(tests_path, cdb_file, domains); } struct sss_domain_info *named_domain(TALLOC_CTX *mem_ctx, const char *name, struct sss_domain_info *parent) { struct sss_domain_info *dom = NULL; dom = talloc_zero(mem_ctx, struct sss_domain_info); if (dom == NULL) { return NULL; } dom->name = talloc_strdup(dom, name); if (dom->name == NULL) { talloc_free(dom); return NULL; } dom->parent = parent; return dom; }