summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/db/sysdb.c76
-rw-r--r--src/db/sysdb.h3
-rw-r--r--src/db/sysdb_ops.c555
-rw-r--r--src/db/sysdb_private.h25
-rw-r--r--src/db/sysdb_search.c47
-rw-r--r--src/tests/cmocka/test_responder_cache_req.c2
-rw-r--r--src/tests/cmocka/test_sysdb_sudo.c1
7 files changed, 673 insertions, 36 deletions
diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 81b731a0d..1224e96ad 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 4f69b6372..2bc20ff97 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 2f06444e7..4ea0d0ad7 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,40 @@ 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) {
+ ret = sysdb_delete_ts_entry(sysdb, dn);
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "sysdb_delete_ts_entry failed: %d\n", ret);
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sysdb_delete_cache_entry failed: %d\n", ret);
+ }
+
+ return ret;
+}
+
/* =Remove-Subentries-From-Sysdb=========================================== */
int sysdb_delete_recursive(struct sysdb_ctx *sysdb,
@@ -719,54 +747,411 @@ done:
return ret;
}
-/* =Replace-Attributes-On-Entry=========================================== */
+/* =Timestamp-cache-functions==============================================*/
-int sysdb_set_entry_attr(struct sysdb_ctx *sysdb,
- struct ldb_dn *entry_dn,
- struct sysdb_attrs *attrs,
- int mod_op)
+/* 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;
- int i, ret;
+ 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) {
+ if (tmp_ctx == NULL) {
return ENOMEM;
}
- if (!entry_dn || attrs->num == 0) {
+ if (entry_dn == NULL) {
ret = EINVAL;
goto done;
}
- msg = ldb_msg_new(tmp_ctx);
- if (!msg) {
+ msg = sysdb_attrs2msg(tmp_ctx, entry_dn, attrs, 0);
+ if (msg == NULL) {
ret = ENOMEM;
goto done;
}
- msg->dn = entry_dn;
+ 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));
+ }
- msg->elements = talloc_array(msg, struct ldb_message_element, attrs->num);
- if (!msg->elements) {
+ 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;
}
- for (i = 0; i < attrs->num; i++) {
- msg->elements[i] = attrs->a[i];
- msg->elements[i].flags = mod_op;
+ ret = sysdb_update_ts_cache(domain, entry_dn, NULL, ts_attrs,
+ SYSDB_MOD_ADD, cache_timeout, now);
+ if (ret != EOK) {
+ goto done;
}
- msg->num_elements = attrs->num;
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
- lret = ldb_modify(sysdb->ldb, msg);
+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(sysdb->ldb));
+ ldb_strerror(lret), lret, ldb_errstring(ldb));
}
ret = sysdb_error_to_errno(lret);
@@ -782,6 +1167,79 @@ done:
return ret;
}
+int sysdb_set_entry_attr(struct sysdb_ctx *sysdb,
+ struct ldb_dn *entry_dn,
+ struct sysdb_attrs *attrs,
+ int mod_op)
+{
+ 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;
+ }
+
+ 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;
+ break;
+ }
+
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
/* =Replace-Attributes-On-User============================================ */
@@ -816,7 +1274,6 @@ done:
return ret;
}
-
/* =Replace-Attributes-On-Group=========================================== */
int sysdb_set_group_attr(struct sss_domain_info *domain,
@@ -1600,6 +2057,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) {
@@ -1694,16 +2158,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;
@@ -2104,14 +2575,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;
@@ -2157,6 +2636,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) {
@@ -2203,21 +2686,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 dae348b0b..9d03d59f0 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 9a1ae7a9f..61b07acc9 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -2293,3 +2293,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 f30f1eaad..ba7fbc194 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, 0, &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 97f80d7e5..aebad88eb 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());