diff options
-rw-r--r-- | src/responder/pac/pacsrv.h | 16 | ||||
-rw-r--r-- | src/responder/pac/pacsrv_utils.c | 156 | ||||
-rw-r--r-- | src/tests/pac_responder-tests.c | 109 |
3 files changed, 279 insertions, 2 deletions
diff --git a/src/responder/pac/pacsrv.h b/src/responder/pac/pacsrv.h index e088e212..c0a13a33 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 101960f0..c9551c99 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 720793cc..02cc242a 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); |