sysdb_init.c revision f983b400bf4f6fb14a2174d6f58071e06e9ec832
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen/*
863f2bc9983c33221f5936421fc9c06caf21639aTimo Sirainen SSSD
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen System Database - initialization
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen Copyright (C) 2008-2011 Simo Sorce <ssorce@redhat.com>
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen Copyright (C) 2008-2011 Stephen Gallagher <ssorce@redhat.com>
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen This program is free software; you can redistribute it and/or modify
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen it under the terms of the GNU General Public License as published by
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen the Free Software Foundation; either version 3 of the License, or
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen (at your option) any later version.
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
863f2bc9983c33221f5936421fc9c06caf21639aTimo Sirainen This program is distributed in the hope that it will be useful,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen GNU General Public License for more details.
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen You should have received a copy of the GNU General Public License
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen*/
ca44a6ba994aaa3231a20ef6e046dfd97a8dcd2dTimo Sirainen
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen#include "util/util.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "util/strtonum.h"
8dec8eab222cb7a0b4ef5e066cb1d7dac8a526d1Timo Sirainen#include "util/sss_utf8.h"
8dec8eab222cb7a0b4ef5e066cb1d7dac8a526d1Timo Sirainen#include "db/sysdb_private.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "confdb/confdb.h"
ca44a6ba994aaa3231a20ef6e046dfd97a8dcd2dTimo Sirainen#include "util/probes.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include <time.h>
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#define LDB_MODULES_PATH "LDB_MODULES_PATH"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen/* If an entry differs only in these attributes, they are written to
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen * the timestamp cache only. In addition, objectclass is added so that
c1847a38dfbc8bad29547d96432ef9d707dbd345Timo Sirainen * we can distinguish between users and groups.
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen */
c1847a38dfbc8bad29547d96432ef9d707dbd345Timo Sirainenconst char *sysdb_ts_cache_attrs[] = {
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen SYSDB_OBJECTCLASS,
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen SYSDB_LAST_UPDATE,
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen SYSDB_CACHE_EXPIRE,
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen SYSDB_ORIG_MODSTAMP,
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen SYSDB_INITGR_EXPIRE,
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen SYSDB_USN,
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen
cd18d7bb3e8d5921c3c852bd0a27fbeff9a9babbTimo Sirainen NULL,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen};
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenerrno_t sysdb_ldb_connect(TALLOC_CTX *mem_ctx,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const char *filename,
149089b97827554ffd17dbf0cbc990b2301703f3Timo Sirainen int flags,
149089b97827554ffd17dbf0cbc990b2301703f3Timo Sirainen struct ldb_context **_ldb)
149089b97827554ffd17dbf0cbc990b2301703f3Timo Sirainen{
149089b97827554ffd17dbf0cbc990b2301703f3Timo Sirainen int ret;
1358e2c58ce29231485a5cfa454756d429ad3d2cTimo Sirainen struct ldb_context *ldb;
c1847a38dfbc8bad29547d96432ef9d707dbd345Timo Sirainen const char *mod_path;
b28a1c61a5d262fd16b46bebe47dbfb90ac9c5fcTimo Sirainen
149089b97827554ffd17dbf0cbc990b2301703f3Timo Sirainen if (_ldb == NULL) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return EINVAL;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ldb = ldb_init(mem_ctx, NULL);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!ldb) {
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen return EIO;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
ret = ldb_set_debug(ldb, ldb_debug_messages, NULL);
if (ret != LDB_SUCCESS) {
return EIO;
}
mod_path = getenv(LDB_MODULES_PATH);
if (mod_path != NULL) {
DEBUG(SSSDBG_TRACE_ALL, "Setting ldb module path to [%s].\n", mod_path);
ldb_set_modules_dir(ldb, mod_path);
}
ret = ldb_connect(ldb, filename, flags, NULL);
if (ret != LDB_SUCCESS) {
return EIO;
}
*_ldb = ldb;
return EOK;
}
static errno_t sysdb_ldb_reconnect(TALLOC_CTX *mem_ctx,
const char *ldb_file,
int flags,
struct ldb_context **ldb)
{
errno_t ret;
talloc_zfree(*ldb);
ret = sysdb_ldb_connect(mem_ctx, ldb_file, flags, ldb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_ldb_connect failed.\n");
}
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,
char **_ts_file)
{
char *ldb_file;
char *ts_file = NULL;
/* special case for the local domain */
if (strcasecmp(provider, "local") == 0) {
ldb_file = talloc_asprintf(mem_ctx, "%s/"LOCAL_SYSDB_FILE,
base_path);
} 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;
}
static errno_t sysdb_domain_create_int(struct ldb_context *ldb,
const char *domain_name)
{
struct ldb_message *msg;
TALLOC_CTX *tmp_ctx;
int ret;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
ret = ENOMEM;
goto done;
}
/* == create base domain object == */
msg = ldb_msg_new(tmp_ctx);
if (!msg) {
ret = ENOMEM;
goto done;
}
msg->dn = ldb_dn_new_fmt(msg, ldb, SYSDB_DOM_BASE, domain_name);
if (!msg->dn) {
ret = ENOMEM;
goto done;
}
ret = ldb_msg_add_string(msg, "cn", domain_name);
if (ret != LDB_SUCCESS) {
ret = EIO;
goto done;
}
/* do a synchronous add */
ret = ldb_add(ldb, msg);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to initialize DB (%d, [%s]) "
"for domain %s!\n",
ret, ldb_errstring(ldb),
domain_name);
ret = EIO;
goto done;
}
talloc_zfree(msg);
/* == create Users tree == */
msg = ldb_msg_new(tmp_ctx);
if (!msg) {
ret = ENOMEM;
goto done;
}
msg->dn = ldb_dn_new_fmt(msg, ldb,
SYSDB_TMPL_USER_BASE, domain_name);
if (!msg->dn) {
ret = ENOMEM;
goto done;
}
ret = ldb_msg_add_string(msg, "cn", "Users");
if (ret != LDB_SUCCESS) {
ret = EIO;
goto done;
}
/* do a synchronous add */
ret = ldb_add(ldb, msg);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to initialize DB (%d, [%s]) "
"for domain %s!\n",
ret, ldb_errstring(ldb),
domain_name);
ret = EIO;
goto done;
}
talloc_zfree(msg);
/* == create Groups tree == */
msg = ldb_msg_new(tmp_ctx);
if (!msg) {
ret = ENOMEM;
goto done;
}
msg->dn = ldb_dn_new_fmt(msg, ldb,
SYSDB_TMPL_GROUP_BASE, domain_name);
if (!msg->dn) {
ret = ENOMEM;
goto done;
}
ret = ldb_msg_add_string(msg, "cn", "Groups");
if (ret != LDB_SUCCESS) {
ret = EIO;
goto done;
}
/* do a synchronous add */
ret = ldb_add(ldb, msg);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to initialize DB (%d, [%s]) for "
"domain %s!\n",
ret, ldb_errstring(ldb),
domain_name);
ret = EIO;
goto done;
}
talloc_zfree(msg);
ret = EOK;
done:
talloc_zfree(tmp_ctx);
return ret;
}
errno_t sysdb_domain_create(struct sysdb_ctx *sysdb, const char *domain_name)
{
return sysdb_domain_create_int(sysdb->ldb, domain_name);
}
/* Compare versions of sysdb, returns ERRNO accordingly */
static errno_t
sysdb_version_check(const char *expected,
const char *received)
{
int ret;
unsigned int exp_major, exp_minor, recv_major, recv_minor;
if (strcmp(received, expected) == 0) {
return EOK;
}
ret = sscanf(expected, "%u.%u", &exp_major, &exp_minor);
if (ret != 2) {
return EINVAL;
}
ret = sscanf(received, "%u.%u", &recv_major, &recv_minor);
if (ret != 2) {
return EINVAL;
}
if (recv_major > exp_major) {
return ERR_SYSDB_VERSION_TOO_NEW;
} else if (recv_major < exp_major) {
return ERR_SYSDB_VERSION_TOO_OLD;
}
if (recv_minor > exp_minor) {
return ERR_SYSDB_VERSION_TOO_NEW;
} else if (recv_minor < exp_minor) {
return ERR_SYSDB_VERSION_TOO_OLD;
}
return EOK;
}
static errno_t sysdb_cache_add_base_ldif(struct ldb_context *ldb,
const char *base_ldif,
const char *domain_name)
{
int ret;
struct ldb_ldif *ldif;
while ((ldif = ldb_ldif_read_string(ldb, &base_ldif))) {
ret = ldb_add(ldb, ldif->msg);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to initialize DB (%d, [%s]) for domain %s!\n",
ret, ldb_errstring(ldb), domain_name);
return EIO;
}
ldb_ldif_read_free(ldb, ldif);
}
return EOK;
}
static errno_t sysdb_cache_create_empty(struct ldb_context *ldb,
const char *base_ldif,
struct sss_domain_info *domain)
{
int ret;
ret = sysdb_cache_add_base_ldif(ldb, base_ldif, domain->name);
if (ret != EOK) {
return ret;
}
ret = sysdb_domain_create_int(ldb, domain->name);
if (ret != EOK) {
return ret;
}
return EOK;
}
static errno_t sysdb_ts_cache_upgrade(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct ldb_context *ldb,
struct sss_domain_info *domain,
const char *cur_version,
const char **_new_version)
{
/* Currently the sysdb cache only has one version */
return EFAULT;
}
static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct ldb_context *ldb,
struct sss_domain_info *domain,
const char *cur_version,
const char **_new_version)
{
errno_t ret;
TALLOC_CTX *tmp_ctx;
const char *version;
struct ldb_context *save_ldb;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
return ENOMEM;
}
/* The upgrade process depends on having ldb around, yet the upgrade
* function shouldn't set the ldb pointer, only the connect function
* should after it's successful. To avoid hard refactoring, save the
* ldb pointer here and restore in the 'done' handler
*/
save_ldb = sysdb->ldb;
version = talloc_strdup(tmp_ctx, cur_version);
if (version == NULL) {
ret = ENOMEM;
goto done;
}
DEBUG(SSSDBG_CONF_SETTINGS,
"Upgrading DB [%s] from version: %s\n",
domain->name, version);
if (strcmp(version, SYSDB_VERSION_0_3) == 0) {
ret = sysdb_upgrade_03(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_4) == 0) {
ret = sysdb_upgrade_04(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_5) == 0) {
ret = sysdb_upgrade_05(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_6) == 0) {
ret = sysdb_upgrade_06(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_7) == 0) {
ret = sysdb_upgrade_07(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_8) == 0) {
ret = sysdb_upgrade_08(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_9) == 0) {
ret = sysdb_upgrade_09(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_10) == 0) {
ret = sysdb_upgrade_10(sysdb, domain, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_11) == 0) {
ret = sysdb_upgrade_11(sysdb, domain, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_12) == 0) {
ret = sysdb_upgrade_12(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_13) == 0) {
ret = sysdb_upgrade_13(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_14) == 0) {
ret = sysdb_upgrade_14(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_15) == 0) {
ret = sysdb_upgrade_15(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
if (strcmp(version, SYSDB_VERSION_0_16) == 0) {
ret = sysdb_upgrade_16(sysdb, &version);
if (ret != EOK) {
goto done;
}
}
ret = EOK;
done:
sysdb->ldb = save_ldb;
*_new_version = talloc_steal(mem_ctx, version);
talloc_free(tmp_ctx);
return ret;
}
static errno_t sysdb_cache_connect(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *ldb_file,
int flags,
const char *exp_version,
const char *base_ldif,
struct ldb_context **_ldb,
const char **_version)
{
TALLOC_CTX *tmp_ctx = NULL;
struct ldb_message_element *el;
struct ldb_result *res;
struct ldb_dn *verdn;
const char *version = NULL;
int ret;
struct ldb_context *ldb;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
ret = ENOMEM;
goto done;
}
ret = sysdb_ldb_connect(tmp_ctx, ldb_file, flags, &ldb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_ldb_connect failed.\n");
goto done;
}
verdn = ldb_dn_new(tmp_ctx, ldb, SYSDB_BASE);
if (!verdn) {
ret = EIO;
goto done;
}
ret = ldb_search(ldb, tmp_ctx, &res,
verdn, LDB_SCOPE_BASE,
NULL, NULL);
if (ret != LDB_SUCCESS) {
ret = EIO;
goto done;
}
if (res->count > 1) {
ret = EIO;
goto done;
}
if (res->count == 1) {
el = ldb_msg_find_element(res->msgs[0], "version");
if (!el) {
ret = EIO;
goto done;
}
if (el->num_values != 1) {
ret = EINVAL;
goto done;
}
version = talloc_strndup(tmp_ctx,
(char *)(el->values[0].data),
el->values[0].length);
if (!version) {
ret = ENOMEM;
goto done;
}
ret = sysdb_version_check(exp_version, version);
/* This is not the latest version. Return what version it is
* and appropriate error
*/
*_version = talloc_steal(mem_ctx, version);
goto done;
}
/* SYSDB_BASE does not exists, means db is empty, populate */
ret = sysdb_cache_create_empty(ldb, base_ldif, domain);
if (ret != EOK) {
goto done;
}
/* The cache has been newly created.
* We need to reopen the LDB to ensure that
* all of the special values take effect
* (such as enabling the memberOf plugin and
* the various indexes).
*/
ret = sysdb_ldb_reconnect(tmp_ctx, ldb_file, flags, &ldb);
if (ret != EOK) {
goto done;
}
/* If we connect to a new database, then the version is the
* latest one
*/
*_version = talloc_strdup(mem_ctx, exp_version);
if (*_version == NULL) {
ret = ENOMEM;
goto done;
}
done:
if (ret == EOK) {
*_ldb = talloc_steal(mem_ctx, ldb);
}
talloc_free(tmp_ctx);
return ret;
}
static int sysdb_domain_cache_connect(struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
bool allow_upgrade)
{
errno_t ret;
const char *version;
TALLOC_CTX *tmp_ctx;
struct ldb_context *ldb;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
return ENOMEM;
}
ret = sysdb_cache_connect(tmp_ctx, domain, sysdb->ldb_file, 0,
SYSDB_VERSION, SYSDB_BASE_LDIF,
&ldb, &version);
switch (ret) {
case ERR_SYSDB_VERSION_TOO_OLD:
if (allow_upgrade == false) {
DEBUG(SSSDBG_FATAL_FAILURE,
"DB version too old [%s], expected [%s] for domain %s!\n",
version, SYSDB_VERSION, domain->name);
goto done;
}
ret = sysdb_domain_cache_upgrade(tmp_ctx, sysdb, ldb, domain, version,
&version);
if (ret != EOK) {
goto done;
}
/* The version should now match SYSDB_VERSION.
* If not, it means we didn't match any of the
* known older versions. The DB might be
* corrupt or generated by a newer version of
* SSSD.
*/
ret = sysdb_version_check(SYSDB_VERSION, version);
if (ret == EOK) {
/* The cache has been upgraded.
* We need to reopen the LDB to ensure that
* any changes made above take effect.
*/
ret = sysdb_ldb_reconnect(tmp_ctx, sysdb->ldb_file, 0, &ldb);
goto done;
}
break;
case ERR_SYSDB_VERSION_TOO_NEW:
DEBUG(SSSDBG_FATAL_FAILURE,
"DB version too new [%s], expected [%s] for domain %s!\n",
version, SYSDB_VERSION, domain->name);
break;
default:
break;
}
done:
if (ret == EOK) {
sysdb->ldb = talloc_steal(sysdb, ldb);
}
talloc_free(tmp_ctx);
return ret;
}
static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
bool allow_upgrade)
{
errno_t ret;
const char *version;
TALLOC_CTX *tmp_ctx;
struct ldb_context *ldb;
if (sysdb->ldb_ts_file == NULL) {
DEBUG(SSSDBG_TRACE_FUNC, "No timestamp cache for %s\n", domain->name);
return EOK;
}
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
return ENOMEM;
}
ret = sysdb_cache_connect(tmp_ctx, domain,
sysdb->ldb_ts_file, LDB_FLG_NOSYNC,
SYSDB_TS_VERSION, SYSDB_TS_BASE_LDIF,
&ldb, &version);
switch (ret) {
case ERR_SYSDB_VERSION_TOO_OLD:
if (allow_upgrade == false) {
DEBUG(SSSDBG_FATAL_FAILURE,
"DB version too old [%s], expected [%s] for domain %s!\n",
version, SYSDB_VERSION, domain->name);
break;
}
ret = sysdb_ts_cache_upgrade(tmp_ctx, sysdb, ldb, domain, version,
&version);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Could not upgrade the timestamp ldb file (%d) (%s)\n",
ret, sss_strerror(ret));
break;
}
/* The version should now match SYSDB_VERSION.
* If not, it means we didn't match any of the
* known older versions. The DB might be
* corrupt or generated by a newer version of
* SSSD.
*/
ret = sysdb_version_check(SYSDB_TS_VERSION, version);
if (ret == EOK) {
/* The cache has been upgraded.
* We need to reopen the LDB to ensure that
* any changes made above take effect.
*/
ret = sysdb_ldb_reconnect(tmp_ctx,
sysdb->ldb_ts_file,
LDB_FLG_NOSYNC,
&ldb);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Could not reopen the timestamp ldb file (%d) (%s)\n",
ret, sss_strerror(ret));
}
}
break;
case ERR_SYSDB_VERSION_TOO_NEW:
DEBUG(SSSDBG_MINOR_FAILURE,
"DB version too new [%s], expected [%s] for domain %s!\n",
version, SYSDB_TS_VERSION, domain->name);
break;
default:
break;
}
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"The timestamps cache could not be opened. "
"Throwing away the database and opening a new one\n");
ret = unlink(sysdb->ldb_ts_file);
if (ret != EOK && errno != ENOENT) {
ret = errno;
DEBUG(SSSDBG_MINOR_FAILURE,
"Could not delete the timestamp ldb file (%d) (%s)\n",
ret, sss_strerror(ret));
return ret;
}
/* Now the connect must succeed because the previous cache doesn't
* exist anymore.
*/
ret = sysdb_cache_connect(tmp_ctx, domain,
sysdb->ldb_ts_file, LDB_FLG_NOSYNC,
SYSDB_TS_VERSION, SYSDB_TS_BASE_LDIF,
&ldb, &version);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Could not delete the timestamp ldb file (%d) (%s)\n",
ret, sss_strerror(ret));
}
}
if (ret == EOK) {
sysdb->ldb_ts = talloc_steal(sysdb, ldb);
}
talloc_free(tmp_ctx);
return ret;
}
int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *db_path,
bool allow_upgrade,
struct sysdb_ctx **_ctx)
{
TALLOC_CTX *tmp_ctx = NULL;
struct sysdb_ctx *sysdb;
int ret;
tmp_ctx = talloc_new(NULL);
if (tmp_ctx == NULL) {
return ENOMEM;
}
sysdb = talloc_zero(mem_ctx, struct sysdb_ctx);
if (!sysdb) {
ret = ENOMEM;
goto done;
}
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) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Could not open the sysdb cache [%d]: %s\n",
ret, sss_strerror(ret));
goto done;
}
ret = sysdb_timestamp_cache_connect(sysdb, domain, allow_upgrade);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Could not open the timestamp cache [%d]: %s\n",
ret, sss_strerror(ret));
goto done;
}
done:
if (ret == EOK) {
*_ctx = talloc_steal(mem_ctx, sysdb);
}
talloc_free(tmp_ctx);
return ret;
}
int sysdb_init(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domains,
bool allow_upgrade)
{
return sysdb_init_ext(mem_ctx, domains, allow_upgrade, false, 0, 0);
}
int sysdb_init_ext(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domains,
bool allow_upgrade,
bool chown_dbfile,
uid_t uid,
gid_t gid)
{
struct sss_domain_info *dom;
struct sysdb_ctx *sysdb;
int ret;
if (allow_upgrade) {
/* check if we have an old sssd.ldb to upgrade */
ret = sysdb_check_upgrade_02(domains, DB_PATH);
if (ret != EOK) {
return ret;
}
}
/* open a db for each domain */
for (dom = domains; dom; dom = dom->next) {
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 = sysdb_chown_db_files(sysdb, uid, gid);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Cannot chown databases for %s: [%d]: %s\n",
dom->name, ret, sss_strerror(ret));
return ret;
}
}
dom->sysdb = talloc_move(dom, &sysdb);
}
return EOK;
}
int sysdb_domain_init(TALLOC_CTX *mem_ctx,
struct sss_domain_info *domain,
const char *db_path,
struct sysdb_ctx **_ctx)
{
return sysdb_domain_init_internal(mem_ctx, domain,
db_path, false, _ctx);
}