From 62a3c79d7923dceb2c92c1b2d31388afd744a8ac Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 10 Feb 2016 14:59:06 +0100 Subject: [PATCH 4/8] AD: process PAC during initgroups request If there is a recently attached PAC blob in the cached user entry the PAC data is used to update the group memberships data of the user. If there is no PAC attached or if it is too old the other configured methods will be used. --- Makefile.am | 20 ++ src/providers/ad/ad_id.c | 52 ++- src/providers/ad/ad_pac.c | 666 ++++++++++++++++++++++++++++++++++++++ src/providers/ad/ad_pac.h | 82 +++++ src/providers/ad/ad_pac_common.c | 86 +++++ src/tests/cmocka/test_ad_common.c | 346 +++++++++++++++++++- 6 files changed, 1243 insertions(+), 9 deletions(-) create mode 100644 src/providers/ad/ad_pac.c create mode 100644 src/providers/ad/ad_pac.h create mode 100644 src/providers/ad/ad_pac_common.c diff --git a/Makefile.am b/Makefile.am index 477043b6ff763e987056de8ca99922322e7b986c..5745f3df54fa060352a1df327265770ac004cc7a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2243,6 +2243,13 @@ ad_common_tests_SOURCES = \ src/tests/cmocka/common_mock_krb5.c \ src/tests/cmocka/test_ad_common.c \ src/providers/ad/ad_opts.c \ + src/providers/ad/ad_pac.c \ + src/providers/ad/ad_pac_common.c \ + src/providers/ldap/sdap_async_initgroups_ad.c \ + $(NULL) +ad_common_tests_CFLAGS = \ + $(NDR_NBT_CFLAGS) \ + $(NDR_KRB5PAC_CFLAGS) \ $(NULL) ad_common_tests_LDFLAGS = \ -Wl,-wrap,sdap_set_sasl_options \ @@ -2252,8 +2259,11 @@ ad_common_tests_LDADD = \ $(CMOCKA_LIBS) \ $(SSSD_LIBS) \ $(KEYUTILS_LIBS) \ + $(NDR_NBT_LIBS) \ + $(NDR_KRB5PAC_LIBS) \ $(KRB5_LIBS) \ $(SSSD_INTERNAL_LTLIBS) \ + libsss_idmap.la \ libsss_ldap_common.la \ libsss_test_common.la \ libdlopen_test_providers.la \ @@ -3044,6 +3054,9 @@ libsss_ipa_la_SOURCES = \ src/providers/ad/ad_common.h \ src/providers/ad/ad_dyndns.c \ src/providers/ad/ad_id.c \ + src/providers/ad/ad_pac.c \ + src/providers/ad/ad_pac_common.c \ + src/providers/ad/ad_pac.h \ src/providers/ad/ad_srv.c \ src/providers/ad/ad_domain_info.c libsss_ipa_la_CFLAGS = \ @@ -3051,11 +3064,13 @@ libsss_ipa_la_CFLAGS = \ $(OPENLDAP_CFLAGS) \ $(DHASH_CFLAGS) \ $(NDR_NBT_CFLAGS) \ + $(NDR_KRB5PAC_CFLAGS) \ $(KRB5_CFLAGS) libsss_ipa_la_LIBADD = \ $(OPENLDAP_LIBS) \ $(DHASH_LIBS) \ $(NDR_NBT_LIBS) \ + $(NDR_KRB5PAC_LIBS) \ $(KRB5_LIBS) \ $(SELINUX_LIBS) \ $(SSSD_INTERNAL_LTLIBS) \ @@ -3094,6 +3109,9 @@ libsss_ad_la_SOURCES = \ src/providers/ad/ad_dyndns.c \ src/providers/ad/ad_machine_pw_renewal.c \ src/providers/ad/ad_id.c \ + src/providers/ad/ad_pac.c \ + src/providers/ad/ad_pac_common.c \ + src/providers/ad/ad_pac.h \ src/providers/ad/ad_id.h \ src/providers/ad/ad_access.c \ src/providers/ad/ad_access.h \ @@ -3124,6 +3142,7 @@ libsss_ad_la_CFLAGS = \ $(DHASH_CFLAGS) \ $(KRB5_CFLAGS) \ $(NDR_NBT_CFLAGS) \ + $(NDR_KRB5PAC_CFLAGS) \ $(SMBCLIENT_CFLAGS) libsss_ad_la_LIBADD = \ $(OPENLDAP_LIBS) \ @@ -3131,6 +3150,7 @@ libsss_ad_la_LIBADD = \ $(DHASH_LIBS) \ $(KRB5_LIBS) \ $(NDR_NBT_LIBS) \ + $(NDR_KRB5PAC_LIBS) \ $(SSSD_INTERNAL_LTLIBS) \ $(SMBCLIENT_LIBS) \ libsss_ldap_common.la \ diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c index 9832aea97218c97ccc499605f4b84f374e043a7b..c464fa9483426f720f7eb89f43200a73e30fe254 100644 --- a/src/providers/ad/ad_id.c +++ b/src/providers/ad/ad_id.c @@ -24,6 +24,7 @@ #include "providers/ad/ad_common.h" #include "providers/ad/ad_id.h" #include "providers/ad/ad_domain_info.h" +#include "providers/ad/ad_pac.h" #include "providers/ldap/sdap_async_enum.h" #include "providers/ldap/sdap_idmap.h" @@ -57,6 +58,7 @@ struct ad_handle_acct_info_state { struct sdap_domain *sdom; size_t cindex; struct ad_options *ad_options; + bool using_pac; int dp_error; const char *err; @@ -117,10 +119,12 @@ immediate: static errno_t ad_handle_acct_info_step(struct tevent_req *req) { - struct tevent_req *subreq; + struct tevent_req *subreq = NULL; struct ad_handle_acct_info_state *state = tevent_req_data(req, struct ad_handle_acct_info_state); bool noexist_delete = false; + struct ldb_message *msg; + int ret; if (state->conn[state->cindex] == NULL) { return EOK; @@ -130,14 +134,42 @@ ad_handle_acct_info_step(struct tevent_req *req) noexist_delete = true; } - subreq = sdap_handle_acct_req_send(state, state->ctx->be, - state->ar, state->ctx, - state->sdom, - state->conn[state->cindex], - noexist_delete); + + state->using_pac = false; + if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) { + ret = check_if_pac_is_available(state, state->sdom->dom, + state->ar, &msg); + + if (ret == EOK) { + /* evaluate PAC */ + state->using_pac = true; + subreq = ad_handle_pac_initgr_send(state, state->ctx->be, + state->ar, state->ctx, + state->sdom, + state->conn[state->cindex], + noexist_delete, + msg); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "ad_handle_pac_initgr_send failed.\n"); + return ENOMEM; + } + + } + + /* Fall through if there is no PAC or any other error */ + } + if (subreq == NULL) { - return ENOMEM; + subreq = sdap_handle_acct_req_send(state, state->ctx->be, + state->ar, state->ctx, + state->sdom, + state->conn[state->cindex], + noexist_delete); + if (subreq == NULL) { + return ENOMEM; + } } + tevent_req_set_callback(subreq, ad_handle_acct_info_done, req); return EAGAIN; } @@ -154,7 +186,11 @@ ad_handle_acct_info_done(struct tevent_req *subreq) struct ad_handle_acct_info_state *state = tevent_req_data(req, struct ad_handle_acct_info_state); - ret = sdap_handle_acct_req_recv(subreq, &dp_error, &err, &sdap_err); + if (state->using_pac) { + ret = ad_handle_pac_initgr_recv(subreq, &dp_error, &err, &sdap_err); + } else { + ret = sdap_handle_acct_req_recv(subreq, &dp_error, &err, &sdap_err); + } if (dp_error == DP_ERR_OFFLINE && state->conn[state->cindex+1] != NULL && state->conn[state->cindex]->ignore_mark_offline) { diff --git a/src/providers/ad/ad_pac.c b/src/providers/ad/ad_pac.c new file mode 100644 index 0000000000000000000000000000000000000000..68d674c4db4b66921cb7f6403b0ece6a23946db0 --- /dev/null +++ b/src/providers/ad/ad_pac.c @@ -0,0 +1,666 @@ +/* + SSSD + + Authors: + Sumit Bose + + Copyright (C) 2016 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 "util/util.h" +#include "providers/ad/ad_pac.h" +#include "providers/ad/ad_common.h" +#include "providers/ad/ad_id.h" +#include "providers/ldap/sdap_idmap.h" +#include "providers/ldap/sdap_async_ad.h" + +static errno_t find_user_entry(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + struct be_acct_req *ar, + struct ldb_message **_msg) +{ + const char *user_attrs[] = { SYSDB_NAME, SYSDB_OBJECTCLASS, + SYSDB_PAC_BLOB, SYSDB_PAC_BLOB_EXPIRE, + NULL }; + struct ldb_message *msg; + struct ldb_result *res; + char *user_name; + int ret; + TALLOC_CTX *tmp_ctx = NULL; + + if (dom == NULL || ar == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing arguments.\n"); + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + if (ar->extra_value && strcmp(ar->extra_value, EXTRA_NAME_IS_UPN) == 0) { + ret = sysdb_search_user_by_upn(tmp_ctx, dom, ar->filter_value, + user_attrs, &msg); + } else { + switch (ar->filter_type) { + case BE_FILTER_SECID: + ret = sysdb_search_user_by_sid_str(tmp_ctx, dom, ar->filter_value, + user_attrs, &msg); + break; + case BE_FILTER_UUID: + ret = sysdb_search_object_by_uuid(tmp_ctx, dom, ar->filter_value, + user_attrs, &res); + + if (ret == EOK) { + if (res->count == 1) { + msg = res->msgs[0]; + } else { + talloc_free(res); + DEBUG(SSSDBG_CRIT_FAILURE, + "Search by UUID returned multiple results.\n"); + ret = EINVAL; + goto done; + } + } + break; + case BE_FILTER_NAME: + + user_name = sss_get_domain_name(tmp_ctx, ar->filter_value, dom); + if (user_name == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sss_get_domain_name failed.\n"); + ret = EINVAL; + goto done; + } else { + ret = sysdb_search_user_by_name(tmp_ctx, dom, user_name, + user_attrs, &msg); + } + break; + default: + DEBUG(SSSDBG_OP_FAILURE, "Unsupported filter type [%d].\n", + ar->filter_type); + ret = EINVAL; + goto done; + } + } + + if (ret != EOK) { + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_ALL, "No user found with filter [%s].\n", + ar->filter_value); + } else { + DEBUG(SSSDBG_OP_FAILURE, + "Looking up user in cache with filter [%s] failed.\n", + ar->filter_value); + } + goto done; + } + + *_msg = talloc_steal(mem_ctx, msg); + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t check_if_pac_is_available(TALLOC_CTX *mem_ctx, + struct sss_domain_info *dom, + struct be_acct_req *ar, + struct ldb_message **_msg) +{ + struct ldb_message *msg; + struct ldb_message_element *el; + uint64_t pac_expires; + time_t now; + int ret; + + ret = find_user_entry(mem_ctx, dom, ar, &msg); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "find_user_entry failed.\n"); + return ret; + } + + el = ldb_msg_find_element(msg, SYSDB_PAC_BLOB); + if (el == NULL) { + DEBUG(SSSDBG_TRACE_ALL, "No PAC available.\n"); + talloc_free(msg); + return ENOENT; + } + + pac_expires = ldb_msg_find_attr_as_uint64(msg, SYSDB_PAC_BLOB_EXPIRE, 0); + now = time(NULL); + if (pac_expires < now) { + DEBUG(SSSDBG_TRACE_FUNC, "PAC avaiable but too old.\n"); + talloc_free(msg); + return ENOENT; + } + + if (_msg != NULL) { + *_msg = msg; + } + + return EOK; +} + +errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx, + struct sss_idmap_ctx *idmap_ctx, + struct PAC_LOGON_INFO *logon_info, + char **_user_sid_str, + char **_primary_group_sid_str, + size_t *_num_sids, + char *** _sid_list) +{ + int ret; + size_t s; + struct netr_SamInfo3 *info3; + char *sid_str = NULL; + char *msid_str = NULL; + char *user_dom_sid_str = NULL; + size_t user_dom_sid_str_len; + enum idmap_error_code err; + hash_table_t *sid_table = NULL; + hash_key_t key; + hash_value_t value; + char *rid_start; + char *user_sid_str = NULL; + char *primary_group_sid_str = NULL; + size_t c; + size_t num_sids; + char **sid_list = NULL; + struct hash_iter_context_t *iter = NULL; + hash_entry_t *entry; + TALLOC_CTX *tmp_ctx; + + if (idmap_ctx == NULL || logon_info == NULL + || _num_sids == NULL || _sid_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing parameter.\n"); + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + info3 = &logon_info->info3; + + ret = sss_hash_create(tmp_ctx, + info3->sidcount + info3->base.groups.count + 2, + &sid_table); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n"); + goto done; + } + + key.type = HASH_KEY_STRING; + value.type = HASH_VALUE_ULONG; + + err = sss_idmap_smb_sid_to_sid(idmap_ctx, info3->base.domain_sid, + &user_dom_sid_str); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n"); + ret = EFAULT; + goto done; + } + + user_dom_sid_str_len = strlen(user_dom_sid_str); + sid_str = talloc_zero_size(tmp_ctx, user_dom_sid_str_len + 12); + if (sid_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); + ret = ENOMEM; + goto done; + } + rid_start = sid_str + user_dom_sid_str_len; + + memcpy(sid_str, user_dom_sid_str, user_dom_sid_str_len); + + memset(rid_start, '\0', 12); + ret = snprintf(rid_start, 12, "-%lu", + (unsigned long) info3->base.rid); + if (ret < 0 || ret > 12) { + DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); + ret = EIO; + goto done; + } + + user_sid_str = talloc_strdup(tmp_ctx, sid_str); + if (user_sid_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + + key.str = sid_str; + value.ul = 0; + + memset(rid_start, '\0', 12); + ret = snprintf(rid_start, 12, "-%lu", + (unsigned long) info3->base.primary_gid); + if (ret < 0 || ret > 12) { + DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); + ret = EIO; + goto done; + } + + primary_group_sid_str = talloc_strdup(tmp_ctx, sid_str); + if (primary_group_sid_str == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + + key.str = sid_str; + value.ul = 0; + + ret = hash_enter(sid_table, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", + ret, hash_error_string(ret)); + ret = EIO; + goto done; + } + + + for (s = 0; s < info3->base.groups.count; s++) { + memset(rid_start, '\0', 12); + ret = snprintf(rid_start, 12, "-%lu", + (unsigned long) info3->base.groups.rids[s].rid); + if (ret < 0 || ret > 12) { + DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n"); + ret = EIO; + goto done; + } + + key.str = sid_str; + value.ul = 0; + + ret = hash_enter(sid_table, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", + ret, hash_error_string(ret)); + ret = EIO; + goto done; + } + + } + + for(s = 0; s < info3->sidcount; s++) { + err = sss_idmap_smb_sid_to_sid(idmap_ctx, info3->sids[s].sid, + &msid_str); + if (err != IDMAP_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n"); + ret = EFAULT; + goto done; + } + + key.str = msid_str; + value.ul = 0; + + ret = hash_enter(sid_table, &key, &value); + sss_idmap_free_sid(idmap_ctx, msid_str); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n", + ret, hash_error_string(ret)); + ret = EIO; + goto done; + } + } + + num_sids = hash_count(sid_table); + sid_list = talloc_array(tmp_ctx, char *, num_sids); + if (sid_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n"); + ret = ENOMEM; + goto done; + } + + iter = new_hash_iter_context(sid_table); + if (iter == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "new_hash_iter_context failed.\n"); + ret = EINVAL; + goto done; + } + + c = 0; + while ((entry = iter->next(iter)) != NULL) { + sid_list[c] = talloc_strdup(sid_list, entry->key.str); + if (sid_list[c] == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + c++; + } + + ret = EOK; + +done: + sss_idmap_free_sid(idmap_ctx, user_dom_sid_str); + hash_destroy(sid_table); + + if (ret == EOK) { + *_sid_list = talloc_steal(mem_ctx, sid_list); + *_user_sid_str = talloc_steal(mem_ctx, user_sid_str); + *_num_sids = num_sids; + *_primary_group_sid_str = talloc_steal(mem_ctx, primary_group_sid_str); + } + + talloc_free(tmp_ctx); + + return ret; +} + +errno_t ad_get_pac_data_from_user_entry(TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + struct sss_idmap_ctx *idmap_ctx, + char **_username, + char **user_sid, + char **primary_group_sid, + size_t *num_sids, + char ***group_sids) +{ + int ret; + struct ldb_message_element *el; + struct PAC_LOGON_INFO *logon_info = NULL; + const char *dummy; + TALLOC_CTX *tmp_ctx = NULL; + char *username; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + el = ldb_msg_find_element(msg, SYSDB_PAC_BLOB); + if (el == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing PAC blob.\n"); + ret = EINVAL; + goto done; + } + + if (el->num_values != 1) { + DEBUG(SSSDBG_OP_FAILURE, "Expected only one PAC blob."); + ret = EINVAL; + goto done; + } + + ret = ad_get_data_from_pac(tmp_ctx, el->values[0].data, + el->values[0].length, + &logon_info); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_data_from_pac failed.\n"); + goto done; + } + + dummy = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); + if (dummy == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "Missing user name in cache entry.\n"); + ret = EINVAL; + goto done; + } + + username = talloc_strdup(tmp_ctx, dummy); + if (username == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + ret = ENOMEM; + goto done; + } + + ret = ad_get_sids_from_pac(mem_ctx, idmap_ctx, logon_info, + user_sid, primary_group_sid, + num_sids, group_sids); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_sids_from_pac failed.\n"); + goto done; + } + + *_username = talloc_steal(mem_ctx, username); + + ret = EOK; +done: + talloc_free(tmp_ctx); + + return ret; +} + +struct ad_handle_pac_initgr_state { + struct be_acct_req *ar; + const char *err; + int dp_error; + int sdap_ret; + + size_t num_missing_sids; + char **missing_sids; + size_t num_cached_groups; + char **cached_groups; + char *username; + struct sss_domain_info *user_dom; +}; + +static void ad_handle_pac_initgr_lookup_sids_done(struct tevent_req *subreq); + +struct tevent_req *ad_handle_pac_initgr_send(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct be_acct_req *ar, + struct sdap_id_ctx *id_ctx, + struct sdap_domain *sdom, + struct sdap_id_conn_ctx *conn, + bool noexist_delete, + struct ldb_message *msg) +{ + int ret; + struct ad_handle_pac_initgr_state *state; + struct tevent_req *req; + struct tevent_req *subreq; + char *user_sid; + char *primary_group_sid; + size_t num_sids; + char **group_sids; + bool use_id_mapping; + + req = tevent_req_create(mem_ctx, &state, + struct ad_handle_pac_initgr_state); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n"); + return NULL; + } + state->user_dom = sdom->dom; + + /* The following variables are currently unused because no sub-request + * returns any of them. But they are needed to allow the same signature as + * sdap_handle_acct_req_recv() from the alternative group-membership + * lookup path. */ + state->err = NULL; + state->dp_error = DP_ERR_OK; + state->sdap_ret = EOK; + + ret = ad_get_pac_data_from_user_entry(state, msg, + id_ctx->opts->idmap_ctx->map, + &state->username, + &user_sid, &primary_group_sid, + &num_sids, &group_sids); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "ad_get_pac_data_from_user_entry failed.\n"); + goto done; + } + + use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping( + id_ctx->opts->idmap_ctx, + sdom->dom->name, + sdom->dom->domain_id); + if (use_id_mapping + && sdom->dom->ignore_group_members == false) { + /* In contrast to the tokenGroups based group-membership lookup the + * PAC based approach can be used for sub-domains with id-mapping as + * well because the PAC will only contain groups which are valid in + * the target domain, i.e. it will not contain domain-local groups for + * domains other than the user domain. This means the groups must not + * be looked up immediately to determine if they are domain-local or + * not. + * + * Additionally, as a temporary workaround until + * https://fedorahosted.org/sssd/ticket/2656 is fixed, we also fetch + * the group object if group members are ignored to avoid having to + * transfer and retain members when the fake tokengroups object + * without name is replaced by the full group object. + */ + + DEBUG(SSSDBG_TRACE_ALL, "Running PAC processing with id-mapping.\n"); + + ret = sdap_ad_save_group_membership_with_idmapping(state->username, + sdom->dom, + id_ctx->opts->idmap_ctx, + num_sids, group_sids); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sdap_ad_save_group_membership_with_idmapping failed.\n"); + } + + /* this path only includes cache operation, so we can finish the + * request immediately */ + goto done; + } else { + + DEBUG(SSSDBG_TRACE_ALL, "Running PAC processing with external IDs.\n"); + + ret = sdap_ad_tokengroups_get_posix_members(state, sdom->dom, + num_sids, group_sids, + &state->num_missing_sids, + &state->missing_sids, + &state->num_cached_groups, + &state->cached_groups); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "sdap_ad_tokengroups_get_posix_members failed.\n"); + goto done; + } + + /* download missing SIDs */ + subreq = sdap_ad_resolve_sids_send(state, be_ctx->ev, id_ctx, + conn, + id_ctx->opts, sdom->dom, + state->missing_sids); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sdap_ad_resolve_sids_send failed.\n"); + ret = ENOMEM; + goto done; + } + + tevent_req_set_callback(subreq, ad_handle_pac_initgr_lookup_sids_done, + req); + + } + + return req; + +done: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, be_ctx->ev); + + return req; +} + +static void ad_handle_pac_initgr_lookup_sids_done(struct tevent_req *subreq) +{ + struct ad_handle_pac_initgr_state *state; + struct tevent_req *req = NULL; + errno_t ret; + char **cached_groups; + size_t num_cached_groups; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ad_handle_pac_initgr_state); + + ret = sdap_ad_resolve_sids_recv(subreq); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to resolve missing SIDs " + "[%d]: %s\n", ret, strerror(ret)); + goto done; + } + + ret = sdap_ad_tokengroups_get_posix_members(state, state->user_dom, + state->num_missing_sids, + state->missing_sids, + NULL, NULL, + &num_cached_groups, + &cached_groups); + if (ret != EOK){ + DEBUG(SSSDBG_MINOR_FAILURE, + "sdap_ad_tokengroups_get_posix_members failed [%d]: %s\n", + ret, strerror(ret)); + goto done; + } + + state->cached_groups = concatenate_string_array(state, + state->cached_groups, + state->num_cached_groups, + cached_groups, + num_cached_groups); + if (state->cached_groups == NULL) { + ret = ENOMEM; + goto done; + } + + /* update membership of existing groups */ + ret = sdap_ad_tokengroups_update_members(state->username, + state->user_dom->sysdb, + state->user_dom, + state->cached_groups); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, "Membership update failed [%d]: %s\n", + ret, strerror(ret)); + goto done; + } + +done: + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + tevent_req_done(req); +} + +errno_t ad_handle_pac_initgr_recv(struct tevent_req *req, + int *_dp_error, const char **_err, + int *sdap_ret) +{ + struct ad_handle_pac_initgr_state *state; + + state = tevent_req_data(req, struct ad_handle_pac_initgr_state); + + if (_dp_error) { + *_dp_error = state->dp_error; + } + + if (_err) { + *_err = state->err; + } + + if (sdap_ret) { + *sdap_ret = state->sdap_ret; + } + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} diff --git a/src/providers/ad/ad_pac.h b/src/providers/ad/ad_pac.h new file mode 100644 index 0000000000000000000000000000000000000000..4218116159233d6bc19406e7201afc1cdee29791 --- /dev/null +++ b/src/providers/ad/ad_pac.h @@ -0,0 +1,82 @@ +/* + SSSD + + Authors: + Sumit Bose + + Copyright (C) 2016 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 . +*/ + +#ifndef AD_PAC_H_ +#define AD_PAC_H_ + +#include +#include +/* ldb_val is defined as datablob in the Samba header files data_blob.h which + * is included via ndr.h -> samba_util.h -> data_blob.h. + * To allow proper type checking we have to make sure to keep the original + * definition from ldb.h */ +#ifdef ldb_val +#error Please make sure to include ad_pac.h before ldb.h +#endif +#include +#include +#include +#undef ldb_val + +#include "util/util.h" +#include "providers/ldap/ldap_common.h" + +errno_t check_if_pac_is_available(TALLOC_CTX *mem_ctx, + struct sss_domain_info *dom, + struct be_acct_req *ar, + struct ldb_message **_msg); + +errno_t ad_get_data_from_pac(TALLOC_CTX *mem_ctx, + uint8_t *pac_blob, size_t pac_len, + struct PAC_LOGON_INFO **_logon_info); + +errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx, + struct sss_idmap_ctx *idmap_ctx, + struct PAC_LOGON_INFO *logon_info, + char **_user_sid_str, + char **_primary_group_sid_str, + size_t *_num_sids, + char *** _sid_list); + +errno_t ad_get_pac_data_from_user_entry(TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + struct sss_idmap_ctx *idmap_ctx, + char **username, + char **user_sid, + char **primary_group_sid, + size_t *num_sids, + char ***group_sids); + +struct tevent_req *ad_handle_pac_initgr_send(TALLOC_CTX *mem_ctx, + struct be_ctx *be_ctx, + struct be_acct_req *ar, + struct sdap_id_ctx *id_ctx, + struct sdap_domain *sdom, + struct sdap_id_conn_ctx *conn, + bool noexist_delete, + struct ldb_message *msg); + +errno_t ad_handle_pac_initgr_recv(struct tevent_req *req, + int *_dp_error, const char **_err, + int *sdap_ret); + +#endif /* AD_PAC_H_ */ diff --git a/src/providers/ad/ad_pac_common.c b/src/providers/ad/ad_pac_common.c new file mode 100644 index 0000000000000000000000000000000000000000..64c7ba4815291520aaee19c04af25fb4039a1dbe --- /dev/null +++ b/src/providers/ad/ad_pac_common.c @@ -0,0 +1,86 @@ +/* + SSSD + + Authors: + Sumit Bose + + Copyright (C) 2016 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 "providers/ad/ad_pac.h" +#include "util/util.h" + +errno_t ad_get_data_from_pac(TALLOC_CTX *mem_ctx, + uint8_t *pac_blob, size_t pac_len, + struct PAC_LOGON_INFO **_logon_info) +{ + DATA_BLOB blob; + struct ndr_pull *ndr_pull; + struct PAC_DATA *pac_data; + enum ndr_err_code ndr_err; + size_t c; + int ret; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + blob.data = pac_blob; + blob.length = pac_len; + + ndr_pull = ndr_pull_init_blob(&blob, tmp_ctx); + if (ndr_pull == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob failed.\n"); + ret = ENOMEM; + goto done; + } + ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC; /* FIXME: is this really needed ? */ + + pac_data = talloc_zero(tmp_ctx, struct PAC_DATA); + if (pac_data == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); + ret = ENOMEM; + goto done; + } + + ndr_err = ndr_pull_PAC_DATA(ndr_pull, NDR_SCALARS|NDR_BUFFERS, pac_data); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_PAC_DATA failed [%d]\n", ndr_err); + ret = EBADMSG; + goto done; + } + + for(c = 0; c < pac_data->num_buffers; c++) { + if (pac_data->buffers[c].type == PAC_TYPE_LOGON_INFO) { + *_logon_info = talloc_steal(mem_ctx, + pac_data->buffers[c].info->logon_info.info); + + ret = EOK; + goto done; + } + } + + ret = EINVAL; + +done: + talloc_free(tmp_ctx); + + return ret; +} diff --git a/src/tests/cmocka/test_ad_common.c b/src/tests/cmocka/test_ad_common.c index b1929ae35df6ed17c391772009b48dcbf33fa69e..369e91d3f347ebe4978aa80421ebccba4e14cb26 100644 --- a/src/tests/cmocka/test_ad_common.c +++ b/src/tests/cmocka/test_ad_common.c @@ -29,6 +29,10 @@ #include #include +#include "providers/ad/ad_pac.h" +#include "util/crypto/sss_crypto.h" +#include "util/util_sss_idmap.h" + /* In order to access opaque types */ #include "providers/ad/ad_common.c" @@ -52,8 +56,326 @@ #define ONEWAY_AUTHID "host/"ONEWAY_HOST_NAME #define ONEWAY_TEST_PRINC ONEWAY_AUTHID"@"ONEWAY_DOMNAME +#define TESTS_PATH "tp_" BASE_FILE_STEM +#define TEST_CONF_DB "test_ad_sysdb.ldb" +#define TEST_ID_PROVIDER "ad" +#define TEST_DOM1_NAME "test_sysdb_subdomains_1" +#define TEST_DOM2_NAME "child2.test_sysdb_subdomains_2" +#define TEST_USER "test_user" + static bool call_real_sasl_options; +const char *domains[] = { TEST_DOM1_NAME, + TEST_DOM2_NAME, + NULL }; +struct ad_sysdb_test_ctx { + struct sss_test_ctx *tctx; +}; + +static int test_ad_sysdb_setup(void **state) +{ + struct ad_sysdb_test_ctx *test_ctx; + struct sss_test_conf_param params[] = { + { NULL, NULL }, /* Sentinel */ + }; + + assert_true(leak_check_setup()); + + test_ctx = talloc_zero(global_talloc_context, + struct ad_sysdb_test_ctx); + assert_non_null(test_ctx); + + test_dom_suite_setup(TESTS_PATH); + + test_ctx->tctx = create_multidom_test_ctx(test_ctx, TESTS_PATH, + TEST_CONF_DB, domains, + TEST_ID_PROVIDER, params); + assert_non_null(test_ctx->tctx); + + *state = test_ctx; + return 0; +} + +static int test_ad_sysdb_teardown(void **state) +{ + struct ad_sysdb_test_ctx *test_ctx = + talloc_get_type(*state, struct ad_sysdb_test_ctx); + + test_multidom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, domains); + talloc_free(test_ctx); + assert_true(leak_check_teardown()); + return 0; +} + +static void test_check_if_pac_is_available(void **state) +{ + int ret; + struct ad_sysdb_test_ctx *test_ctx = + talloc_get_type(*state, struct ad_sysdb_test_ctx); + struct be_acct_req *ar; + struct ldb_message *msg = NULL; + struct sysdb_attrs *attrs; + + ret = check_if_pac_is_available(NULL, NULL, NULL, NULL); + assert_int_equal(ret, EINVAL); + + ar = talloc_zero(test_ctx, struct be_acct_req); + assert_non_null(ar); + + ret = check_if_pac_is_available(test_ctx, test_ctx->tctx->dom, ar, &msg); + assert_int_equal(ret, EINVAL); + + ar->filter_type = BE_FILTER_NAME; + ar->filter_value = discard_const(TEST_USER); + + ret = check_if_pac_is_available(test_ctx, test_ctx->tctx->dom, ar, &msg); + assert_int_equal(ret, ENOENT); + + ret = sysdb_add_user(test_ctx->tctx->dom, TEST_USER, 123, 456, NULL, NULL, + NULL, NULL, NULL, 0, 0); + assert_int_equal(ret, EOK); + + ret = check_if_pac_is_available(test_ctx, test_ctx->tctx->dom, ar, &msg); + assert_int_equal(ret, ENOENT); + + attrs = sysdb_new_attrs(test_ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_string(attrs, SYSDB_PAC_BLOB, "pac"); + assert_int_equal(ret, EOK); + + ret = sysdb_set_user_attr(test_ctx->tctx->dom, TEST_USER, attrs, + SYSDB_MOD_REP); + + /* PAC available but too old */ + ret = check_if_pac_is_available(test_ctx, test_ctx->tctx->dom, ar, &msg); + assert_int_equal(ret, ENOENT); + + talloc_free(attrs); + attrs = sysdb_new_attrs(test_ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_time_t(attrs, SYSDB_PAC_BLOB_EXPIRE, 123); + assert_int_equal(ret, EOK); + + ret = sysdb_set_user_attr(test_ctx->tctx->dom, TEST_USER, attrs, + SYSDB_MOD_REP); + + /* PAC available but still too old */ + ret = check_if_pac_is_available(test_ctx, test_ctx->tctx->dom, ar, &msg); + assert_int_equal(ret, ENOENT); + + talloc_free(attrs); + attrs = sysdb_new_attrs(test_ctx); + assert_non_null(attrs); + + ret = sysdb_attrs_add_time_t(attrs, SYSDB_PAC_BLOB_EXPIRE, time(NULL) + 10); + assert_int_equal(ret, EOK); + + ret = sysdb_set_user_attr(test_ctx->tctx->dom, TEST_USER, attrs, + SYSDB_MOD_REP); + + /* PAC available but still too old */ + ret = check_if_pac_is_available(test_ctx, test_ctx->tctx->dom, ar, &msg); + assert_int_equal(ret, EOK); + assert_non_null(msg); + assert_string_equal(ldb_msg_find_attr_as_string(msg, SYSDB_NAME, "x"), + TEST_USER); + + talloc_free(attrs); + talloc_free(ar); +} + +#define TEST_PAC_BASE64 \ + "BQAAAAAAAAABAAAA6AEAAFgAAAAAAAAACgAAABAAAABAAgAAAA" \ + "AAAAwAAAA4AAAAUAIAAAAAAAAGAAAAFAAAAIgCAAAAAAAABwAA" \ + "ABQAAACgAgAAAAAAAAEQCADMzMzM2AEAAAAAAAAAAAIA2hr35p" \ + "Ji0QH/////////f/////////9/4veKrwAP0AHit/TZyQ/QAf//" \ + "//////9/BgAGAAQAAgAGAAYACAACAAAAAAAMAAIAAAAAABAAAg" \ + "AAAAAAFAACAAAAAAAYAAIATwAAAFAEAAABAgAABQAAABwAAgAg" \ + "AAAAAAAAAAAAAAAAAAAAAAAAABIAFAAgAAIABAAGACQAAgAoAA" \ + "IAAAAAAAAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \ + "AAAAAAEAAAAsAAIAAAAAAAAAAAAAAAAAAwAAAAAAAAADAAAAdA" \ + "B1ADEAAAADAAAAAAAAAAMAAAB0ACAAdQAAAAAAAAAAAAAAAAAA" \ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \ + "UAAAD9ogAABwAAAAECAAAHAAAAXAQAAAcAAABWBAAABwAAAImm" \ + "AAAHAAAACgAAAAAAAAAJAAAAQQBEAC0AUwBFAFIAVgBFAFIAAA" \ + "ADAAAAAAAAAAIAAABBAEQABAAAAAEEAAAAAAAFFQAAAPgSE9xH" \ + "8xx2Ry8u1wEAAAAwAAIABwAAAAUAAAABBQAAAAAABRUAAAApyU" \ + "/ZwjzDeDZVh/hUBAAAgD5SqNxk0QEGAHQAdQAxABgAEAAQACgA" \ + "AAAAAAAAAAB0AHUAMQBAAGEAZAAuAGQAZQB2AGUAbABBAEQALg" \ + "BEAEUAVgBFAEwAdv///4yBQZ5ZQnp3qwj2lKGcd0UAAAAAdv//" \ + "/39fn4UneD5l6YxP8w/U0coAAAAA" + +static void test_ad_get_data_from_pac(void **state) +{ + int ret; + struct PAC_LOGON_INFO *logon_info; + uint8_t *test_pac_blob; + size_t test_pac_blob_size; + + struct ad_common_test_ctx *test_ctx = talloc_get_type(*state, + struct ad_common_test_ctx); + + test_pac_blob = sss_base64_decode(test_ctx, TEST_PAC_BASE64, + &test_pac_blob_size); + assert_non_null(test_pac_blob_size); + + ret = ad_get_data_from_pac(test_ctx, test_pac_blob, test_pac_blob_size, + &logon_info); + assert_int_equal(ret, EOK); + assert_non_null(logon_info); + assert_string_equal(logon_info->info3.base.account_name.string, "tu1"); + assert_string_equal(logon_info->info3.base.full_name.string, "t u"); + assert_int_equal(logon_info->info3.base.rid, 1104); + assert_int_equal(logon_info->info3.base.primary_gid, 513); + assert_int_equal(logon_info->info3.base.groups.count, 5); + assert_string_equal(logon_info->info3.base.logon_domain.string, "AD"); + assert_int_equal(logon_info->info3.sidcount, 1); + + talloc_free(test_pac_blob); + talloc_free(logon_info); +} + +static void test_ad_get_sids_from_pac(void **state) +{ + int ret; + struct PAC_LOGON_INFO *logon_info; + uint8_t *test_pac_blob; + size_t test_pac_blob_size; + char *user_sid; + char *primary_group_sid; + size_t num_sids; + char **sid_list; + struct sss_idmap_ctx *idmap_ctx; + enum idmap_error_code err; + size_t c; + size_t s; + + const char *sid_check_list[] = { "S-1-5-21-3692237560-1981608775-3610128199-513", + "S-1-5-21-3692237560-1981608775-3610128199-1110", + "S-1-5-21-3692237560-1981608775-3610128199-1116", + "S-1-5-21-3692237560-1981608775-3610128199-41725", + "S-1-5-21-3692237560-1981608775-3610128199-42633", + "S-1-5-21-3645884713-2026060994-4169618742-1108", + NULL }; + + struct ad_common_test_ctx *test_ctx = talloc_get_type(*state, + struct ad_common_test_ctx); + + err = sss_idmap_init(sss_idmap_talloc, test_ctx, sss_idmap_talloc_free, + &idmap_ctx); + assert_int_equal(err, IDMAP_SUCCESS); + + test_pac_blob = sss_base64_decode(test_ctx, TEST_PAC_BASE64, + &test_pac_blob_size); + assert_non_null(test_pac_blob_size); + + ret = ad_get_data_from_pac(test_ctx, test_pac_blob, test_pac_blob_size, + &logon_info); + assert_int_equal(ret, EOK); + + ret = ad_get_sids_from_pac(test_ctx, idmap_ctx, logon_info, &user_sid, + &primary_group_sid, &num_sids, &sid_list); + assert_int_equal(ret, EOK); + assert_string_equal(user_sid, + "S-1-5-21-3692237560-1981608775-3610128199-1104"); + assert_string_equal(primary_group_sid, + "S-1-5-21-3692237560-1981608775-3610128199-513"); + assert_int_equal(num_sids, 6); + + for (c = 0; sid_check_list[c] != NULL; c++) { + for (s = 0; s < num_sids; s++) { + if (strcmp(sid_check_list[c], sid_list[s]) == 0) { + break; + } + } + if (s == num_sids) { + fail_msg("SID [%s] not found in SID list.", sid_check_list[c]); + } + } + + talloc_free(test_pac_blob); + talloc_free(logon_info); + talloc_free(user_sid); + talloc_free(primary_group_sid); + talloc_free(sid_list); + sss_idmap_free(idmap_ctx); +} + +static void test_ad_get_pac_data_from_user_entry(void **state) +{ + int ret; + struct ldb_message *user_msg; + struct ldb_val val; + struct ad_common_test_ctx *test_ctx = talloc_get_type(*state, + struct ad_common_test_ctx); + struct sss_idmap_ctx *idmap_ctx; + enum idmap_error_code err; + char *username; + char *user_sid; + char *primary_group_sid; + size_t num_sids; + char **sid_list; + size_t c; + size_t s; + const char *sid_check_list[] = { "S-1-5-21-3692237560-1981608775-3610128199-513", + "S-1-5-21-3692237560-1981608775-3610128199-1110", + "S-1-5-21-3692237560-1981608775-3610128199-1116", + "S-1-5-21-3692237560-1981608775-3610128199-41725", + "S-1-5-21-3692237560-1981608775-3610128199-42633", + "S-1-5-21-3645884713-2026060994-4169618742-1108", + NULL }; + + err = sss_idmap_init(sss_idmap_talloc, test_ctx, sss_idmap_talloc_free, + &idmap_ctx); + assert_int_equal(err, IDMAP_SUCCESS); + + user_msg = ldb_msg_new(test_ctx); + assert_non_null(user_msg); + + ret = ldb_msg_add_string(user_msg, SYSDB_NAME, "username"); + assert_int_equal(ret, EOK); + ret = ldb_msg_add_string(user_msg, SYSDB_OBJECTCLASS, "user"); + assert_int_equal(ret, EOK); + ret = ldb_msg_add_string(user_msg, SYSDB_PAC_BLOB_EXPIRE, "12345"); + assert_int_equal(ret, EOK); + val.data = sss_base64_decode(test_ctx, TEST_PAC_BASE64, &val.length); + ret = ldb_msg_add_value(user_msg, SYSDB_PAC_BLOB, &val, NULL); + assert_int_equal(ret, EOK); + + + ret = ad_get_pac_data_from_user_entry(test_ctx, user_msg, idmap_ctx, + &username, &user_sid, + &primary_group_sid, &num_sids, + &sid_list); + assert_int_equal(ret, EOK); + assert_string_equal(username, "username"); + assert_string_equal(user_sid, + "S-1-5-21-3692237560-1981608775-3610128199-1104"); + assert_string_equal(primary_group_sid, + "S-1-5-21-3692237560-1981608775-3610128199-513"); + assert_int_equal(num_sids, 6); + for (c = 0; sid_check_list[c] != NULL; c++) { + for (s = 0; s < num_sids; s++) { + if (strcmp(sid_check_list[c], sid_list[s]) == 0) { + break; + } + } + if (s == num_sids) { + fail_msg("SID [%s] not found in SID list.", sid_check_list[c]); + } + } + + talloc_free(username); + talloc_free(user_sid); + talloc_free(primary_group_sid); + talloc_free(sid_list); + talloc_free(val.data); + talloc_free(user_msg); + sss_idmap_free(idmap_ctx); +} + krb5_error_code __wrap_krb5_kt_default(krb5_context context, krb5_keytab *id) { return krb5_kt_resolve(context, KEYTAB_PATH, id); @@ -81,6 +403,8 @@ static void test_ad_create_default_options(void **state) assert_null(s); assert_non_null(ad_options->id); + + talloc_free(ad_options); } static int test_ad_common_setup(void **state) @@ -479,6 +803,7 @@ int main(int argc, const char *argv[]) { poptContext pc; int opt; + int ret; struct poptOption long_options[] = { POPT_AUTOHELP SSSD_DEBUG_OPTS @@ -505,6 +830,18 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_user_conn_list, test_ldap_conn_setup, test_ldap_conn_teardown), + cmocka_unit_test_setup_teardown(test_check_if_pac_is_available, + test_ad_sysdb_setup, + test_ad_sysdb_teardown), + cmocka_unit_test_setup_teardown(test_ad_get_data_from_pac, + test_ad_common_setup, + test_ad_common_teardown), + cmocka_unit_test_setup_teardown(test_ad_get_sids_from_pac, + test_ad_common_setup, + test_ad_common_teardown), + cmocka_unit_test_setup_teardown(test_ad_get_pac_data_from_user_entry, + test_ad_common_setup, + test_ad_common_teardown), }; /* Set debug level to invalid value so we can deside if -d 0 was used. */ @@ -526,5 +863,12 @@ int main(int argc, const char *argv[]) tests_set_cwd(); - return cmocka_run_group_tests(tests, NULL, NULL); + ret = cmocka_run_group_tests(tests, NULL, NULL); + +#ifdef HAVE_NSS + /* Cleanup NSS and NSPR to make valgrind happy. */ + nspr_nss_cleanup(); +#endif + + return ret; } -- 2.1.0