From 14f389ce835d3785469e486f357e872275738bf2 Mon Sep 17 00:00:00 2001
From: Ondrej Kos <okos@redhat.com>
Date: Thu, 28 Mar 2013 15:35:03 +0100
Subject: [PATCH] DB: Switch to new libini_config API

https://fedorahosted.org/sssd/ticket/1786

Since we need to support the old interface as well, the configure scritp
is modified and correct ini interface is chosen.
---
 Makefile.am                         |   2 +
 src/confdb/confdb_setup.c           | 325 +++++++++++----------------------
 src/external/libini_config.m4       |  26 ++-
 src/monitor/monitor.c               |   2 -
 src/responder/nss/nsssrv_netgroup.c |   2 +-
 src/responder/nss/nsssrv_services.c |   1 -
 src/util/sss_ini.c                  | 352 ++++++++++++++++++++++++++++++++++++
 src/util/sss_ini.h                  | 120 ++++++++++++
 8 files changed, 603 insertions(+), 227 deletions(-)
 create mode 100644 src/util/sss_ini.c
 create mode 100644 src/util/sss_ini.h

diff --git a/Makefile.am b/Makefile.am
index 3209cbab3c2d867fc5a420a6eae1f744a7a69dc6..df9004c4e099cd77373e6bf2b06583e06d7860e7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -389,6 +389,7 @@ dist_noinst_HEADERS = \
     src/util/sss_selinux.h \
     src/util/sss_utf8.h \
     src/util/sss_ssh.h \
+    src/util/sss_ini.h \
     src/util/refcount.h \
     src/util/find_uid.h \
     src/util/user_info_msg.h \
@@ -547,6 +548,7 @@ libsss_util_la_SOURCES = \
     src/util/domain_info_utils.c \
     src/util/util_lock.c \
     src/util/util_errors.c \
+    src/util/sss_ini.c \
     src/util/io.c
 libsss_util_la_LIBADD = \
     $(SSSD_LIBS) \
diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
index 6c68461faf1e14270a03dc979c4b9c21c0374af2..1060d2a25b1b8da2423cbd69019ecc525e1e6221 100644
--- a/src/confdb/confdb_setup.c
+++ b/src/confdb/confdb_setup.c
@@ -26,9 +26,7 @@
 #include "confdb.h"
 #include "confdb_private.h"
 #include "confdb_setup.h"
-#include "collection.h"
-#include "collection_tools.h"
-#include "ini_config.h"
+#include "util/sss_ini.h"
 
 
 int confdb_test(struct confdb_ctx *cdb)
@@ -126,280 +124,172 @@ int confdb_create_base(struct confdb_ctx *cdb)
     return EOK;
 }
 
-static int confdb_create_ldif(TALLOC_CTX *mem_ctx,
-                              struct collection_item *sssd_config,
-                              const char **config_ldif)
-{
-    int ret, i, j;
-    char *ldif;
-    char *tmp_ldif;
-    char **sections;
-    int section_count;
-    char *dn;
-    char *tmp_dn;
-    char *sec_dn;
-    char **attrs;
-    int attr_count;
-    char *ldif_attr;
-    struct collection_item *attr;
-    TALLOC_CTX *tmp_ctx;
-    size_t dn_size;
-    size_t ldif_len;
-    size_t attr_len;
-
-    ldif_len = strlen(CONFDB_INTERNAL_LDIF);
-    ldif = talloc_array(mem_ctx, char, ldif_len+1);
-    if (!ldif) return ENOMEM;
-
-    tmp_ctx = talloc_new(ldif);
-    if (!tmp_ctx) {
-        ret = ENOMEM;
-        goto error;
-    }
-
-    memcpy(ldif, CONFDB_INTERNAL_LDIF, ldif_len);
-
-    /* Read in the collection and convert it to an LDIF */
-    /* Get the list of sections */
-    sections = get_section_list(sssd_config, &section_count, &ret);
-    if (ret != EOK) {
-        goto error;
-    }
-
-    for(i = 0; i < section_count; i++) {
-        const char *rdn = NULL;
-        DEBUG(6,("Processing config section [%s]\n", sections[i]));
-        ret = parse_section(tmp_ctx, sections[i], &sec_dn, &rdn);
-        if (ret != EOK) {
-            goto error;
-        }
-
-        dn = talloc_asprintf(tmp_ctx,
-                             "dn: %s,cn=config\n"
-                             "cn: %s\n",
-                             sec_dn, rdn);
-        if(!dn) {
-            ret = ENOMEM;
-            free_section_list(sections);
-            goto error;
-        }
-        dn_size = strlen(dn);
-
-        /* Get all of the attributes and their values as LDIF */
-        attrs = get_attribute_list(sssd_config, sections[i],
-                                   &attr_count, &ret);
-        if (ret != EOK) {
-            free_section_list(sections);
-            goto error;
-        }
-
-        for(j = 0; j < attr_count; j++) {
-            DEBUG(6, ("Processing attribute [%s]\n", attrs[j]));
-            ret = get_config_item(sections[i], attrs[j], sssd_config,
-                                   &attr);
-            if (ret != EOK) goto error;
-
-            const char *value = get_const_string_config_value(attr, &ret);
-            if (ret != EOK) goto error;
-            if (value && value[0] == '\0') {
-                DEBUG(1, ("Attribute '%s' has empty value, ignoring\n", attrs[j]));
-                continue;
-            }
-
-            ldif_attr = talloc_asprintf(tmp_ctx,
-                                        "%s: %s\n", attrs[j], value);
-            DEBUG(9, ("%s", ldif_attr));
-
-            attr_len = strlen(ldif_attr);
-
-            tmp_dn = talloc_realloc(tmp_ctx, dn, char,
-                                    dn_size+attr_len+1);
-            if(!tmp_dn) {
-                ret = ENOMEM;
-                free_attribute_list(attrs);
-                free_section_list(sections);
-                goto error;
-            }
-            dn = tmp_dn;
-            memcpy(dn+dn_size, ldif_attr, attr_len+1);
-            dn_size += attr_len;
-        }
-
-        dn_size ++;
-        tmp_dn = talloc_realloc(tmp_ctx, dn, char,
-                                dn_size+1);
-        if(!tmp_dn) {
-            ret = ENOMEM;
-            free_attribute_list(attrs);
-            free_section_list(sections);
-            goto error;
-        }
-        dn = tmp_dn;
-        dn[dn_size-1] = '\n';
-        dn[dn_size] = '\0';
-
-        DEBUG(9, ("Section dn\n%s", dn));
-
-        tmp_ldif = talloc_realloc(mem_ctx, ldif, char,
-                                  ldif_len+dn_size+1);
-        if(!tmp_ldif) {
-            ret = ENOMEM;
-            free_attribute_list(attrs);
-            free_section_list(sections);
-            goto error;
-        }
-        ldif = tmp_ldif;
-        memcpy(ldif+ldif_len, dn, dn_size);
-        ldif_len += dn_size;
-
-        free_attribute_list(attrs);
-        talloc_free(dn);
-    }
-
-    ldif[ldif_len] = '\0';
-
-    free_section_list(sections);
-
-    *config_ldif = (const char *)ldif;
-    talloc_free(tmp_ctx);
-    return EOK;
-
-error:
-    talloc_free(ldif);
-    return ret;
-}
-
 int confdb_init_db(const char *config_file, struct confdb_ctx *cdb)
 {
+    TALLOC_CTX *tmp_ctx;
     int ret;
-    int fd = -1;
-    struct collection_item *sssd_config = NULL;
-    struct collection_item *error_list = NULL;
-    struct collection_item *item = NULL;
+    int version;
+    char timestr[21];
+    char *lasttimestr;
     const char *config_ldif;
-    struct ldb_ldif *ldif;
-    TALLOC_CTX *tmp_ctx;
-    char *lasttimestr, timestr[21];
     const char *vals[2] = { timestr, NULL };
-    struct stat cstat;
-    int version;
+    struct ldb_ldif *ldif;
+    struct sss_ini_initdata *init_data;
+
 
     tmp_ctx = talloc_new(cdb);
-    if (tmp_ctx == NULL) return ENOMEM;
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("Out of memory.\n"));
+        return ENOMEM;
+    }
 
-    ret = check_and_open_readonly(config_file, &fd, 0, 0, (S_IRUSR|S_IWUSR),
-                                  CHECK_REG);
+    init_data = talloc_zero(tmp_ctx, struct sss_ini_initdata);
+    if (!init_data) {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("Out of memory.\n"));
+        return ENOMEM;
+    }
+
+    /* Open config file */
+    ret = sss_ini_config_file_open(config_file,
+                                   &init_data->file);
     if (ret != EOK) {
-        DEBUG(1, ("Permission check on config file failed.\n"));
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to open configuration file.\n"));
         talloc_zfree(tmp_ctx);
+        return EIO;
+    }
+
+    ret = sss_ini_config_access_check((void *)(intptr_t)init_data->file);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+                ("Permission check on config file failed.\n"));
+        sss_ini_close_file((void *)(uintptr_t)init_data->file);
         return EPERM;
     }
 
     /* Determine if the conf file has changed since we last updated
      * the confdb
      */
-    ret = fstat(fd, &cstat);
-    if (ret != 0) {
-        DEBUG(0, ("Unable to stat config file [%s]! (%d [%s])\n",
-                  config_file, errno, strerror(errno)));
-        close(fd);
+    ret = sss_ini_get_stat((void *)(intptr_t)init_data->file,
+                           &(init_data->cstat));
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("No stat data though stat collection was requested.\n"));
+        sss_ini_close_file((void *)(uintptr_t)init_data->file);
         talloc_zfree(tmp_ctx);
         return errno;
     }
-    ret = snprintf(timestr, 21, "%llu", (long long unsigned)cstat.st_mtime);
+
+    errno = 0;
+
+    ret = sss_ini_get_mtime(timestr, (void *)&init_data->cstat);
     if (ret <= 0 || ret >= 21) {
-        DEBUG(0, ("Failed to convert time_t to string ??\n"));
-        close(fd);
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Failed to convert time_t to string ??\n"));
+        sss_ini_close_file((void *)(uintptr_t)init_data->file);
         talloc_zfree(tmp_ctx);
         return errno ? errno: EFAULT;
     }
+    ret = confdb_get_string(cdb, tmp_ctx, "config", "lastUpdate",
+                            NULL, &lasttimestr);
+    if (ret == EOK) {
 
-    /* check if we need to re-init the db */
-    ret = confdb_get_string(cdb, tmp_ctx, "config", "lastUpdate", NULL, &lasttimestr);
-    if (ret == EOK && lasttimestr != NULL) {
-
-        /* now check if we lastUpdate and last file modification change differ*/
-        if (strcmp(lasttimestr, timestr) == 0) {
+        /* check if we lastUpdate and last file modification change differ*/
+        if ((lasttimestr != NULL) && (strcmp(lasttimestr, timestr) == 0)) {
             /* not changed, get out, nothing more to do */
-            close(fd);
+            sss_ini_close_file((void *)(uintptr_t)init_data->file);
             talloc_zfree(tmp_ctx);
             return EOK;
         }
-    }
-
-    /* Set up a transaction to replace the configuration */
-    ret = ldb_transaction_start(cdb->ldb);
-    if (ret != LDB_SUCCESS) {
-        DEBUG(0, ("Failed to start a transaction for updating the configuration\n"));
-        talloc_zfree(tmp_ctx);
-        close(fd);
-        return sysdb_error_to_errno(ret);
-    }
-
-    /* Purge existing database */
-    ret = confdb_purge(cdb);
-    if (ret != EOK) {
-        DEBUG(0, ("Could not purge existing configuration\n"));
-        close(fd);
+    } else {
+        DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to get lastUpdate attribute.\n"));
         goto done;
     }
 
-    /* Read the configuration into a collection */
-    ret = config_from_fd("sssd", fd, config_file, &sssd_config,
-                         INI_STOP_ON_ANY, &error_list);
-    close(fd);
+    ret = sss_ini_get_config(config_file, init_data);
     if (ret != EOK) {
-        DEBUG(0, ("Parse error reading configuration file [%s]\n",
-                  config_file));
-        print_file_parsing_errors(stderr, error_list);
-        free_ini_config_errors(error_list);
-        free_ini_config(sssd_config);
+        DEBUG(SSSDBG_FATAL_FAILURE, ("Failed to load configuration\n"));
+        sss_ini_close_file((void *)(uintptr_t)init_data->file);
+        talloc_zfree(tmp_ctx);
         goto done;
     }
 
     /* Make sure that the config file version matches the confdb version */
-    ret = get_config_item("sssd", "config_file_version",
-                          sssd_config, &item);
+    ret = sss_ini_get_config_obj("sssd", "config_file_version",
+                              init_data->sssd_config, INI_GET_FIRST_VALUE,
+                              &init_data->obj);
     if (ret != EOK) {
         DEBUG(0, ("Internal error determining config_file_version\n"));
         goto done;
     }
-    if (item == NULL) {
+    if (init_data->obj == NULL) {
         /* No known version. Assumed to be version 1 */
-        DEBUG(0, ("Config file is an old version. "
-                  "Please run configuration upgrade script.\n"));
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Config file is an old version. "
+                 "Please run configuration upgrade script.\n"));
         ret = EINVAL;
         goto done;
     }
-    version = get_int_config_value(item, 1, -1, &ret);
+
+    version = sss_ini_get_int_config_value(init_data->obj, 1, -1, &ret);
     if (ret != EOK) {
-        DEBUG(0, ("Config file version could not be determined\n"));
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Config file version could not be determined\n"));
+        sss_ini_config_destroy(init_data->sssd_config);
         goto done;
     } else if (version < CONFDB_VERSION_INT) {
-        DEBUG(0, ("Config file is an old version. "
-                  "Please run configuration upgrade script.\n"));
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Config file is an old version. "
+                 "Please run configuration upgrade script.\n"));
+        sss_ini_config_destroy(init_data->sssd_config);
         ret = EINVAL;
         goto done;
     } else if (version > CONFDB_VERSION_INT) {
-        DEBUG(0, ("Config file version is newer than confdb\n"));
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Config file version is newer than confdb\n"));
+        sss_ini_config_destroy(init_data->sssd_config);
         ret = EINVAL;
         goto done;
     }
 
-    ret = confdb_create_ldif(tmp_ctx, sssd_config, &config_ldif);
-    free_ini_config(sssd_config);
+    /* Set up a transaction to replace the configuration */
+    ret = ldb_transaction_start(cdb->ldb);
+    if (ret != LDB_SUCCESS) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Failed to start a transaction for "
+                 "updating the configuration\n"));
+        talloc_zfree(tmp_ctx);
+        sss_ini_close_file((void *)(uintptr_t)init_data->file);
+        return sysdb_error_to_errno(ret);
+    }
+
+    /* Purge existing database */
+    ret = confdb_purge(cdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Could not purge existing configuration\n"));
+        sss_ini_close_file((void *)(uintptr_t)init_data->file);
+        goto done;
+    }
+
+    ret = sss_confdb_create_ldif(tmp_ctx,
+                                 init_data->sssd_config,
+                                 &config_ldif);
+
+    sss_ini_free_ini_config(init_data->sssd_config);
+
     if (ret != EOK) {
-        DEBUG(0, ("Could not create LDIF for confdb\n"));
+        DEBUG(SSSDBG_FATAL_FAILURE, ("Could not create LDIF for confdb\n"));
         goto done;
     }
 
-    DEBUG(7, ("LDIF file to import: \n%s", config_ldif));
+    DEBUG(SSSDBG_TRACE_LIBS, ("LDIF file to import: \n%s", config_ldif));
 
     while ((ldif = ldb_ldif_read_string(cdb->ldb, &config_ldif))) {
         ret = ldb_add(cdb->ldb, ldif->msg);
         if (ret != LDB_SUCCESS) {
-            DEBUG(0, ("Failed to initialize DB (%d,[%s]), aborting!\n",
-                      ret, ldb_errstring(cdb->ldb)));
+            DEBUG(SSSDBG_FATAL_FAILURE,
+                    ("Failed to initialize DB (%d,[%s]), aborting!\n",
+                     ret, ldb_errstring(cdb->ldb)));
             ret = EIO;
             goto done;
         }
@@ -411,9 +301,12 @@ int confdb_init_db(const char *config_file, struct confdb_ctx *cdb)
 
     ret = confdb_add_param(cdb, true, "config", "lastUpdate", vals);
     if (ret != EOK) {
-        DEBUG(1, ("Failed to set last update time on db!\n"));
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Failed to set last update time on db!\n"));
     }
 
+    sss_ini_close_file((void *)(uintptr_t)init_data->file);
+
     ret = EOK;
 
 done:
diff --git a/src/external/libini_config.m4 b/src/external/libini_config.m4
index f41f31917d1cf12dda49ec2e1f2411e39dbcc759..fc2c2a4456e05b7fb1354eb96fe124192f411d85 100644
--- a/src/external/libini_config.m4
+++ b/src/external/libini_config.m4
@@ -1,10 +1,22 @@
+PKG_CHECK_MODULES(INI_CONFIG, [
+    ini_config >= 1.0.0], [
+
+        HAVE_LIBINI_CONFIG_V1=1
+        AC_DEFINE_UNQUOTED(HAVE_LIBINI_CONFIG_V1, 1, [libini_config version greater than 1.0.0])
+    ], [
+        AC_MSG_WARN([libini_config-devel >= 1.0.0 not available, trying older version])
+        PKG_CHECK_MODULES(INI_CONFIG, [
+            ini_config >= 0.6.1], [
+
+                HAVE_LIBINI_CONFIG_V0=1
+                AC_DEFINE_UNQUOTED(HAVE_LIBINI_CONFIG_V0, 1, [libini_config version lesser than 1.0.0])
+            ], [
+                AC_MSG_ERROR([Please install libini_config-devel])
+            ]
+        )
+    ]
+)
+
 AC_SUBST(INI_CONFIG_OBJ)
 AC_SUBST(INI_CONFIG_CFLAGS)
 AC_SUBST(INI_CONFIG_LIBS)
-
-PKG_CHECK_MODULES(INI_CONFIG,
-    ini_config >= 0.6.1,
-    ,
-    AC_MSG_ERROR("Please install libini_config-devel")
-    )
-
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 7a543908f131e3ea302979171372f4970a419b60..affe9da8de12f9532d9113463cb21583574ee826 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -44,8 +44,6 @@
 #include "tevent.h"
 #include "confdb/confdb.h"
 #include "confdb/confdb_setup.h"
-#include "collection.h"
-#include "ini_config.h"
 #include "db/sysdb.h"
 #include "monitor/monitor.h"
 #include "dbus/dbus.h"
diff --git a/src/responder/nss/nsssrv_netgroup.c b/src/responder/nss/nsssrv_netgroup.c
index 30459beaa9f9b98aab5d29c81fbc9a195e071bff..36792365fb545a230426ff324e101e7b4e3f8ea6 100644
--- a/src/responder/nss/nsssrv_netgroup.c
+++ b/src/responder/nss/nsssrv_netgroup.c
@@ -22,7 +22,7 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include <collection.h>
+
 #include "util/util.h"
 #include "responder/nss/nsssrv.h"
 #include "responder/nss/nsssrv_private.h"
diff --git a/src/responder/nss/nsssrv_services.c b/src/responder/nss/nsssrv_services.c
index 7b76cad86e28a7f091833295659836289e351099..c99074235b3b93ab1492b89138d3f59beb633ba2 100644
--- a/src/responder/nss/nsssrv_services.c
+++ b/src/responder/nss/nsssrv_services.c
@@ -21,7 +21,6 @@
 */
 
 
-#include <collection.h>
 #include <arpa/inet.h>
 #include "util/util.h"
 #include "responder/nss/nsssrv.h"
diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c
new file mode 100644
index 0000000000000000000000000000000000000000..91970b4c20d4a4a8f9c9909dd5865ae4362c175a
--- /dev/null
+++ b/src/util/sss_ini.c
@@ -0,0 +1,352 @@
+/*
+    SSSD
+
+    sss_ini.c
+
+    Authors:
+        Ondrej Kos <okos@redhat.com>
+
+    Copyright (C) 2013 Red Hat
+
+    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 <stdio.h>
+#include <errno.h>
+#include <talloc.h>
+
+#include "config.h"
+#include "util/util.h"
+#include "util/sss_ini.h"
+
+/* Close file descriptor */
+
+void sss_ini_close_file(void *file_desc)
+{
+#ifdef HAVE_LIBINI_CONFIG_V1
+    ini_config_file_destroy(file_desc);
+#elif HAVE_LIBINI_CONFIG_V0
+    int *fd;
+    fd = (int *)file_desc;
+
+    close(*fd);
+#endif
+}
+
+/* Open configuration file */
+
+int sss_ini_config_file_open(const char *config_file,
+                             void *file_desc)
+{
+#ifdef HAVE_LIBINI_CONFIG_V1
+    return ini_config_file_open(config_file,
+                                INI_META_STATS,
+                                file_desc);
+#elif HAVE_LIBINI_CONFIG_V0
+    int *fd;
+    fd = (int *)file_desc;
+
+    return check_and_open_readonly(config_file, fd, 0, 0,
+                                   (S_IRUSR|S_IWUSR), CHECK_REG);
+#endif
+}
+
+
+/* Check configuration file permissions */
+
+int sss_ini_config_access_check(void *file_desc)
+{
+#ifdef HAVE_LIBINI_CONFIG_V1
+    return ini_config_access_check(file_desc,
+                                   INI_ACCESS_CHECK_MODE |
+                                   INI_ACCESS_CHECK_UID |
+                                   INI_ACCESS_CHECK_GID,
+                                   0, /* owned by root */
+                                   0, /* owned by root */
+                                   (S_IRUSR|S_IWUSR), /* rw------- */
+                                   0); /* check all there parts */
+#elif HAVE_LIBINI_CONFIG_V0
+    return EOK;
+#endif
+}
+
+
+/* Cstat */
+
+int sss_ini_get_stat(void *file_desc, void *cstat)
+{
+#ifdef HAVE_LIBINI_CONFIG_V1
+    const struct stat **cs;
+    cs = cstat;
+    *cs = ini_config_get_stat(file_desc);
+
+    if (!cstat) return EIO;
+
+    return EOK;
+#elif HAVE_LIBINI_CONFIG_V0
+    int *fd;
+    fd = (int *)file_desc;
+
+    return fstat(*fd, cstat);
+#endif
+}
+
+
+/* Get mtime */
+
+int sss_ini_get_mtime(char *timestr, struct stat *cstat)
+{
+    long long unsigned mtime;
+#ifdef HAVE_LIBINI_CONFIG_V1
+    mtime = ((struct stat *)cstat)->st_mtime;
+
+    return snprintf(timestr, 21, "%llu", mtime);
+#elif HAVE_LIBINI_CONFIG_V0
+    mtime = ((struct stat *)cstat)->st_mtime;
+
+    return snprintf(timestr, 21, "%llu", mtime);
+#endif
+}
+
+
+/* Load configuration */
+
+int sss_ini_get_config(const char *config_file,
+                       struct sss_ini_initdata *init_data)
+{
+    int ret;
+#ifdef HAVE_LIBINI_CONFIG_V1
+
+    /* Create config object */
+    ret = ini_config_create(&(init_data->sssd_config));
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Failed to create config object. Error %d.\n", ret));
+        return ret;
+    }
+
+    /* Parse file */
+    ret = ini_config_parse(init_data->file,
+                           INI_STOP_ON_ANY,
+                           0, /* <- check that you really want this */
+                           0,
+                           init_data->sssd_config);
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Failed to parse configuration. Error %d.\n", ret));
+
+        if (ini_config_error_count(init_data->sssd_config)) {
+            DEBUG(SSSDBG_FATAL_FAILURE,
+                    ("Errors detected while parsing: %s\n",
+                     ini_config_get_filename(init_data->file));
+
+            ini_config_get_errors(init_data->sssd_config,
+                                  &init_data->error_list);
+            ini_config_print_errors(stderr, init_data->error_list));
+            ini_config_free_errors(init_data->error_list);
+        }
+        ini_config_destroy(init_data->sssd_config);
+        return ret;
+    }
+
+    return ret;
+
+#elif HAVE_LIBINI_CONFIG_V0
+
+    /* Read the configuration into a collection */
+    ret = config_from_fd("sssd",
+                         init_data->file,
+                         config_file,
+                         &init_data->sssd_config,
+                         INI_STOP_ON_ANY,
+                         &init_data->error_list);
+    close(init_data->file);
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+                ("Parse error reading configuration file [%s]\n",
+                 config_file));
+
+        print_file_parsing_errors(stderr, init_data->error_list);
+
+        free_ini_config_errors(init_data->error_list);
+        free_ini_config(init_data->sssd_config);
+
+        return ret;
+    }
+
+    return ret;
+
+#endif
+}
+
+/* Create LDIF */
+
+#ifdef HAVE_LIBINI_CONFIG_V1
+int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
+                                  struct ini_cfgobj *sssd_config,
+                                  const char **config_ldif)
+#elif HAVE_LIBINI_CONFIG_V0
+int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
+                                  struct collection_item *sssd_config,
+                                  const char **config_ldif)
+#endif
+{
+    int ret, i, j;
+    char *ldif;
+    char *tmp_ldif;
+    char **sections;
+    int section_count;
+    char *dn;
+    char *tmp_dn;
+    char *sec_dn;
+    char **attrs;
+    int attr_count;
+    char *ldif_attr;
+    TALLOC_CTX *tmp_ctx;
+    size_t dn_size;
+    size_t ldif_len;
+    size_t attr_len;
+#ifdef HAVE_LIBINI_CONFIG_V1
+    struct value_obj *obj = NULL;
+#elif HAVE_LIBINI_CONFIG_V0
+    struct collection_item *obj = NULL;
+#endif
+
+    ldif_len = strlen(CONFDB_INTERNAL_LDIF);
+    ldif = talloc_array(mem_ctx, char, ldif_len+1);
+    if (!ldif) return ENOMEM;
+
+    tmp_ctx = talloc_new(ldif);
+    if (!tmp_ctx) {
+        ret = ENOMEM;
+        goto error;
+    }
+
+    memcpy(ldif, CONFDB_INTERNAL_LDIF, ldif_len);
+
+    /* Read in the collection and convert it to an LDIF */
+    /* Get the list of sections */
+    sections = sss_ini_get_sec_list(sssd_config, &section_count, &ret);
+    if (ret != EOK) {
+        goto error;
+    }
+
+    for(i = 0; i < section_count; i++) {
+        const char *rdn = NULL;
+        DEBUG(SSSDBG_TRACE_FUNC,
+                ("Processing config section [%s]\n", sections[i]));
+        ret = parse_section(tmp_ctx, sections[i], &sec_dn, &rdn);
+        if (ret != EOK) {
+            goto error;
+        }
+
+        dn = talloc_asprintf(tmp_ctx,
+                             "dn: %s,cn=config\n"
+                             "cn: %s\n",
+                             sec_dn, rdn);
+        if(!dn) {
+            ret = ENOMEM;
+            free_section_list(sections);
+            goto error;
+        }
+        dn_size = strlen(dn);
+
+        /* Get all of the attributes and their values as LDIF */
+        attrs = sss_ini_get_attr_list(sssd_config, sections[i],
+                                   &attr_count, &ret);
+        if (ret != EOK) {
+            free_section_list(sections);
+            goto error;
+        }
+
+        for(j = 0; j < attr_count; j++) {
+            DEBUG(SSSDBG_TRACE_FUNC,
+                    ("Processing attribute [%s]\n", attrs[j]));
+            ret = sss_ini_get_config_obj(sections[i], attrs[j], sssd_config,
+                                      INI_GET_FIRST_VALUE, &obj);
+            if (ret != EOK) goto error;
+
+            const char *value = sss_ini_get_const_string_config_value(obj, &ret);
+            if (ret != EOK) goto error;
+            if (value && value[0] == '\0') {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                        ("Attribute '%s' has empty value, ignoring\n",
+                         attrs[j]));
+                continue;
+            }
+
+            ldif_attr = talloc_asprintf(tmp_ctx,
+                                        "%s: %s\n", attrs[j], value);
+            DEBUG(9, ("%s", ldif_attr));
+
+            attr_len = strlen(ldif_attr);
+
+            tmp_dn = talloc_realloc(tmp_ctx, dn, char,
+                                    dn_size+attr_len+1);
+            if(!tmp_dn) {
+                ret = ENOMEM;
+                free_attribute_list(attrs);
+                free_section_list(sections);
+                goto error;
+            }
+            dn = tmp_dn;
+            memcpy(dn+dn_size, ldif_attr, attr_len+1);
+            dn_size += attr_len;
+        }
+
+        dn_size ++;
+        tmp_dn = talloc_realloc(tmp_ctx, dn, char,
+                                dn_size+1);
+        if(!tmp_dn) {
+            ret = ENOMEM;
+            free_attribute_list(attrs);
+            free_section_list(sections);
+            goto error;
+        }
+        dn = tmp_dn;
+        dn[dn_size-1] = '\n';
+        dn[dn_size] = '\0';
+
+        DEBUG(SSSDBG_TRACE_ALL, ("Section dn\n%s", dn));
+
+        tmp_ldif = talloc_realloc(mem_ctx, ldif, char,
+                                  ldif_len+dn_size+1);
+        if(!tmp_ldif) {
+            ret = ENOMEM;
+            free_attribute_list(attrs);
+            free_section_list(sections);
+            goto error;
+        }
+        ldif = tmp_ldif;
+        memcpy(ldif+ldif_len, dn, dn_size);
+        ldif_len += dn_size;
+
+        free_attribute_list(attrs);
+        talloc_free(dn);
+    }
+
+    ldif[ldif_len] = '\0';
+
+    free_section_list(sections);
+
+    *config_ldif = (const char *)ldif;
+    talloc_free(tmp_ctx);
+    return EOK;
+
+error:
+    talloc_free(ldif);
+    return ret;
+}
diff --git a/src/util/sss_ini.h b/src/util/sss_ini.h
new file mode 100644
index 0000000000000000000000000000000000000000..47eeb788c98f122983ce00eee0a277fae6238e6e
--- /dev/null
+++ b/src/util/sss_ini.h
@@ -0,0 +1,120 @@
+/*
+    SSSD
+
+    sss_ini.c
+
+    Authors:
+        Ondrej Kos <okos@redhat.com>
+
+    Copyright (C) 2013 Red Hat
+
+    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/>.
+*/
+
+
+#ifndef __SSS_INI_H__
+#define __SSS_INI_H__
+
+
+#include "config.h"
+#include "util/util.h"
+#include "confdb/confdb_setup.h"
+#include "confdb/confdb_private.h"
+
+
+#ifdef HAVE_LIBINI_CONFIG_V1
+#include "ini_configobj.h"
+#endif
+#include "ini_config.h"
+
+#ifdef HAVE_LIBINI_CONFIG_V0
+#include "collection.h"
+#include "collection_tools.h"
+#endif
+
+
+#ifdef HAVE_LIBINI_CONFIG_V1
+
+struct sss_ini_initdata {
+    char **error_list;
+    struct ini_cfgobj *sssd_config;
+    struct value_obj *obj;
+    const struct stat *cstat;
+    struct ini_cfgfile *file;
+};
+
+#define sss_ini_get_sec_list                   ini_get_section_list
+#define sss_ini_get_attr_list                  ini_get_attribute_list
+#define sss_ini_get_const_string_config_value  ini_get_const_string_config_value
+#define sss_ini_get_int_config_value           ini_get_int_config_value
+#define sss_ini_config_destroy(cfg);           ini_config_destroy(cfg);
+#define sss_ini_get_config_obj                 ini_get_config_valueobj
+#define sss_ini_free_ini_config(cfg);
+
+
+#elif HAVE_LIBINI_CONFIG_V0
+
+struct sss_ini_initdata {
+    struct collection_item *error_list;
+    struct collection_item *sssd_config;
+    struct collection_item *obj;
+    struct stat cstat;
+    int file;
+};
+
+#define sss_ini_get_sec_list                   get_section_list
+#define sss_ini_get_attr_list                  get_attribute_list
+#define sss_ini_get_const_string_config_value  get_const_string_config_value
+#define sss_ini_get_int_config_value           get_int_config_value
+#define sss_ini_config_destroy(cfg);
+#define sss_ini_get_config_obj(secs,attrs,cfg,flag,attr) \
+    get_config_item(secs,attrs,cfg,attr)
+#define sss_ini_free_ini_config(cfg)           free_ini_config(cfg)
+
+#endif
+
+/* Function declarations */
+
+/* Close file descriptor */
+void sss_ini_close_file(void *file_desc);
+
+/* Open config file */
+int sss_ini_config_file_open(const char *config_file,
+                             void *file_desc);
+
+/* Check file permissions */
+int sss_ini_config_access_check(void *file_desc);
+
+/* Cstat */
+int sss_ini_get_stat(void *file_desc, void *cstat);
+
+/* Get mtime */
+int sss_ini_get_mtime(char *timestr, struct stat *cstat);
+
+/* Load configuration */
+int sss_ini_get_config(const char *config_file,
+                       struct sss_ini_initdata *init_data);
+/* Create LDIF */
+#ifdef HAVE_LIBINI_CONFIG_V1
+int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
+                                  struct ini_cfgobj *sssd_config,
+                                  const char **config_ldif);
+#elif HAVE_LIBINI_CONFIG_V0
+int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
+                                  struct collection_item *sssd_config,
+                                  const char **config_ldif);
+#endif
+
+
+#endif /* __SSS_INI_H__ */
-- 
1.8.1.4

