summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2011-01-12 16:41:26 -0500
committerStephen Gallagher <sgallagh@redhat.com>2011-01-21 16:34:54 -0500
commitc6257286e9a31dfd42d28c99a22a69e2c4717a61 (patch)
treeb51f2c14c4d916ca385c38d002d6fd8e136bebb3
parentc3a2e4aae7198a5ec2ac8ff028d2379668dc8aa1 (diff)
downloadsssd-c6257286e9a31dfd42d28c99a22a69e2c4717a61.tar.gz
sssd-c6257286e9a31dfd42d28c99a22a69e2c4717a61.tar.bz2
sssd-c6257286e9a31dfd42d28c99a22a69e2c4717a61.zip
Delete attributes that are removed from LDAP
Sometimes, a value in LDAP will cease to exist (the classic example being shadowExpire). We need to make sure we purge that value from SSSD's sysdb as well. https://fedorahosted.org/sssd/ticket/750
-rw-r--r--src/db/sysdb.h7
-rw-r--r--src/db/sysdb_ops.c118
-rw-r--r--src/providers/ldap/ldap_common.c117
-rw-r--r--src/providers/ldap/ldap_common.h13
-rw-r--r--src/providers/ldap/sdap_async_accounts.c41
-rw-r--r--src/providers/proxy/proxy_id.c12
-rw-r--r--src/tests/sysdb-tests.c2
7 files changed, 297 insertions, 13 deletions
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 3fefdf21..ae0b33ce 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -521,6 +521,7 @@ int sysdb_store_user(TALLOC_CTX *mem_ctx,
const char *homedir,
const char *shell,
struct sysdb_attrs *attrs,
+ char **remove_attrs,
uint64_t cache_timeout);
int sysdb_store_group(TALLOC_CTX *mem_ctx,
@@ -712,4 +713,10 @@ errno_t sysdb_set_enumerated(struct sysdb_ctx *ctx,
struct sss_domain_info *dom,
bool enumerated);
+errno_t sysdb_remove_attrs(struct sysdb_ctx *sysdb,
+ struct sss_domain_info *domain,
+ const char *name,
+ enum sysdb_member_type type,
+ char **remove_attrs);
+
#endif /* __SYS_DB_H__ */
diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index e8ef9a24..c36b0ee8 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -1362,12 +1362,15 @@ int sysdb_store_user(TALLOC_CTX *mem_ctx,
const char *homedir,
const char *shell,
struct sysdb_attrs *attrs,
+ char **remove_attrs,
uint64_t cache_timeout)
{
TALLOC_CTX *tmpctx;
struct ldb_message *msg;
time_t now;
int ret;
+ errno_t sret = EOK;
+ bool in_transaction = false;
tmpctx = talloc_new(mem_ctx);
if (!tmpctx) {
@@ -1379,6 +1382,11 @@ int sysdb_store_user(TALLOC_CTX *mem_ctx,
if (ret) goto done;
}
+ ret = sysdb_transaction_start(ctx);
+ if (ret != EOK) goto done;
+
+ in_transaction = true;
+
ret = sysdb_search_user_by_name(tmpctx, ctx,
domain, name, NULL, &msg);
if (ret && ret != ENOENT) {
@@ -1443,8 +1451,33 @@ int sysdb_store_user(TALLOC_CTX *mem_ctx,
ret = sysdb_set_user_attr(tmpctx, ctx,
domain, name, attrs, SYSDB_MOD_REP);
+ if (ret != EOK) goto done;
+
+ if (remove_attrs) {
+ ret = sysdb_remove_attrs(ctx, domain, name,
+ SYSDB_MEMBER_USER,
+ remove_attrs);
+ if (ret != EOK) {
+ DEBUG(4, ("Could not remove missing attributes\n"));
+ }
+ }
done:
+ if (in_transaction) {
+ if (ret == EOK) {
+ sret = sysdb_transaction_commit(ctx);
+ if (sret != EOK) {
+ DEBUG(2, ("Could not commit transaction\n"));
+ }
+ }
+
+ if (ret != EOK || sret != EOK){
+ sret = sysdb_transaction_cancel(ctx);
+ if (sret != EOK) {
+ DEBUG(2, ("Could not cancel transaction\n"));
+ }
+ }
+ }
if (ret) {
DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));
}
@@ -2767,3 +2800,88 @@ done:
talloc_free(msg);
return ret;
}
+
+errno_t sysdb_remove_attrs(struct sysdb_ctx *sysdb,
+ struct sss_domain_info *domain,
+ const char *name,
+ enum sysdb_member_type type,
+ char **remove_attrs)
+{
+ errno_t ret;
+ errno_t sret = EOK;
+ bool in_transaction = false;
+ struct ldb_message *msg;
+ int lret;
+ size_t i;
+
+ msg = ldb_msg_new(NULL);
+ if (!msg) return ENOMEM;
+
+ if (type == SYSDB_MEMBER_USER) {
+ msg->dn = sysdb_user_dn(sysdb, msg, domain->name, name);
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+ } else if (type == SYSDB_MEMBER_GROUP) {
+ msg->dn = sysdb_group_dn(sysdb, msg, domain->name, name);
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+ } else {
+ ret = EINVAL;
+ goto done;
+ }
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret != EOK) goto done;
+
+ in_transaction = true;
+
+ for (i = 0; remove_attrs[i]; i++) {
+ DEBUG(8, ("Removing attribute [%s] from [%s]\n",
+ remove_attrs[i], name));
+ lret = ldb_msg_add_empty(msg, remove_attrs[i],
+ LDB_FLAG_MOD_DELETE, NULL);
+ if (lret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(lret);
+ goto done;
+ }
+
+ /* We need to do individual modifies so that we can
+ * skip unknown attributes. Otherwise, any nonexistent
+ * attribute in the sysdb will cause other removals to
+ * fail.
+ */
+ lret = ldb_modify(sysdb->ldb, msg);
+ if (lret != LDB_SUCCESS && lret != LDB_ERR_NO_SUCH_ATTRIBUTE) {
+ ret = sysdb_error_to_errno(lret);
+ goto done;
+ }
+
+ /* Remove this attribute and move on to the next one */
+ ldb_msg_remove_attr(msg, remove_attrs[i]);
+ }
+
+ ret = EOK;
+
+done:
+ if (in_transaction) {
+ if (ret == EOK) {
+ sret = sysdb_transaction_commit(sysdb);
+ if (sret != EOK) {
+ DEBUG(2, ("Could not commit transaction\n"));
+ }
+ }
+
+ if (ret != EOK || sret != EOK){
+ sret = sysdb_transaction_cancel(sysdb);
+ if (sret != EOK) {
+ DEBUG(2, ("Could not cancel transaction\n"));
+ }
+ }
+ }
+ talloc_free(msg);
+ return ret;
+}
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index e669ba6c..f56d01f0 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -872,3 +872,120 @@ errno_t string_to_shadowpw_days(const char *s, long *d)
return EOK;
}
+errno_t get_sysdb_attr_name(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map *map,
+ size_t map_size,
+ const char *ldap_name,
+ char **sysdb_name)
+{
+ size_t i;
+
+ for (i = 0; i < map_size; i++) {
+ /* Skip map entries with no name (may depend on
+ * schema selected)
+ */
+ if (!map[i].name) continue;
+
+ /* Check if it is a mapped attribute */
+ if(strcasecmp(ldap_name, map[i].name) == 0) break;
+ }
+
+ if (i < map_size) {
+ /* We found a mapped name, return that */
+ *sysdb_name = talloc_strdup(mem_ctx, map[i].sys_name);
+ } else {
+ /* Not mapped, use the same name */
+ *sysdb_name = talloc_strdup(mem_ctx, ldap_name);
+ }
+
+ if (!*sysdb_name) {
+ return ENOMEM;
+ }
+
+ return EOK;
+}
+
+errno_t list_missing_attrs(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map *map,
+ size_t map_size,
+ const char **expected_attrs,
+ struct sysdb_attrs *recvd_attrs,
+ char ***missing_attrs)
+{
+ errno_t ret;
+ size_t attr_count = 0;
+ size_t i, j, k;
+ char **missing = NULL;
+ char *sysdb_name;
+ TALLOC_CTX *tmp_ctx;
+
+ if (!expected_attrs || !recvd_attrs || !missing_attrs) {
+ return EINVAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ /* Count the expected attrs */
+ while(expected_attrs[attr_count]) attr_count++;
+
+ /* Allocate the maximum possible values for missing_attrs, to
+ * be on the safe side
+ */
+ missing = talloc_array(tmp_ctx, char *, attr_count);
+ if (!missing) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ k = 0;
+ /* Check for each expected attribute */
+ for (i = 0; i < attr_count; i++) {
+ ret = get_sysdb_attr_name(tmp_ctx, map, map_size,
+ expected_attrs[i],
+ &sysdb_name);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* objectClass is a special-case and we need to
+ * check for it explicitly.
+ */
+ if (strcasecmp(sysdb_name, "objectClass") == 0) {
+ talloc_free(sysdb_name);
+ continue;
+ }
+
+ for (j = 0; j < recvd_attrs->num; j++) {
+ /* Check whether this expected attribute appeared in the
+ * received attributes and had a non-zero number of
+ * values.
+ */
+ if ((strcasecmp(recvd_attrs->a[j].name, sysdb_name) == 0) &&
+ (recvd_attrs->a[j].num_values > 0)) {
+ break;
+ }
+ }
+
+ if (j < recvd_attrs->num) {
+ /* Attribute was found, therefore not missing */
+ talloc_free(sysdb_name);
+ } else {
+ /* Attribute could not be found. Add to the missing list */
+ missing[k] = talloc_steal(missing, sysdb_name);
+ k++;
+ }
+ }
+
+ /* Terminate the list */
+ missing[k] = NULL;
+
+ ret = EOK;
+ *missing_attrs = talloc_steal(mem_ctx, missing);
+
+done:
+ talloc_free(tmp_ctx);
+ return ret;
+}
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index ba8d1303..3cbf3f60 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -142,4 +142,17 @@ int setup_child(struct sdap_id_ctx *ctx);
errno_t string_to_shadowpw_days(const char *s, long *d);
+
+errno_t get_sysdb_attr_name(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map *map,
+ size_t map_size,
+ const char *ldap_name,
+ char **sysdb_name);
+
+errno_t list_missing_attrs(TALLOC_CTX *mem_ctx,
+ struct sdap_attr_map *map,
+ size_t map_size,
+ const char **expected_attrs,
+ struct sysdb_attrs *recvd_attrs,
+ char ***missing_attrs);
#endif /* _LDAP_COMMON_H_ */
diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c
index 7abe3571..648f9a73 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_accounts.c
@@ -34,6 +34,7 @@ static int sdap_save_user(TALLOC_CTX *memctx,
struct sdap_options *opts,
struct sss_domain_info *dom,
struct sysdb_attrs *attrs,
+ const char **ldap_attrs,
bool is_initgr,
char **_usn_value)
{
@@ -53,6 +54,7 @@ static int sdap_save_user(TALLOC_CTX *memctx,
int cache_timeout;
char *usn_value = NULL;
size_t c;
+ char **missing = NULL;
DEBUG(9, ("Save user\n"));
@@ -266,12 +268,28 @@ static int sdap_save_user(TALLOC_CTX *memctx,
}
}
+ /* Make sure that any attributes we requested from LDAP that we
+ * did not receive are also removed from the sysdb
+ */
+ ret = list_missing_attrs(NULL, opts->user_map, SDAP_OPTS_USER,
+ ldap_attrs, attrs, &missing);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ /* Remove missing attributes */
+ if (missing && !missing[0]) {
+ /* Nothing to remove */
+ talloc_zfree(missing);
+ }
+
DEBUG(6, ("Storing info for user %s\n", name));
ret = sysdb_store_user(memctx, ctx, dom,
name, pwd, uid, gid, gecos, homedir, shell,
- user_attrs, cache_timeout);
+ user_attrs, missing, cache_timeout);
if (ret) goto fail;
+ talloc_zfree(missing);
if (_usn_value) {
*_usn_value = usn_value;
@@ -281,6 +299,7 @@ static int sdap_save_user(TALLOC_CTX *memctx,
fail:
DEBUG(2, ("Failed to save user %s\n", name));
+ talloc_free(missing);
return ret;
}
@@ -289,6 +308,7 @@ fail:
static int sdap_save_users(TALLOC_CTX *memctx,
struct sysdb_ctx *sysdb,
+ const char **attrs,
struct sss_domain_info *dom,
struct sdap_options *opts,
struct sysdb_attrs **users,
@@ -320,7 +340,8 @@ static int sdap_save_users(TALLOC_CTX *memctx,
usn_value = NULL;
ret = sdap_save_user(tmpctx, sysdb, opts, dom,
- users[i], false, &usn_value);
+ users[i], attrs, false,
+ &usn_value);
/* Do not fail completely on errors.
* Just report the failure to save and go on */
@@ -446,6 +467,7 @@ static void sdap_get_users_process(struct tevent_req *subreq)
}
ret = sdap_save_users(state, state->sysdb,
+ state->attrs,
state->dom, state->opts,
state->users, state->count,
&state->higher_usn);
@@ -1449,7 +1471,8 @@ next:
}
if (state->check_count == 0) {
- ret = sdap_save_users(state, state->sysdb, state->dom, state->opts,
+ ret = sdap_save_users(state, state->sysdb, state->attrs,
+ state->dom, state->opts,
state->new_members, state->count, NULL);
if (ret) {
DEBUG(2, ("Failed to store users.\n"));
@@ -1770,7 +1793,8 @@ static void sdap_nested_done(struct tevent_req *subreq)
/* Save all of the users first so that they are in
* place for the groups to add them.
*/
- ret = sdap_save_users(state, state->sysdb, state->dom, state->opts,
+ ret = sdap_save_users(state, state->sysdb, state->attrs,
+ state->dom, state->opts,
users, count, &state->higher_usn);
if (ret != EOK) {
tevent_req_error(req, ret);
@@ -2320,6 +2344,7 @@ struct sdap_get_initgr_state {
struct sdap_id_ctx *id_ctx;
const char *name;
const char **grp_attrs;
+ const char **ldap_attrs;
struct sysdb_attrs *orig_user;
};
@@ -2338,7 +2363,6 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
struct sdap_get_initgr_state *state;
const char *base_dn;
char *filter;
- const char **attrs;
int ret;
DEBUG(9, ("Retrieving info for initgroups call\n"));
@@ -2373,7 +2397,7 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
}
ret = build_attrs_from_map(state, state->opts->user_map,
- SDAP_OPTS_USER, &attrs);
+ SDAP_OPTS_USER, &state->ldap_attrs);
if (ret) {
talloc_zfree(req);
return NULL;
@@ -2382,7 +2406,7 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
subreq = sdap_get_generic_send(state, state->ev,
state->opts, state->sh,
base_dn, LDAP_SCOPE_SUBTREE,
- filter, attrs,
+ filter, state->ldap_attrs,
state->opts->user_map, SDAP_OPTS_USER,
dp_opt_get_int(state->opts->basic,
SDAP_SEARCH_TIMEOUT));
@@ -2443,7 +2467,8 @@ static void sdap_get_initgr_user(struct tevent_req *subreq)
ret = sdap_save_user(state, state->sysdb,
state->opts, state->dom,
- state->orig_user, true, NULL);
+ state->orig_user, state->ldap_attrs,
+ true, NULL);
if (ret) {
sysdb_transaction_cancel(state->sysdb);
tevent_req_error(req, ret);
diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
index 4fd656fe..3df21063 100644
--- a/src/providers/proxy/proxy_id.c
+++ b/src/providers/proxy/proxy_id.c
@@ -105,7 +105,8 @@ static int get_pw_name(TALLOC_CTX *mem_ctx,
pwd->pw_gecos,
pwd->pw_dir,
pwd->pw_shell,
- NULL, ctx->entry_cache_timeout);
+ NULL, NULL,
+ ctx->entry_cache_timeout);
if (ret) {
goto done;
}
@@ -219,7 +220,8 @@ static int get_pw_uid(TALLOC_CTX *mem_ctx,
pwd->pw_gecos,
pwd->pw_dir,
pwd->pw_shell,
- NULL, ctx->entry_cache_timeout);
+ NULL, NULL,
+ ctx->entry_cache_timeout);
if (ret) {
goto done;
}
@@ -358,7 +360,8 @@ again:
pwd->pw_gecos,
pwd->pw_dir,
pwd->pw_shell,
- NULL, ctx->entry_cache_timeout);
+ NULL, NULL,
+ ctx->entry_cache_timeout);
if (ret) {
/* Do not fail completely on errors.
* Just report the failure to save and go on */
@@ -933,7 +936,8 @@ static int get_initgr(TALLOC_CTX *mem_ctx,
pwd->pw_gecos,
pwd->pw_dir,
pwd->pw_shell,
- NULL, ctx->entry_cache_timeout);
+ NULL, NULL,
+ ctx->entry_cache_timeout);
if (ret) {
goto done;
}
diff --git a/src/tests/sysdb-tests.c b/src/tests/sysdb-tests.c
index 2beb2588..eada9a3a 100644
--- a/src/tests/sysdb-tests.c
+++ b/src/tests/sysdb-tests.c
@@ -210,7 +210,7 @@ static int test_store_user(struct test_data *data)
data->ctx->domain, data->username, "x",
data->uid, 0, gecos, homedir,
data->shell ? data->shell : "/bin/bash",
- NULL, -1);
+ NULL, NULL, -1);
return ret;
}