dpward / rpms / sssd

Forked from rpms/sssd 3 years ago
Clone
Blob Blame History Raw
From 92b8f8d404bfe72abe8cd324f5569be5ba2c6db1 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 9 Oct 2018 15:32:12 +0200
Subject: [PATCH 63/66] SSSD: Allow refreshing only certain section with
 --genconf
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Related:
https://pagure.io/SSSD/sssd/issue/3862

Adds a new option --genconf-section for the sssd binary.  If this new
option --genconf-section is used, then only the section passed as this
option's value is refreshed.

Conversely, if this section no longer exists in the config file, then it
is removed from the confdb

Reviewed-by: Michal Židek <mzidek@redhat.com>
---
 src/confdb/confdb_setup.c    | 80 +++++++++++++++++++++++++++---------
 src/confdb/confdb_setup.h    |  1 +
 src/man/sssd.8.xml           | 27 ++++++++++++
 src/monitor/monitor.c        | 17 +++++++-
 src/tools/common/sss_tools.c |  1 +
 src/util/sss_ini.c           | 54 ++++++++++++++++++++++++
 src/util/sss_ini.h           |  1 +
 7 files changed, 160 insertions(+), 21 deletions(-)

diff --git a/src/confdb/confdb_setup.c b/src/confdb/confdb_setup.c
index c2b7f9f73..7acefbe6b 100644
--- a/src/confdb/confdb_setup.c
+++ b/src/confdb/confdb_setup.c
@@ -138,6 +138,7 @@ static int confdb_create_base(struct confdb_ctx *cdb)
 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,
                                      const char **_timestr,
                                      const char **_ldif)
@@ -222,7 +223,7 @@ static int confdb_ldif_from_ini_file(TALLOC_CTX *mem_ctx,
         }
     }
 
-    ret = sss_confdb_create_ldif(mem_ctx, init_data, _ldif);
+    ret = sss_confdb_create_ldif(mem_ctx, init_data, only_section, _ldif);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Could not create LDIF for confdb\n");
         return ret;
@@ -249,7 +250,50 @@ static int confdb_fallback_ldif(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
-static int confdb_init_db(const char *config_file, const char *config_dir,
+static int confdb_write_ldif(struct confdb_ctx *cdb,
+                             const char *config_ldif,
+                             bool replace_whole_db)
+{
+    int ret;
+    struct ldb_ldif *ldif;
+
+    while ((ldif = ldb_ldif_read_string(cdb->ldb, &config_ldif))) {
+        if (ldif->changetype == LDB_CHANGETYPE_DELETE) {
+            /* We should remove this section */
+            ret = ldb_delete(cdb->ldb, ldif->msg->dn);
+            if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+                /* Removing a non-existing section is not an error */
+                ret = LDB_SUCCESS;
+            }
+        } else {
+            ret = ldb_add(cdb->ldb, ldif->msg);
+            if (ret != LDB_SUCCESS && replace_whole_db == false) {
+                /* This section already existed, remove and re-add it. We
+                * really want to replace the whole thing instead of messing
+                * around with changetypes and flags on individual elements
+                */
+                ret = ldb_delete(cdb->ldb, ldif->msg->dn);
+                if (ret == LDB_SUCCESS) {
+                    ret = ldb_add(cdb->ldb, ldif->msg);
+                }
+            }
+        }
+
+        if (ret != LDB_SUCCESS) {
+            DEBUG(SSSDBG_FATAL_FAILURE,
+                "Failed to initialize DB (%d,[%s]), aborting!\n",
+                ret, ldb_errstring(cdb->ldb));
+            return EIO;
+        }
+        ldb_ldif_read_free(cdb->ldb, ldif);
+    }
+
+    return EOK;
+}
+
+static int confdb_init_db(const char *config_file,
+                          const char *config_dir,
+                          const char *only_section,
                           struct confdb_ctx *cdb)
 {
     TALLOC_CTX *tmp_ctx;
@@ -259,7 +303,6 @@ static int confdb_init_db(const char *config_file, const char *config_dir,
     const char *timestr = NULL;
     const char *config_ldif;
     const char *vals[2] = { NULL, NULL };
-    struct ldb_ldif *ldif;
     struct sss_ini_initdata *init_data;
 
     tmp_ctx = talloc_new(cdb);
@@ -281,6 +324,7 @@ static int confdb_init_db(const char *config_file, const char *config_dir,
         ret = confdb_ldif_from_ini_file(tmp_ctx,
                                         config_file,
                                         config_dir,
+                                        only_section,
                                         init_data,
                                         &timestr,
                                         &config_ldif);
@@ -318,24 +362,21 @@ static int confdb_init_db(const char *config_file, const char *config_dir,
     }
     in_transaction = true;
 
-    /* Purge existing database */
-    ret = confdb_purge(cdb);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_FATAL_FAILURE,
-              "Could not purge existing configuration\n");
-        goto done;
-    }
-
-    while ((ldif = ldb_ldif_read_string(cdb->ldb, &config_ldif))) {
-        ret = ldb_add(cdb->ldb, ldif->msg);
-        if (ret != LDB_SUCCESS) {
+    /* Purge existing database, if we are reinitializing the confdb completely */
+    if (only_section == NULL) {
+        ret = confdb_purge(cdb);
+        if (ret != EOK) {
             DEBUG(SSSDBG_FATAL_FAILURE,
-                  "Failed to initialize DB (%d,[%s]), aborting!\n",
-                  ret, ldb_errstring(cdb->ldb));
-            ret = EIO;
+                "Could not purge existing configuration\n");
             goto done;
         }
-        ldb_ldif_read_free(cdb->ldb, ldif);
+    }
+
+    ret = confdb_write_ldif(cdb,
+                            config_ldif,
+                            only_section == NULL ? true : false);
+    if (ret != EOK) {
+        goto done;
     }
 
     /* now store the lastUpdate time so that we do not re-init if nothing
@@ -377,6 +418,7 @@ errno_t confdb_setup(TALLOC_CTX *mem_ctx,
                      const char *cdb_file,
                      const char *config_file,
                      const char *config_dir,
+                     const char *only_section,
                      struct confdb_ctx **_cdb)
 {
     TALLOC_CTX *tmp_ctx;
@@ -432,7 +474,7 @@ errno_t confdb_setup(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    ret = confdb_init_db(config_file, config_dir, cdb);
+    ret = confdb_init_db(config_file, config_dir, only_section, cdb);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "ConfDB initialization has failed "
               "[%d]: %s\n", ret, sss_strerror(ret));
diff --git a/src/confdb/confdb_setup.h b/src/confdb/confdb_setup.h
index 9f647ec16..c7fe59541 100644
--- a/src/confdb/confdb_setup.h
+++ b/src/confdb/confdb_setup.h
@@ -49,6 +49,7 @@ errno_t confdb_setup(TALLOC_CTX *mem_ctx,
                      const char *cdb_file,
                      const char *config_file,
                      const char *config_dir,
+                     const char *only_section,
                      struct confdb_ctx **_cdb);
 
 #endif /* CONFDB_SETUP_H_ */
diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml
index f2cbe015b..ff3d8825d 100644
--- a/src/man/sssd.8.xml
+++ b/src/man/sssd.8.xml
@@ -164,6 +164,33 @@
                     </para>
                 </listitem>
             </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>-g</option>,<option>--genconf</option>
+                </term>
+                <listitem>
+                    <para>
+                        Do not start the SSSD, but refresh the configuration
+                        database from the contents of
+                        <filename>/etc/sssd/sssd.conf</filename> and exit.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <option>-s</option>,<option>--genconf-section</option>
+                </term>
+                <listitem>
+                    <para>
+                        Similar to <quote>--genconf</quote>, but only refresh
+                        a single section from the configuration file.  This
+                        option is useful mainly to be called from systemd
+                        unit files to allow socket-activated responders
+                        to refresh their configuration without requiring
+                        the administrator to restart the whole SSSD.
+                    </para>
+                </listitem>
+            </varlistentry>
             <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/param_help.xml" />
             <varlistentry>
                 <term>
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index ea689c604..136cf8f27 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -1579,6 +1579,7 @@ static int monitor_ctx_destructor(void *mem)
 errno_t load_configuration(TALLOC_CTX *mem_ctx,
                            const char *config_file,
                            const char *config_dir,
+                           const char *only_section,
                            struct mt_ctx **monitor)
 {
     errno_t ret;
@@ -1600,7 +1601,8 @@ errno_t load_configuration(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    ret = confdb_setup(ctx, cdb_file, config_file, config_dir, &ctx->cdb);
+    ret = confdb_setup(ctx, cdb_file, config_file, config_dir, only_section,
+                       &ctx->cdb);
     if (ret != EOK) {
         DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup ConfDB [%d]: %s\n",
              ret, sss_strerror(ret));
@@ -2329,6 +2331,7 @@ int main(int argc, const char *argv[])
     char *opt_config_file = NULL;
     char *opt_logger = NULL;
     char *config_file = NULL;
+    char *opt_genconf_section = NULL;
     int flags = 0;
     struct main_context *main_ctx;
     TALLOC_CTX *tmp_ctx;
@@ -2352,6 +2355,9 @@ int main(int argc, const char *argv[])
         {"genconf", 'g', POPT_ARG_NONE, &opt_genconf, 0, \
          _("Refresh the configuration database, then exit"), \
          NULL}, \
+        {"genconf-section", 's', POPT_ARG_STRING, &opt_genconf_section, 0, \
+         _("Similar to --genconf, but only refreshes the given section"), \
+         NULL}, \
         {"version", '\0', POPT_ARG_NONE, &opt_version, 0, \
          _("Print version number and exit"), NULL }, \
         POPT_TABLEEND
@@ -2378,6 +2384,13 @@ int main(int argc, const char *argv[])
         return EXIT_SUCCESS;
     }
 
+    if (opt_genconf_section) {
+        /* --genconf-section implies genconf, just restricted to a single
+         * section
+         */
+        opt_genconf = 1;
+    }
+
     /* If the level or timestamps was passed at the command-line, we want
      * to save it and pass it to the children later.
      */
@@ -2529,7 +2542,7 @@ int main(int argc, const char *argv[])
 
     /* Parse config file, fail if cannot be done */
     ret = load_configuration(tmp_ctx, config_file, CONFDB_DEFAULT_CONFIG_DIR,
-                             &monitor);
+                             opt_genconf_section, &monitor);
     if (ret != EOK) {
         switch (ret) {
         case EPERM:
diff --git a/src/tools/common/sss_tools.c b/src/tools/common/sss_tools.c
index 701db2d93..0d918f164 100644
--- a/src/tools/common/sss_tools.c
+++ b/src/tools/common/sss_tools.c
@@ -98,6 +98,7 @@ static errno_t sss_tool_confdb_init(TALLOC_CTX *mem_ctx,
 
     ret = confdb_setup(mem_ctx, path,
                        SSSD_CONFIG_FILE, CONFDB_DEFAULT_CONFIG_DIR,
+                       NULL,
                        &confdb);
     talloc_zfree(path);
     if (ret != EOK) {
diff --git a/src/util/sss_ini.c b/src/util/sss_ini.c
index 9a059fc00..3c15b2809 100644
--- a/src/util/sss_ini.c
+++ b/src/util/sss_ini.c
@@ -414,6 +414,7 @@ void sss_ini_config_destroy(struct sss_ini_initdata *init_data)
 
 int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
                            struct sss_ini_initdata *init_data,
+                           const char *only_section,
                            const char **config_ldif)
 {
     int ret, i, j;
@@ -436,6 +437,14 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
 #else
     struct collection_item *obj = NULL;
 #endif
+    bool section_handled = true;
+
+    if (only_section != NULL) {
+        /* If the section is specified, we must handle it, either by adding
+         * its contents or by deleting the section if it doesn't exist
+         */
+        section_handled = false;
+    }
 
     ldif_len = strlen(CONFDB_INTERNAL_LDIF);
     ldif = talloc_array(mem_ctx, char, ldif_len+1);
@@ -466,6 +475,18 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
             goto error;
         }
 
+        if (only_section != NULL) {
+            if (strcasecmp(only_section, sections[i])) {
+                DEBUG(SSSDBG_TRACE_FUNC, "Skipping section %s\n", sections[i]);
+                continue;
+            } else {
+                /* Mark the requested section as handled so that we don't
+                 * try to re-add it later
+                 */
+                section_handled = true;
+            }
+        }
+
         dn = talloc_asprintf(tmp_ctx,
                              "dn: %s,cn=config\n"
                              "cn: %s\n",
@@ -552,6 +573,39 @@ int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
         talloc_free(dn);
     }
 
+
+    if (only_section != NULL && section_handled == false) {
+        /* If only a single section was supposed to be
+         * handled, but it wasn't found in the INI file,
+         * create an LDIF that would remove the section
+         */
+        ret = parse_section(tmp_ctx, only_section, &sec_dn, NULL);
+        if (ret != EOK) {
+            goto error;
+        }
+
+        dn = talloc_asprintf(tmp_ctx,
+                             "dn: %s,cn=config\n"
+                             "changetype: delete\n\n",
+                             sec_dn);
+        if (dn == NULL) {
+            ret = ENOMEM;
+            goto error;
+        }
+        dn_size = strlen(dn);
+
+        tmp_ldif = talloc_realloc(mem_ctx, ldif, char,
+                                  ldif_len+dn_size+1);
+        if (!tmp_ldif) {
+            ret = ENOMEM;
+            goto error;
+        }
+
+        ldif = tmp_ldif;
+        memcpy(ldif+ldif_len, dn, dn_size);
+        ldif_len += dn_size;
+    }
+
     ldif[ldif_len] = '\0';
 
     free_section_list(sections);
diff --git a/src/util/sss_ini.h b/src/util/sss_ini.h
index 0b173831d..470b88f99 100644
--- a/src/util/sss_ini.h
+++ b/src/util/sss_ini.h
@@ -77,6 +77,7 @@ void sss_ini_config_destroy(struct sss_ini_initdata *init_data);
 /* Create LDIF */
 int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
                            struct sss_ini_initdata *init_data,
+                           const char *only_section,
                            const char **config_ldif);
 
 /* Validate sssd.conf if libini_config support it */
-- 
2.19.1