From 44fbe880013af8ecec1b89619418b49f5d582118 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 23 May 2016 18:18:00 +0200 Subject: [PATCH 08/14] SYSDB: If modifyTimestamp is the same, only update the TS cache If the entry being saved contains the original modifyTimestamp attribute and the modifyTimestamp attribute is the same as the one we already saved to the timestamp cache, only the expire timestamps in the asynchronous timestamp cache will be bumped and the sysdb code will avoid writes to the main cache completely. If the modifyTimestamp is either missing or differs, we assume the entry had changed and do a full write to the main cache. Also amends the generic sysdb_set_attrs* and similar functions that their results is also reflected in the timestamps cache. --- src/db/sysdb.c | 76 ++++ src/db/sysdb.h | 3 + src/db/sysdb_ops.c | 596 +++++++++++++++++++++++++--- src/db/sysdb_private.h | 25 ++ src/db/sysdb_search.c | 47 +++ src/tests/cmocka/test_responder_cache_req.c | 2 + src/tests/cmocka/test_sysdb_sudo.c | 1 + 7 files changed, 691 insertions(+), 59 deletions(-) diff --git a/src/db/sysdb.c b/src/db/sysdb.c index 81b731a0d04729c209656bdefac1befb53ed78cd..1224e96add5e89c9912a332af3196c62905828d3 100644 --- a/src/db/sysdb.c +++ b/src/db/sysdb.c @@ -1524,6 +1524,42 @@ errno_t sysdb_msg2attrs(TALLOC_CTX *mem_ctx, size_t count, return EOK; } +struct ldb_message *sysdb_attrs2msg(TALLOC_CTX *mem_ctx, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct ldb_message *msg; + errno_t ret; + + msg = ldb_msg_new(mem_ctx); + if (msg == NULL) { + ret = ENOMEM; + goto done; + } + + msg->dn = entry_dn; + + msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num); + if (msg->elements == NULL) { + ret = ENOMEM; + goto done; + } + + for (int i = 0; i < attrs->num; i++) { + msg->elements[i] = attrs->a[i]; + msg->elements[i].flags = mod_op; + } + msg->num_elements = attrs->num; + + ret = EOK; +done: + if (ret != EOK) { + talloc_zfree(msg); + } + return msg; +} + int sysdb_compare_usn(const char *a, const char *b) { size_t len_a; @@ -1715,3 +1751,43 @@ bool is_ts_ldb_dn(struct ldb_dn *dn) return false; } + +bool sysdb_msg_attrs_modts_differs(struct ldb_message *old_entry, + struct sysdb_attrs *new_entry) +{ + const char *old_entry_ts_attr = NULL; + const char *new_entry_ts_attr = NULL; + errno_t ret; + + old_entry_ts_attr = ldb_msg_find_attr_as_string(old_entry, + SYSDB_ORIG_MODSTAMP, + NULL); + if (old_entry_ts_attr == NULL) { + /* we didn't know the originalModifyTimestamp earlier. Regardless + * of whether the new_entry has the timestamp, we should do + * a comparison of the attributes + */ + return true; + } + + if (new_entry == NULL) { + return false; + } + + ret = sysdb_attrs_get_string(new_entry, SYSDB_ORIG_MODSTAMP, + &new_entry_ts_attr); + if (ret != EOK) { + /* Nothing to compare against in the new entry either, do + * a comparison of the attributes + */ + return true; + } + + if (old_entry_ts_attr != NULL + && new_entry_ts_attr != NULL + && strcmp(old_entry_ts_attr, new_entry_ts_attr) == 0) { + return false; + } + + return true; +} diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 4f69b6372c7f43b549c25fe0a36f5e82a26ca2de..2bc20ff97818655768b0f338e5cf7ed5222315f5 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -314,6 +314,9 @@ struct range_info { /* These attributes are stored in the timestamp cache */ extern const char *sysdb_ts_cache_attrs[]; +/* These attributes are stored in the timestamp cache */ +extern const char *sysdb_ts_cache_attrs[]; + /* values are copied in the structure, allocated on "attrs" */ int sysdb_attrs_add_val(struct sysdb_attrs *attrs, const char *name, const struct ldb_val *val); diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 505af2a356cc661b82d08a758595174be4b0c02d..7ecbfc83c1a1e6a05c07a8e3b94e09e7d78fbdb4 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -96,14 +96,13 @@ int sss_ldb_modify_permissive(struct ldb_context *ldb, /* =Remove-Entry-From-Sysdb=============================================== */ - -int sysdb_delete_entry(struct sysdb_ctx *sysdb, - struct ldb_dn *dn, - bool ignore_not_found) +static int sysdb_delete_cache_entry(struct ldb_context *ldb, + struct ldb_dn *dn, + bool ignore_not_found) { int ret; - ret = ldb_delete(sysdb->ldb, dn); + ret = ldb_delete(ldb, dn); switch (ret) { case LDB_SUCCESS: return EOK; @@ -114,11 +113,35 @@ int sysdb_delete_entry(struct sysdb_ctx *sysdb, /* fall through */ default: DEBUG(SSSDBG_CRIT_FAILURE, "LDB Error: %s(%d)\nError Message: [%s]\n", - ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); + ldb_strerror(ret), ret, ldb_errstring(ldb)); return sysdb_error_to_errno(ret); } } +static int sysdb_delete_ts_entry(struct sysdb_ctx *sysdb, + struct ldb_dn *dn) +{ + if (sysdb->ldb_ts == NULL) { + return EOK; + } + + return sysdb_delete_cache_entry(sysdb->ldb_ts, dn, true); +} + +int sysdb_delete_entry(struct sysdb_ctx *sysdb, + struct ldb_dn *dn, + bool ignore_not_found) +{ + errno_t ret; + + ret = sysdb_delete_cache_entry(sysdb->ldb, dn, ignore_not_found); + if (ret == EOK) { + sysdb_delete_ts_entry(sysdb, dn); + } + + return EOK; +} + /* =Remove-Subentries-From-Sysdb=========================================== */ int sysdb_delete_recursive(struct sysdb_ctx *sysdb, @@ -712,70 +735,500 @@ done: return ret; } +/* =Timestamp-cache-functions==============================================*/ + +/* If modifyTimestamp is the same in the TS cache, return EOK. Return ERR_NO_TS + * if there is no timestamps cache for this domain and ERR_TS_CACHE_MISS if + * the entry had changed and the caller needs to update the sysdb cache as well. + */ +static errno_t sysdb_check_ts_cache(struct sss_domain_info *domain, + struct ldb_dn *entry_dn, + struct sysdb_attrs *entry) +{ + errno_t ret; + TALLOC_CTX *tmp_ctx; + size_t msgs_count; + struct ldb_message **msgs; + bool mod_ts_differs; + + if (domain->sysdb->ldb_ts == NULL) { + return ERR_NO_TS; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + /* Check if the entry is in the timestamp cache */ + ret = sysdb_search_ts_entry(tmp_ctx, + domain->sysdb, + entry_dn, + LDB_SCOPE_BASE, + NULL, + sysdb_ts_cache_attrs, + &msgs_count, + &msgs); + if (ret != EOK) { + DEBUG(SSSDBG_TRACE_INTERNAL, + "Cannot find TS cache entry for [%s]: [%d]: %s\n", + ldb_dn_get_linearized(entry_dn), ret, sss_strerror(ret)); + goto done; + } + + if (msgs_count != 1) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Expected 1 result for base search, got %zu\n", msgs_count); + return EIO; + } + + mod_ts_differs = sysdb_msg_attrs_modts_differs(msgs[0], entry); + if (mod_ts_differs == true) { + ret = ERR_TS_CACHE_MISS; + goto done; + } + + ret = EOK; +done: + talloc_zfree(tmp_ctx); + return ret; +} + +static int sysdb_set_ts_entry_attr(struct sysdb_ctx *sysdb, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op); + +static errno_t sysdb_create_ts_entry(struct sysdb_ctx *sysdb, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs) +{ + struct ldb_message *msg; + errno_t ret; + int lret; + TALLOC_CTX *tmp_ctx; + + if (sysdb->ldb_ts == NULL || attrs->num == 0) { + return EOK; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + if (entry_dn == NULL) { + ret = EINVAL; + goto done; + } + + msg = sysdb_attrs2msg(tmp_ctx, entry_dn, attrs, 0); + if (msg == NULL) { + ret = ENOMEM; + goto done; + } + + lret = ldb_add(sysdb->ldb_ts, msg); + if (lret != LDB_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, + "ldb_add failed: [%s](%d)[%s]\n", + ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb_ts)); + } + + ret = sysdb_error_to_errno(lret); +done: + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n"); + } else if (ret) { + DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret)); + } + talloc_zfree(tmp_ctx); + return ret; +} + +static struct sysdb_attrs *ts_obj_attrs(TALLOC_CTX *mem_ctx, + enum sysdb_obj_type obj_type) +{ + struct sysdb_attrs *attrs; + const char *oc; + errno_t ret; + + switch (obj_type) { + case SYSDB_USER: + oc = SYSDB_USER_CLASS; + break; + case SYSDB_GROUP: + oc = SYSDB_GROUP_CLASS; + break; + default: + return NULL; + } + + attrs = sysdb_new_attrs(mem_ctx); + if (attrs == NULL) { + return NULL; + } + + ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, oc); + if (ret != EOK) { + talloc_free(attrs); + return NULL; + } + + return attrs; +} + +static errno_t sysdb_update_ts_cache(struct sss_domain_info *domain, + struct ldb_dn *entry_dn, + struct sysdb_attrs *entry_attrs, + struct sysdb_attrs *ts_attrs, + int mod_op, + uint64_t cache_timeout, + time_t now) +{ + errno_t ret; + TALLOC_CTX *tmp_ctx; + const char *modstamp; + + if (domain->sysdb->ldb_ts == NULL) { + DEBUG(SSSDBG_TRACE_INTERNAL, "No timestamp cache for this domain\n"); + return EOK; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + if (ts_attrs == NULL) { + ts_attrs = sysdb_new_attrs(tmp_ctx); + if (ts_attrs == NULL) { + ret = ENOMEM; + goto done; + } + } + + ret = sysdb_attrs_add_time_t(ts_attrs, SYSDB_LAST_UPDATE, now); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to add %s to tsdb\n", SYSDB_LAST_UPDATE); + goto done; + } + + ret = sysdb_attrs_add_time_t(ts_attrs, SYSDB_CACHE_EXPIRE, + ((cache_timeout) ? + (now + cache_timeout) : 0)); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to add %s to tsdb\n", SYSDB_CACHE_EXPIRE); + goto done; + } + + if (entry_attrs != NULL) { + ret = sysdb_attrs_get_string(entry_attrs, SYSDB_ORIG_MODSTAMP, + &modstamp); + if (ret == EOK) { + ret = sysdb_attrs_add_string(ts_attrs, + SYSDB_ORIG_MODSTAMP, modstamp); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to add %s to tsdb\n", SYSDB_ORIG_MODSTAMP); + goto done; + } + } + } + + ret = sysdb_set_ts_entry_attr(domain->sysdb, entry_dn, + ts_attrs, mod_op); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Cannot set ts attrs for group %s\n", + ldb_dn_get_linearized(entry_dn)); + /* Not fatal */ + } + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + +static errno_t sysdb_check_and_update_ts_cache(struct sss_domain_info *domain, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + uint64_t cache_timeout, + time_t now) +{ + errno_t ret; + + ret = sysdb_check_ts_cache(domain, entry_dn, attrs); + switch (ret) { + case ENOENT: + DEBUG(SSSDBG_TRACE_INTERNAL, "No timestamps entry\n"); + break; + case EOK: + /* The entry's timestamp was the same. Just update the ts cache */ + ret = sysdb_update_ts_cache(domain, entry_dn, attrs, NULL, + SYSDB_MOD_REP, cache_timeout, now); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot update the timestamps cache [%d]: %s\n", + ret, sss_strerror(ret)); + } + break; + case ERR_TS_CACHE_MISS: + case ERR_NO_TS: + /* Either there is no cache or the cache is up-do-date. Just report + * what's up + */ + break; + default: + DEBUG(SSSDBG_OP_FAILURE, + "Error checking the timestamps cache [%d]: %s\n", + ret, sss_strerror(ret)); + break; + } + + return ret; +} + +static errno_t get_sysdb_obj_dn(TALLOC_CTX *mem_ctx, + struct sss_domain_info *domain, + enum sysdb_obj_type obj_type, + const char *obj_name, + struct ldb_dn **_obj_dn) +{ + struct ldb_dn *obj_dn; + + switch (obj_type) { + case SYSDB_USER: + obj_dn = sysdb_user_dn(mem_ctx, domain, obj_name); + break; + case SYSDB_GROUP: + obj_dn = sysdb_group_dn(mem_ctx, domain, obj_name); + break; + default: + return EINVAL; + } + + if (obj_dn == NULL) { + return ENOMEM; + } + + *_obj_dn = obj_dn; + return EOK; +} + +static errno_t sysdb_check_and_update_ts_obj(struct sss_domain_info *domain, + enum sysdb_obj_type obj_type, + const char *obj_name, + struct sysdb_attrs *attrs, + uint64_t cache_timeout, + time_t now) +{ + struct ldb_dn *entry_dn; + TALLOC_CTX *tmp_ctx; + errno_t ret; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + ret = get_sysdb_obj_dn(tmp_ctx, domain, obj_type, obj_name, &entry_dn); + if (ret != EOK) { + goto done; + } + + ret = sysdb_check_and_update_ts_cache(domain, entry_dn, attrs, + cache_timeout, now); +done: + talloc_zfree(tmp_ctx); + return ret; +} + +static errno_t sysdb_create_ts_obj(struct sss_domain_info *domain, + enum sysdb_obj_type obj_type, + const char *obj_name, + uint64_t cache_timeout, + time_t now) +{ + struct ldb_dn *entry_dn; + struct sysdb_attrs *ts_attrs = NULL; + TALLOC_CTX *tmp_ctx; + errno_t ret; + + if (domain->sysdb->ldb_ts == NULL) { + return EOK; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = get_sysdb_obj_dn(tmp_ctx, domain, obj_type, obj_name, &entry_dn); + if (ret != EOK) { + goto done; + } + + ts_attrs = ts_obj_attrs(tmp_ctx, obj_type); + if (ts_attrs == NULL) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_update_ts_cache(domain, entry_dn, NULL, ts_attrs, + SYSDB_MOD_ADD, cache_timeout, now); + if (ret != EOK) { + goto done; + } + +done: + talloc_zfree(tmp_ctx); + return ret; +} + +static errno_t sysdb_check_and_update_ts_grp(struct sss_domain_info *domain, + const char *grp_name, + struct sysdb_attrs *attrs, + uint64_t cache_timeout, + time_t now) +{ + return sysdb_check_and_update_ts_obj(domain, SYSDB_GROUP, grp_name, + attrs, cache_timeout, now); +} + +static errno_t sysdb_create_ts_grp(struct sss_domain_info *domain, + const char *grp_name, + uint64_t cache_timeout, + time_t now) +{ + return sysdb_create_ts_obj(domain, SYSDB_GROUP, grp_name, + cache_timeout, now); +} + /* =Replace-Attributes-On-Entry=========================================== */ +static int sysdb_set_cache_entry_attr(struct ldb_context *ldb, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct ldb_message *msg; + int ret; + int lret; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + if (entry_dn == NULL || attrs->num == 0) { + ret = EINVAL; + goto done; + } + + msg = sysdb_attrs2msg(tmp_ctx, entry_dn, attrs, mod_op); + if (msg == NULL) { + ret = ENOMEM; + goto done; + } + + lret = ldb_modify(ldb, msg); + if (lret != LDB_SUCCESS) { + DEBUG(SSSDBG_MINOR_FAILURE, + "ldb_modify failed: [%s](%d)[%s]\n", + ldb_strerror(lret), lret, ldb_errstring(ldb)); + } + + ret = sysdb_error_to_errno(lret); + +done: + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n"); + } + else if (ret) { + DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret)); + } + talloc_zfree(tmp_ctx); + return ret; +} int sysdb_set_entry_attr(struct sysdb_ctx *sysdb, struct ldb_dn *entry_dn, struct sysdb_attrs *attrs, int mod_op) { - struct ldb_message *msg; - int i, ret; - int lret; + errno_t ret = EOK; + errno_t tret = EOK; + + ret = sysdb_set_cache_entry_attr(sysdb->ldb, entry_dn, attrs, mod_op); + if (ret == EOK) { + tret = sysdb_set_ts_entry_attr(sysdb, entry_dn, attrs, mod_op); + if (tret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Cannot set ts attrs for %s\n", ldb_dn_get_linearized(entry_dn)); + /* Not fatal */ + } + } + + return ret; +} + +static int sysdb_rep_ts_entry_attr(struct sysdb_ctx *sysdb, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs) +{ + if (sysdb->ldb_ts == NULL || attrs->num == 0) { + return EOK; + } + + return sysdb_set_cache_entry_attr(sysdb->ldb_ts, entry_dn, + attrs, SYSDB_MOD_REP); +} + +static int sysdb_set_ts_entry_attr(struct sysdb_ctx *sysdb, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op) +{ + struct sysdb_attrs *ts_attrs; TALLOC_CTX *tmp_ctx; + errno_t ret; + + if (sysdb->ldb_ts == NULL) { + return EOK; + } tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } - if (!entry_dn || attrs->num == 0) { + ts_attrs = sysdb_filter_ts_attrs(tmp_ctx, attrs); + if (ts_attrs == NULL) { + ret = ENOMEM; + goto done; + } + + switch (mod_op) { + case SYSDB_MOD_REP: + ret = sysdb_rep_ts_entry_attr(sysdb, entry_dn, ts_attrs); + break; + case SYSDB_MOD_ADD: + ret = sysdb_create_ts_entry(sysdb, entry_dn, ts_attrs); + break; + default: ret = EINVAL; - goto done; + break; } - msg = ldb_msg_new(tmp_ctx); - if (!msg) { - ret = ENOMEM; - goto done; - } - - msg->dn = entry_dn; - - msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num); - if (!msg->elements) { - ret = ENOMEM; - goto done; - } - - for (i = 0; i < attrs->num; i++) { - msg->elements[i] = attrs->a[i]; - msg->elements[i].flags = mod_op; - } - - msg->num_elements = attrs->num; - - lret = ldb_modify(sysdb->ldb, msg); - if (lret != LDB_SUCCESS) { - DEBUG(SSSDBG_MINOR_FAILURE, - "ldb_modify failed: [%s](%d)[%s]\n", - ldb_strerror(lret), lret, ldb_errstring(sysdb->ldb)); - } - - ret = sysdb_error_to_errno(lret); - done: - if (ret == ENOENT) { - DEBUG(SSSDBG_TRACE_FUNC, "No such entry\n"); - } - else if (ret) { - DEBUG(SSSDBG_OP_FAILURE, "Error: %d (%s)\n", ret, strerror(ret)); - } talloc_zfree(tmp_ctx); return ret; } - /* =Replace-Attributes-On-User============================================ */ int sysdb_set_user_attr(struct sss_domain_info *domain, @@ -809,7 +1262,6 @@ done: return ret; } - /* =Replace-Attributes-On-Group=========================================== */ int sysdb_set_group_attr(struct sss_domain_info *domain, @@ -1593,6 +2045,13 @@ int sysdb_add_group(struct sss_domain_info *domain, goto done; } + ret = sysdb_create_ts_grp(domain, name, cache_timeout, now); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Cannot set timestamp cache attributes for a group\n"); + /* Not fatal */ + } + if (!attrs) { attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { @@ -1687,16 +2146,23 @@ int sysdb_add_incomplete_group(struct sss_domain_info *domain, ret = sysdb_add_basic_group(domain, name, gid); if (ret) goto done; + if (!now) { + now = time(NULL); + } + + ret = sysdb_create_ts_grp(domain, name, now-1, now); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Cannot set timestamp cache attributes for a group\n"); + /* Not fatal */ + } + attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { ret = ENOMEM; goto done; } - if (!now) { - now = time(NULL); - } - ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now); if (ret) goto done; @@ -2097,14 +2563,22 @@ int sysdb_store_group(struct sss_domain_info *domain, time_t now) { TALLOC_CTX *tmp_ctx; - static const char *src_attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, - SYSDB_ORIG_MODSTAMP, NULL }; + static const char *src_attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL }; struct ldb_message *msg; bool new_group = false; int ret; errno_t sret = EOK; bool in_transaction = false; + ret = sysdb_check_and_update_ts_grp(domain, name, attrs, + cache_timeout, now); + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_LIBS, + "The group record of %s did not change, only updated " + "the timestamp cache\n", name); + return EOK; + } + tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; @@ -2150,6 +2624,10 @@ int sysdb_store_group(struct sss_domain_info *domain, } else { ret = sysdb_store_group_attrs(domain, name, gid, attrs, cache_timeout, now); } + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Cache update failed: %d\n", ret); + goto done; + } sret = sysdb_transaction_commit(domain->sysdb); if (sret != EOK) { @@ -2196,21 +2674,21 @@ static errno_t sysdb_store_new_group(struct sss_domain_info *domain, /* Not found by GID, return the original EEXIST, * this may be a conflict in MPG domain or something * else */ - DEBUG(SSSDBG_TRACE_LIBS, + DEBUG(SSSDBG_OP_FAILURE, "sysdb_delete_group failed (while renaming group). Not " "found by gid: [%"SPRIgid"].\n", gid); return EEXIST; } else if (ret != EOK) { - DEBUG(SSSDBG_TRACE_LIBS, "sysdb_add_group failed.\n"); + DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_group failed.\n"); return ret; } - DEBUG(SSSDBG_MINOR_FAILURE, + DEBUG(SSSDBG_TRACE_FUNC, "A group with the same GID [%"SPRIgid"] was removed from " "the cache\n", gid); ret = sysdb_add_group(domain, name, gid, attrs, cache_timeout, now); if (ret) { - DEBUG(SSSDBG_MINOR_FAILURE, + DEBUG(SSSDBG_OP_FAILURE, "sysdb_add_group failed (while renaming group) for: " "%s [%"SPRIgid"].\n", name, gid); return ret; diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h index dae348b0b34ac791e9af47506d9a807d8c7eb2a1..9d03d59f099dc6413759fad5b2319610cc43f2c5 100644 --- a/src/db/sysdb_private.h +++ b/src/db/sysdb_private.h @@ -194,6 +194,18 @@ struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, */ bool is_ts_ldb_dn(struct ldb_dn *dn); +/* Returns true if the attrname is an attribute we store to the timestamp + * cache, false if it's a sysdb-only attribute + */ +bool is_ts_cache_attr(const char *attrname); + +/* Returns a subset of attrs that only contains the attributes we store to + * the timestamps cache. Useful in generic functions that set some attributes + * and we want to mirror that change in the timestamps cache + */ +struct sysdb_attrs *sysdb_filter_ts_attrs(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *attrs); + /* Given a ldb_result found in the timestamp cache, merge in the * corresponding full attributes from the sysdb cache. The new * attributes are allocated on the messages in the ldb_result. @@ -239,4 +251,17 @@ int sysdb_search_ts_groups(TALLOC_CTX *mem_ctx, size_t *msgs_count, struct ldb_message ***msgs); +/* Compares the modifyTimestamp attribute between old_entry and + * new_entry. Returns true if they differ (or either entry is missing + * the attribute) and false if the attribute is the same + */ +bool sysdb_msg_attrs_modts_differs(struct ldb_message *old_entry, + struct sysdb_attrs *new_entry); + +/* Given a sysdb_attrs pointer, returns a corresponding ldb_message */ +struct ldb_message *sysdb_attrs2msg(TALLOC_CTX *mem_ctx, + struct ldb_dn *entry_dn, + struct sysdb_attrs *attrs, + int mod_op); + #endif /* __INT_SYS_DB_H__ */ diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c index 989f0a3e3094ef0be62f7ce0d6229b2aa54e5d5f..27ea16dc830746fe93ff832ceb31ca29fb94c8d5 100644 --- a/src/db/sysdb_search.c +++ b/src/db/sysdb_search.c @@ -2288,3 +2288,50 @@ struct ldb_result *sss_merge_ldb_results(struct ldb_result *sysdb_res, sysdb_res->count = count; return sysdb_res; } + +bool is_ts_cache_attr(const char *attrname) +{ + size_t i; + + for (i = 0; sysdb_ts_cache_attrs[i] != NULL; i++) { + if (strcmp(attrname, sysdb_ts_cache_attrs[i]) == 0) { + break; + } + } + + if (sysdb_ts_cache_attrs[i] == NULL) { + return false; + } + + return true; +} + +struct sysdb_attrs *sysdb_filter_ts_attrs(TALLOC_CTX *mem_ctx, + struct sysdb_attrs *attrs) +{ + struct sysdb_attrs *ts_attrs; + int ti = 0; + + ts_attrs = sysdb_new_attrs(mem_ctx); + if (ts_attrs == NULL) { + return NULL; + } + + ts_attrs->a = talloc_zero_array(ts_attrs, + struct ldb_message_element, + attrs->num); + if (ts_attrs->a == NULL) { + talloc_free(ts_attrs); + return NULL; + } + + for (int i = 0; i < attrs->num; i++) { + if (is_ts_cache_attr(attrs->a[i].name)) { + ts_attrs->a[ti] = attrs->a[i]; + ti++; + } + } + ts_attrs->num = ti; + + return ts_attrs; +} diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c index 6c13500cef9ec82dde9d97f97f7fb492fe0e3b8f..1d8450414bc081601a8cc14b9aee309c60c903c7 100644 --- a/src/tests/cmocka/test_responder_cache_req.c +++ b/src/tests/cmocka/test_responder_cache_req.c @@ -483,6 +483,7 @@ static int test_multi_domain_setup(void **state) ret = sss_ncache_init(test_ctx, 10, &test_ctx->ncache); assert_int_equal(ret, EOK); + reset_ldb_errstrings(test_ctx->tctx->dom); check_leaks_push(test_ctx); return 0; @@ -497,6 +498,7 @@ static int test_multi_domain_teardown(void **state) talloc_zfree(test_ctx->result); talloc_zfree(test_ctx->name); + reset_ldb_errstrings(test_ctx->tctx->dom); assert_true(check_leaks_pop(test_ctx)); talloc_zfree(test_ctx); test_multidom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, domains); diff --git a/src/tests/cmocka/test_sysdb_sudo.c b/src/tests/cmocka/test_sysdb_sudo.c index 97f80d7e5dfa9d921c8188dcff21ad0d2e372dc2..aebad88ebb7661cc350a498b5081b1d2cc308b0f 100644 --- a/src/tests/cmocka/test_sysdb_sudo.c +++ b/src/tests/cmocka/test_sysdb_sudo.c @@ -155,6 +155,7 @@ static int test_sysdb_teardown(void **state) test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME); + reset_ldb_errstrings(test_ctx->tctx->dom); assert_true(check_leaks_pop(test_ctx)); talloc_zfree(test_ctx); assert_true(leak_check_teardown()); -- 2.4.11