From 65b859687a949395f176f2e88321df2b8668e11f Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 21 Apr 2016 13:48:04 +0200 Subject: [PATCH 05/14] SYSDB: Open a timestamps cache for caching domains For all domain types, except the local domain, open a connection to a new ldb file located at /var/lib/sss/db names timestamps_$domain.ldb. Constructs the ldb file path manually in sysdb_check_upgrade_02() but that should be acceptable because nobody should be running such an old cache these days anyway. --- src/db/sysdb.h | 3 ++ src/db/sysdb_init.c | 81 ++++++++++++++++++++++++++++----- src/db/sysdb_private.h | 7 ++- src/db/sysdb_upgrade.c | 8 ++-- src/responder/common/responder_common.c | 3 +- src/tests/common_dom.c | 34 ++++++++++++-- 6 files changed, 114 insertions(+), 22 deletions(-) diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 42f845033b8d828d3fbb1315df6cc8be54f8c8a2..e343de20c8c2d3694e6ab2e7f69d9e59929517d1 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -28,6 +28,7 @@ #include #define CACHE_SYSDB_FILE "cache_%s.ldb" +#define CACHE_TIMESTAMPS_FILE "timestamps_%s.ldb" #define LOCAL_SYSDB_FILE "sssd.ldb" #define SYSDB_BASE "cn=sysdb" @@ -309,6 +310,8 @@ struct range_info { char *range_type; }; +/* 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, diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c index 49a8d2b914776a3d506ed911bc772f3b16cc1333..d27b169d83343e37fb146a447784006003301fe0 100644 --- a/src/db/sysdb_init.c +++ b/src/db/sysdb_init.c @@ -30,6 +30,21 @@ #define LDB_MODULES_PATH "LDB_MODULES_PATH" +/* If an entry differs only in these attributes, they are written to + * the timestamp cache only. In addition, objectclass is added so that + * we can distinguish between users and groups. + */ +const char *sysdb_ts_cache_attrs[] = { + SYSDB_OBJECTCLASS, + SYSDB_LAST_UPDATE, + SYSDB_CACHE_EXPIRE, + SYSDB_ORIG_MODSTAMP, + SYSDB_INITGR_EXPIRE, + SYSDB_USN, + + NULL, +}; + errno_t sysdb_ldb_connect(TALLOC_CTX *mem_ctx, const char *filename, int flags, @@ -85,11 +100,43 @@ static errno_t sysdb_ldb_reconnect(TALLOC_CTX *mem_ctx, return ret; } +static errno_t sysdb_chown_db_files(struct sysdb_ctx *sysdb, + uid_t uid, gid_t gid) +{ + errno_t ret; + + ret = chown(sysdb->ldb_file, uid, gid); + if (ret != 0) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot set sysdb ownership of %s to %"SPRIuid":%"SPRIgid"\n", + sysdb->ldb_file, uid, gid); + return ret; + } + + if (sysdb->ldb_ts_file != NULL) { + ret = chown(sysdb->ldb_ts_file, uid, gid); + if (ret != 0) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot set sysdb ownership of %s to %"SPRIuid":%"SPRIgid"\n", + sysdb->ldb_ts_file, uid, gid); + return ret; + } + } + + return EOK; +} + int sysdb_get_db_file(TALLOC_CTX *mem_ctx, - const char *provider, const char *name, - const char *base_path, char **_ldb_file) + const char *provider, + const char *name, + const char *base_path, + char **_ldb_file, + char **_ts_file) { char *ldb_file; + char *ts_file = NULL; /* special case for the local domain */ if (strcasecmp(provider, "local") == 0) { @@ -98,12 +145,19 @@ int sysdb_get_db_file(TALLOC_CTX *mem_ctx, } else { ldb_file = talloc_asprintf(mem_ctx, "%s/"CACHE_SYSDB_FILE, base_path, name); + ts_file = talloc_asprintf(mem_ctx, "%s/"CACHE_TIMESTAMPS_FILE, + base_path, name); + if (ts_file == NULL) { + talloc_free(ldb_file); + return ENOMEM; + } } if (!ldb_file) { return ENOMEM; } *_ldb_file = ldb_file; + *_ts_file = ts_file; return EOK; } @@ -737,14 +791,17 @@ int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx, goto done; } - ret = sysdb_get_db_file(sysdb, domain->provider, - domain->name, db_path, - &sysdb->ldb_file); + ret = sysdb_get_db_file(sysdb, domain->provider, domain->name, db_path, + &sysdb->ldb_file, &sysdb->ldb_ts_file); if (ret != EOK) { goto done; } DEBUG(SSSDBG_FUNC_DATA, "DB File for %s: %s\n", domain->name, sysdb->ldb_file); + if (sysdb->ldb_ts_file) { + DEBUG(SSSDBG_FUNC_DATA, + "Timestamp file for %s: %s\n", domain->name, sysdb->ldb_ts_file); + } ret = sysdb_domain_cache_connect(sysdb, domain, allow_upgrade); if (ret != EOK) { @@ -802,17 +859,19 @@ int sysdb_init_ext(TALLOC_CTX *mem_ctx, ret = sysdb_domain_init_internal(mem_ctx, dom, DB_PATH, allow_upgrade, &sysdb); if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Cannot connect to database for %s: [%d]: %s\n", + dom->name, ret, sss_strerror(ret)); return ret; } if (chown_dbfile) { - ret = chown(sysdb->ldb_file, uid, gid); - if (ret != 0) { - ret = errno; + ret = sysdb_chown_db_files(sysdb, uid, gid); + if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, - "Cannot set sysdb ownership to %"SPRIuid":%"SPRIgid"\n", - uid, gid); - return ret; + "Cannot chown databases for %s: [%d]: %s\n", + dom->name, ret, sss_strerror(ret)); + return ret; } } diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h index 5f7a1ed6f82726b0f6c81fb79eb77cdb3d1612de..828863df7e9514a3562ec4e55cc0a433960ef116 100644 --- a/src/db/sysdb_private.h +++ b/src/db/sysdb_private.h @@ -118,8 +118,11 @@ struct sysdb_ctx { /* Internal utility functions */ int sysdb_get_db_file(TALLOC_CTX *mem_ctx, - const char *provider, const char *name, - const char *base_path, char **_ldb_file); + const char *provider, + const char *name, + const char *base_path, + char **_ldb_file, + char **_ts_file); errno_t sysdb_ldb_connect(TALLOC_CTX *mem_ctx, const char *filename, int flags, diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c index 873c8eedede63e7089edfb18bffd9eee86ed4f69..1858111cdc34c78a9e0a7b26c59ed83a8c6602cf 100644 --- a/src/db/sysdb_upgrade.c +++ b/src/db/sysdb_upgrade.c @@ -282,10 +282,10 @@ int sysdb_check_upgrade_02(struct sss_domain_info *domains, return ENOMEM; } - ret = sysdb_get_db_file(tmp_ctx, - "local", "UPGRADE", - db_path, &ldb_file); - if (ret != EOK) { + ldb_file = talloc_asprintf(tmp_ctx, "%s/"LOCAL_SYSDB_FILE, + db_path); + if (ldb_file == NULL) { + ret = ENOMEM; goto exit; } diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c index 883b22a6548c29738f23a5ccf6747969f4e7146c..2c0c5ae60786f4d038ec3a4f774a01f3b3b83303 100644 --- a/src/responder/common/responder_common.c +++ b/src/responder/common/responder_common.c @@ -935,7 +935,8 @@ int sss_process_init(TALLOC_CTX *mem_ctx, ret = sysdb_init(rctx, rctx->domains, false); if (ret != EOK) { SYSDB_VERSION_ERROR_DAEMON(ret); - DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n"); + DEBUG(SSSDBG_FATAL_FAILURE, + "fatal error initializing sysdb connection\n"); goto fail; } diff --git a/src/tests/common_dom.c b/src/tests/common_dom.c index 1d4800179e54ab876545f4333b864ef3361e6da7..f1eabd412520a59ae762adaad3341ee29850e420 100644 --- a/src/tests/common_dom.c +++ b/src/tests/common_dom.c @@ -24,6 +24,8 @@ #include #include +/* Including private header makes sure we can initialize test domains. */ +#include "db/sysdb_private.h" #include "tests/common.h" static errno_t @@ -192,6 +194,10 @@ mock_domain(TALLOC_CTX *mem_ctx, /* reset ldb error if any */ ldb_reset_err_string(sysdb_ctx_get_ldb(domain->sysdb)); + if (domain->sysdb->ldb_ts != NULL) { + ldb_reset_err_string(domain->sysdb->ldb_ts); + } + /* init with an AD-style regex to be able to test flat name */ ret = sss_names_init_from_args(domain, "(((?P[^\\\\]+)\\\\(?P.+$))|" \ @@ -303,6 +309,7 @@ void test_multidom_suite_cleanup(const char *tests_path, TALLOC_CTX *tmp_ctx = NULL; char *cdb_path = NULL; char *sysdb_path = NULL; + char *sysdb_ts_path = NULL; errno_t ret; int i; @@ -332,11 +339,20 @@ void test_multidom_suite_cleanup(const char *tests_path, for (i = 0; domains[i] != NULL; i++) { if (strcmp(domains[i], LOCAL_SYSDB_FILE) == 0) { /* local domain */ - sysdb_path = talloc_asprintf(tmp_ctx, "%s/%s", - tests_path, domains[i]); + ret = sysdb_get_db_file(tmp_ctx, "local", domains[i], tests_path, + &sysdb_path, &sysdb_ts_path); + if (ret != EOK) { + goto done; + } } else { - sysdb_path = talloc_asprintf(tmp_ctx, "%s/cache_%s.ldb", - tests_path, domains[i]); + /* The mocked database doesn't really care about its provider type, just + * distinguishes between a local and non-local databases + */ + ret = sysdb_get_db_file(tmp_ctx, "fake_nonlocal", domains[i], tests_path, + &sysdb_path, &sysdb_ts_path); + if (ret != EOK) { + goto done; + } } if (sysdb_path == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct sysdb path\n"); @@ -351,6 +367,16 @@ void test_multidom_suite_cleanup(const char *tests_path, "ldb file [%d]: (%s)\n", ret, sss_strerror(ret)); } + if (sysdb_ts_path) { + errno = 0; + ret = unlink(sysdb_ts_path); + if (ret != 0 && errno != ENOENT) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, "Could not delete the test domain " + "ldb timestamp file [%d]: (%s)\n", ret, sss_strerror(ret)); + } + } + talloc_zfree(sysdb_path); } } -- 2.4.11