[SSSD] [PATCH] AD/IPA: add krb5_confd_path configuration option

Sumit Bose sbose at redhat.com
Mon Nov 24 10:11:05 UTC 2014


Hi,

this patch provides a fix for https://fedorahosted.org/sssd/ticket/2473.

I tired to not restrict it to the localauth plugin but make it possible
to easily add other snippets in future.

Currently I don't do any specific checks on the given path because if it
is really changed to some other path by the admin we cannot expected and
permissions or ownerships. If you think that some checks are need I'd be
happy to add them.

The first patch fixes an issues in the autoconf/automake machinery which
I came across while testing the patch.

bye,
Sumit
-------------- next part --------------
From 88c54586c141c38a21dcb70083707d2a2d3dcae9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 21 Nov 2014 15:22:24 +0100
Subject: [PATCH 1/2] Fix KRB5_CONF_PATH

Currently a shell/Makefile variable is used in the definition of
KRB5_CONF_PATH for C code. This patch replaces it with a complier macro.
---
 Makefile.am                 | 1 +
 src/conf_macros.m4          | 2 +-
 src/tests/cwrap/Makefile.am | 2 ++
 3 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index 53ace65..56a562c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -386,6 +386,7 @@ AM_CPPFLAGS = \
     $(JOURNALD_CFLAGS) \
     -DLIBDIR=\"$(libdir)\" \
     -DVARDIR=\"$(localstatedir)\" \
+    -DSYSCONFDIR=\"$(sysconfdir)\" \
     -DSHLIBEXT=\"$(SHLIBEXT)\" \
     -DSSSD_LIBEXEC_PATH=\"$(sssdlibexecdir)\" \
     -DSSSD_CONF_DIR=\"$(sssdconfdir)\" \
diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
index fbee81f..df9d1dd 100644
--- a/src/conf_macros.m4
+++ b/src/conf_macros.m4
@@ -353,7 +353,7 @@ AC_DEFUN([WITH_KRB5_CONF],
                 ]
                )
 
-    KRB5_CONF_PATH="${sysconfdir}/krb5.conf"
+    KRB5_CONF_PATH="\"SYSCONFDIR\"/krb5.conf"
     if test x"$with_krb5_conf" != x; then
         KRB5_CONF_PATH=$with_krb5_conf
     fi
diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am
index d98bb33..c1991a1 100644
--- a/src/tests/cwrap/Makefile.am
+++ b/src/tests/cwrap/Makefile.am
@@ -4,7 +4,9 @@ AM_CPPFLAGS = \
     -I$(top_srcdir)/src \
     -I. \
     -DLOCALEDIR=\"$(localedir)\" \
+    -DLIBDIR=\"$(libdir)\" \
     -DVARDIR=\"$(localstatedir)\" \
+    -DSYSCONFDIR=\"$(sysconfdir)\" \
     $(DBUS_CFLAGS) \
     $(GLIB2_CFLAGS) \
     $(NULL)
-- 
1.8.3.1

-------------- next part --------------
From 67b370cb38e1d2396340f09c0c1f893c0744f1f6 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose at redhat.com>
Date: Fri, 21 Nov 2014 18:07:10 +0100
Subject: [PATCH 2/2] AD/IPA: add krb5_confd_path configuration option

With this new parameter the directory where Kerberos configuration
snippets are created can be specified.

Fixes https://fedorahosted.org/sssd/ticket/2473
---
 src/config/SSSDConfig/__init__.py.in    |   1 +
 src/config/etc/sssd.api.d/sssd-ad.conf  |   1 +
 src/config/etc/sssd.api.d/sssd-ipa.conf |   1 +
 src/man/sssd-ad.5.xml                   |  18 +++++
 src/man/sssd-ipa.5.xml                  |  18 +++++
 src/providers/ad/ad_common.c            |  11 +++
 src/providers/ad/ad_common.h            |   1 +
 src/providers/ad/ad_opts.h              |   1 +
 src/providers/ad/ad_subdomains.c        |   8 ++
 src/providers/ipa/ipa_common.c          |  11 +++
 src/providers/ipa/ipa_common.h          |   1 +
 src/providers/ipa/ipa_opts.h            |   1 +
 src/providers/ipa/ipa_subdomains.c      |   8 ++
 src/tests/cmocka/test_utils.c           |  45 +++++++++++
 src/util/domain_info_utils.c            | 129 +++++++++++++++++++++++++++++++-
 src/util/util.h                         |   6 ++
 16 files changed, 258 insertions(+), 3 deletions(-)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 283ed2d..500bd71 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -195,6 +195,7 @@ option_strings = {
     'krb5_realm' : _('Kerberos realm'),
     'krb5_auth_timeout' : _('Authentication timeout'),
     'krb5_use_kdcinfo' : _('Whether to create kdcinfo files'),
+    'krb5_confd_path' : _('Where to drop krb5 config snippets'),
 
     # [provider/krb5/auth]
     'krb5_ccachedir' : _('Directory to store credential caches'),
diff --git a/src/config/etc/sssd.api.d/sssd-ad.conf b/src/config/etc/sssd.api.d/sssd-ad.conf
index 3daa256..3496fb4 100644
--- a/src/config/etc/sssd.api.d/sssd-ad.conf
+++ b/src/config/etc/sssd.api.d/sssd-ad.conf
@@ -54,6 +54,7 @@ ldap_page_size = int, None, false
 ldap_deref_threshold = int, None, false
 ldap_connection_expire_timeout = int, None, false
 ldap_disable_paging = bool, None, false
+krb5_confd_path = str, None, false
 
 [provider/ad/id]
 ldap_search_timeout = int, None, false
diff --git a/src/config/etc/sssd.api.d/sssd-ipa.conf b/src/config/etc/sssd.api.d/sssd-ipa.conf
index 5df5258..2a3b7ef 100644
--- a/src/config/etc/sssd.api.d/sssd-ipa.conf
+++ b/src/config/etc/sssd.api.d/sssd-ipa.conf
@@ -51,6 +51,7 @@ ldap_page_size = int, None, false
 ldap_deref_threshold = int, None, false
 ldap_connection_expire_timeout = int, None, false
 ldap_disable_paging = bool, None, false
+krb5_confd_path = str, None, false
 
 [provider/ipa/id]
 ldap_search_timeout = int, None, false
diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
index f63a496..4e29d4f 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -778,6 +778,24 @@ FOREST:EXAMPLE.COM:(memberOf=cn=admins,ou=groups,dc=example,dc=com)
                         </para>
                     </listitem>
                 </varlistentry>
+
+                <varlistentry>
+                    <term>krb5_confd_path (string)</term>
+                    <listitem>
+                        <para>
+                            Absolute path of a directory where SSSD should place
+                            Kerberos configuration snippets.
+                        </para>
+                        <para>
+                            To disable the creation of the configuration
+                            snippets set the parameter to 'none'.
+                        </para>
+                        <para>
+                            Default: not set (krb5.include.d subdirectory of
+                            SSSD's pubconf directory)
+                        </para>
+                    </listitem>
+                </varlistentry>
             </variablelist>
         </para>
     </refsect1>
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index e8a716c..2d8654a 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -447,6 +447,24 @@
                 </varlistentry>
 
                 <varlistentry>
+                    <term>krb5_confd_path (string)</term>
+                    <listitem>
+                        <para>
+                            Absolute path of a directory where SSSD should place
+                            Kerberos configuration snippets.
+                        </para>
+                        <para>
+                            To disable the creation of the configuration
+                            snippets set the parameter to 'none'.
+                        </para>
+                        <para>
+                            Default: not set (krb5.include.d subdirectory of
+                            SSSD's pubconf directory)
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
                     <term>ipa_hbac_refresh (integer)</term>
                     <listitem>
                         <para>
diff --git a/src/providers/ad/ad_common.c b/src/providers/ad/ad_common.c
index 7b08c2b..10c80a0 100644
--- a/src/providers/ad/ad_common.c
+++ b/src/providers/ad/ad_common.c
@@ -264,6 +264,7 @@ ad_get_common_options(TALLOC_CTX *mem_ctx,
     char *ad_hostname;
     char hostname[HOST_NAME_MAX + 1];
     char *case_sensitive_opt;
+    char *krb5_confd_path;
 
     opts = talloc_zero(mem_ctx, struct ad_options);
     if (!opts) return ENOMEM;
@@ -333,6 +334,16 @@ ad_get_common_options(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
+    krb5_confd_path = dp_opt_get_string(opts->basic, AD_KRB5_CONFD_PATH);
+    if (krb5_confd_path == NULL) {
+        ret = dp_opt_set_string(opts->basic, AD_KRB5_CONFD_PATH,
+                                KRB5_MAPPING_DIR);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "dp_opt_set_string failed.\n");
+            goto done;
+        }
+    }
+
     /* Active Directory is always case-insensitive */
     ret = confdb_get_string(cdb, mem_ctx, conf_path,
                             CONFDB_DOMAIN_CASE_SENSITIVE, "false",
diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h
index df8dcff..b39ade4 100644
--- a/src/providers/ad/ad_common.h
+++ b/src/providers/ad/ad_common.h
@@ -60,6 +60,7 @@ enum ad_basic_opt {
     AD_GPO_MAP_PERMIT,
     AD_GPO_MAP_DENY,
     AD_GPO_DEFAULT_RIGHT,
+    AD_KRB5_CONFD_PATH,
 
     AD_OPTS_BASIC /* opts counter */
 };
diff --git a/src/providers/ad/ad_opts.h b/src/providers/ad/ad_opts.h
index ac6006c..508bcd2 100644
--- a/src/providers/ad/ad_opts.h
+++ b/src/providers/ad/ad_opts.h
@@ -48,6 +48,7 @@ struct dp_option ad_basic_opts[] = {
     { "ad_gpo_map_permit", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ad_gpo_map_deny", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     { "ad_gpo_default_right", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "krb5_confd_path", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     DP_OPTION_TERMINATOR
 };
 
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
index bc5bc89..3c61d13 100644
--- a/src/providers/ad/ad_subdomains.c
+++ b/src/providers/ad/ad_subdomains.c
@@ -461,6 +461,14 @@ static errno_t ad_subdom_reinit(struct ad_subdomains_ctx *ctx)
 {
     errno_t ret;
 
+    ret = sss_write_krb5_conf_snippet(
+                            dp_opt_get_string(ctx->ad_id_ctx->ad_options->basic,
+                                              AD_KRB5_CONFD_PATH));
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
+        /* Just continue */
+    }
+
     ret = sysdb_update_subdomains(ctx->be_ctx->domain);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c
index 2940a42..debaea3 100644
--- a/src/providers/ipa/ipa_common.c
+++ b/src/providers/ipa/ipa_common.c
@@ -48,6 +48,7 @@ int ipa_get_options(TALLOC_CTX *memctx,
     char *server;
     char *realm;
     char *ipa_hostname;
+    char *krb5_confd_path;
     int ret;
     char hostname[HOST_NAME_MAX + 1];
 
@@ -111,6 +112,16 @@ int ipa_get_options(TALLOC_CTX *memctx,
         }
     }
 
+    krb5_confd_path = dp_opt_get_string(opts->basic, IPA_KRB5_CONFD_PATH);
+    if (krb5_confd_path == NULL) {
+        ret = dp_opt_set_string(opts->basic, IPA_KRB5_CONFD_PATH,
+                                KRB5_MAPPING_DIR);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, "dp_opt_set_string failed.\n");
+            goto done;
+        }
+    }
+
     ret = EOK;
     *_opts = opts;
 
diff --git a/src/providers/ipa/ipa_common.h b/src/providers/ipa/ipa_common.h
index 4952765..3308519 100644
--- a/src/providers/ipa/ipa_common.h
+++ b/src/providers/ipa/ipa_common.h
@@ -54,6 +54,7 @@ enum ipa_basic_opt {
     IPA_ENABLE_DNS_SITES,
     IPA_SERVER_MODE,
     IPA_VIEWS_SEARCH_BASE,
+    IPA_KRB5_CONFD_PATH,
 
     IPA_OPTS_BASIC /* opts counter */
 };
diff --git a/src/providers/ipa/ipa_opts.h b/src/providers/ipa/ipa_opts.h
index 59282e8..84b5ffe 100644
--- a/src/providers/ipa/ipa_opts.h
+++ b/src/providers/ipa/ipa_opts.h
@@ -51,6 +51,7 @@ struct dp_option ipa_basic_opts[] = {
     { "ipa_enable_dns_sites", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ipa_server_mode", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
     { "ipa_views_search_base", DP_OPT_STRING, NULL_STRING, NULL_STRING },
+    { "krb5_confd_path", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     DP_OPTION_TERMINATOR
 };
 
diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c
index 63f64c2..15b937e 100644
--- a/src/providers/ipa/ipa_subdomains.c
+++ b/src/providers/ipa/ipa_subdomains.c
@@ -321,6 +321,14 @@ ipa_subdom_reinit(struct ipa_subdomains_ctx *ctx)
 {
     errno_t ret;
 
+    ret = sss_write_krb5_conf_snippet(
+                              dp_opt_get_string(ctx->id_ctx->ipa_options->basic,
+                                                IPA_KRB5_CONFD_PATH));
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "sss_write_krb5_conf_snippet failed.\n");
+        /* Just continue */
+    }
+
     ret = sysdb_update_subdomains(ctx->be_ctx->domain);
     if (ret != EOK) {
         DEBUG(SSSDBG_OP_FAILURE, "sysdb_update_subdomains failed.\n");
diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
index d978137..9a30c1f 100644
--- a/src/tests/cmocka/test_utils.c
+++ b/src/tests/cmocka/test_utils.c
@@ -20,6 +20,8 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#define _GNU_SOURCE
+#include <stdio.h>
 #include <popt.h>
 
 #include "tests/cmocka/common_mock.h"
@@ -983,6 +985,48 @@ void test_add_strings_lists(void **state)
     talloc_free(res);
 }
 
+void test_sss_write_krb5_conf_snippet(void **state)
+{
+    int ret;
+    char buf[PATH_MAX];
+    char *cwd;
+    char *path;
+    char *file;
+
+    ret = sss_write_krb5_conf_snippet(NULL);
+    assert_int_equal(ret, EINVAL);
+
+    ret = sss_write_krb5_conf_snippet("abc");
+    assert_int_equal(ret, EINVAL);
+
+    ret = sss_write_krb5_conf_snippet("");
+    assert_int_equal(ret, EOK);
+
+    ret = sss_write_krb5_conf_snippet("none");
+    assert_int_equal(ret, EOK);
+
+    cwd = getcwd(buf, PATH_MAX);
+    assert_non_null(cwd);
+
+    ret = asprintf(&path, "%s/%s", cwd, TESTS_PATH);
+    assert_true(ret > 0);
+
+    ret = asprintf(&file, "%s/%s/localauth_plugin", cwd, TESTS_PATH);
+    assert_true(ret > 0);
+
+    ret = sss_write_krb5_conf_snippet(path);
+    assert_int_equal(ret, EOK);
+
+    /* Check if writing a second time will work as well */
+    ret = sss_write_krb5_conf_snippet(path);
+    assert_int_equal(ret, EOK);
+
+#ifdef BUILD_LIBWBCLIENT
+    ret = unlink(file);
+    assert_int_equal(ret, EOK);
+#endif
+}
+
 int main(int argc, const char *argv[])
 {
     poptContext pc;
@@ -1030,6 +1074,7 @@ int main(int argc, const char *argv[])
         unit_test_setup_teardown(test_add_strings_lists,
                                  setup_add_strings_lists,
                                  teardown_add_strings_lists),
+        unit_test(test_sss_write_krb5_conf_snippet),
     };
 
     /* Set debug level to invalid value so we can deside if -d 0 was used. */
diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c
index 4e2c14c..d24e64c 100644
--- a/src/util/domain_info_utils.c
+++ b/src/util/domain_info_utils.c
@@ -24,9 +24,6 @@
 #include "db/sysdb.h"
 #include "util/util.h"
 
-/* the directory domain - realm mappings are written to */
-#define KRB5_MAPPING_DIR PUBCONF_PATH"/krb5.include.d"
-
 struct sss_domain_info *get_domains_head(struct sss_domain_info *domain)
 {
     struct sss_domain_info *dom = NULL;
@@ -637,3 +634,129 @@ done:
     talloc_free(tmp_ctx);
     return ret;
 }
+
+#define LOCALAUTH_PLUGIN_CONFIG \
+"[plugins]\n" \
+" localauth = {\n" \
+"  module = sssd:"APP_MODULES_PATH"/sssd_krb5_localauth_plugin.so\n" \
+"  enable_only = sssd\n" \
+" }"
+
+errno_t sss_write_krb5_conf_snippet(const char *path)
+{
+    errno_t ret;
+    errno_t err;
+    TALLOC_CTX *tmp_ctx;
+    const char *file_name;
+    char *tmp_file = NULL;
+    int fd = -1;
+    mode_t old_mode;
+    ssize_t written;
+    size_t size;
+
+    if (path != NULL && (*path == '\0' || strcasecmp(path, "none") == 0)) {
+        DEBUG(SSSDBG_TRACE_FUNC, "Empty path, nothing to do.\n");
+        return EOK;
+    }
+
+    if (path == NULL || *path != '/') {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Invalid or missing path [%s]-\n",
+                                    path == NULL ? "missing" : path);
+        return EINVAL;
+    }
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
+        return ENOMEM;
+    }
+
+#ifdef BUILD_LIBWBCLIENT
+    file_name = talloc_asprintf(tmp_ctx, "%s/localauth_plugin",
+                                   path);
+    if (file_name == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_FUNC_DATA, "File for localauth plugin configuration is [%s]\n",
+                             file_name);
+
+    tmp_file = talloc_asprintf(tmp_ctx, "%sXXXXXX", file_name);
+    if (tmp_file == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
+        ret = ENOMEM;
+        goto done;
+    }
+
+    old_mode = umask(077);
+    fd = mkstemp(tmp_file);
+    umask(old_mode);
+    if (fd < 0) {
+        DEBUG(SSSDBG_OP_FAILURE, "creating the temp file [%s] for domain-realm "
+                                  "mappings failed.", tmp_file);
+        ret = EIO;
+        talloc_zfree(tmp_ctx);
+        goto done;
+    }
+
+    size = sizeof(LOCALAUTH_PLUGIN_CONFIG) -1;
+    written = sss_atomic_write_s(fd, discard_const(LOCALAUTH_PLUGIN_CONFIG),
+                                 size);
+    close(fd);
+    if (written == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "write failed [%d][%s]\n", ret, sss_strerror(ret));
+        goto done;
+    }
+
+    if (written != size) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "Wrote %zd bytes expected %zu\n", written, size);
+        ret = EIO;
+        goto done;
+    }
+
+    ret = rename(tmp_file, file_name);
+    if (ret == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "rename failed [%d][%s].\n", ret, sss_strerror(ret));
+        goto done;
+    }
+    tmp_file = NULL;
+
+    ret = chmod(file_name, 0644);
+    if (ret == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "chmod failed [%d][%s].\n", ret, sss_strerror(ret));
+        goto done;
+    }
+#endif
+
+    ret = EOK;
+
+done:
+    err = sss_krb5_touch_config();
+    if (err != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unable to change last modification time "
+              "of krb5.conf. Created mappings may not be loaded.\n");
+        /* Ignore */
+    }
+
+    if (tmp_file != NULL) {
+        err = unlink(tmp_file);
+        if (err == -1) {
+            err = errno;
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "Could not remove file [%s]: [%d]: %s",
+                   tmp_file, err, sss_strerror(err));
+        }
+    }
+
+    talloc_free(tmp_ctx);
+    return ret;
+}
diff --git a/src/util/util.h b/src/util/util.h
index 7c335b9..45efd1a 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -576,8 +576,14 @@ errno_t sssd_domain_init(TALLOC_CTX *mem_ctx,
 
 #define DOM_HAS_VIEWS(dom) ((dom)->has_views)
 
+/* the directory domain - realm mappings and other krb5 config snippers are
+ * written to */
+#define KRB5_MAPPING_DIR PUBCONF_PATH"/krb5.include.d"
+
 errno_t sss_write_domain_mappings(struct sss_domain_info *domain);
 
+errno_t sss_write_krb5_conf_snippet(const char *path);
+
 errno_t get_dom_names(TALLOC_CTX *mem_ctx,
                       struct sss_domain_info *start_dom,
                       char ***_dom_names,
-- 
1.8.3.1



More information about the sssd-devel mailing list