summaryrefslogtreecommitdiffstats
path: root/src/db/sysdb_search.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/db/sysdb_search.c')
-rw-r--r--src/db/sysdb_search.c394
1 files changed, 389 insertions, 5 deletions
diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c
index e9c384046..9a1ae7a9f 100644
--- a/src/db/sysdb_search.c
+++ b/src/db/sysdb_search.c
@@ -25,6 +25,158 @@
#include <time.h>
#include <ctype.h>
+/* helpers */
+static errno_t merge_ts_attr(struct ldb_message *ts_msg,
+ struct ldb_message *sysdb_msg,
+ const char *ts_attr,
+ const char *want_attrs[])
+{
+ errno_t ret;
+ bool include = true;
+ struct ldb_message_element *ts_el;
+ struct ldb_message_element *sysdb_el;
+
+ if (want_attrs != NULL) {
+ /* Otherwise merge all ts attrs */
+ include = string_in_list(ts_attr, discard_const(want_attrs), true);
+ }
+ if (include == false) {
+ return EOK;
+ }
+
+ ts_el = ldb_msg_find_element(ts_msg, ts_attr);
+ if (ts_el == NULL || ts_el->num_values == 0) {
+ return EOK;
+ }
+
+ if (ts_el->num_values > 1) {
+ return EIO;
+ }
+
+ sysdb_el = ldb_msg_find_element(sysdb_msg, ts_attr);
+ if (sysdb_el == NULL || sysdb_el->num_values == 0) {
+ ret = ldb_msg_add_steal_value(sysdb_msg, ts_attr, &ts_el->values[0]);
+ if (ret != EOK) {
+ return sysdb_error_to_errno(ret);
+ }
+ } else {
+ /* Assumes the timestamps cache only holds single-valued
+ * attributes */
+ sysdb_el->values = talloc_steal(sysdb_el->values, ts_el->values);
+ }
+
+ return EOK;
+}
+
+static errno_t merge_msg_ts_attrs(struct sysdb_ctx *sysdb,
+ struct ldb_message *sysdb_msg,
+ const char *attrs[])
+{
+ errno_t ret;
+ TALLOC_CTX *tmp_ctx;
+ size_t msgs_count;
+ struct ldb_message **ts_msgs;
+ bool ts_dn;
+
+ ts_dn = is_ts_ldb_dn(sysdb_msg->dn);
+ if (ts_dn == false) {
+ return ERR_NO_TS;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_search_ts_entry(tmp_ctx, sysdb, sysdb_msg->dn,
+ LDB_SCOPE_BASE,
+ NULL,
+ sysdb_ts_cache_attrs,
+ &msgs_count,
+ &ts_msgs);
+ if (ret == ENOENT) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "No such DN in the timestamp cache: %s\n",
+ ldb_dn_get_linearized(sysdb_msg->dn));
+ ret = ERR_TS_CACHE_MISS;
+ goto done;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "Cannot find TS cache entry for [%s]: [%d]: %s\n",
+ ldb_dn_get_linearized(sysdb_msg->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;
+ }
+
+ /* Deliberately start from 1 in order to not merge objectclass and avoid
+ * breaking MPGs where the OC might be made up
+ */
+ for (size_t c = 1; sysdb_ts_cache_attrs[c]; c++) {
+ ret = merge_ts_attr(ts_msgs[0], sysdb_msg,
+ sysdb_ts_cache_attrs[c], attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Canot merge ts attr %s\n", sysdb_ts_cache_attrs[c]);
+ goto done;
+ }
+ }
+
+ ret = EOK;
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+errno_t sysdb_merge_res_ts_attrs(struct sysdb_ctx *ctx,
+ struct ldb_result *res,
+ const char *attrs[])
+{
+ errno_t ret;
+
+ if (res == NULL || ctx->ldb_ts == NULL) {
+ return EOK;
+ }
+
+ for (size_t c = 0; c < res->count; c++) {
+ ret = merge_msg_ts_attrs(ctx, res->msgs[c], attrs);
+ if (ret == ERR_NO_TS) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "TS cache doesn't handle this DN type, skipping\n");
+ continue;
+ } else if (ret == ERR_TS_CACHE_MISS) {
+ DEBUG(SSSDBG_TRACE_INTERNAL,
+ "TS cache doesn't contain this DN, skipping\n");
+ continue;
+ } else if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "Cannot merge timestamp cache values for %s\n",
+ ldb_dn_get_linearized(res->msgs[c]->dn));
+ /* non-fatal */
+ continue;
+ }
+ }
+
+ return EOK;
+}
+
+errno_t sysdb_merge_msg_list_ts_attrs(struct sysdb_ctx *ctx,
+ size_t msgs_count,
+ struct ldb_message **msgs,
+ const char *attrs[])
+{
+ struct ldb_result res;
+
+ res.count = msgs_count;
+ res.msgs = msgs;
+ return sysdb_merge_res_ts_attrs(ctx, &res, attrs);
+}
+
/* users */
int sysdb_getpwnam(TALLOC_CTX *mem_ctx,
@@ -75,6 +227,13 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx,
goto done;
}
+ /* Merge in the timestamps from the fast ts db */
+ ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot merge timestamp cache values\n");
+ /* non-fatal */
+ }
+
*_res = talloc_steal(mem_ctx, res);
done:
@@ -180,6 +339,13 @@ int sysdb_getpwuid(TALLOC_CTX *mem_ctx,
goto done;
}
+ /* Merge in the timestamps from the fast ts db */
+ ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot merge timestamp cache values\n");
+ /* non-fatal */
+ }
+
*_res = talloc_steal(mem_ctx, res);
done:
@@ -324,6 +490,73 @@ done:
return ret;
}
+static errno_t search_ts_matches(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *sysdb,
+ const char *attrs[],
+ struct ldb_result *ts_res,
+ const char *filter,
+ struct ldb_result **_res)
+{
+ char *dn_filter;
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_result *res;
+ errno_t ret;
+
+ if (ts_res->count == 0) {
+ *_res = NULL;
+ ret = EOK;
+ goto done;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ res = talloc_zero(tmp_ctx, struct ldb_result);
+ if (res == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ dn_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(|", SYSDB_NAME, filter);
+ if (dn_filter == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (size_t i = 0; i < ts_res->count; i++) {
+ dn_filter = talloc_asprintf_append(
+ dn_filter,
+ "(%s=%s)",
+ SYSDB_DN,
+ ldb_dn_get_linearized(ts_res->msgs[i]->dn));
+ if (dn_filter == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ dn_filter = talloc_asprintf_append(dn_filter, "))");
+ if (dn_filter == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, NULL,
+ LDB_SCOPE_SUBTREE, attrs, "%s", dn_filter);
+ if (ret) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = EOK;
+ *_res = talloc_steal(mem_ctx, res);
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *name_filter,
@@ -333,8 +566,11 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx,
TALLOC_CTX *tmp_ctx;
static const char *attrs[] = SYSDB_PW_ATTRS;
char *filter = NULL;
+ const char *ts_filter = NULL;
struct ldb_dn *base_dn;
struct ldb_result *res;
+ struct ldb_result ts_res;
+ struct ldb_result *ts_cache_res;
int ret;
tmp_ctx = talloc_new(NULL);
@@ -348,6 +584,28 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx,
goto done;
}
+ ts_filter = enum_filter(tmp_ctx, SYSDB_PWENT_FILTER,
+ NULL, addtl_filter);
+ if (ts_filter == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_LIBS, "Searching timestamp cache with [%s]\n", ts_filter);
+
+ ZERO_STRUCT(ts_res);
+ ret = sysdb_search_ts_users(tmp_ctx, domain, ts_filter,
+ sysdb_ts_cache_attrs,
+ (size_t *) &ts_res.count, &ts_res.msgs);
+ if (ret != EOK && ret != ENOENT) {
+ goto done;
+ }
+
+ ret = search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res,
+ name_filter, &ts_cache_res);
+ if (ret != EOK && ret != ENOENT) {
+ goto done;
+ }
+
filter = enum_filter(tmp_ctx, SYSDB_PWENT_FILTER,
name_filter, addtl_filter);
if (filter == NULL) {
@@ -363,6 +621,19 @@ int sysdb_enumpwent_filter(TALLOC_CTX *mem_ctx,
goto done;
}
+ /* Merge in the timestamps from the fast ts db */
+ ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot merge timestamp cache values\n");
+ /* non-fatal */
+ }
+
+ res = sss_merge_ldb_results(res, ts_cache_res);
+ if (res == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
*_res = talloc_steal(mem_ctx, res);
done:
@@ -618,6 +889,12 @@ int sysdb_getgrnam(TALLOC_CTX *mem_ctx,
goto done;
}
+ ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot merge timestamp cache values\n");
+ /* non-fatal */
+ }
+
*_res = talloc_steal(mem_ctx, res);
done:
@@ -755,6 +1032,12 @@ int sysdb_getgrgid(TALLOC_CTX *mem_ctx,
goto done;
}
+ ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot merge timestamp cache values\n");
+ /* non-fatal */
+ }
+
*_res = talloc_steal(mem_ctx, res);
done:
@@ -771,10 +1054,18 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
TALLOC_CTX *tmp_ctx;
static const char *attrs[] = SYSDB_GRSRC_ATTRS;
const char *filter = NULL;
+ const char *ts_filter = NULL;
const char *base_filter;
struct ldb_dn *base_dn;
struct ldb_result *res;
- int ret;
+ struct ldb_result ts_res;
+ struct ldb_result *ts_cache_res;
+ int ret, lret;
+
+ if (_res == NULL) {
+ return EINVAL;
+ }
+ *_res = NULL;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
@@ -794,6 +1085,28 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
goto done;
}
+ ts_filter = enum_filter(tmp_ctx, base_filter,
+ NULL, addtl_filter);
+ if (ts_filter == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_LIBS, "Searching timestamp cache with [%s]\n", ts_filter);
+
+ ZERO_STRUCT(ts_res);
+ ret = sysdb_search_ts_groups(tmp_ctx, domain, ts_filter,
+ sysdb_ts_cache_attrs,
+ (size_t *) &ts_res.count, &ts_res.msgs);
+ if (ret != EOK && ret != ENOENT) {
+ goto done;
+ }
+
+ ret = search_ts_matches(tmp_ctx, domain->sysdb, attrs, &ts_res,
+ name_filter, &ts_cache_res);
+ if (ret != EOK && ret != ENOENT) {
+ goto done;
+ }
+
filter = enum_filter(tmp_ctx, base_filter,
name_filter, addtl_filter);
if (filter == NULL) {
@@ -802,10 +1115,10 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
}
DEBUG(SSSDBG_TRACE_LIBS, "Searching cache with [%s]\n", filter);
- ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
- LDB_SCOPE_SUBTREE, attrs, "%s", filter);
- if (ret) {
- ret = sysdb_error_to_errno(ret);
+ lret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res, base_dn,
+ LDB_SCOPE_SUBTREE, attrs, "%s", filter);
+ if (lret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(lret);
goto done;
}
@@ -814,6 +1127,19 @@ int sysdb_enumgrent_filter(TALLOC_CTX *mem_ctx,
goto done;
}
+ /* Merge in the timestamps from the fast ts db */
+ ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot merge timestamp cache values\n");
+ /* non-fatal */
+ }
+
+ res = sss_merge_ldb_results(res, ts_cache_res);
+ if (res == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
*_res = talloc_steal(mem_ctx, res);
done:
@@ -1212,6 +1538,13 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx,
goto done;
}
+ /* Merge in the timestamps from the fast ts db */
+ ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attributes);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot merge timestamp cache values\n");
+ /* non-fatal */
+ }
+
*_res = talloc_steal(mem_ctx, res);
done:
@@ -1909,3 +2242,54 @@ done:
talloc_free(tmp_ctx);
return ret;
}
+
+struct ldb_result *sss_merge_ldb_results(struct ldb_result *sysdb_res,
+ struct ldb_result *ts_res)
+{
+ size_t i, ii, count, total;
+ int ret;
+
+ if (ts_res == NULL || ts_res->count == 0) {
+ return sysdb_res;
+ }
+
+ total = sysdb_res->count + ts_res->count;
+ sysdb_res->msgs = talloc_realloc(sysdb_res, sysdb_res->msgs,
+ struct ldb_message *,
+ total);
+ if (sysdb_res->msgs == NULL) {
+ return NULL;
+ }
+
+ /* FIXME - this is O(2), so inefficient for large sets! */
+ count = sysdb_res->count;
+ for (i = 0; i < ts_res->count; i++) {
+ for (ii = 0; ii < sysdb_res->count; ii++) {
+ ret = ldb_dn_compare(ts_res->msgs[i]->dn, sysdb_res->msgs[ii]->dn);
+ if (ret == 0) {
+ break;
+ }
+ }
+
+ if (ii < sysdb_res->count) {
+ /* We already have this DN but ts_res might be more up-to-date
+ * wrt timestamps */
+ sysdb_res->msgs[ii] = talloc_steal(sysdb_res, ts_res->msgs[i]);
+ continue;
+ }
+ /* new DN, merge */
+ sysdb_res->msgs[count] = talloc_steal(sysdb_res, ts_res->msgs[i]);
+ count++;
+ }
+
+ if (count < total) {
+ sysdb_res->msgs = talloc_realloc(sysdb_res, sysdb_res->msgs,
+ struct ldb_message *,
+ count);
+ if (sysdb_res->msgs == NULL) {
+ return NULL;
+ }
+ }
+ sysdb_res->count = count;
+ return sysdb_res;
+}