summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ldb_modules/memberof.c271
-rw-r--r--src/tests/sysdb-tests.c480
2 files changed, 715 insertions, 36 deletions
diff --git a/src/ldb_modules/memberof.c b/src/ldb_modules/memberof.c
index 7b6e3b799..2f81f9db8 100644
--- a/src/ldb_modules/memberof.c
+++ b/src/ldb_modules/memberof.c
@@ -45,6 +45,11 @@
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
+struct mbof_val_array {
+ struct ldb_val *vals;
+ int num;
+};
+
struct mbof_dn_array {
struct ldb_dn **dns;
int num;
@@ -147,11 +152,15 @@ struct mbof_mod_ctx {
struct mbof_ctx *ctx;
const struct ldb_message_element *membel;
+ const struct ldb_message_element *ghel;
struct ldb_message *entry;
struct mbof_dn_array *mb_add;
struct mbof_dn_array *mb_remove;
+ struct mbof_val_array *gh_add;
+ struct mbof_val_array *gh_remove;
+
struct ldb_message *msg;
bool terminate;
};
@@ -2279,7 +2288,8 @@ static int mbof_del_mod_callback(struct ldb_request *req,
}
static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
- struct mbof_dn_array *ael);
+ struct mbof_dn_array *ael,
+ struct mbof_val_array *addgh);
static int mbof_del_progeny(struct mbof_del_operation *delop)
{
@@ -2338,7 +2348,8 @@ static int mbof_del_progeny(struct mbof_del_operation *delop)
/* see if there are follow functions to run */
if (del_ctx->follow_mod) {
return mbof_mod_add(del_ctx->follow_mod,
- del_ctx->follow_mod->mb_add);
+ del_ctx->follow_mod->mb_add,
+ del_ctx->follow_mod->gh_add);
}
/* ok, no more ops, this means our job is done */
@@ -2619,7 +2630,8 @@ static int mbof_del_muop_callback(struct ldb_request *req,
/* see if there are follow functions to run */
else if (del_ctx->follow_mod) {
return mbof_mod_add(del_ctx->follow_mod,
- del_ctx->follow_mod->mb_add);
+ del_ctx->follow_mod->mb_add,
+ del_ctx->follow_mod->gh_add);
}
else {
return ldb_module_done(ctx->req,
@@ -2731,7 +2743,8 @@ static int mbof_del_ghop_callback(struct ldb_request *req,
/* see if there are follow functions to run */
else if (del_ctx->follow_mod) {
return mbof_mod_add(del_ctx->follow_mod,
- del_ctx->follow_mod->mb_add);
+ del_ctx->follow_mod->mb_add,
+ del_ctx->follow_mod->gh_add);
}
else {
return ldb_module_done(ctx->req,
@@ -2784,19 +2797,30 @@ static int mbof_mod_process_membel(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
const struct ldb_message_element *membel,
struct mbof_dn_array **_added,
struct mbof_dn_array **_removed);
+static int mbof_mod_process_ghel(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+ struct ldb_message *entry,
+ const struct ldb_message_element *membel,
+ struct mbof_val_array **_added,
+ struct mbof_val_array **_removed);
static int mbof_mod_delete(struct mbof_mod_ctx *mod_ctx,
- struct mbof_dn_array *del);
+ struct mbof_dn_array *del,
+ struct mbof_val_array *delgh);
static int mbof_fill_dn_array(TALLOC_CTX *memctx,
struct ldb_context *ldb,
const struct ldb_message_element *el,
struct mbof_dn_array **dn_array);
+static int mbof_fill_vals_array(TALLOC_CTX *memctx,
+ struct ldb_context *ldb,
+ const struct ldb_message_element *el,
+ struct mbof_val_array **val_array);
static int memberof_mod(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_message_element *el;
struct mbof_mod_ctx *mod_ctx;
struct mbof_ctx *ctx;
- static const char *attrs[] = {DB_MEMBER, DB_MEMBEROF, NULL};
+ static const char *attrs[] = { DB_OC, DB_GHOST,
+ DB_MEMBER, DB_MEMBEROF, NULL};
struct ldb_context *ldb = ldb_module_get_ctx(module);
struct ldb_request *search;
int ret;
@@ -2839,15 +2863,15 @@ static int memberof_mod(struct ldb_module *module, struct ldb_request *req)
return LDB_ERR_OPERATIONS_ERROR;
}
- /* continue with normal ops if there are no members */
- el = ldb_msg_find_element(mod_ctx->msg, DB_MEMBER);
- if (!el) {
+ mod_ctx->membel = ldb_msg_find_element(mod_ctx->msg, DB_MEMBER);
+ mod_ctx->ghel = ldb_msg_find_element(mod_ctx->msg, DB_GHOST);
+
+ /* continue with normal ops if there are no members and no ghosts */
+ if (mod_ctx->membel == NULL && mod_ctx->ghel == NULL) {
mod_ctx->terminate = true;
return mbof_orig_mod(mod_ctx);
}
- mod_ctx->membel = el;
-
/* can't do anything,
* must check first what's on the entry */
ret = ldb_build_search_req(&search, ldb, mod_ctx,
@@ -3020,16 +3044,24 @@ static int mbof_mod_process(struct mbof_mod_ctx *mod_ctx, bool *done)
return ret;
}
+ ret = mbof_mod_process_ghel(mod_ctx, ldb, mod_ctx->entry, mod_ctx->ghel,
+ &mod_ctx->gh_add, &mod_ctx->gh_remove);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
/* Process the operations */
/* if we have something to remove do it first */
- if (mod_ctx->mb_remove && mod_ctx->mb_remove->num) {
- return mbof_mod_delete(mod_ctx, mod_ctx->mb_remove);
+ if ((mod_ctx->mb_remove && mod_ctx->mb_remove->num) ||
+ (mod_ctx->gh_remove && mod_ctx->gh_remove->num)) {
+ return mbof_mod_delete(mod_ctx, mod_ctx->mb_remove, mod_ctx->gh_remove);
}
/* if there is nothing to remove and we have stuff to add
* do it right away */
- if (mod_ctx->mb_add && mod_ctx->mb_add->num) {
- return mbof_mod_add(mod_ctx, mod_ctx->mb_add);
+ if ((mod_ctx->mb_add && mod_ctx->mb_add->num) ||
+ (mod_ctx->gh_add && mod_ctx->gh_add->num)) {
+ return mbof_mod_add(mod_ctx, mod_ctx->mb_add, mod_ctx->gh_add);
}
/* the replacement function resulted in a null op,
@@ -3137,8 +3169,109 @@ static int mbof_mod_process_membel(TALLOC_CTX *mem_ctx,
return LDB_SUCCESS;
}
+static int mbof_mod_process_ghel(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+ struct ldb_message *entry,
+ const struct ldb_message_element *ghel,
+ struct mbof_val_array **_added,
+ struct mbof_val_array **_removed)
+{
+ const struct ldb_message_element *el;
+ struct mbof_val_array *removed = NULL;
+ struct mbof_val_array *added = NULL;
+ int i, j, ret;
+
+ if (!ghel) {
+ /* Nothing to do.. */
+ return LDB_SUCCESS;
+ }
+
+ el = ldb_msg_find_element(entry, DB_MEMBEROF);
+ if (!el || el->num_values == 0) {
+ /* no memberof attributes ... */
+ return LDB_SUCCESS;
+ }
+
+ switch (ghel->flags) {
+ case LDB_FLAG_MOD_ADD:
+ ret = mbof_fill_vals_array(mem_ctx, ldb, ghel, &added);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ break;
+
+ case LDB_FLAG_MOD_DELETE:
+ if (ghel->num_values == 0) {
+ el = ldb_msg_find_element(entry, DB_GHOST);
+ } else {
+ el = ghel;
+ }
+
+ if (!el) {
+ /* nothing to do really */
+ break;
+ }
+
+ ret = mbof_fill_vals_array(mem_ctx, ldb, ghel, &removed);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ break;
+
+ case LDB_FLAG_MOD_REPLACE:
+ el = ldb_msg_find_element(entry, DB_GHOST);
+ if (el) {
+ ret = mbof_fill_vals_array(mem_ctx, ldb, el, &removed);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ el = ghel;
+ if (el) {
+ ret = mbof_fill_vals_array(mem_ctx, ldb, el, &added);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(removed);
+ return ret;
+ }
+ }
+
+ /* remove from arrays values that ended up unchanged */
+ if (removed && removed->num && added && added->num) {
+ for (i = 0; i < added->num; i++) {
+ for (j = 0; j < removed->num; j++) {
+ if (strcmp((const char *) added->vals[i].data,
+ (const char *) removed->vals[j].data) == 0) {
+ break;
+ }
+ }
+ if (j < removed->num) {
+ /* preexisting one, not removed, nor added */
+ for (; j+1 < removed->num; j++) {
+ removed->vals[j] = removed->vals[j+1];
+ }
+ removed->num--;
+ for (j = i; j+1 < added->num; j++) {
+ added->vals[j] = added->vals[j+1];
+ }
+ added->num--;
+ i--;
+ }
+ }
+ }
+ break;
+
+ default:
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ *_added = added;
+ *_removed = removed;
+ return LDB_SUCCESS;
+}
+
static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
- struct mbof_dn_array *ael)
+ struct mbof_dn_array *ael,
+ struct mbof_val_array *addgh)
{
const struct ldb_message_element *el;
struct mbof_dn_array *parents;
@@ -3158,14 +3291,6 @@ static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
return ret;
}
- parents->dns = talloc_realloc(parents, parents->dns,
- struct ldb_dn *, parents->num + 1);
- if (!parents->dns) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
- parents->dns[parents->num] = mod_ctx->entry->dn;
- parents->num++;
-
add_ctx = talloc_zero(mod_ctx, struct mbof_add_ctx);
if (!add_ctx) {
return LDB_ERR_OPERATIONS_ERROR;
@@ -3173,18 +3298,42 @@ static int mbof_mod_add(struct mbof_mod_ctx *mod_ctx,
add_ctx->ctx = ctx;
add_ctx->msg_dn = mod_ctx->msg->dn;
- for (i = 0; i < ael->num; i++) {
- ret = mbof_append_addop(add_ctx, parents, ael->dns[i]);
+ if (addgh != NULL) {
+ /* Build the memberuid add op */
+ ret = mbof_add_fill_ghop_ex(add_ctx, mod_ctx->entry,
+ parents, addgh->vals, addgh->num);
if (ret != LDB_SUCCESS) {
return ret;
}
}
- return mbof_next_add(add_ctx->add_list);
+ if (ael != NULL) {
+ /* Add itself to the list of the parents to also get the memberuid */
+ parents->dns = talloc_realloc(parents, parents->dns,
+ struct ldb_dn *, parents->num + 1);
+ if (!parents->dns) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ parents->dns[parents->num] = mod_ctx->entry->dn;
+ parents->num++;
+
+ /* Build the member-add array */
+ for (i = 0; i < ael->num; i++) {
+ ret = mbof_append_addop(add_ctx, parents, ael->dns[i]);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return mbof_next_add(add_ctx->add_list);
+ }
+
+ return mbof_add_muop(add_ctx);
}
static int mbof_mod_delete(struct mbof_mod_ctx *mod_ctx,
- struct mbof_dn_array *del)
+ struct mbof_dn_array *del,
+ struct mbof_val_array *delgh)
{
struct mbof_del_operation *first;
struct mbof_del_ctx *del_ctx;
@@ -3209,25 +3358,39 @@ static int mbof_mod_delete(struct mbof_mod_ctx *mod_ctx,
}
del_ctx->first = first;
+ /* add followup function if we also have stuff to add */
+ if ((mod_ctx->mb_add && mod_ctx->mb_add->num > 0) ||
+ (mod_ctx->gh_add && mod_ctx->gh_add->num > 0)) {
+ del_ctx->follow_mod = mod_ctx;
+ }
+
first->del_ctx = del_ctx;
first->entry = mod_ctx->entry;
first->entry_dn = mod_ctx->entry->dn;
- /* prepare del sets */
- for (i = 0; i < del->num; i++) {
- ret = mbof_append_delop(first, del->dns[i]);
+ if (delgh != NULL) {
+ ret = mbof_del_fill_ghop_ex(del_ctx, del_ctx->first->entry,
+ delgh->vals, delgh->num);
if (ret != LDB_SUCCESS) {
return ret;
}
}
- /* add followup function if we also have stuff to add */
- if (mod_ctx->mb_add) {
- del_ctx->follow_mod = mod_ctx;
+ /* prepare del sets */
+ if (del != NULL) {
+ for (i = 0; i < del->num; i++) {
+ ret = mbof_append_delop(first, del->dns[i]);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ /* now that sets are built, start processing */
+ return mbof_del_execute_op(first->children[0]);
}
- /* now that sets are built, start processing */
- return mbof_del_execute_op(first->children[0]);
+ /* No member processing, just delete ghosts */
+ return mbof_del_ghop(del_ctx);
}
static int mbof_fill_dn_array(TALLOC_CTX *memctx,
@@ -3268,6 +3431,42 @@ static int mbof_fill_dn_array(TALLOC_CTX *memctx,
return LDB_SUCCESS;
}
+static int mbof_fill_vals_array(TALLOC_CTX *memctx,
+ struct ldb_context *ldb,
+ const struct ldb_message_element *el,
+ struct mbof_val_array **val_array)
+{
+ struct mbof_val_array *var;
+ int i;
+
+ var = talloc_zero(memctx, struct mbof_val_array);
+ if (!var) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ *val_array = var;
+
+ if (!el || el->num_values == 0) {
+ return LDB_SUCCESS;
+ }
+
+ var->vals = talloc_array(var, struct ldb_val, el->num_values);
+ if (!var->vals) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ var->num = el->num_values;
+
+ for (i = 0; i < var->num; i++) {
+ var->vals[i].length = strlen((const char *) el->values[i].data);
+ var->vals[i].data = (uint8_t *) talloc_strdup(var,
+ (const char *) el->values[i].data);
+ if (var->vals[i].data == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
/*************************
* Cleanup task routines *
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 85abc41ce..27095e1a2 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -1996,6 +1996,190 @@ START_TEST (test_sysdb_memberof_store_group_with_ghosts)
}
END_TEST
+
+START_TEST (test_sysdb_memberof_mod_add)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ char *ghostname;
+ int ret;
+ struct ldb_message_element *el;
+ struct ldb_val gv, *test_gv;
+ gid_t itergid;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i;
+ data->groupname = talloc_asprintf(data, "testgroup%d", data->gid);
+
+ data->attrs = sysdb_new_attrs(data);
+ if (ret != EOK) {
+ fail("Could not create the changeset");
+ return;
+ }
+
+ ghostname = talloc_asprintf(data, "testghost%d", _i);
+ fail_unless(ghostname != NULL, "Out of memory\n");
+ ret = sysdb_attrs_steal_string(data->attrs, SYSDB_GHOST, ghostname);
+ fail_unless(ret == EOK, "Cannot add attr\n");
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed.");
+ data->attrlist[0] = SYSDB_GHOST;
+ data->attrlist[1] = NULL;
+
+ /* Before the add, the groups should not contain the ghost attribute */
+ for (itergid = data->gid ; itergid < MBO_GROUP_BASE + NUM_GHOSTS; itergid++) {
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ itergid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname;
+ gv.length = strlen(ghostname);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ if (data->gid > MBO_GROUP_BASE) {
+ /* The first group would have the ghost attribute gone completely */
+ fail_if(el == NULL, "Cannot find ghost element\n");
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_unless(test_gv == NULL,
+ "Ghost user %s unexpectedly found\n", ghostname);
+ } else {
+ fail_unless(el == NULL, "Stray values in ghost element?\n");
+ }
+ }
+
+ /* Perform the add operation */
+ ret = sysdb_set_group_attr(test_ctx->sysdb, data->groupname,
+ data->attrs, SYSDB_MOD_ADD);
+ fail_unless(ret == EOK, "Cannot set group attrs\n");
+
+ /* Before the delete, all groups with gid >= _i have the testuser%_i
+ * as a member
+ */
+ for (itergid = data->gid ; itergid < MBO_GROUP_BASE + NUM_GHOSTS; itergid++) {
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ itergid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname;
+ gv.length = strlen(ghostname);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ fail_if(el == NULL, "Cannot find ghost element\n");
+
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_if(test_gv == NULL, "Cannot find ghost user %s\n", ghostname);
+ }
+ talloc_free(test_ctx);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_mod_replace)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ char *ghostname_del;
+ char *ghostname_add;
+ int ret;
+ struct ldb_message_element *el;
+ struct ldb_val gv, *test_gv;
+ gid_t itergid;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i;
+ data->groupname = talloc_asprintf(data, "testgroup%d", data->gid);
+
+ data->attrs = sysdb_new_attrs(data);
+ if (ret != EOK) {
+ fail("Could not create the changeset");
+ return;
+ }
+
+ /* The test replaces the testuser%i attribute with testghost%i */
+ ghostname_del = talloc_asprintf(data, "testuser%d", _i);
+ fail_unless(ghostname_del != NULL, "Out of memory\n");
+
+ ghostname_add = talloc_asprintf(data, "testghost%d", _i);
+ fail_unless(ghostname_add != NULL, "Out of memory\n");
+ ret = sysdb_attrs_steal_string(data->attrs, SYSDB_GHOST, ghostname_add);
+ fail_unless(ret == EOK, "Cannot add attr\n");
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed.");
+ data->attrlist[0] = SYSDB_GHOST;
+ data->attrlist[1] = NULL;
+
+ /* Before the replace, all groups with gid >= _i have the testuser%_i
+ * as a member
+ */
+ for (itergid = data->gid ; itergid < MBO_GROUP_BASE + NUM_GHOSTS; itergid++) {
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ itergid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname_del;
+ gv.length = strlen(ghostname_del);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ fail_if(el == NULL, "Cannot find ghost element\n");
+
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_if(test_gv == NULL, "Cannot find ghost user %s\n", ghostname_del);
+ }
+
+ /* Perform the replace operation */
+ ret = sysdb_set_group_attr(test_ctx->sysdb, data->groupname,
+ data->attrs, SYSDB_MOD_REP);
+ fail_unless(ret == EOK, "Cannot set group attrs\n");
+
+ /* After the replace, all groups with gid >= _i have the testghost%_i
+ * as a member
+ */
+ for (itergid = data->gid ; itergid < MBO_GROUP_BASE + NUM_GHOSTS; itergid++) {
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ itergid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname_add;
+ gv.length = strlen(ghostname_add);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ fail_if(el == NULL, "Cannot find ghost element\n");
+
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_if(test_gv == NULL, "Cannot find ghost user %s\n", ghostname_add);
+ }
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
START_TEST (test_sysdb_memberof_close_loop)
{
struct sysdb_test_ctx *test_ctx;
@@ -2367,6 +2551,97 @@ START_TEST (test_sysdb_memberof_remove_child_group_and_check_ghost)
}
END_TEST
+START_TEST (test_sysdb_memberof_mod_del)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ char *ghostname;
+ int ret;
+ struct ldb_message_element *el;
+ struct ldb_val gv, *test_gv;
+ gid_t itergid;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i;
+ data->groupname = talloc_asprintf(data, "testgroup%d", data->gid);
+
+ data->attrs = sysdb_new_attrs(data);
+ if (ret != EOK) {
+ fail("Could not create the changeset");
+ return;
+ }
+
+ ghostname = talloc_asprintf(data, "testuser%d", _i);
+ fail_unless(ghostname != NULL, "Out of memory\n");
+ ret = sysdb_attrs_steal_string(data->attrs, SYSDB_GHOST, ghostname);
+ fail_unless(ret == EOK, "Cannot add attr\n");
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed.");
+ data->attrlist[0] = SYSDB_GHOST;
+ data->attrlist[1] = NULL;
+
+ /* Before the delete, all groups with gid >= _i have the testuser%_i
+ * as a member
+ */
+ for (itergid = data->gid ; itergid < MBO_GROUP_BASE + NUM_GHOSTS; itergid++) {
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ itergid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname;
+ gv.length = strlen(ghostname);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ fail_if(el == NULL, "Cannot find ghost element\n");
+
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_if(test_gv == NULL, "Cannot find ghost user %s\n", ghostname);
+ }
+
+ /* Delete the attribute */
+ ret = sysdb_set_group_attr(test_ctx->sysdb, data->groupname,
+ data->attrs, SYSDB_MOD_DEL);
+ fail_unless(ret == EOK, "Cannot set group attrs\n");
+
+ /* After the delete, we shouldn't be able to find the ghost attribute */
+ for (itergid = data->gid ; itergid < MBO_GROUP_BASE + NUM_GHOSTS; itergid++) {
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ itergid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname;
+ gv.length = strlen(ghostname);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ if (itergid > data->gid) {
+ /* The first group would have the ghost attribute gone completely */
+ fail_if(el == NULL, "Cannot find ghost element\n");
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_unless(test_gv == NULL,
+ "Ghost user %s unexpectedly found\n", ghostname);
+ } else {
+ fail_unless(el == NULL, "Stray values in ghost element?\n");
+ }
+ }
+
+ talloc_free(test_ctx);
+}
+END_TEST
+
START_TEST (test_sysdb_memberof_check_ghost)
{
struct sysdb_test_ctx *test_ctx;
@@ -2521,6 +2796,170 @@ START_TEST (test_sysdb_memberof_check_convert)
}
END_TEST
+START_TEST (test_sysdb_memberof_ghost_replace)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ char *ghostname_del;
+ char *ghostname_add;
+ int ret;
+ struct ldb_message_element *el;
+ struct ldb_val gv, *test_gv;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i;
+ data->groupname = talloc_asprintf(data, "testgroup%d", data->gid);
+
+ data->attrs = sysdb_new_attrs(data);
+ if (ret != EOK) {
+ fail("Could not create the changeset");
+ return;
+ }
+
+ /* The test replaces the testghost%i attribute with testuser%i */
+ ghostname_del = talloc_asprintf(data, "testghost%d", _i - 1);
+ fail_unless(ghostname_del != NULL, "Out of memory\n");
+
+ ghostname_add = talloc_asprintf(data, "testuser%d", _i - 1);
+ fail_unless(ghostname_add != NULL, "Out of memory\n");
+ ret = sysdb_attrs_steal_string(data->attrs, SYSDB_GHOST, ghostname_add);
+ fail_unless(ret == EOK, "Cannot add attr\n");
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed.");
+ data->attrlist[0] = SYSDB_GHOST;
+ data->attrlist[1] = NULL;
+
+ /* Before the replace, the group has the testghost%_i as a member */
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ data->gid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname_del;
+ gv.length = strlen(ghostname_del);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ fail_if(el == NULL, "Cannot find ghost element\n");
+
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_if(test_gv == NULL, "Cannot find ghost user %s\n", ghostname_del);
+
+ /* Perform the replace operation */
+ ret = sysdb_set_group_attr(test_ctx->sysdb, data->groupname,
+ data->attrs, SYSDB_MOD_REP);
+ fail_unless(ret == EOK, "Cannot set group attrs\n");
+
+ /* After the replace, the group has the testghost%_i as a member */
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ data->gid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname_add;
+ gv.length = strlen(ghostname_add);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ fail_if(el == NULL, "Cannot find ghost element\n");
+
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_if(test_gv == NULL, "Cannot find ghost user %s\n", ghostname_add);
+}
+END_TEST
+
+START_TEST (test_sysdb_memberof_ghost_replace_noop)
+{
+ struct sysdb_test_ctx *test_ctx;
+ struct test_data *data;
+ char *ghostname_del;
+ char *ghostname_add;
+ int ret;
+ struct ldb_message_element *el;
+ struct ldb_val gv, *test_gv;
+
+ /* Setup */
+ ret = setup_sysdb_tests(&test_ctx);
+ if (ret != EOK) {
+ fail("Could not set up the test");
+ return;
+ }
+
+ data = talloc_zero(test_ctx, struct test_data);
+ data->ctx = test_ctx;
+ data->ev = test_ctx->ev;
+ data->gid = _i;
+ data->groupname = talloc_asprintf(data, "testgroup%d", data->gid);
+
+ data->attrs = sysdb_new_attrs(data);
+ if (ret != EOK) {
+ fail("Could not create the changeset");
+ return;
+ }
+
+ /* The test replaces the testghost%i attribute with testuser%i */
+ ghostname_del = talloc_asprintf(data, "testuser%d", _i - 1);
+ fail_unless(ghostname_del != NULL, "Out of memory\n");
+
+ ghostname_add = talloc_asprintf(data, "testuser%d", _i - 1);
+ fail_unless(ghostname_add != NULL, "Out of memory\n");
+ ret = sysdb_attrs_steal_string(data->attrs, SYSDB_GHOST, ghostname_add);
+ fail_unless(ret == EOK, "Cannot add attr\n");
+
+ data->attrlist = talloc_array(data, const char *, 2);
+ fail_unless(data->attrlist != NULL, "talloc_array failed.");
+ data->attrlist[0] = SYSDB_GHOST;
+ data->attrlist[1] = NULL;
+
+ /* Before the replace, the group has the testghost%_i as a member */
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ data->gid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname_del;
+ gv.length = strlen(ghostname_del);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ fail_if(el == NULL, "Cannot find ghost element\n");
+
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_if(test_gv == NULL, "Cannot find ghost user %s\n", ghostname_del);
+
+ /* Perform the replace operation */
+ ret = sysdb_set_group_attr(test_ctx->sysdb, data->groupname,
+ data->attrs, SYSDB_MOD_REP);
+ fail_unless(ret == EOK, "Cannot set group attrs\n");
+
+ /* After the replace, the group has the testghost%_i as a member */
+ ret = sysdb_search_group_by_gid(data, test_ctx->sysdb,
+ data->gid,
+ data->attrlist, &data->msg);
+ fail_if(ret != EOK, "Cannot retrieve group %llu\n",
+ (unsigned long long) data->gid);
+
+ gv.data = (uint8_t *) ghostname_add;
+ gv.length = strlen(ghostname_add);
+
+ el = ldb_msg_find_element(data->msg, SYSDB_GHOST);
+ fail_if(el == NULL, "Cannot find ghost element\n");
+
+ test_gv = ldb_msg_find_val(el, &gv);
+ fail_if(test_gv == NULL, "Cannot find ghost user %s\n", ghostname_add);
+}
+END_TEST
+
START_TEST (test_sysdb_memberof_user_cleanup)
{
struct sysdb_test_ctx *test_ctx;
@@ -4456,12 +4895,53 @@ Suite *create_sysdb_suite(void)
/* Check the members and ghosts are there as appropriate */
tcase_add_loop_test(tc_memberof, test_sysdb_memberof_check_convert,
MBO_GROUP_BASE , MBO_GROUP_BASE + NUM_GHOSTS);
+ /* Rename the other half */
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_ghost_replace,
+ MBO_GROUP_BASE + NUM_GHOSTS/2 + 1,
+ MBO_GROUP_BASE + NUM_GHOSTS);
+ /* Attempt to replace with the same data to check if noop works correctly */
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_ghost_replace_noop,
+ MBO_GROUP_BASE + NUM_GHOSTS/2 + 1,
+ MBO_GROUP_BASE + NUM_GHOSTS);
/* Remove the real users */
tcase_add_loop_test(tc_memberof, test_sysdb_memberof_user_cleanup,
MBO_GROUP_BASE , MBO_GROUP_BASE + NUM_GHOSTS/2);
tcase_add_loop_test(tc_memberof, test_sysdb_remove_local_group_by_gid,
MBO_GROUP_BASE , MBO_GROUP_BASE + NUM_GHOSTS);
+ /* ghost users - memberof mod_del */
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_store_group_with_ghosts,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_check_nested_ghosts,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_mod_del,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_remove_local_group_by_gid,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + NUM_GHOSTS);
+
+ /* ghost users - memberof mod_add */
+ /* Add groups without ghosts first */
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_store_group, 0, 10);
+ /* Add ghosts to groups so that they propagate */
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_mod_add,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+ /* Check if the ghosts in fact propagated */
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_check_nested_ghosts,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+ /* Clean up */
+ tcase_add_loop_test(tc_memberof, test_sysdb_remove_local_group_by_gid,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+
+ /* ghost users - replace */
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_store_group_with_ghosts,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_check_nested_ghosts,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_memberof_mod_replace,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+ tcase_add_loop_test(tc_memberof, test_sysdb_remove_local_group_by_gid,
+ MBO_GROUP_BASE , MBO_GROUP_BASE + 10);
+
suite_add_tcase(s, tc_memberof);
TCase *tc_subdomain = tcase_create("SYSDB sub-domain Tests");