From f63c88f5b91512b48dd5b01d289194f4518ce882 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Wed, 5 Oct 2011 13:57:24 -0400
Subject: [PATCH] SYSDB: New source file for sysdb upgrade routines

---
 Makefile.am            |    1 +
 src/db/sysdb.c         |  897 +-----------------------------------------------
 src/db/sysdb_private.h |   21 ++
 src/db/sysdb_upgrade.c |  894 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 926 insertions(+), 887 deletions(-)
 create mode 100644 src/db/sysdb_upgrade.c

diff --git a/Makefile.am b/Makefile.am
index f628059096a6845f544dbea124de8f27a738cbb0..78ec82e755264d81d56ead57884f6480760c6d64 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -354,6 +354,7 @@ libsss_util_la_SOURCES = \
     src/db/sysdb.c \
     src/db/sysdb_ops.c \
     src/db/sysdb_search.c \
+    src/db/sysdb_upgrade.c \
     src/monitor/monitor_sbus.c \
     src/providers/dp_auth_util.c \
     src/providers/dp_pam_data_util.c \
diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 1a326030c82d681151c611228263958cb13eac2d..6eef6e1086234dc9a93eee3db0319adc1575b1a8 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -27,8 +27,8 @@
 
 #define LDB_MODULES_PATH "LDB_MODULES_PATH"
 
-static errno_t sysdb_ldb_connect(TALLOC_CTX *mem_ctx, const char *filename,
-                           struct ldb_context **_ldb)
+errno_t sysdb_ldb_connect(TALLOC_CTX *mem_ctx, const char *filename,
+                          struct ldb_context **_ldb)
 {
     int ret;
     struct ldb_context *ldb;
@@ -772,15 +772,9 @@ int sysdb_transaction_cancel(struct sysdb_ctx *sysdb)
 
 /* =Initialization======================================================== */
 
-static 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);
-
-static int sysdb_get_db_file(TALLOC_CTX *mem_ctx,
-                             const char *provider, const char *name,
-                             const char *base_path, char **_ldb_file)
+int sysdb_get_db_file(TALLOC_CTX *mem_ctx,
+                      const char *provider, const char *name,
+                      const char *base_path, char **_ldb_file)
 {
     char *ldb_file;
 
@@ -800,882 +794,11 @@ static int sysdb_get_db_file(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
-static int finish_upgrade(int result, struct ldb_context *ldb,
-                          const char *next_ver, const char **ver)
-{
-    int ret = result;
-
-    if (ret == EOK) {
-        ret = ldb_transaction_commit(ldb);
-        ret = sysdb_error_to_errno(ret);
-        if (ret == EOK) {
-            *ver = next_ver;
-        }
-    }
-
-    if (ret != EOK) {
-        ret = ldb_transaction_cancel(ldb);
-        ret = sysdb_error_to_errno(ret);
-    }
-
-    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
- */
-static 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;
-    const char *filter = "(&(memberUid=*)(objectclass=group))";
-    const char *attrs[] = { "memberUid", NULL };
-    const char *mdn;
-    char *domain;
-    int ret, i, j;
-    TALLOC_CTX *tmp_ctx;
-
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    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, filter);
-    if (ret != LDB_SUCCESS) {
-        ret = EIO;
-        goto done;
-    }
-
-    ret = ldb_transaction_start(ldb);
-    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(1, ("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, 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_2);
-    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 = EOK;
-
-done:
-    ret = finish_upgrade(ret, ldb, SYSDB_VERSION_0_2, ver);
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-static 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;
-    }
-
-    ret = sysdb_get_db_file(tmp_ctx,
-                            "local", "UPGRADE",
-                            db_path, &ldb_file);
-    if (ret != EOK) {
-        goto exit;
-    }
-
-    ret = sysdb_ldb_connect(tmp_ctx, ldb_file, &ldb);
-    if (ret != EOK) {
-        DEBUG(1, ("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(4, ("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(0, ("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, 0);
-    if (ret != EOK) {
-        goto exit;
-    }
-
-    /* reopen */
-    ret = sysdb_ldb_connect(tmp_ctx, ldb_file, &ldb);
-    if (ret != EOK) {
-        DEBUG(1, ("sysdb_ldb_connect failed.\n"));
-        return ret;
-    }
-
-    /* open a transaction */
-    ret = ldb_transaction_start(ldb);
-    if (ret != LDB_SUCCESS) {
-        DEBUG(1, ("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;
-
-        /* skip local */
-        if (strcasecmp(dom->provider, "local") == 0) {
-            continue;
-        }
-
-        /* 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(1, ("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, sysdb->domain->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;
-        }
-
-        users_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
-                                 SYSDB_TMPL_USER_BASE, sysdb->domain->name);
-        if (!users_dn) {
-            ret = ENOMEM;
-            goto done;
-        }
-        groups_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
-                                   SYSDB_TMPL_GROUP_BASE, sysdb->domain->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(0, ("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(0, ("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(9, ("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(9, ("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(9, ("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(1, ("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(1, ("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(1, ("Failed to cancel ldb transaction! (%d)\n", ret));
-            }
-        }
-        ret = ldb_transaction_cancel(ldb);
-        if (ret != LDB_SUCCESS) {
-            DEBUG(1, ("Failed to cancel ldb transaction! (%d)\n", ret));
-        }
-    }
-
-exit:
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-static int sysdb_upgrade_03(struct sysdb_ctx *sysdb, const char **ver)
-{
-    TALLOC_CTX *tmp_ctx;
-    int ret;
-    struct ldb_message *msg;
-
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) {
-        return ENOMEM;
-    }
-
-    DEBUG(0, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_4));
-
-    ret = ldb_transaction_start(sysdb->ldb);
-    if (ret != LDB_SUCCESS) {
-        ret = EIO;
-        goto done;
-    }
-
-    /* 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, upgrade version number */
-    msg = ldb_msg_new(tmp_ctx);
-    if (!msg) {
-        ret = ENOMEM;
-        goto done;
-    }
-    msg->dn = ldb_dn_new(tmp_ctx, sysdb->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_4);
-    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;
-    }
-
-    ret = EOK;
-
-done:
-    ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_4, ver);
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-static int sysdb_upgrade_04(struct sysdb_ctx *sysdb, const char **ver)
-{
-    TALLOC_CTX *tmp_ctx;
-    int ret;
-    struct ldb_message *msg;
-
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) {
-        return ENOMEM;
-    }
-
-    DEBUG(0, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_5));
-
-    ret = ldb_transaction_start(sysdb->ldb);
-    if (ret != LDB_SUCCESS) {
-        ret = EIO;
-        goto done;
-    }
-
-    /* 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, upgrade version number */
-    msg = ldb_msg_new(tmp_ctx);
-    if (!msg) {
-        ret = ENOMEM;
-        goto done;
-    }
-    msg->dn = ldb_dn_new(tmp_ctx, sysdb->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_5);
-    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;
-    }
-
-    ret = EOK;
-
-done:
-    ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_5, ver);
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-static int sysdb_upgrade_05(struct sysdb_ctx *sysdb, const char **ver)
-{
-    TALLOC_CTX *tmp_ctx;
-    int ret;
-    struct ldb_message *msg;
-
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) {
-        return ENOMEM;
-    }
-
-    DEBUG(0, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_6));
-
-    ret = ldb_transaction_start(sysdb->ldb);
-    if (ret != LDB_SUCCESS) {
-        ret = EIO;
-        goto done;
-    }
-
-    /* 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, upgrade version number */
-    msg = ldb_msg_new(tmp_ctx);
-    if (!msg) {
-        ret = ENOMEM;
-        goto done;
-    }
-    msg->dn = ldb_dn_new(tmp_ctx, sysdb->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_6);
-    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;
-    }
-
-    ret = EOK;
-
-done:
-    ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_6, ver);
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-static int sysdb_upgrade_06(struct sysdb_ctx *sysdb, const char **ver)
-{
-    TALLOC_CTX *tmp_ctx;
-    int ret;
-    struct ldb_message *msg;
-
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) {
-        return ENOMEM;
-    }
-
-    DEBUG(0, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_7));
-
-    ret = ldb_transaction_start(sysdb->ldb);
-    if (ret != LDB_SUCCESS) {
-        ret = EIO;
-        goto done;
-    }
-
-    /* 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, upgrade version number */
-    msg = ldb_msg_new(tmp_ctx);
-    if (!msg) {
-        ret = ENOMEM;
-        goto done;
-    }
-    msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "cn=sysdb");
-    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_7);
-    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;
-    }
-
-    ret = EOK;
-
-done:
-    ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_7, ver);
-    talloc_free(tmp_ctx);
-    return ret;
-}
-
-static 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)
+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;
diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h
index 0cbb3a45a6ee5d0a25e830b7f493960ae3a65716..bb98181a1746e4d349bf8cd6ae6a785828aaff7e 100644
--- a/src/db/sysdb_private.h
+++ b/src/db/sysdb_private.h
@@ -74,4 +74,25 @@ struct sysdb_ctx {
     char *ldb_file;
 };
 
+/* 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);
+errno_t sysdb_ldb_connect(TALLOC_CTX *mem_ctx, const char *filename,
+                          struct ldb_context **_ldb);
+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);
+
+/* Upgrade routines */
+int sysdb_upgrade_01(struct ldb_context *ldb, const char **ver);
+int sysdb_check_upgrade_02(struct sss_domain_info *domains,
+                           const char *db_path);
+int sysdb_upgrade_03(struct sysdb_ctx *sysdb, const char **ver);
+int sysdb_upgrade_04(struct sysdb_ctx *sysdb, const char **ver);
+int sysdb_upgrade_05(struct sysdb_ctx *sysdb, const char **ver);
+int sysdb_upgrade_06(struct sysdb_ctx *sysdb, const char **ver);
+
 #endif /* __INT_SYS_DB_H__ */
diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c
new file mode 100644
index 0000000000000000000000000000000000000000..caf86eacd0188bbf8b4d3b72f5408ac3b79818ca
--- /dev/null
+++ b/src/db/sysdb_upgrade.c
@@ -0,0 +1,894 @@
+/*
+    SSSD
+
+    Authors:
+        Stephen Gallagher <sgallagh@redhat.com>
+
+    Copyright (C) 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"
+
+static int finish_upgrade(int result, struct ldb_context *ldb,
+                          const char *next_ver, const char **ver)
+{
+    int ret = result;
+
+    if (ret == EOK) {
+        ret = ldb_transaction_commit(ldb);
+        ret = sysdb_error_to_errno(ret);
+        if (ret == EOK) {
+            *ver = next_ver;
+        }
+    }
+
+    if (ret != EOK) {
+        ret = ldb_transaction_cancel(ldb);
+        ret = sysdb_error_to_errno(ret);
+    }
+
+    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;
+    const char *filter = "(&(memberUid=*)(objectclass=group))";
+    const char *attrs[] = { "memberUid", NULL };
+    const char *mdn;
+    char *domain;
+    int ret, i, j;
+    TALLOC_CTX *tmp_ctx;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    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, filter);
+    if (ret != LDB_SUCCESS) {
+        ret = EIO;
+        goto done;
+    }
+
+    ret = ldb_transaction_start(ldb);
+    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(1, ("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, 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_2);
+    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 = EOK;
+
+done:
+    ret = finish_upgrade(ret, ldb, SYSDB_VERSION_0_2, 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;
+    }
+
+    ret = sysdb_get_db_file(tmp_ctx,
+                            "local", "UPGRADE",
+                            db_path, &ldb_file);
+    if (ret != EOK) {
+        goto exit;
+    }
+
+    ret = sysdb_ldb_connect(tmp_ctx, ldb_file, &ldb);
+    if (ret != EOK) {
+        DEBUG(1, ("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(4, ("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(0, ("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, 0);
+    if (ret != EOK) {
+        goto exit;
+    }
+
+    /* reopen */
+    ret = sysdb_ldb_connect(tmp_ctx, ldb_file, &ldb);
+    if (ret != EOK) {
+        DEBUG(1, ("sysdb_ldb_connect failed.\n"));
+        return ret;
+    }
+
+    /* open a transaction */
+    ret = ldb_transaction_start(ldb);
+    if (ret != LDB_SUCCESS) {
+        DEBUG(1, ("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;
+
+        /* skip local */
+        if (strcasecmp(dom->provider, "local") == 0) {
+            continue;
+        }
+
+        /* 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(1, ("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, sysdb->domain->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;
+        }
+
+        users_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
+                                 SYSDB_TMPL_USER_BASE, sysdb->domain->name);
+        if (!users_dn) {
+            ret = ENOMEM;
+            goto done;
+        }
+        groups_dn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb,
+                                   SYSDB_TMPL_GROUP_BASE, sysdb->domain->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(0, ("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(0, ("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(9, ("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(9, ("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(9, ("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(1, ("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(1, ("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(1, ("Failed to cancel ldb transaction! (%d)\n", ret));
+            }
+        }
+        ret = ldb_transaction_cancel(ldb);
+        if (ret != LDB_SUCCESS) {
+            DEBUG(1, ("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;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    DEBUG(0, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_4));
+
+    ret = ldb_transaction_start(sysdb->ldb);
+    if (ret != LDB_SUCCESS) {
+        ret = EIO;
+        goto done;
+    }
+
+    /* 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, upgrade version number */
+    msg = ldb_msg_new(tmp_ctx);
+    if (!msg) {
+        ret = ENOMEM;
+        goto done;
+    }
+    msg->dn = ldb_dn_new(tmp_ctx, sysdb->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_4);
+    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;
+    }
+
+    ret = EOK;
+
+done:
+    ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_4, 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;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    DEBUG(0, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_5));
+
+    ret = ldb_transaction_start(sysdb->ldb);
+    if (ret != LDB_SUCCESS) {
+        ret = EIO;
+        goto done;
+    }
+
+    /* 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, upgrade version number */
+    msg = ldb_msg_new(tmp_ctx);
+    if (!msg) {
+        ret = ENOMEM;
+        goto done;
+    }
+    msg->dn = ldb_dn_new(tmp_ctx, sysdb->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_5);
+    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;
+    }
+
+    ret = EOK;
+
+done:
+    ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_5, 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;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    DEBUG(0, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_6));
+
+    ret = ldb_transaction_start(sysdb->ldb);
+    if (ret != LDB_SUCCESS) {
+        ret = EIO;
+        goto done;
+    }
+
+    /* 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, upgrade version number */
+    msg = ldb_msg_new(tmp_ctx);
+    if (!msg) {
+        ret = ENOMEM;
+        goto done;
+    }
+    msg->dn = ldb_dn_new(tmp_ctx, sysdb->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_6);
+    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;
+    }
+
+    ret = EOK;
+
+done:
+    ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_6, 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;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        return ENOMEM;
+    }
+
+    DEBUG(0, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_7));
+
+    ret = ldb_transaction_start(sysdb->ldb);
+    if (ret != LDB_SUCCESS) {
+        ret = EIO;
+        goto done;
+    }
+
+    /* 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, upgrade version number */
+    msg = ldb_msg_new(tmp_ctx);
+    if (!msg) {
+        ret = ENOMEM;
+        goto done;
+    }
+    msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "cn=sysdb");
+    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_7);
+    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;
+    }
+
+    ret = EOK;
+
+done:
+    ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_7, ver);
+    talloc_free(tmp_ctx);
+    return ret;
+}
-- 
1.7.6.4

