summaryrefslogtreecommitdiffstats
path: root/src/db/sysdb_upgrade.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 05:31:45 +0000
commit74aa0bc6779af38018a03fd2cf4419fe85917904 (patch)
tree9cb0681aac9a94a49c153d5823e7a55d1513d91f /src/db/sysdb_upgrade.c
parentInitial commit. (diff)
downloadsssd-74aa0bc6779af38018a03fd2cf4419fe85917904.tar.xz
sssd-74aa0bc6779af38018a03fd2cf4419fe85917904.zip
Adding upstream version 2.9.4.upstream/2.9.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/db/sysdb_upgrade.c')
-rw-r--r--src/db/sysdb_upgrade.c2791
1 files changed, 2791 insertions, 0 deletions
diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
new file mode 100644
index 0000000..346a1cb
--- /dev/null
+++ b/src/db/sysdb_upgrade.c
@@ -0,0 +1,2791 @@
+/*
+ SSSD
+
+ Authors:
+ Simo Sorce <ssorce@redhat.com>
+ Stephen Gallagher <sgallagh@redhat.com>
+
+ Copyright (C) 2008-2011 Simo Sorce <ssorce@redhat.com>
+ Copyright (C) 2008-2011 Stephen Gallagher
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "db/sysdb_private.h"
+#include "db/sysdb_autofs.h"
+#include "db/sysdb_iphosts.h"
+#include "db/sysdb_ipnetworks.h"
+
+struct upgrade_ctx {
+ struct ldb_context *ldb;
+ const char *new_version;
+};
+
+static errno_t commence_upgrade(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
+ const char *new_ver, struct upgrade_ctx **_ctx)
+{
+ struct upgrade_ctx *ctx;
+ int ret;
+
+ DEBUG(SSSDBG_IMPORTANT_INFO, "UPGRADING DB TO VERSION %s\n", new_ver);
+
+ ctx = talloc(mem_ctx, struct upgrade_ctx);
+ if (!ctx) {
+ return ENOMEM;
+ }
+
+ ctx->ldb = ldb;
+ ctx->new_version = new_ver;
+
+ ret = ldb_transaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(ctx);
+ } else {
+ *_ctx = ctx;
+ }
+ return ret;
+}
+
+static errno_t update_version(struct upgrade_ctx *ctx)
+{
+ struct ldb_message *msg = NULL;
+ errno_t ret;
+
+ msg = ldb_msg_new(ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(msg, ctx->ldb, SYSDB_BASE);
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "version", LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "version", ctx->new_version);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(ctx->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(msg);
+ return ret;
+}
+
+static int finish_upgrade(int ret, struct upgrade_ctx **ctx, const char **ver)
+{
+ int lret;
+
+ if (ret == EOK) {
+ lret = ldb_transaction_commit((*ctx)->ldb);
+ ret = sysdb_error_to_errno(lret);
+ if (ret == EOK) {
+ *ver = (*ctx)->new_version;
+ }
+ }
+
+ if (ret != EOK) {
+ lret = ldb_transaction_cancel((*ctx)->ldb);
+ if (lret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Could not cancel transaction! [%s]\n",
+ ldb_strerror(lret));
+ /* Do not overwrite ret here, we want to return
+ * the original failure, not the failure of the
+ * transaction cancellation.
+ */
+ }
+ }
+
+ talloc_zfree(*ctx);
+ return ret;
+}
+
+/* serach all groups that have a memberUid attribute.
+ * change it into a member attribute for a user of same domain.
+ * remove the memberUid attribute
+ * add the new member attribute
+ * finally stop indexing memberUid
+ * upgrade version to 0.2
+ */
+int sysdb_upgrade_01(struct ldb_context *ldb, const char **ver)
+{
+ struct ldb_message_element *el;
+ struct ldb_result *res;
+ struct ldb_dn *basedn;
+ struct ldb_dn *mem_dn;
+ struct ldb_message *msg;
+ const struct ldb_val *val;
+ /* No change needed because this version has objectclass group */
+ const char *filter = "(&(memberUid=*)(objectclass=group))";
+ const char *attrs[] = { "memberUid", NULL };
+ const char *mdn;
+ char *domain;
+ int ret, i, j;
+ TALLOC_CTX *tmp_ctx;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(tmp_ctx, ldb, SYSDB_VERSION_0_2, &ctx);
+ if (ret) {
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ basedn = ldb_dn_new(tmp_ctx, ldb, SYSDB_BASE);
+ if (!basedn) {
+ ret = EIO;
+ goto done;
+ }
+
+ ret = ldb_search(ldb, tmp_ctx, &res,
+ basedn, LDB_SCOPE_SUBTREE,
+ attrs, "%s", filter);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ for (i = 0; i < res->count; i++) {
+ el = ldb_msg_find_element(res->msgs[i], "memberUid");
+ if (!el) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "memberUid is missing from message [%s], skipping\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn));
+ continue;
+ }
+
+ /* create modification message */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = res->msgs[i]->dn;
+
+ ret = ldb_msg_add_empty(msg, "memberUid", LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, SYSDB_MEMBER, LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* get domain name component value */
+ val = ldb_dn_get_component_val(res->msgs[i]->dn, 2);
+ domain = talloc_strndup(tmp_ctx, (const char *)val->data, val->length);
+ if (!domain) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (j = 0; j < el->num_values; j++) {
+ mem_dn = ldb_dn_new_fmt(tmp_ctx, ldb, SYSDB_TMPL_USER,
+ (const char *)el->values[j].data, domain);
+ if (!mem_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ mdn = talloc_strdup(msg, ldb_dn_get_linearized(mem_dn));
+ if (!mdn) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, SYSDB_MEMBER, mdn);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_zfree(mem_dn);
+ }
+
+ /* ok now we are ready to modify the entry */
+ ret = ldb_modify(ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ talloc_zfree(msg);
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_check_upgrade_02(struct sss_domain_info *domains,
+ const char *db_path)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_context *ldb;
+ char *ldb_file;
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *dom;
+ struct ldb_message_element *el;
+ struct ldb_message *msg;
+ struct ldb_result *res;
+ struct ldb_dn *verdn;
+ const char *version = NULL;
+ bool do_02_upgrade = false;
+ bool ctx_trans = false;
+ int ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ldb_file = talloc_asprintf(tmp_ctx, "%s/"LOCAL_SYSDB_FILE,
+ db_path);
+ if (ldb_file == NULL) {
+ ret = ENOMEM;
+ goto exit;
+ }
+
+ ret = sysdb_ldb_connect(tmp_ctx, ldb_file, 0, &ldb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_ldb_connect failed.\n");
+ return ret;
+ }
+
+ verdn = ldb_dn_new(tmp_ctx, ldb, SYSDB_BASE);
+ if (!verdn) {
+ ret = EIO;
+ goto exit;
+ }
+
+ ret = ldb_search(ldb, tmp_ctx, &res,
+ verdn, LDB_SCOPE_BASE,
+ NULL, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto exit;
+ }
+ if (res->count > 1) {
+ ret = EIO;
+ goto exit;
+ }
+
+ if (res->count == 1) {
+ el = ldb_msg_find_element(res->msgs[0], "version");
+ if (el) {
+ if (el->num_values != 1) {
+ ret = EINVAL;
+ goto exit;
+ }
+ version = talloc_strndup(tmp_ctx,
+ (char *)(el->values[0].data),
+ el->values[0].length);
+ if (!version) {
+ ret = ENOMEM;
+ goto exit;
+ }
+
+ if (strcmp(version, SYSDB_VERSION) == 0) {
+ /* all fine, return */
+ ret = EOK;
+ goto exit;
+ }
+
+ DEBUG(SSSDBG_CONF_SETTINGS,
+ "Upgrading DB from version: %s\n", version);
+
+ if (strcmp(version, SYSDB_VERSION_0_1) == 0) {
+ /* convert database */
+ ret = sysdb_upgrade_01(ldb, &version);
+ if (ret != EOK) goto exit;
+ }
+
+ if (strcmp(version, SYSDB_VERSION_0_2) == 0) {
+ /* need to convert database to split files */
+ do_02_upgrade = true;
+ }
+
+ }
+ }
+
+ if (!do_02_upgrade) {
+ /* not a v2 upgrade, return and let the normal code take over any
+ * further upgrade */
+ ret = EOK;
+ goto exit;
+ }
+
+ /* == V2->V3 UPGRADE == */
+
+ DEBUG(SSSDBG_IMPORTANT_INFO,
+ "UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_3);
+
+ /* ldb uses posix locks,
+ * posix is stupid and kills all locks when you close *any* file
+ * descriptor associated to the same file.
+ * Therefore we must close and reopen the ldb file here */
+
+ /* == Backup and reopen ldb == */
+
+ /* close */
+ talloc_zfree(ldb);
+
+ /* backup*/
+ ret = backup_file(ldb_file, SSSDBG_FATAL_FAILURE);
+ if (ret != EOK) {
+ goto exit;
+ }
+
+ /* reopen */
+ ret = sysdb_ldb_connect(tmp_ctx, ldb_file, 0, &ldb);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_ldb_connect failed.\n");
+ return ret;
+ }
+
+ /* open a transaction */
+ ret = ldb_transaction_start(ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to start ldb transaction! (%d)\n", ret);
+ ret = EIO;
+ goto exit;
+ }
+
+ /* == Upgrade contents == */
+
+ for (dom = domains; dom; dom = dom->next) {
+ struct ldb_dn *domain_dn;
+ struct ldb_dn *users_dn;
+ struct ldb_dn *groups_dn;
+ int i;
+
+ /* create new dom db */
+ ret = sysdb_domain_init_internal(tmp_ctx, dom,
+ db_path, false, &sysdb);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = ldb_transaction_start(sysdb->ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to start ldb transaction! (%d)\n", ret);
+ ret = EIO;
+ goto done;
+ }
+ ctx_trans = true;
+
+ /* search all entries for this domain in local,
+ * copy them all in the new database,
+ * then remove them from local */
+
+ domain_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
+ SYSDB_DOM_BASE, dom->name);
+ if (!domain_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(ldb, tmp_ctx, &res,
+ domain_dn, LDB_SCOPE_SUBTREE,
+ NULL, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ /*
+ * dom->sysdb->ldb is not initialized,
+ * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn()
+ */
+ users_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
+ SYSDB_TMPL_USER_BASE, dom->name);
+ if (!users_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /*
+ * dom->sysdb->ldb is not initialized,
+ * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn()
+ */
+ groups_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
+ SYSDB_TMPL_GROUP_BASE, dom->name);
+ if (!groups_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < res->count; i++) {
+
+ struct ldb_dn *orig_dn;
+
+ msg = res->msgs[i];
+
+ /* skip pre-created congtainers */
+ if ((ldb_dn_compare(msg->dn, domain_dn) == 0) ||
+ (ldb_dn_compare(msg->dn, users_dn) == 0) ||
+ (ldb_dn_compare(msg->dn, groups_dn) == 0)) {
+ continue;
+ }
+
+ /* regenerate the DN against the new ldb as it may have different
+ * casefolding rules (example: name changing from case insensitive
+ * to case sensitive) */
+ orig_dn = msg->dn;
+ msg->dn = ldb_dn_new(msg, sysdb->ldb,
+ ldb_dn_get_linearized(orig_dn));
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_add(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "WARNING: Could not add entry %s,"
+ " to new ldb file! (%d [%s])\n",
+ ldb_dn_get_linearized(msg->dn),
+ ret, ldb_errstring(sysdb->ldb));
+ }
+
+ ret = ldb_delete(ldb, orig_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "WARNING: Could not remove entry %s,"
+ " from old ldb file! (%d [%s])\n",
+ ldb_dn_get_linearized(orig_dn),
+ ret, ldb_errstring(ldb));
+ }
+ }
+
+ /* now remove the basic containers from local */
+ /* these were optional so debug at level 9 in case
+ * of failure just for tracing */
+ ret = ldb_delete(ldb, groups_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_TRACE_ALL, "WARNING: Could not remove entry %s,"
+ " from old ldb file! (%d [%s])\n",
+ ldb_dn_get_linearized(groups_dn),
+ ret, ldb_errstring(ldb));
+ }
+ ret = ldb_delete(ldb, users_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_TRACE_ALL, "WARNING: Could not remove entry %s,"
+ " from old ldb file! (%d [%s])\n",
+ ldb_dn_get_linearized(users_dn),
+ ret, ldb_errstring(ldb));
+ }
+ ret = ldb_delete(ldb, domain_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_TRACE_ALL, "WARNING: Could not remove entry %s,"
+ " from old ldb file! (%d [%s])\n",
+ ldb_dn_get_linearized(domain_dn),
+ ret, ldb_errstring(ldb));
+ }
+
+ ret = ldb_transaction_commit(sysdb->ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to commit ldb transaction! (%d)\n", ret);
+ ret = EIO;
+ goto done;
+ }
+ ctx_trans = false;
+
+ talloc_zfree(domain_dn);
+ talloc_zfree(groups_dn);
+ talloc_zfree(users_dn);
+ talloc_zfree(res);
+ }
+
+ /* conversion done, upgrade version number */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, ldb, SYSDB_BASE);
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "version", LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "version", SYSDB_VERSION_0_3);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = ldb_transaction_commit(ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to commit ldb transaction! (%d)\n", ret);
+ ret = EIO;
+ goto exit;
+ }
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ if (ctx_trans) {
+ ret = ldb_transaction_cancel(sysdb->ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to cancel ldb transaction! (%d)\n", ret);
+ }
+ }
+ ret = ldb_transaction_cancel(ldb);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to cancel ldb transaction! (%d)\n", ret);
+ }
+ }
+
+exit:
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_03(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_4, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Make this database case-sensitive */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@ATTRIBUTES");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_04(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_5, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add new index */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@INDEXLIST");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "originalDN");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* Rebuild memberuid and memberoif attributes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@MEMBEROF-REBUILD");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_add(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_05(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_6, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@INDEXLIST");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Add Index for dataExpireTimestamp */
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "dataExpireTimestamp");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Add index to speed up ONELEVEL searches */
+ ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "@IDXONE", "1");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_06(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_7, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@ATTRIBUTES");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Case insensitive search for originalDN */
+ ret = ldb_msg_add_empty(msg, SYSDB_ORIG_DN, LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, SYSDB_ORIG_DN, "CASE_INSENSITIVE");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_07(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_8, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@INDEXLIST");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Add Index for nameAlias */
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "nameAlias");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_08(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_9, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@INDEXLIST");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Add Index for servicePort and serviceProtocol */
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "servicePort");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "serviceProtocol");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_09(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_10, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@INDEXLIST");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Add Index for ipHostNumber and ipNetworkNumber */
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "sudoUser");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_10(struct sysdb_ctx *sysdb, struct sss_domain_info *domain,
+ const char **ver)
+{
+
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_result *res;
+ struct ldb_message *msg;
+ struct ldb_message *user;
+ struct ldb_message_element *memberof_el;
+ const char *name;
+ struct ldb_dn *basedn;
+ /* No change needed because version 10 has objectclass user */
+ const char *filter = "(&(objectClass=user)(!(uidNumber=*))(memberOf=*))";
+ const char *attrs[] = { "name", "memberof", NULL };
+ struct upgrade_ctx *ctx;
+ int i, j;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_11, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /*
+ * dom->sysdb->ldb is not initialized,
+ * so ldb_dn_new_fmt() shouldn't be changed to sysdb_*_base_dn()
+ */
+ basedn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
+ SYSDB_TMPL_USER_BASE, domain->name);
+ if (basedn == NULL) {
+ ret = EIO;
+ goto done;
+ }
+
+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, basedn, LDB_SCOPE_SUBTREE,
+ attrs, "%s", filter);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ for (i = 0; i < res->count; i++) {
+ user = res->msgs[i];
+ memberof_el = ldb_msg_find_element(user, "memberof");
+ if (memberof_el == NULL) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ name = ldb_msg_find_attr_as_string(user, "name", NULL);
+ if (name == NULL) {
+ ret = EIO;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, "User [%s] is a member of %d groups\n",
+ name, memberof_el->num_values);
+
+ for (j = 0; j < memberof_el->num_values; j++) {
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_from_ldb_val(tmp_ctx, sysdb->ldb, &memberof_el->values[j]);
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (!ldb_dn_validate(msg->dn)) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "DN validation failed during "
+ "upgrade: [%s]\n",
+ memberof_el->values[j].data);
+ talloc_zfree(msg);
+ continue;
+ }
+
+ ret = ldb_msg_add_empty(msg, "ghost", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "ghost", name);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Adding ghost [%s] to entry [%s]\n",
+ name, ldb_dn_get_linearized(msg->dn));
+
+ ret = sss_ldb_modify_permissive(sysdb->ldb, msg);
+ talloc_zfree(msg);
+ if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
+ /* If we failed adding the ghost user(s) because the values already
+ * exist, they were probably propagated from a parent that was
+ * upgraded before us. Mark the group as expired so that it is
+ * refreshed on next request.
+ */
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_from_ldb_val(tmp_ctx, sysdb->ldb, &memberof_el->values[j]);
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, SYSDB_CACHE_EXPIRE,
+ LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, SYSDB_CACHE_EXPIRE, "1");
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+
+ ret = sss_ldb_modify_permissive(sysdb->ldb, msg);
+ talloc_zfree(msg);
+ if (ret != LDB_SUCCESS) {
+ goto done;
+ }
+ } else if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Removing fake user [%s]\n",
+ ldb_dn_get_linearized(user->dn));
+
+ ret = ldb_delete(sysdb->ldb, user->dn);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_11(struct sysdb_ctx *sysdb, struct sss_domain_info *domain,
+ const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret;
+ struct ldb_result *res;
+ struct ldb_message *entry;
+ const char *key;
+ const char *value;
+ struct ldb_message_element *memberof_el;
+ struct ldb_dn *memberof_dn;
+ struct ldb_dn *basedn;
+ const struct ldb_val *val;
+ const char *attrs[] = { SYSDB_AUTOFS_ENTRY_KEY,
+ SYSDB_AUTOFS_ENTRY_VALUE,
+ SYSDB_MEMBEROF,
+ NULL };
+ struct upgrade_ctx *ctx;
+ size_t i, j;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_12, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_CUSTOM_SUBTREE,
+ AUTOFS_ENTRY_SUBDIR, domain->name);
+ if (basedn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_search(sysdb->ldb, tmp_ctx, &res, basedn, LDB_SCOPE_SUBTREE,
+ attrs, "(objectClass=%s)", SYSDB_AUTOFS_ENTRY_OC);
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_LIBS, "Found %d autofs entries\n", res->count);
+
+ for (i = 0; i < res->count; i++) {
+ entry = res->msgs[i];
+ key = ldb_msg_find_attr_as_string(entry,
+ SYSDB_AUTOFS_ENTRY_KEY, NULL);
+ value = ldb_msg_find_attr_as_string(entry,
+ SYSDB_AUTOFS_ENTRY_VALUE, NULL);
+ memberof_el = ldb_msg_find_element(entry, SYSDB_MEMBEROF);
+
+ if (key && value && memberof_el) {
+ for (j = 0; j < memberof_el->num_values; j++) {
+ memberof_dn = ldb_dn_from_ldb_val(tmp_ctx, sysdb->ldb,
+ &(memberof_el->values[j]));
+ if (!memberof_dn) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot convert memberof into DN, skipping\n");
+ continue;
+ }
+
+ val = ldb_dn_get_rdn_val(memberof_dn);
+ if (!val) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot get map name from map DN\n");
+ continue;
+ }
+
+ ret = sysdb_save_autofsentry(domain,
+ (const char *) val->data,
+ key, value, NULL, 0, 0);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot save autofs entry [%s]-[%s] into map %s\n",
+ key, value, val->data);
+ continue;
+ }
+ }
+
+ }
+
+ /* Delete the old entry if it was either processed or incomplete */
+ DEBUG(SSSDBG_TRACE_LIBS, "Deleting [%s]\n",
+ ldb_dn_get_linearized(entry->dn));
+
+ ret = ldb_delete(sysdb->ldb, entry->dn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot delete old autofs entry %s\n",
+ ldb_dn_get_linearized(entry->dn));
+ continue;
+ }
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_12(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_13, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@INDEXLIST");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* add index for sshKnownHostsExpire */
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "sshKnownHostsExpire");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_13(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ struct ldb_result *dom_res;
+ struct ldb_result *res;
+ struct ldb_dn *basedn;
+ const char *attrs[] = { "cn", "name", NULL };
+ const char *tmp_str;
+ errno_t ret;
+ int i, j, l, n;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_14, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ basedn = ldb_dn_new(ctx, sysdb->ldb, SYSDB_BASE);
+ if (!basedn) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
+ ret = EIO;
+ goto done;
+ }
+
+ ret = ldb_search(sysdb->ldb, ctx, &dom_res,
+ basedn, LDB_SCOPE_ONELEVEL,
+ attrs, "objectclass=%s", SYSDB_SUBDOMAIN_CLASS);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to search subdomains\n");
+ ret = EIO;
+ goto done;
+ }
+
+ for (i = 0; i < dom_res->count; i++) {
+
+ tmp_str = ldb_msg_find_attr_as_string(dom_res->msgs[i], "cn", NULL);
+ if (tmp_str == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "The object [%s] doesn't have a name\n",
+ ldb_dn_get_linearized(dom_res->msgs[i]->dn));
+ continue;
+ }
+
+ basedn = ldb_dn_new_fmt(ctx, sysdb->ldb, SYSDB_DOM_BASE, tmp_str);
+ if (!basedn) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to build base dn for subdomain %s\n", tmp_str);
+ continue;
+ }
+
+ ret = ldb_search(sysdb->ldb, ctx, &res,
+ basedn, LDB_SCOPE_SUBTREE, attrs, NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to search subdomain %s\n", tmp_str);
+ talloc_free(basedn);
+ continue;
+ }
+
+ l = ldb_dn_get_comp_num(basedn);
+ for (j = 0; j < res->count; j++) {
+ n = ldb_dn_get_comp_num(res->msgs[j]->dn);
+ if (n <= l + 1) {
+ /* Do not remove subdomain containers, only their contents */
+ continue;
+ }
+ ret = ldb_delete(sysdb->ldb, res->msgs[j]->dn);
+ if (ret) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to delete %s\n",
+ ldb_dn_get_linearized(res->msgs[j]->dn));
+ continue;
+ }
+ }
+
+ talloc_free(basedn);
+ talloc_free(res);
+ }
+
+ talloc_free(dom_res);
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
+int sysdb_upgrade_14(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ struct ldb_message *msg;
+ struct ldb_result *res;
+ struct ldb_dn *basedn;
+ struct ldb_dn *newdn;
+ const char *attrs[] = { SYSDB_NAME, NULL };
+ const char *tmp_str;
+ errno_t ret;
+ int i;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_15, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ basedn = ldb_dn_new(ctx, sysdb->ldb, SYSDB_BASE);
+ if (!basedn) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to build base dn\n");
+ ret = EIO;
+ goto done;
+ }
+
+ /* create base ranges container */
+ msg = ldb_msg_new(ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(msg, sysdb->ldb, SYSDB_TMPL_RANGE_BASE);
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, "cn", "ranges");
+ if (ret != LDB_SUCCESS) {
+ ret = EIO;
+ goto done;
+ }
+ /* do a synchronous add */
+ ret = ldb_add(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to upgrade DB (%d, [%s])!\n",
+ ret, ldb_errstring(sysdb->ldb));
+ ret = EIO;
+ goto done;
+ }
+ talloc_zfree(msg);
+
+ ret = ldb_search(sysdb->ldb, ctx, &res,
+ basedn, LDB_SCOPE_SUBTREE, attrs,
+ "objectclass=%s", SYSDB_ID_RANGE_CLASS);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to search range objects\n");
+ ret = EIO;
+ goto done;
+ }
+
+ /* Failure to convert any range is not fatal. As long as there are no
+ * left-over objects we can fail to move them around, as they will be
+ * recreated on the next online access */
+ for (i = 0; i < res->count; i++) {
+ tmp_str = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_NAME, NULL);
+ if (tmp_str == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "The object [%s] doesn't have a name\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn));
+ ret = ldb_delete(sysdb->ldb, res->msgs[i]->dn);
+ if (ret) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to delete %s\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn));
+ ret = EIO;
+ goto done;
+ }
+ continue;
+ }
+
+ newdn = ldb_dn_new_fmt(ctx, sysdb->ldb, SYSDB_TMPL_RANGE, tmp_str);
+ if (!newdn) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to create new DN to move [%s]\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn));
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_rename(sysdb->ldb, res->msgs[i]->dn, newdn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Failed to move [%s] to [%s]\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn),
+ ldb_dn_get_linearized(newdn));
+ ret = ldb_delete(sysdb->ldb, res->msgs[i]->dn);
+ if (ret) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to delete %s\n",
+ ldb_dn_get_linearized(res->msgs[i]->dn));
+ ret = EIO;
+ goto done;
+ }
+ }
+ talloc_zfree(newdn);
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
+int sysdb_upgrade_15(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_16, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (!msg) {
+ ret = ENOMEM;
+ goto done;
+ }
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@ATTRIBUTES");
+ if (!msg->dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Case insensitive search for canonicalUserPrincipalName */
+ ret = ldb_msg_add_empty(msg, SYSDB_CANONICAL_UPN, LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_string(msg, SYSDB_CANONICAL_UPN, "CASE_INSENSITIVE");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_16(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+ errno_t ret;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_17, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ msg = ldb_msg_new(ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* add index for objectSIDString */
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", "objectSIDString");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
+static char *object_domain_from_dn(TALLOC_CTX *mem_ctx,
+ struct ldb_dn *dn,
+ unsigned domain_index)
+{
+ const struct ldb_val *val;
+
+ val = ldb_dn_get_component_val(dn, domain_index);
+ if (val == NULL) {
+ return NULL;
+ }
+ return talloc_strdup(mem_ctx, (const char *) val->data);
+}
+
+static char *object_domain(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ struct ldb_message *msg,
+ const char *domain_attr,
+ unsigned domain_index)
+{
+ struct ldb_dn *dom_dn;
+
+ if (domain_attr != NULL) {
+ dom_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, domain_attr);
+ } else {
+ /* If no specific attribute to take the domain from is specified,
+ * use the DN */
+ dom_dn = msg->dn;
+ }
+
+ if (dom_dn == NULL) {
+ return NULL;
+ }
+
+ return object_domain_from_dn(mem_ctx, dom_dn, domain_index);
+}
+
+/* Used for attributes like sudoUser which contain group or user name or
+ * ID, depending on the value prefix */
+typedef bool (*should_qualify_val_fn)(const char *val);
+
+/* Qualifies a string attribute using domain_name. Optionally, if qfn is
+ * given, only qualifies the name if qfn returns true */
+static errno_t qualify_attr(struct ldb_message *msg,
+ struct ldb_message *mod_msg,
+ struct sss_names_ctx *names,
+ const char *domain_name,
+ const char *attrname,
+ should_qualify_val_fn qfn)
+{
+ struct ldb_message_element *el;
+ struct ldb_message_element *mod_el;
+ char *fqval;
+ char *shortname;
+ const char *rawname;
+ int ret;
+ struct ldb_val val;
+ bool exists = false;
+
+ el = ldb_msg_find_element(msg, attrname);
+ if (el == NULL) {
+ /* This entry does not have this element, fine */
+ return EOK;
+ }
+
+ for (size_t c = 0; c < el->num_values; c++) {
+ rawname = (const char *) el->values[c].data;
+
+ if (qfn != NULL && qfn(rawname) == false) {
+ continue;
+ }
+
+ ret = sss_parse_name(mod_msg, names, rawname, NULL, &shortname);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot parse raw attribute %s\n", rawname);
+ continue;
+ }
+
+ fqval = sss_create_internal_fqname(el->values, shortname, domain_name);
+ talloc_free(shortname);
+ if (fqval == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot qualify %s@%s\n",
+ shortname, domain_name);
+ continue;
+ }
+
+
+ mod_el = ldb_msg_find_element(mod_msg, attrname);
+ if (mod_el != NULL) {
+ val.data = (uint8_t *) fqval;
+ val.length = strlen(fqval);
+
+ if (ldb_msg_find_val(mod_el, &val) != NULL) {
+ return true;
+ }
+ }
+
+ DEBUG(SSSDBG_TRACE_FUNC, "Qualified %s:%s into %s\n",
+ attrname, rawname, fqval);
+
+ if (!exists) {
+ ret = ldb_msg_add_empty(mod_msg, attrname, LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ continue;
+ }
+
+ exists = true;
+ }
+
+ ret = ldb_msg_add_steal_string(mod_msg, attrname, fqval);
+ if (ret != LDB_SUCCESS) {
+ continue;
+ }
+ }
+
+ return EOK;
+}
+
+/* Returns a copy of old_dn_val with RDN qualified. The domain name
+ * is read from the DN itself
+ */
+static struct ldb_dn *qualify_rdn(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ struct sss_names_ctx *names,
+ struct ldb_dn *old_dn_val)
+{
+ struct ldb_dn *parent_dn = NULL;
+ const struct ldb_val *val = NULL;
+ const char *rdn_name = NULL;
+ struct ldb_dn *new_dn = NULL;
+ char *fqrdn = NULL;
+ char *shortname = NULL;
+ char *dn_domain = NULL;
+ TALLOC_CTX *tmp_ctx = NULL;
+ int ret;
+
+ rdn_name = ldb_dn_get_rdn_name(old_dn_val);
+ if (rdn_name == NULL) {
+ return NULL;
+ }
+
+ if (strcmp(rdn_name, SYSDB_NAME) != 0) {
+ /* Only qualify DNs with name= rdn. This applies to overrideDNs mostly,
+ * because those can contain either names or UUIDs
+ */
+ return ldb_dn_copy(mem_ctx, old_dn_val);
+ }
+
+ val = ldb_dn_get_rdn_val(old_dn_val);
+ if (val == NULL) {
+ return NULL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+
+ dn_domain = object_domain_from_dn(tmp_ctx, old_dn_val, 2);
+ if (dn_domain == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot determine domain of %s\n",
+ ldb_dn_get_linearized(old_dn_val));
+ goto done;
+ }
+
+ ret = sss_parse_name(tmp_ctx, names, (const char *) val->data,
+ NULL, &shortname);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot parse raw RDN %s\n", (const char *) val->data);
+ goto done;
+ }
+
+ fqrdn = sss_create_internal_fqname(tmp_ctx, shortname, dn_domain);
+ if (fqrdn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot qualify %s@%s\n",
+ shortname, dn_domain);
+ goto done;
+ }
+
+ parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn_val);
+ if (parent_dn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot get parent of %s\n",
+ ldb_dn_get_linearized(old_dn_val));
+ goto done;
+ }
+
+ new_dn = ldb_dn_new_fmt(mem_ctx, ldb, "%s=%s,%s",
+ rdn_name, fqrdn,
+ ldb_dn_get_linearized(parent_dn));
+done:
+ talloc_free(tmp_ctx);
+ return new_dn;
+}
+
+static errno_t qualify_dn_attr(struct ldb_context *ldb,
+ struct ldb_message *msg,
+ struct ldb_message *mod_msg,
+ struct sss_names_ctx *names,
+ const char *attrname)
+{
+ struct ldb_message_element *el;
+ struct ldb_message_element *mod_el;
+ struct ldb_dn *attr_dn;
+ struct ldb_dn *fqdn;
+ errno_t ret;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ el = ldb_msg_find_element(msg, attrname);
+ if (el == NULL || el->num_values == 0) {
+ return EOK;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ for (size_t c = 0; c < el->num_values; c++) {
+ attr_dn = ldb_dn_new(tmp_ctx, ldb, (const char *) el->values[c].data);
+ if (attr_dn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot create DN from %s\n",
+ (const char *) el->values[c].data);
+ continue;
+ }
+
+ if (!ldb_dn_validate(attr_dn)) {
+ DEBUG(SSSDBG_OP_FAILURE, "DN %s does not validate\n",
+ (const char *) el->values[c].data);
+ continue;
+ }
+
+ fqdn = qualify_rdn(tmp_ctx, ldb, names, attr_dn);
+ if (fqdn == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot qualify %s\n",
+ (const char *) el->values[c].data);
+ continue;
+ }
+
+ ret = ldb_msg_add_linearized_dn(mod_msg, attrname, fqdn);
+ if (ret != LDB_SUCCESS) {
+ continue;
+ }
+
+ talloc_free(attr_dn);
+ talloc_free(fqdn);
+ }
+
+ mod_el = ldb_msg_find_element(mod_msg, attrname);
+ if (mod_el != NULL) {
+ mod_el->flags = LDB_FLAG_MOD_REPLACE;
+ }
+
+ talloc_free(tmp_ctx);
+ return EOK;
+}
+
+static errno_t expire_object(struct ldb_message *object,
+ struct ldb_message *mod_msg)
+{
+ errno_t ret;
+ struct ldb_message_element *el;
+ const char *attrs[] = { SYSDB_CACHE_EXPIRE,
+ SYSDB_LAST_UPDATE,
+ SYSDB_INITGR_EXPIRE,
+ NULL
+ };
+
+ for (size_t c = 0; attrs[c] != NULL; c++) {
+ el = ldb_msg_find_element(object, attrs[c]);
+ if (el == NULL) {
+ continue;
+ }
+
+ ret = ldb_msg_add_empty(mod_msg, attrs[c], LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ ret = ldb_msg_add_fmt(mod_msg, attrs[c], "%d", 1);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t qualify_object(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb,
+ struct sss_names_ctx *names,
+ struct ldb_message *object,
+ bool qualify_dn,
+ const char *domain_attr,
+ unsigned domain_index,
+ const char *name_attrs[],
+ const char *dn_attrs[],
+ should_qualify_val_fn qfn)
+{
+ int ret;
+ struct ldb_message *mod_msg = NULL;
+ struct ldb_dn *new_object_dn = NULL;
+ const char *dom_name;
+
+ mod_msg = ldb_msg_new(mem_ctx);
+ if (mod_msg == NULL) {
+ return ENOMEM;
+ }
+ mod_msg->dn = object->dn;
+
+ dom_name = object_domain(mod_msg, ldb, object, domain_attr, domain_index);
+ if (dom_name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot determine domain of %s\n",
+ ldb_dn_get_linearized(mod_msg->dn));
+ return EINVAL;
+ }
+
+ if (name_attrs != NULL) {
+ for (size_t c = 0; name_attrs[c]; c++) {
+ ret = qualify_attr(object, mod_msg, names,
+ dom_name, name_attrs[c], qfn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot qualify %s of %s\n",
+ name_attrs[c], ldb_dn_get_linearized(object->dn));
+ continue;
+ }
+ }
+ }
+
+ if (dn_attrs != NULL) {
+ for (size_t c = 0; dn_attrs[c]; c++) {
+ ret = qualify_dn_attr(ldb, object, mod_msg,
+ names, dn_attrs[c]);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot qualify %s of %s\n",
+ dn_attrs[c], ldb_dn_get_linearized(object->dn));
+ }
+ }
+ }
+
+ ret = expire_object(object, mod_msg);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot expire %s\n", ldb_dn_get_linearized(object->dn));
+ }
+
+ /* Override objects can contain both qualified and non-qualified names.
+ * Need to use permissive modification here, otherwise we might attempt
+ * to store duplicate qualified names
+ */
+ ret = sss_ldb_modify_permissive(ldb, mod_msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot modify %s\n", ldb_dn_get_linearized(object->dn));
+ goto done;
+ }
+
+ if (qualify_dn) {
+ new_object_dn = qualify_rdn(mod_msg, ldb, names, mod_msg->dn);
+ if (new_object_dn == NULL) {
+ ret = EIO;
+ goto done;
+ }
+
+ ret = ldb_rename(ldb, object->dn, new_object_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Cannot rename %s to %s\n",
+ ldb_dn_get_linearized(object->dn),
+ ldb_dn_get_linearized(new_object_dn));
+ goto done;
+ }
+ }
+
+ ret = EOK;
+done:
+ talloc_free(mod_msg);
+ return ret;
+}
+
+static void qualify_objects(struct upgrade_ctx *ctx,
+ struct ldb_context *ldb,
+ struct sss_names_ctx *names,
+ struct ldb_dn *base_dn,
+ bool qualify_dn,
+ const char *domain_attr,
+ unsigned domain_index,
+ const char *filter,
+ const char *name_attrs[],
+ const char *dn_attrs[],
+ should_qualify_val_fn qfn)
+{
+ errno_t ret;
+ struct ldb_result *objects = NULL;
+ const char *attrs[] = { "*", NULL };
+
+ ret = ldb_search(ldb, ctx, &objects, base_dn,
+ LDB_SCOPE_SUBTREE, attrs, "%s", filter);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to search objects: %d\n", ret);
+ return;
+ }
+
+ if (objects == NULL || objects->count == 0) {
+ DEBUG(SSSDBG_TRACE_LIBS, "No match for: %s\n", filter);
+ return;
+ }
+
+ for (size_t c = 0; c < objects->count; c++) {
+ ret = qualify_object(ctx, ldb, names, objects->msgs[c],
+ qualify_dn, domain_attr, domain_index,
+ name_attrs, dn_attrs, qfn);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Could not qualify object %s: %d\n",
+ ldb_dn_get_linearized(objects->msgs[c]->dn), ret);
+ continue;
+ }
+ }
+ talloc_free(objects);
+}
+
+static void qualify_users(struct upgrade_ctx *ctx,
+ struct ldb_context *ldb,
+ struct sss_names_ctx *names,
+ struct ldb_dn *base_dn)
+{
+ /* No change needed because this version has objectclass user */
+ const char *user_filter = "objectclass=user";
+ const char *user_name_attrs[] = { SYSDB_NAME,
+ SYSDB_NAME_ALIAS,
+ SYSDB_DEFAULT_OVERRIDE_NAME,
+ ORIGINALAD_PREFIX SYSDB_NAME,
+ NULL
+ };
+ const char *user_dn_attrs[] = { SYSDB_MEMBEROF,
+ SYSDB_OVERRIDE_DN,
+ NULL
+ };
+
+ return qualify_objects(ctx, ldb, names, base_dn,
+ true, /* qualify dn */
+ NULL, /* no special domain attr, use DN */
+ 2, /* DN's domain is third RDN from top */
+ user_filter,
+ user_name_attrs, user_dn_attrs, NULL);
+}
+
+static void qualify_groups(struct upgrade_ctx *ctx,
+ struct ldb_context *ldb,
+ struct sss_names_ctx *names,
+ struct ldb_dn *base_dn)
+{
+ /* No change needed because this version has objectclass group */
+ const char *group_filter = "objectclass=group";
+ const char *group_name_attrs[] = { SYSDB_NAME,
+ SYSDB_NAME_ALIAS,
+ SYSDB_DEFAULT_OVERRIDE_NAME,
+ ORIGINALAD_PREFIX SYSDB_NAME,
+ SYSDB_MEMBERUID,
+ SYSDB_GHOST,
+ NULL
+ };
+ const char *group_dn_attrs[] = { SYSDB_MEMBER,
+ SYSDB_MEMBEROF,
+ SYSDB_OVERRIDE_DN,
+ NULL
+ };
+
+ return qualify_objects(ctx, ldb, names, base_dn, true,
+ NULL, 2, group_filter,
+ group_name_attrs, group_dn_attrs, NULL);
+}
+
+static void qualify_user_overrides(struct upgrade_ctx *ctx,
+ struct ldb_context *ldb,
+ struct sss_names_ctx *names,
+ struct ldb_dn *base_dn)
+{
+ const char *user_override_filter = "objectclass=userOverride";
+ const char *user_ovr_name_attrs[] = { SYSDB_NAME,
+ SYSDB_NAME_ALIAS,
+ NULL
+ };
+ const char *user_ovr_dn_attrs[] = { SYSDB_OVERRIDE_OBJECT_DN,
+ NULL
+ };
+
+ return qualify_objects(ctx, ldb, names, base_dn,
+ /* Don't qualify RDN of override DN */
+ false,
+ /* Read domain from override DN */
+ SYSDB_OVERRIDE_OBJECT_DN,
+ 2, /* Third RDN from top is domain */
+ user_override_filter, user_ovr_name_attrs,
+ user_ovr_dn_attrs, NULL);
+}
+
+static void qualify_group_overrides(struct upgrade_ctx *ctx,
+ struct ldb_context *ldb,
+ struct sss_names_ctx *names,
+ struct ldb_dn *base_dn)
+{
+ const char *group_override_filter = "objectclass=groupOverride";
+ const char *group_ovr_name_attrs[] = { SYSDB_NAME,
+ SYSDB_NAME_ALIAS,
+ NULL
+ };
+ const char *group_ovr_dn_attrs[] = { SYSDB_OVERRIDE_OBJECT_DN,
+ NULL
+ };
+
+ return qualify_objects(ctx, ldb, names, base_dn,
+ false, SYSDB_OVERRIDE_OBJECT_DN, 2,
+ group_override_filter, group_ovr_name_attrs,
+ group_ovr_dn_attrs, NULL);
+}
+
+static void qualify_sudo_rules(struct upgrade_ctx *ctx,
+ struct ldb_context *ldb,
+ struct sss_names_ctx *names,
+ struct ldb_dn *base_dn)
+{
+ const char *group_override_filter = "objectclass=sudoRule";
+ const char *sudo_rule_name_attrs[] = { "sudoUser",
+ NULL
+ };
+
+ return qualify_objects(ctx, ldb, names, base_dn,
+ false, NULL, 3,
+ group_override_filter, sudo_rule_name_attrs,
+ NULL, is_user_or_group_name);
+}
+
+
+int sysdb_upgrade_17(struct sysdb_ctx *sysdb,
+ struct sysdb_dom_upgrade_ctx *upgrade_ctx,
+ const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ errno_t ret, envret;
+ struct ldb_dn *base_dn;
+ struct sss_names_ctx *names = upgrade_ctx->names;
+
+ if (names == NULL) {
+ return EINVAL;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_18, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Disable memberof plugin during this update */
+ ret = setenv("SSSD_UPGRADE_DB", "1", 1);
+ if (ret != 0) {
+ goto done;
+ }
+
+ base_dn = ldb_dn_new_fmt(ctx, sysdb->ldb, SYSDB_BASE);
+ if (base_dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ qualify_users(ctx, sysdb->ldb, names, base_dn);
+ qualify_groups(ctx, sysdb->ldb, names, base_dn);
+ qualify_user_overrides(ctx, sysdb->ldb, names, base_dn);
+ qualify_group_overrides(ctx, sysdb->ldb, names, base_dn);
+ qualify_sudo_rules(ctx, sysdb->ldb, names, base_dn);
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ envret = unsetenv("SSSD_UPGRADE_DB");
+ if (envret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "Cannot unset SSSD_UPGRADE_DB, SSSD might not work correctly\n");
+ }
+ return ret;
+}
+
+int sysdb_upgrade_18(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ errno_t ret;
+ struct ldb_message *msg = NULL;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_19, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add missing indices */
+ msg = ldb_msg_new(ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_GHOST);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_UPN);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_CANONICAL_UPN);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_UUID);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_USER_EMAIL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ talloc_free(msg);
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
+static errno_t add_object_category(struct ldb_context *ldb,
+ struct upgrade_ctx *ctx)
+{
+ errno_t ret;
+ struct ldb_result *objects = NULL;
+ const char *attrs[] = { SYSDB_OBJECTCLASS, NULL };
+ struct ldb_dn *base_dn;
+ size_t c;
+ const char *class_name;
+ struct ldb_message *msg = NULL;
+ struct ldb_message *del_msg = NULL;
+
+ base_dn = ldb_dn_new(ctx, ldb, SYSDB_BASE);
+ if (base_dn == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed create base dn.\n");
+ return ENOMEM;
+ }
+
+ ret = ldb_search(ldb, ctx, &objects, base_dn,
+ LDB_SCOPE_SUBTREE, attrs,
+ "(|("SYSDB_OBJECTCLASS"="SYSDB_USER_CLASS")"
+ "("SYSDB_OBJECTCLASS"="SYSDB_GROUP_CLASS"))");
+ talloc_free(base_dn);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to search objects: %d\n", ret);
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ if (objects == NULL || objects->count == 0) {
+ DEBUG(SSSDBG_TRACE_LIBS, "No objects found, nothing to do.");
+ ret = EOK;
+ goto done;
+ }
+
+ del_msg = ldb_msg_new(ctx);
+ if (del_msg == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+ ret = ldb_msg_add_empty(del_msg, SYSDB_OBJECTCLASS, LDB_FLAG_MOD_DELETE,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_ALL, "Found [%d] objects.\n", objects->count);
+ for (c = 0; c < objects->count; c++) {
+ DEBUG(SSSDBG_TRACE_ALL, "Updating [%s].\n",
+ ldb_dn_get_linearized(objects->msgs[c]->dn));
+
+ class_name = ldb_msg_find_attr_as_string(objects->msgs[c],
+ SYSDB_OBJECTCLASS, NULL);
+ if (class_name == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "Searched objects by objectClass, "
+ "but result does not have one.\n");
+ ret = EINVAL;
+ goto done;
+ }
+
+ talloc_free(msg);
+ msg = ldb_msg_new(ctx);
+ if (msg == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n");
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = objects->msgs[c]->dn;
+ del_msg->dn = objects->msgs[c]->dn;
+
+ ret = ldb_msg_add_empty(msg, SYSDB_OBJECTCATEGORY, LDB_FLAG_MOD_ADD,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n");
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, SYSDB_OBJECTCATEGORY, class_name);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n");
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ DEBUG(SSSDBG_TRACE_ALL, "Adding [%s] to [%s].\n", class_name,
+ ldb_dn_get_linearized(objects->msgs[c]->dn));
+ ret = ldb_modify(ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to add objectCategory to %s: %d.\n",
+ ldb_dn_get_linearized(objects->msgs[c]->dn),
+ sysdb_error_to_errno(ret));
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ ret = ldb_modify(ldb, del_msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Failed to remove objectClass from %s: %d.\n",
+ ldb_dn_get_linearized(objects->msgs[c]->dn),
+ sysdb_error_to_errno(ret));
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+ }
+
+ ret = EOK;
+
+done:
+ talloc_free(msg);
+ talloc_free(del_msg);
+ talloc_free(objects);
+
+ return ret;
+}
+
+int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ errno_t ret;
+ struct ldb_message *msg = NULL;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_20, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ ret = add_object_category(sysdb->ldb, ctx);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "add_object_category failed: %d\n", ret);
+ goto done;
+ }
+
+ /* Remove @IDXONE from index */
+ msg = ldb_msg_new(ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_USER_MAPPED_CERT);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
+int sysdb_upgrade_20(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ errno_t ret;
+ struct ldb_message *msg = NULL;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_21, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add missing indices */
+ msg = ldb_msg_new(ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_CCACHE_FILE);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ talloc_free(msg);
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
+int sysdb_upgrade_21(struct sysdb_ctx *sysdb, const char **ver)
+{
+ TALLOC_CTX *tmp_ctx;
+ int ret;
+ struct ldb_message *msg;
+ struct upgrade_ctx *ctx;
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_22, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Case insensitive search for ipHostNumber and ipNetworkNumber */
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@ATTRIBUTES");
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, SYSDB_IP_HOST_ATTR_ADDRESS, LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, SYSDB_IP_HOST_ATTR_ADDRESS, "CASE_INSENSITIVE");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, SYSDB_IP_NETWORK_ATTR_NUMBER,
+ LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, SYSDB_IP_NETWORK_ATTR_NUMBER,
+ "CASE_INSENSITIVE");
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ talloc_zfree(msg);
+
+ /* Add new indexes */
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@INDEXLIST");
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Add Index for ipHostNumber */
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_IP_HOST_ATTR_ADDRESS);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_IP_NETWORK_ATTR_NUMBER);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+int sysdb_upgrade_22(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ errno_t ret;
+ struct ldb_message *msg = NULL;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_23, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Add missing indices */
+ msg = ldb_msg_new(ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "@IDXATTR", LDB_FLAG_MOD_ADD, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "@IDXATTR", SYSDB_ORIG_AD_GID_NUMBER);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ talloc_free(msg);
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
+int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ errno_t ret;
+ struct ldb_message *msg = NULL;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_TS_VERSION_0_2, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* Remove @IDXONE from index */
+ talloc_free(msg);
+ msg = ldb_msg_new(ctx);
+ if (msg == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST");
+ if (msg->dn == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL);
+ if (ret != LDB_SUCCESS) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ldb_modify(sysdb->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ ret = sysdb_error_to_errno(ret);
+ goto done;
+ }
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+
+/*
+ * Example template for future upgrades.
+ * Copy and change version numbers as appropriate.
+ */
+#if 0
+
+int sysdb_upgrade_13(struct sysdb_ctx *sysdb, const char **ver)
+{
+ struct upgrade_ctx *ctx;
+ errno_t ret;
+
+ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_14, &ctx);
+ if (ret) {
+ return ret;
+ }
+
+ /* DO STUFF HERE (use ctx, as the local temporary memory context) */
+
+ /* conversion done, update version number */
+ ret = update_version(ctx);
+
+done:
+ ret = finish_upgrade(ret, &ctx, ver);
+ return ret;
+}
+#endif