From 1a456e464803c6d1e82081e9b4d618fa0b07b3d7 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Nov 11 2012 02:44:29 +0000 Subject: Add diff_gid_lists() with test This patch adds a new call which compares a list of current GIDs with a list of new GIDs and return a list of GIDs which are currently missing and must be added and another list of GIDs which are not used anymore and must be deleted. The method is the same as used by diff_string_lists(). --- diff --git a/src/responder/pac/pacsrv.h b/src/responder/pac/pacsrv.h index e088e21..c0a13a3 100644 --- a/src/responder/pac/pacsrv.h +++ b/src/responder/pac/pacsrv.h @@ -67,6 +67,12 @@ struct local_mapping_ranges { struct range secondary_rids; }; +struct grp_info { + gid_t gid; + char *orig_dn; + struct ldb_dn *dn; +}; + int pac_cmd_execute(struct cli_ctx *cctx); struct sss_cmd_table *get_pac_cmds(void); @@ -106,4 +112,14 @@ errno_t get_pwd_from_pac(TALLOC_CTX *mem_ctx, struct PAC_LOGON_INFO *logon_info, struct passwd **_pwd, struct sysdb_attrs **_attrs); + +errno_t diff_gid_lists(TALLOC_CTX *mem_ctx, + size_t cur_grp_num, + struct grp_info *cur_gid_list, + size_t new_gid_num, + gid_t *new_gid_list, + size_t *_add_gid_num, + gid_t **_add_gid_list, + size_t *_del_gid_num, + struct grp_info ***_del_gid_list); #endif /* __PACSRV_H__ */ diff --git a/src/responder/pac/pacsrv_utils.c b/src/responder/pac/pacsrv_utils.c index 101960f..c9551c9 100644 --- a/src/responder/pac/pacsrv_utils.c +++ b/src/responder/pac/pacsrv_utils.c @@ -616,3 +616,159 @@ done: return ret; } + +errno_t diff_gid_lists(TALLOC_CTX *mem_ctx, + size_t cur_grp_num, + struct grp_info *cur_grp_list, + size_t new_gid_num, + gid_t *new_gid_list, + size_t *_add_gid_num, + gid_t **_add_gid_list, + size_t *_del_grp_num, + struct grp_info ***_del_grp_list) +{ + int ret; + size_t c; + hash_table_t *table; + hash_key_t key; + hash_value_t value; + size_t add_gid_num = 0; + gid_t *add_gid_list = NULL; + size_t del_grp_num = 0; + struct grp_info **del_grp_list = NULL; + TALLOC_CTX *tmp_ctx = NULL; + unsigned long value_count; + hash_value_t *values; + + if ((cur_grp_num != 0 && cur_grp_list == NULL) || + (new_gid_num != 0 && new_gid_list == NULL)) { + DEBUG(SSSDBG_OP_FAILURE, ("Missing group array.\n")); + return EINVAL; + } + + if (cur_grp_num == 0 && new_gid_num == 0) { + ret = EOK; + goto done; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_new failed.\n")); + ret = ENOMEM; + goto done; + } + + if (cur_grp_num == 0 && new_gid_num != 0) { + add_gid_num = new_gid_num; + add_gid_list = talloc_array(tmp_ctx, gid_t, add_gid_num); + if (add_gid_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_array failed.\n")); + ret = ENOMEM; + goto done; + } + + for (c = 0; c < add_gid_num; c++) { + add_gid_list[c] = new_gid_list[c]; + } + + ret = EOK; + goto done; + } + + if (cur_grp_num != 0 && new_gid_num == 0) { + del_grp_num = cur_grp_num; + del_grp_list = talloc_array(tmp_ctx, struct grp_info *, del_grp_num); + if (del_grp_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_array failed.\n")); + ret = ENOMEM; + goto done; + } + + for (c = 0; c < del_grp_num; c++) { + del_grp_list[c] = &cur_grp_list[c]; + } + + ret = EOK; + goto done; + } + + /* Add all current GIDs to a hash and then compare with the new ones in a + * single loop */ + ret = sss_hash_create(tmp_ctx, cur_grp_num, &table); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("sss_hash_create failed.\n")); + goto done; + } + + key.type = HASH_KEY_ULONG; + value.type = HASH_VALUE_PTR; + for (c = 0; c < cur_grp_num; c++) { + key.ul = (unsigned long) cur_grp_list[c].gid; + value.ptr = &cur_grp_list[c]; + + ret = hash_enter(table, &key, &value); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("hash_enter failed.\n")); + ret = EIO; + goto done; + } + } + + for (c = 0; c < new_gid_num; c++) { + key.ul = (unsigned long) new_gid_list[c]; + + ret = hash_delete(table, &key); + if (ret == HASH_ERROR_KEY_NOT_FOUND) { + /* gid not found, must be added */ + add_gid_num++; + add_gid_list = talloc_realloc(tmp_ctx, add_gid_list, gid_t, add_gid_num); + if (add_gid_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_realloc failed.\n")); + ret = ENOMEM; + goto done; + } + + add_gid_list[add_gid_num - 1] = new_gid_list[c]; + } else if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("hash_delete failed.\n")); + ret = EIO; + goto done; + } + } + + /* the remaining entries in the hash are not in the new list anymore and + * must be deleted */ + ret = hash_values(table, &value_count, &values); + if (ret != HASH_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, ("hash_keys failed.\n")); + ret = EIO; + goto done; + } + + del_grp_num = value_count; + del_grp_list = talloc_array(tmp_ctx, struct grp_info *, del_grp_num); + if (del_grp_list == NULL) { + DEBUG(SSSDBG_OP_FAILURE, ("talloc_array failed.\n")); + ret = ENOMEM; + goto done; + } + + for (c = 0; c < del_grp_num; c++) { + del_grp_list[c] = (struct grp_info *) values[c].ptr; + } + + ret = EOK; + +done: + + if (ret == EOK) { + *_add_gid_num = add_gid_num; + *_add_gid_list = talloc_steal(mem_ctx, add_gid_list); + *_del_grp_num = del_grp_num; + *_del_grp_list = talloc_steal(mem_ctx, del_grp_list); + } + + talloc_free(tmp_ctx); + + return ret; +} diff --git a/src/tests/pac_responder-tests.c b/src/tests/pac_responder-tests.c index 720793c..02cc242 100644 --- a/src/tests/pac_responder-tests.c +++ b/src/tests/pac_responder-tests.c @@ -70,18 +70,123 @@ START_TEST(pac_test_seondary_local_sid_to_id) } END_TEST +START_TEST(pac_test_get_gids_to_add_and_remove) +{ + TALLOC_CTX *mem_ctx; + int ret; + size_t c; + size_t add_gid_count = 0; + gid_t *add_gids = NULL; + size_t del_gid_count = 0; + struct grp_info **del_gids = NULL; + + gid_t gid_list_2[] = {2}; + gid_t gid_list_3[] = {3}; + gid_t gid_list_23[] = {2, 3}; + + struct grp_info grp_info_1 = {1, NULL, NULL}; + struct grp_info grp_info_2 = {2, NULL, NULL}; + struct grp_info grp_list_1[] = {grp_info_1}; + struct grp_info grp_list_12[] = {grp_info_1, grp_info_2}; + + struct a_and_r_data { + size_t cur_gid_count; + struct grp_info *cur_gids; + size_t gid_count; + gid_t *gids; + int exp_ret; + size_t exp_add_gid_count; + gid_t *exp_add_gids; + size_t exp_del_gid_count; + struct grp_info *exp_del_gids; + } a_and_r_data[] = { + {1, grp_list_1, 1, gid_list_2, EOK, 1, gid_list_2, 1, grp_list_1}, + {1, grp_list_1, 0, NULL, EOK, 0, NULL, 1, grp_list_1}, + {0, NULL, 1, gid_list_2, EOK, 1, gid_list_2, 0, NULL}, + {2, grp_list_12, 1, gid_list_2, EOK, 0, NULL, 1, grp_list_1}, + {2, grp_list_12, 2, gid_list_23, EOK, 1, gid_list_3, 1, grp_list_1}, + {0, NULL, 0, NULL, 0, 0, NULL, 0, NULL} + }; + + mem_ctx = talloc_new(NULL); + fail_unless(mem_ctx != NULL, "talloc_new failed."); + + ret = diff_gid_lists(mem_ctx, 0, NULL, 0, NULL, + &add_gid_count, &add_gids, + &del_gid_count, &del_gids); + fail_unless(ret == EOK, "get_gids_to_add_and_remove failed with empty " \ + "groups."); + + ret = diff_gid_lists(mem_ctx, 1, NULL, 0, NULL, + &add_gid_count, &add_gids, + &del_gid_count, &del_gids); + fail_unless(ret == EINVAL, "get_gids_to_add_and_remove failed with " \ + "invalid current groups."); + + ret = diff_gid_lists(mem_ctx, 0, NULL, 1, NULL, + &add_gid_count, &add_gids, + &del_gid_count, &del_gids); + fail_unless(ret == EINVAL, "get_gids_to_add_and_remove failed with " \ + "invalid new groups."); + + for (c = 0; a_and_r_data[c].cur_gids != NULL || + a_and_r_data[c].gids != NULL; c++) { + ret = diff_gid_lists(mem_ctx, + a_and_r_data[c].cur_gid_count, + a_and_r_data[c].cur_gids, + a_and_r_data[c].gid_count, + a_and_r_data[c].gids, + &add_gid_count, &add_gids, + &del_gid_count, &del_gids); + fail_unless(ret == a_and_r_data[c].exp_ret, + "Unexpected return value for test data #%d, " \ + "expected [%d], got [%d]", + c, a_and_r_data[c].exp_ret, ret); + fail_unless(add_gid_count == a_and_r_data[c].exp_add_gid_count, + "Unexpected numer of groups to add for test data #%d, " \ + "expected [%d], got [%d]", + c, a_and_r_data[c].exp_add_gid_count, add_gid_count); + fail_unless(del_gid_count == a_and_r_data[c].exp_del_gid_count, + "Unexpected numer of groups to delete for test data #%d, " \ + "expected [%d], got [%d]", + c, a_and_r_data[c].exp_del_gid_count, del_gid_count); + + /* The lists might be returned in any order, to make tests simple we + * only look at lists with 1 element. TODO: add code to compare lists + * with more than 1 member. */ + if (add_gid_count == 1) { + fail_unless(add_gids[0] == a_and_r_data[c].exp_add_gids[0], + "Unexpected gid to add for test data #%d, " \ + "expected [%d], got [%d]", + c, a_and_r_data[c].exp_add_gids[0], add_gids[0]); + } + + if (del_gid_count == 1) { + fail_unless(del_gids[0]->gid == a_and_r_data[c].exp_del_gids[0].gid, + "Unexpected gid to delete for test data #%d, " \ + "expected [%d], got [%d]", + c, a_and_r_data[c].exp_del_gids[0].gid, + del_gids[0]->gid); + } + } + + talloc_free(mem_ctx); +} +END_TEST + Suite *idmap_test_suite (void) { Suite *s = suite_create ("PAC responder"); TCase *tc_pac = tcase_create("PAC responder tests"); - /*tcase_add_checked_fixture(tc_init, + tcase_add_checked_fixture(tc_pac, leak_check_setup, - leak_check_teardown);*/ + leak_check_teardown); tcase_add_test(tc_pac, pac_test_local_sid_to_id); tcase_add_test(tc_pac, pac_test_seondary_local_sid_to_id); + tcase_add_test(tc_pac, pac_test_get_gids_to_add_and_remove); suite_add_tcase(s, tc_pac);