URL: https://github.com/SSSD/sssd/pull/946
Author: thalman
 Title: #946: INI: sssctl config-check giving the wrong message
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/946/head:pr946
git checkout pr946
From 183e99ccd7bb6146929c1b02bc9f7aed7478e8e9 Mon Sep 17 00:00:00 2001
From: Tomas Halman <thal...@redhat.com>
Date: Fri, 22 Nov 2019 15:00:26 +0100
Subject: [PATCH] INI: sssctl config-check giving the wrong message

The sssctl config-check is giving the wrong error message when
there are only snippet files and no sssd.conf.

To address this problem sss_ini code had to be partially
rewritten to allow proper configuration testing.

Resolves:
https://pagure.io/SSSD/sssd/issue/3938
---
 src/confdb/confdb.h                           |   3 +
 src/confdb/confdb_setup.c                     |  50 +--
 src/tests/cmocka/test_config_check.c          |  13 +-
 src/tools/sssctl/sssctl_config.c              |  88 +++--
 .../sssd_check_socket_activated_responders.c  |  90 +----
 src/util/sss_ini.c                            | 344 +++++++++++++-----
 src/util/sss_ini.h                            | 171 ++++++---
 src/util/util_errors.c                        |   6 +
 src/util/util_errors.h                        |   6 +
 9 files changed, 464 insertions(+), 307 deletions(-)

diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 2560efc767..ec9be60e69 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -45,6 +45,9 @@
 #define SSSD_MIN_ID 1
 #define SSSD_LOCAL_MINID 1000
 #define CONFDB_DEFAULT_SHELL_FALLBACK "/bin/sh"
+#define CONFDB_FALLBACK_CONFIG \
+    "[sssd]\n" \
+    "services = nss\n"
 
 
 /* Configuration options */
diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
index b7b316fd6f..1df9c3c089 100644
--- a/src/confdb/confdb_setup.c
+++ b/src/confdb/confdb_setup.c
@@ -129,38 +129,22 @@ static int confdb_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
                                      const char *config_file,
                                      const char *config_dir,
                                      const char *only_section,
-                                     struct sss_ini_initdata *init_data,
+                                     struct sss_ini *init_data,
                                      const char **_timestr,
                                      const char **_ldif)
 {
     errno_t ret;
     char timestr[21];
     int version;
-    char fallback_cfg[] =
-        "[sssd]\n"
-        "services = nss\n";
 
-    /* Open config file */
-    ret = sss_ini_config_file_open(init_data, config_file);
-    if (ret == ENOENT) {
-        DEBUG(SSSDBG_TRACE_FUNC, "No sssd.conf.\n");
-        ret = sss_ini_config_file_from_mem(fallback_cfg,
-                                           strlen(fallback_cfg),
-                                           init_data);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_FATAL_FAILURE,
-                  "sss_ini_config_file_from_mem failed. Error %d: %s\n",
-                  ret, sss_strerror(ret));
-            return ret;
-        }
-    } else if (ret == EOK) {
-        ret = sss_ini_config_access_check(init_data);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "Permission check on config file failed.\n");
-            return EPERM;
-        }
+    ret = sss_ini_read_sssd_conf(init_data,
+                                 config_file,
+                                 config_dir);
+    if (ret != EOK) {
+        return ret;
+    }
 
+    if (sss_ini_exists(init_data)) {
         ret = sss_ini_get_stat(init_data);
         if (ret != EOK) {
             ret = errno;
@@ -177,11 +161,6 @@ static int confdb_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
                   "Failed to convert time_t to string??\n");
             return ret;
         }
-    } else {
-        DEBUG(SSSDBG_CONF_SETTINGS,
-              "sss_ini_config_file_open failed: %s [%d]\n", sss_strerror(ret),
-              ret);
-        return ret;
     }
 
     /* FIXME: Determine if the conf file or any snippet has changed
@@ -189,12 +168,6 @@ static int confdb_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
      * added or removed.
      */
 
-    ret = sss_ini_get_config(init_data, config_file, config_dir);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load configuration\n");
-        return ret;
-    }
-
     ret = sss_ini_call_validators(init_data,
                                   SSSDDATADIR"/cfg_rules.ini");
     if (ret != EOK) {
@@ -303,7 +276,7 @@ static int confdb_init_db(const char *config_file,
     const char *timestr = NULL;
     const char *config_ldif;
     const char *vals[2] = { NULL, NULL };
-    struct sss_ini_initdata *init_data;
+    struct sss_ini *init_data;
 
     tmp_ctx = talloc_new(cdb);
     if (tmp_ctx == NULL) {
@@ -311,7 +284,7 @@ static int confdb_init_db(const char *config_file,
         return ENOMEM;
     }
 
-    init_data = sss_ini_initdata_init(tmp_ctx);
+    init_data = sss_ini_new(tmp_ctx);
     if (!init_data) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory.\n");
         ret = ENOMEM;
@@ -390,9 +363,6 @@ static int confdb_init_db(const char *config_file,
         }
     }
 
-    sss_ini_config_destroy(init_data);
-    sss_ini_close_file(init_data);
-
     talloc_zfree(tmp_ctx);
     return ret;
 }
diff --git a/src/tests/cmocka/test_config_check.c b/src/tests/cmocka/test_config_check.c
index dcb560bbf9..861875743c 100644
--- a/src/tests/cmocka/test_config_check.c
+++ b/src/tests/cmocka/test_config_check.c
@@ -31,7 +31,7 @@
 
 #define RULES_PATH ABS_SRC_DIR"/src/config/cfg_rules.ini"
 
-struct sss_ini_initdata {
+struct sss_ini {
     char **error_list;
     struct ref_array *ra_success_list;
     struct ref_array *ra_error_list;
@@ -39,13 +39,14 @@ struct sss_ini_initdata {
     struct value_obj *obj;
     const struct stat *cstat;
     struct ini_cfgfile *file;
+    bool main_config_exists;
 };
 
 void config_check_test_common(const char *cfg_string,
                               size_t num_errors_expected,
                               const char **errors_expected)
 {
-    struct sss_ini_initdata *init_data;
+    struct sss_ini *init_data;
     size_t num_errors;
     char **strs;
     int ret;
@@ -54,11 +55,9 @@ void config_check_test_common(const char *cfg_string,
     tmp_ctx = talloc_new(NULL);
     assert_non_null(tmp_ctx);
 
-    init_data = sss_ini_initdata_init(tmp_ctx);
+    init_data = sss_ini_new(tmp_ctx);
 
-    ret = ini_config_file_from_mem(discard_const(cfg_string),
-                                   strlen(cfg_string),
-                                   &init_data->file);
+    ret = sss_ini_open(init_data, NULL, cfg_string);
     assert_int_equal(ret, EOK);
 
     ret = ini_config_create(&(init_data->sssd_config));
@@ -90,8 +89,6 @@ void config_check_test_common(const char *cfg_string,
     /* Check if the number of errors is the same */
     assert_int_equal(num_errors_expected, num_errors);
 
-    sss_ini_close_file(init_data);
-    sss_ini_config_destroy(init_data);
     talloc_free(tmp_ctx);
 }
 
diff --git a/src/tools/sssctl/sssctl_config.c b/src/tools/sssctl/sssctl_config.c
index 4852e22165..4889e5f25e 100644
--- a/src/tools/sssctl/sssctl_config.c
+++ b/src/tools/sssctl/sssctl_config.c
@@ -31,19 +31,20 @@
 #include "tools/sssctl/sssctl.h"
 #include "confdb/confdb.h"
 
+
+
 #ifdef HAVE_LIBINI_CONFIG_V1_3
 errno_t sssctl_config_check(struct sss_cmdline *cmdline,
                             struct sss_tool_ctx *tool_ctx,
                             void *pvt)
 {
     errno_t ret;
-    struct ini_errobj *errobj = NULL;
-    struct sss_ini_initdata *init_data;
-    struct ref_array *ra;
+    struct sss_ini *init_data;
+    struct ref_array *ra_error, *ra_success;
     char *msg;
     uint32_t i = 0;
     size_t num_errors;
-    size_t num_ra_error;
+    size_t num_ra_error, num_ra_success;
     char **strs = NULL;
     TALLOC_CTX *tmp_ctx = NULL;
 
@@ -54,79 +55,89 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
     }
 
     tmp_ctx = talloc_new(NULL);
-    init_data = sss_ini_initdata_init(tmp_ctx);
+    init_data = sss_ini_new(tmp_ctx);
     if (!init_data) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory.\n");
         ret = ENOMEM;
         goto done;
     }
 
-    /* Open config file */
-    ret = sss_ini_config_file_open(init_data, SSSD_CONFIG_FILE);
-    if (ret == ENOENT) {
-        PRINT("File %1$s does not exist. SSSD will use default "
-              "configuration with files provider.\n", SSSD_CONFIG_FILE);
-        ret = EOK;
-    } else if (ret != EOK) {
-        DEBUG(SSSDBG_TRACE_FUNC,
-              "sss_ini_config_file_open failed: %s [%d]\n",
-              sss_strerror(ret),
-              ret);
+    ret = sss_ini_read_sssd_conf(init_data,
+                                 SSSD_CONFIG_FILE,
+                                 CONFDB_DEFAULT_CONFIG_DIR);
+
+    if (ret == ERR_INI_OPEN_FAILED) {
+        PRINT("Failed to open %s\n", SSSD_CONFIG_FILE);
         goto done;
     }
 
-    /* Check the file permissions */
-    ret = sss_ini_config_access_check(init_data);
-    if (ret != EOK) {
+    if (!sss_ini_exists(init_data)) {
+        PRINT("File %1$s does not exist.\n", SSSD_CONFIG_FILE);
+    }
+
+    if (ret == ERR_INI_INVALID_PERMISSION) {
         PRINT("File ownership and permissions check failed. "
               "Expected root:root and 0600.\n");
-        ret = EPERM;
         goto done;
     }
 
-    ret = sss_ini_get_config(init_data,
-                             SSSD_CONFIG_FILE,
-                             CONFDB_DEFAULT_CONFIG_DIR);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to load configuration\n");
+    if (ret == ERR_INI_PARSE_FAILED) {
+        PRINT("Failed to load configuration configuration from %s.\n",
+              SSSD_CONFIG_FILE);
+        goto done;
+    }
+
+    if (ret == ERR_INI_ADD_SNIPPETS_FAILED) {
+        PRINT("Error while reading configuration directory.\n");
         goto done;
     }
 
-    /* Read rules */
+    /* Used snippet files */
+    ra_success = sss_ini_get_ra_success_list(init_data);
+    num_ra_success = ref_array_len(ra_success);
+    if ((sss_ini_exists(init_data) == false) && (num_ra_success == 0)) {
+        PRINT("There is no configuration."
+#ifdef ADD_FILES_DOMAIN
+              " SSSD will use default configuration with files provider."
+#endif
+              "\n");
+    }
+
+    /* Run validators */
     ret = sss_ini_call_validators_strs(tmp_ctx, init_data,
                                        SSSDDATADIR"/cfg_rules.ini",
                                        &strs, &num_errors);
     if (ret) {
+        PRINT("Failed to run validators");
         goto done;
     }
 
-    /* Output from validators */
     PRINT("Issues identified by validators: %zu\n", num_errors);
     for (i = 0; i < num_errors; i++) {
         printf("%s\n", strs[i]);
     }
 
+    printf("\n");
+
     /* Merging issues */
-    ra = sss_ini_get_ra_error_list(init_data);
-    num_ra_error = ref_array_len(ra);
+    ra_error = sss_ini_get_ra_error_list(init_data);
+    num_ra_error = ref_array_len(ra_error);
 
-    printf("\n");
-    PRINT("Messages generated during configuration merging: %zu\n",num_ra_error);
+    PRINT("Messages generated during configuration merging: %zu\n", num_ra_error);
 
     i = 0;
-    while (ref_array_get(ra, i, &msg) != NULL) {
+    while (ref_array_get(ra_error, i, &msg) != NULL) {
         printf("%s\n", msg);
         i++;
     }
 
-    /* Used snippet files */
-    ra = sss_ini_get_ra_success_list(init_data);
-
     printf("\n");
-    PRINT("Used configuration snippet files: %u\n", ref_array_len(ra));
+
+    /* Used snippets */
+    PRINT("Used configuration snippet files: %zu\n", num_ra_success);
 
     i = 0;
-    while (ref_array_get(ra, i, &msg) != NULL) {
+    while (ref_array_get(ra_success, i, &msg) != NULL) {
         printf("%s\n", msg);
         i++;
     }
@@ -138,8 +149,7 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline,
     }
 
 done:
-    ini_errobj_destroy(&errobj);
-    sss_ini_config_destroy(init_data);
+    talloc_free(tmp_ctx);
     return ret;
 }
 #endif /* HAVE_LIBINI_CONFIG_V1_3 */
diff --git a/src/tools/sssd_check_socket_activated_responders.c b/src/tools/sssd_check_socket_activated_responders.c
index fb9df39091..dbd2331026 100644
--- a/src/tools/sssd_check_socket_activated_responders.c
+++ b/src/tools/sssd_check_socket_activated_responders.c
@@ -22,109 +22,61 @@
 
 #include <popt.h>
 #include <stdio.h>
-#include <ini_configobj.h>
 
 #include "util/util.h"
+#include "util/sss_ini.h"
 #include "confdb/confdb.h"
 
 static errno_t check_socket_activated_responder(const char *responder)
 {
     errno_t ret;
-    struct ini_cfgfile *file_ctx = NULL;
-    struct ini_cfgobj *ini_config = NULL;
-    struct ini_cfgobj *modified_ini_config = NULL;
-    struct value_obj *vobj = NULL;
-    struct access_check snip_check;
     const char *services;
-    const char *patterns[] = { "^[^\\.].*\\.conf$", NULL };
-    const char *sections[] = { "sssd", NULL };
     const char *str;
     TALLOC_CTX *tmp_ctx;
+    struct sss_ini *init_data;
 
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
         return ENOMEM;
     }
 
-    ret = ini_config_create(&ini_config);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "ini_config_create() failed [%d][%s]\n",
-              ret, sss_strerror(ret));
+    init_data = sss_ini_new(tmp_ctx);
+    if (init_data == NULL) {
+        ret = ENOMEM;
         goto done;
     }
 
-    ret = ini_config_file_open(SSSD_CONFIG_FILE, 0, &file_ctx);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "ini_config_file_open() failed [%d][%s]\n",
-              ret, sss_strerror(ret));
-        goto done;
-    }
-
-    /* Using the same flags used by sss_ini_get_config(), which is used to
-     * load the config file ... */
-    ret = ini_config_parse(file_ctx,
-                           INI_STOP_ON_ANY,
-                           INI_MV1S_OVERWRITE,
-                           INI_PARSE_NOWRAP,
-                           ini_config);
-    if (ret != 0) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "ini_config_parse() failed [%d][%s]\n",
-              ret, sss_strerror(ret));
-        goto done;
-    }
-
-    /* And also check the snippets ... */
-    snip_check.flags = INI_ACCESS_CHECK_MODE |
-                       INI_ACCESS_CHECK_UID |
-                       INI_ACCESS_CHECK_GID;
-    snip_check.uid = 0; /* owned by root */
-    snip_check.gid = 0; /* owned by root */
-    snip_check.mode = S_IRUSR; /* r**------ */
-    snip_check.mask = ALLPERMS & ~(S_IWUSR | S_IXUSR);
-
-    ret = ini_config_augment(ini_config,
-                             CONFDB_DEFAULT_CONFIG_DIR,
-                             patterns,
-                             sections,
-                             &snip_check,
-                             INI_STOP_ON_ANY,
-                             INI_MV1S_OVERWRITE,
-                             INI_PARSE_NOWRAP,
-                             INI_MV2S_OVERWRITE,
-                             &modified_ini_config,
-                             NULL,
-                             NULL);
+    ret = sss_ini_read_sssd_conf(init_data,
+                                 SSSD_CONFIG_FILE,
+                                 CONFDB_DEFAULT_CONFIG_DIR);
     if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "ini_config_augment failed [%d][%s]\n",
-              ret, sss_strerror(ret));
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Failed to read configuration: [%d] [%s]",
+              ret,
+              sss_strerror(ret));
         goto done;
     }
 
-    if (modified_ini_config != NULL) {
-        ini_config_destroy(ini_config);
-        ini_config = modified_ini_config;
-    }
+    ret = sss_ini_get_cfgobj(init_data, "sssd", "services");
 
-    ret = ini_get_config_valueobj("sssd", "services", ini_config,
-                                  INI_GET_FIRST_VALUE, &vobj);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
-              "ini_get_config_valueobj() failed [%d][%s]\n",
-              ret, sss_strerror(ret));
+              "sss_ini_get_cfgobj() failed [%d].\n", ret);
         goto done;
     }
 
-    /* In case there's no services' line at all, just return EOK. */
-    if (vobj == NULL) {
+    ret = sss_ini_check_config_obj(init_data);
+    if (ret == ENOENT) {
+        /* In case there's no services' line at all, just return EOK. */
         ret = EOK;
         goto done;
     }
 
-    services = ini_get_string_config_value(vobj, &ret);
+    services = sss_ini_get_string_config_value(init_data, &ret);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
-              "ini_get_string_config_value() failed [%d][%s]\n",
-              ret, sss_strerror(ret));
+              "sss_ini_get_string_config_value() failed [%d]\n",
+              ret);
         goto done;
     }
 
@@ -137,8 +89,6 @@ static errno_t check_socket_activated_responder(const char *responder)
     ret = EOK;
 
 done:
-    ini_config_file_destroy(file_ctx);
-    ini_config_destroy(ini_config);
     talloc_free(tmp_ctx);
 
     return ret;
diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c
index cf61a17225..e3699805de 100644
--- a/src/util/sss_ini.c
+++ b/src/util/sss_ini.c
@@ -35,7 +35,7 @@
 #include "ini_configobj.h"
 #include "ini_config.h"
 
-struct sss_ini_initdata {
+struct sss_ini {
     char **error_list;
     struct ref_array *ra_success_list;
     struct ref_array *ra_error_list;
@@ -43,6 +43,7 @@ struct sss_ini_initdata {
     struct value_obj *obj;
     const struct stat *cstat;
     struct ini_cfgfile *file;
+    bool main_config_exists;
 };
 
 #define sss_ini_get_sec_list                   ini_get_section_list
@@ -50,51 +51,109 @@ struct sss_ini_initdata {
 #define sss_ini_get_const_string_config_value  ini_get_const_string_config_value
 #define sss_ini_get_config_obj                 ini_get_config_valueobj
 
-/* Initialize data structure */
 
-struct sss_ini_initdata* sss_ini_initdata_init(TALLOC_CTX *mem_ctx)
+static void sss_ini_free_error_messages(struct sss_ini *self)
 {
-    return talloc_zero(mem_ctx, struct sss_ini_initdata);
+    if (self != NULL) {
+        ini_config_free_errors(self->error_list);
+        self->error_list = NULL;
+    }
 }
 
+static void sss_ini_free_ra_messages(struct sss_ini *self)
+{
+    if (self != NULL) {
+        ref_array_destroy(self->ra_success_list);
+        self->ra_success_list = NULL;
+        ref_array_destroy(self->ra_error_list);
+        self->ra_error_list = NULL;
+    }
+}
 
+static void sss_ini_free_config(struct sss_ini *self)
+{
+    if (self != NULL && self->sssd_config != NULL) {
+        ini_config_destroy(self->sssd_config);
+        self->sssd_config = NULL;
+    }
+}
 
 /* Close file descriptor */
 
-void sss_ini_close_file(struct sss_ini_initdata *init_data)
+static void sss_ini_close_file(struct sss_ini *self)
 {
-    if (init_data == NULL) return;
-    if (init_data->file != NULL) {
-        ini_config_file_destroy(init_data->file);
-        init_data->file = NULL;
+    if (self != NULL && self->file != NULL) {
+        ini_config_file_destroy(self->file);
+        self->file = NULL;
     }
 }
 
+/* sss_ini destructor */
+
+static int sss_ini_destroy(struct sss_ini *self)
+{
+    sss_ini_free_error_messages(self);
+    sss_ini_free_ra_messages(self);
+    sss_ini_free_config(self);
+    sss_ini_close_file(self);
+    return 0;
+}
+
+/* Initialize data structure */
+
+struct sss_ini* sss_ini_new(TALLOC_CTX *mem_ctx)
+{
+    struct sss_ini *self;
+
 
+    self = talloc_zero(mem_ctx, struct sss_ini);
+    if (!self) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Not enough memory for sss_ini_data.\n");
+        return NULL;
+    }
+    talloc_set_destructor(self, sss_ini_destroy);
+    return self;
+}
 
 /* Open configuration file */
 
-int sss_ini_config_file_open(struct sss_ini_initdata *init_data,
-                             const char *config_file)
+static int sss_ini_config_file_open(struct sss_ini *self,
+                                    const char *config_file)
 {
-    return ini_config_file_open(config_file,
-                                INI_META_STATS,
-                                &init_data->file);
+    int ret;
+
+    if (self == NULL) {
+        return EINVAL;
+    }
+
+    ret = ini_config_file_open(config_file,
+                               INI_META_STATS,
+                               &self->file);
+    self->main_config_exists = (ret != ENOENT);
+    return ret;
 }
 
-int sss_ini_config_file_from_mem(void *data_buf,
-                                 uint32_t data_len,
-                                 struct sss_ini_initdata *init_data)
+static int sss_ini_config_file_from_mem(struct sss_ini *self,
+                                        void *data_buf,
+                                        uint32_t data_len)
 {
+    if (self == NULL) {
+        return EINVAL;
+    }
+
     return ini_config_file_from_mem(data_buf, strlen(data_buf),
-                                   &init_data->file);
+                                   &self->file);
 }
 
 /* Check configuration file permissions */
 
-int sss_ini_config_access_check(struct sss_ini_initdata *init_data)
+static int sss_ini_access_check(struct sss_ini *self)
 {
-    return ini_config_access_check(init_data->file,
+    if (!self->main_config_exists) {
+        return EOK;
+    }
+
+    return ini_config_access_check(self->file,
                                    INI_ACCESS_CHECK_MODE |
                                    INI_ACCESS_CHECK_UID |
                                    INI_ACCESS_CHECK_GID,
@@ -108,11 +167,11 @@ int sss_ini_config_access_check(struct sss_ini_initdata *init_data)
 
 /* Get cstat */
 
-int sss_ini_get_stat(struct sss_ini_initdata *init_data)
+int sss_ini_get_stat(struct sss_ini *self)
 {
-    init_data->cstat = ini_config_get_stat(init_data->file);
+    self->cstat = ini_config_get_stat(self->file);
 
-    if (!init_data->cstat) return EIO;
+    if (!self->cstat) return EIO;
 
     return EOK;
 }
@@ -121,15 +180,20 @@ int sss_ini_get_stat(struct sss_ini_initdata *init_data)
 
 /* Get mtime */
 
-int sss_ini_get_mtime(struct sss_ini_initdata *init_data,
+int sss_ini_get_mtime(struct sss_ini *self,
                       size_t timestr_len,
                       char *timestr)
 {
     return snprintf(timestr, timestr_len, "%llu",
-                    (long long unsigned)init_data->cstat->st_mtime);
+                    (long long unsigned)self->cstat->st_mtime);
 }
 
+/* Get file_exists */
 
+bool sss_ini_exists(struct sss_ini *self)
+{
+    return self->main_config_exists;
+}
 
 /* Print ini_config errors */
 
@@ -147,26 +211,19 @@ static void sss_ini_config_print_errors(char **error_list)
     }
 }
 
-
-
-/* Load configuration */
-
-int sss_ini_get_config(struct sss_ini_initdata *init_data,
-                       const char *config_file,
-                       const char *config_dir)
+static int sss_ini_parse(struct sss_ini *self)
 {
     int ret;
-#ifdef HAVE_LIBINI_CONFIG_V1_3
-    const char *patterns[] = { "^[^\\.].*\\.conf$", NULL };
-    const char *sections[] = { ".*", NULL };
-    uint32_t i = 0;
-    char *msg = NULL;
-    struct access_check snip_check;
-    struct ini_cfgobj *modified_sssd_config = NULL;
-#endif /* HAVE_LIBINI_CONFIG_V1_3 */
+
+    if (!self) {
+        return EINVAL;
+    }
+
+    sss_ini_free_error_messages(self);
+    sss_ini_free_config(self);
 
     /* Create config object */
-    ret = ini_config_create(&(init_data->sssd_config));
+    ret = ini_config_create(&(self->sssd_config));
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE,
                 "Failed to create config object. Error %d.\n", ret);
@@ -174,32 +231,46 @@ int sss_ini_get_config(struct sss_ini_initdata *init_data,
     }
 
     /* Parse file */
-    ret = ini_config_parse(init_data->file,
+    ret = ini_config_parse(self->file,
                            INI_STOP_ON_ANY,
                            INI_MV1S_OVERWRITE,
                            INI_PARSE_NOWRAP,
-                           init_data->sssd_config);
+                           self->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)) {
+        if (ini_config_error_count(self->sssd_config)) {
             DEBUG(SSSDBG_FATAL_FAILURE,
                     "Errors detected while parsing: %s\n",
-                     ini_config_get_filename(init_data->file));
+                     ini_config_get_filename(self->file));
 
-            ini_config_get_errors(init_data->sssd_config,
-                                  &init_data->error_list);
-            sss_ini_config_print_errors(init_data->error_list);
-            ini_config_free_errors(init_data->error_list);
+            ini_config_get_errors(self->sssd_config,
+                                  &(self->error_list));
         }
-        ini_config_destroy(init_data->sssd_config);
-        init_data->sssd_config = NULL;
-        return ret;
     }
+    return ret;
+}
 
+static int sss_ini_add_snippets(struct sss_ini *self,
+                                const char *config_dir)
+{
 #ifdef HAVE_LIBINI_CONFIG_V1_3
+    int ret;
+    const char *patterns[] = { "^[^\\.].*\\.conf$", NULL };
+    const char *sections[] = { ".*", NULL };
+    uint32_t i = 0;
+    char *msg = NULL;
+    struct ini_cfgobj *modified_sssd_config = NULL;
+    struct access_check snip_check;
+
+    if (self == NULL || self->sssd_config == NULL || config_dir == NULL) {
+        return EINVAL;
+    }
+
+    sss_ini_free_ra_messages(self);
+
     snip_check.flags = INI_ACCESS_CHECK_MODE | INI_ACCESS_CHECK_UID
                        | INI_ACCESS_CHECK_GID;
     snip_check.uid = 0; /* owned by root */
@@ -207,7 +278,7 @@ int sss_ini_get_config(struct sss_ini_initdata *init_data,
     snip_check.mode = S_IRUSR; /* r**------ */
     snip_check.mask = ALLPERMS & ~(S_IWUSR | S_IXUSR);
 
-    ret = ini_config_augment(init_data->sssd_config,
+    ret = ini_config_augment(self->sssd_config,
                              config_dir,
                              patterns,
                              sections,
@@ -217,22 +288,22 @@ int sss_ini_get_config(struct sss_ini_initdata *init_data,
                              INI_PARSE_NOWRAP,
                              INI_MV2S_OVERWRITE,
                              &modified_sssd_config,
-                             &init_data->ra_error_list,
-                             &init_data->ra_success_list);
+                             &self->ra_error_list,
+                             &self->ra_success_list);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
-              "Failed to augment configuration [%d]: %s",
-              ret, sss_strerror(ret));
+              "Failed to augment configuration: Error %d",
+              ret);
     }
 
-    while (ref_array_get(init_data->ra_success_list, i, &msg) != NULL) {
+    while (ref_array_get(self->ra_success_list, i, &msg) != NULL) {
         DEBUG(SSSDBG_TRACE_FUNC,
               "Config merge success: %s\n", msg);
         i++;
     }
 
     i = 0;
-    while (ref_array_get(init_data->ra_error_list, i, &msg) != NULL) {
+    while (ref_array_get(self->ra_error_list, i, &msg) != NULL) {
         DEBUG(SSSDBG_CRIT_FAILURE,
               "Config merge error: %s\n", msg);
         i++;
@@ -240,31 +311,34 @@ int sss_ini_get_config(struct sss_ini_initdata *init_data,
 
     /* switch config objects if there are no errors */
     if (modified_sssd_config != NULL) {
-        ini_config_destroy(init_data->sssd_config);
-        init_data->sssd_config = modified_sssd_config;
+        ini_config_destroy(self->sssd_config);
+        self->sssd_config = modified_sssd_config;
     } else {
         DEBUG(SSSDBG_TRACE_FUNC,
               "Using only main configuration file due to errors in merging\n");
     }
-#endif
     return ret;
+
+#else /* HAVE_LIBINI_CONFIG_V1_3 */
+    return EOK
+#endif /* ! HAVE_LIBINI_CONFIG_V1_3 */
 }
 
 struct ref_array *
-sss_ini_get_ra_success_list(struct sss_ini_initdata *init_data)
+sss_ini_get_ra_success_list(struct sss_ini *self)
 {
 #ifdef HAVE_LIBINI_CONFIG_V1_3
-    return init_data->ra_success_list;
+    return self->ra_success_list;
 #else
     return NULL;
 #endif /* HAVE_LIBINI_CONFIG_V1_3 */
 }
 
 struct ref_array *
-sss_ini_get_ra_error_list(struct sss_ini_initdata *init_data)
+sss_ini_get_ra_error_list(struct sss_ini *self)
 {
 #ifdef HAVE_LIBINI_CONFIG_V1_3
-    return init_data->ra_error_list;
+    return self->ra_error_list;
 #else
     return NULL;
 #endif /* HAVE_LIBINI_CONFIG_V1_3 */
@@ -272,18 +346,18 @@ sss_ini_get_ra_error_list(struct sss_ini_initdata *init_data)
 
 /* Get configuration object */
 
-int sss_ini_get_cfgobj(struct sss_ini_initdata *init_data,
+int sss_ini_get_cfgobj(struct sss_ini *self,
                        const char *section, const char *name)
 {
-    return sss_ini_get_config_obj(section,name, init_data->sssd_config,
-                                  INI_GET_FIRST_VALUE, &init_data->obj);
+    return sss_ini_get_config_obj(section,name, self->sssd_config,
+                                  INI_GET_FIRST_VALUE, &self->obj);
 }
 
 /* Check configuration object */
 
-int sss_ini_check_config_obj(struct sss_ini_initdata *init_data)
+int sss_ini_check_config_obj(struct sss_ini *self)
 {
-    if (init_data->obj == NULL) {
+    if (self->obj == NULL) {
         return ENOENT;
     }
 
@@ -294,32 +368,24 @@ int sss_ini_check_config_obj(struct sss_ini_initdata *init_data)
 
 /* Get integer value */
 
-int sss_ini_get_int_config_value(struct sss_ini_initdata *init_data,
+int sss_ini_get_int_config_value(struct sss_ini *self,
                                  int strict, int def, int *error)
 {
-    return ini_get_int_config_value(init_data->obj, strict, def, error);
+    return ini_get_int_config_value(self->obj, strict, def, error);
 }
 
+/* Get string value */
 
-
-/* Destroy ini config (v1) */
-
-void sss_ini_config_destroy(struct sss_ini_initdata *init_data)
+const char *sss_ini_get_string_config_value(struct sss_ini *self,
+                                            int *error)
 {
-    if (init_data == NULL) return;
-
-    if (init_data->sssd_config != NULL) {
-        ini_config_destroy(init_data->sssd_config);
-        init_data->sssd_config = NULL;
-    }
+    return ini_get_string_config_value(self->obj, error);
 }
 
-
-
 /* Create LDIF */
 
 int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
-                           struct sss_ini_initdata *init_data,
+                           struct sss_ini *self,
                            const char *only_section,
                            const char **config_ldif)
 {
@@ -362,7 +428,7 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
 
     /* Read in the collection and convert it to an LDIF */
     /* Get the list of sections */
-    sections = sss_ini_get_sec_list(init_data->sssd_config,
+    sections = sss_ini_get_sec_list(self->sssd_config,
                                     &section_count, &ret);
     if (ret != EOK) {
         goto error;
@@ -401,7 +467,7 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
         dn_size = strlen(dn);
 
         /* Get all of the attributes and their values as LDIF */
-        attrs = sss_ini_get_attr_list(init_data->sssd_config, sections[i],
+        attrs = sss_ini_get_attr_list(self->sssd_config, sections[i],
                                    &attr_count, &ret);
         if (ret != EOK) {
             free_section_list(sections);
@@ -412,7 +478,7 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
             DEBUG(SSSDBG_TRACE_FUNC,
                     "Processing attribute [%s]\n", attrs[j]);
             ret = sss_ini_get_config_obj(sections[i], attrs[j],
-                                         init_data->sssd_config,
+                                         self->sssd_config,
                                          INI_GET_FIRST_VALUE, &obj);
             if (ret != EOK) goto error;
 
@@ -570,7 +636,7 @@ static int custom_sssd_checks(const char *rule_name,
     return EOK;
 }
 
-static int sss_ini_call_validators_errobj(struct sss_ini_initdata *data,
+static int sss_ini_call_validators_errobj(struct sss_ini *data,
                                           const char *rules_path,
                                           struct ini_errobj *errobj)
 {
@@ -601,7 +667,7 @@ static int sss_ini_call_validators_errobj(struct sss_ini_initdata *data,
 }
 #endif /* HAVE_LIBINI_CONFIG_V1_3 */
 
-int sss_ini_call_validators(struct sss_ini_initdata *data,
+int sss_ini_call_validators(struct sss_ini *data,
                             const char *rules_path)
 {
 #ifdef HAVE_LIBINI_CONFIG_V1_3
@@ -643,7 +709,7 @@ int sss_ini_call_validators(struct sss_ini_initdata *data,
 }
 
 int sss_ini_call_validators_strs(TALLOC_CTX *mem_ctx,
-                                 struct sss_ini_initdata *data,
+                                 struct sss_ini *data,
                                  const char *rules_path,
                                  char ***_errors,
                                  size_t *_num_errors)
@@ -710,7 +776,7 @@ int sss_ini_call_validators_strs(TALLOC_CTX *mem_ctx,
 
 #else
     DEBUG(SSSDBG_TRACE_FUNC,
-          "libini_config does not support configuration file validataion\n");
+          "libini_config does not support configuration file validation\n");
 
     if (_num_errors == NULL || _errors == NULL) {
         return EINVAL;
@@ -720,3 +786,95 @@ int sss_ini_call_validators_strs(TALLOC_CTX *mem_ctx,
     return EOK;
 #endif /* HAVE_LIBINI_CONFIG_V1_3 */
 }
+
+int sss_ini_open(struct sss_ini *self,
+                 const char *config_file,
+                 const char *fallback_cfg)
+{
+    int ret;
+
+    if (self == NULL) {
+        return EINVAL;
+    }
+
+    if (config_file != NULL) {
+        ret = sss_ini_config_file_open(self, config_file);
+    } else {
+        ret = ENOENT;
+    }
+
+    switch (ret) {
+    case EOK:
+        break;
+    case ENOENT:
+        DEBUG(SSSDBG_TRACE_FUNC, "No %s.\n", config_file);
+        if (fallback_cfg == NULL) {
+            return ret;
+        }
+
+        ret = sss_ini_config_file_from_mem(self,
+                                           discard_const(fallback_cfg),
+                                           strlen(fallback_cfg));
+        if (ret != EOK) {
+            DEBUG(SSSDBG_FATAL_FAILURE,
+                  "sss_ini_config_file_from_mem failed. Error %d\n",
+                  ret);
+        }
+        break;
+    default:
+        DEBUG(SSSDBG_CONF_SETTINGS,
+              "sss_ini_config_file_open failed: Error %d\n",
+              ret);
+        sss_ini_config_print_errors(self->error_list);
+        break;
+    }
+    return ret;
+}
+
+int sss_ini_read_sssd_conf(struct sss_ini *self,
+                           const char *config_file,
+                           const char *config_dir)
+{
+    errno_t ret;
+
+    if (self == NULL) {
+        return EINVAL;
+    }
+
+    ret = sss_ini_open(self, config_file, CONFDB_FALLBACK_CONFIG);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "The sss_ini_open failed %s: %d\n",
+              config_file,
+              ret);
+        return ERR_INI_OPEN_FAILED;
+    }
+
+    if (sss_ini_exists(self)) {
+        ret = sss_ini_access_check(self);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE,
+                  "Permission check on config file failed.\n");
+            return ERR_INI_INVALID_PERMISSION;
+        } else {
+            DEBUG(SSSDBG_CONF_SETTINGS,
+                  "File %1$s does not exist.\n",
+                  (config_file ? config_file : "NULL"));
+        }
+    }
+
+    ret = sss_ini_parse(self);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse configuration.\n");
+        return ERR_INI_PARSE_FAILED;
+    }
+
+    ret = sss_ini_add_snippets(self, config_dir);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              "Error while reading configuration directory.\n");
+        return ERR_INI_ADD_SNIPPETS_FAILED;
+    }
+
+    return ret;
+}
diff --git a/src/util/sss_ini.h b/src/util/sss_ini.h
index 0bf9c0ff5b..4e3f67fd6d 100644
--- a/src/util/sss_ini.h
+++ b/src/util/sss_ini.h
@@ -27,81 +27,138 @@
 #ifndef __SSS_INI_H__
 #define __SSS_INI_H__
 
-/* Structure declarations */
-
-/* INI data structure */
-struct sss_ini_initdata;
-
-
-/* Function declarations */
-
-/* Initialize data structure */
-struct sss_ini_initdata* sss_ini_initdata_init(TALLOC_CTX *tmp_ctx);
-
-/* Close file descriptor */
-void sss_ini_close_file(struct sss_ini_initdata *init_data);
-
-/* Open config file */
-int sss_ini_config_file_open(struct sss_ini_initdata *init_data,
-                             const char *config_file);
-
-/* Load config from buffer */
-int sss_ini_config_file_from_mem(void *data_buf,
-                                 uint32_t data_len,
-                                 struct sss_ini_initdata *init_data);
-
-/* Check file permissions */
-int sss_ini_config_access_check(struct sss_ini_initdata *init_data);
-
-/* Cstat */
-int sss_ini_get_stat(struct sss_ini_initdata *init_data);
-
-/* Get mtime */
-int sss_ini_get_mtime(struct sss_ini_initdata *init_data,
+#include <stdbool.h>
+
+/**
+ * @brief INI data structure
+ */
+struct sss_ini;
+
+/**
+ * @brief create new ini data object
+ *
+ * @param[in] tmp_ctx  talloc context
+ *
+ * @return
+ *  - pointer to newly allocated and initialized structure
+ *  - NULL in case of error
+ */
+struct sss_ini* sss_ini_new(TALLOC_CTX *tmp_ctx);
+
+
+/**
+ * @brief Open ini file or use fallback_cfg if file is not present. Include
+ *        configuration snippets and perform access check.
+ *
+ * @param[in] self          pointer to sss_ini structure
+ * @param[in] config_file   ini file
+ * @param[in] config_dir    directory containing ini files to be included
+ *
+ * @return
+ *  - EOK - success
+ *  - ERR_INI_OPEN_FAILED - sss_ini_open failed
+ *  - ERR_INI_INVALID_PERMISSION - access check failed
+ *  - ERR_INI_PARSE_FAILED - failed to parse configuration file
+ *  - ERR_INI_ADD_SNIPPETS_FAILED - failed to add configuration snippets
+ */
+int sss_ini_read_sssd_conf(struct sss_ini *self,
+                           const char *config_file,
+                           const char *config_dir);
+
+/**
+ * @brief Open ini file or use fallback_cfg if file is not present
+ *
+ * @param[in] self          pointer to sss_ini structure
+ * @param[in] config_file   ini file
+ * @param[in] fallback_cfg  string with ini content. This parameter is used
+ *                          when config_file doesn't exist or it is set to NULL
+ *
+ * @return error code
+ */
+int sss_ini_open(struct sss_ini *self,
+                 const char *config_file,
+                 const char *fallback_cfg);
+
+/**
+ * @brief Check whether sss_ini_open() reported that ini file is
+ *        not present
+ *
+ * @param[in] self  pointer to sss_ini structure
+ *
+ * @return
+ *   - true   we are using ini file
+ *   - false  file was not found
+ */
+bool sss_ini_exists(struct sss_ini *self);
+
+/**
+ * @brief get Cstat structure of the ini file
+ */
+int sss_ini_get_stat(struct sss_ini *self);
+
+/**
+ * @brief Get mtime of the ini file
+ */
+int sss_ini_get_mtime(struct sss_ini *self,
                       size_t timestr_len,
                       char *timestr);
 
-/* Load configuration */
-int sss_ini_get_config(struct sss_ini_initdata *init_data,
-                       const char *config_file,
-                       const char *config_dir);
-/* Get configuration object */
-int sss_ini_get_cfgobj(struct sss_ini_initdata *init_data,
+/**
+ * @brief Get pointer to list of snippet parsing errors
+ */
+struct ref_array *
+sss_ini_get_ra_error_list(struct sss_ini *self);
+
+/**
+ * @brief Get pointer to list of successfully merged snippet files
+ */
+struct ref_array *
+sss_ini_get_ra_success_list(struct sss_ini *self);
+
+/**
+ * @brief Get configuration object
+ */
+int sss_ini_get_cfgobj(struct sss_ini *self,
                        const char *section, const char *name);
 
-/* Check configuration object */
-int sss_ini_check_config_obj(struct sss_ini_initdata *init_data);
+/**
+ * @brief Check configuration object
+ */
+int sss_ini_check_config_obj(struct sss_ini *self);
 
-/* Get int value */
-int sss_ini_get_int_config_value(struct sss_ini_initdata *init_data,
+/**
+ * @brief Get int value
+ */
+int sss_ini_get_int_config_value(struct sss_ini *self,
                                  int strict, int def, int *error);
 
-/* Destroy ini config */
-void sss_ini_config_destroy(struct sss_ini_initdata *init_data);
+/**
+ * @brief Get string value
+ */
+const char *sss_ini_get_string_config_value(struct sss_ini *self,
+                                            int *error);
 
-/* Create LDIF */
+/**
+ * @brief Create LDIF
+ */
 int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
-                           struct sss_ini_initdata *init_data,
+                           struct sss_ini *self,
                            const char *only_section,
                            const char **config_ldif);
 
-/* Validate sssd.conf if libini_config support it */
-int sss_ini_call_validators(struct sss_ini_initdata *data,
+/**
+ * @brief Validate sssd.conf if libini_config support it
+ */
+int sss_ini_call_validators(struct sss_ini *data,
                             const char *rules_path);
 
-/* Get errors from validators in array of strings */
+/**
+ * @brief Get errors from validators in array of strings
+ */
 int sss_ini_call_validators_strs(TALLOC_CTX *mem_ctx,
-                                 struct sss_ini_initdata *data,
+                                 struct sss_ini *data,
                                  const char *rules_path,
                                  char ***_strs,
                                  size_t *_num_errors);
 
-/* Get pointer to list of snippet parsing errors */
-struct ref_array *
-sss_ini_get_ra_error_list(struct sss_ini_initdata *init_data);
-
-/* Get pointer to list of successfully merged snippet files */
-struct ref_array *
-sss_ini_get_ra_success_list(struct sss_ini_initdata *init_data);
-
 #endif /* __SSS_INI_H__ */
diff --git a/src/util/util_errors.c b/src/util/util_errors.c
index 0148958d35..05a66d293b 100644
--- a/src/util/util_errors.c
+++ b/src/util/util_errors.c
@@ -137,6 +137,12 @@ struct err_string error_to_str[] = {
     { "Unknown bus owner" }, /* ERR_SBUS_UNKNOWN_OWNER */
     { "No reply was received" }, /* ERR_SBUS_NO_REPLY */
 
+    /* ini parsing errors */
+    { "Failed to open configuration" }, /* ERR_INI_OPEN_FAILED */
+    { "File ownership and permissions check failed" }, /* ERR_INI_INVALID_PERMISSION */
+    { "Error while parsing configuration file" }, /* ERR_INI_PARSE_FAILED */
+    { "Failed to add configuration snippets" }, /* ERR_INI_ADD_SNIPPETS_FAILED */
+
     { "ERR_LAST" } /* ERR_LAST */
 };
 
diff --git a/src/util/util_errors.h b/src/util/util_errors.h
index ec31a9ee93..41697ea522 100644
--- a/src/util/util_errors.h
+++ b/src/util/util_errors.h
@@ -158,6 +158,12 @@ enum sssd_errors {
     ERR_SBUS_UNKNOWN_OWNER,
     ERR_SBUS_NO_REPLY,
 
+    /* ini parsing errors */
+    ERR_INI_OPEN_FAILED,
+    ERR_INI_INVALID_PERMISSION,
+    ERR_INI_PARSE_FAILED,
+    ERR_INI_ADD_SNIPPETS_FAILED,
+
     ERR_LAST            /* ALWAYS LAST */
 };
 
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org

Reply via email to