From c230bce668a65649e9f2ca8b4424148ef9e19491 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 21 Nov 2014 18:07:10 +0100 Subject: [PATCH 109/112] 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 Reviewed-by: Jakub Hrozek --- 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.h | 1 + src/providers/ad/ad_opts.h | 1 + src/providers/ad/ad_subdomains.c | 8 ++ 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 | 48 +++++++++++ src/util/domain_info_utils.c | 146 +++++++++++++++++++++++++++++++- src/util/util.h | 6 ++ 14 files changed, 256 insertions(+), 3 deletions(-) diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in index 283ed2d37c894db95bac38c23d25c4ac8d1f4a40..500bd717fec7abcaafd5153ccca7847b91e208ad 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 3daa2560b14d74f7686ed47cf1b09e2005eb8917..3496fb4006697d380f7c9729ed9997272cbce2ea 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 5df52581e67657e41e2f08820b885f100ccd7ca9..2a3b7ef1519e3476cb4b432336da0c359b1844ba 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 f63a496d9c7294749fb046995985985e2cae4a57..4e29d4f75cae5bf17e4bb85fa46c921b25ee8047 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) + + + krb5_confd_path (string) + + + Absolute path of a directory where SSSD should place + Kerberos configuration snippets. + + + To disable the creation of the configuration + snippets set the parameter to 'none'. + + + Default: not set (krb5.include.d subdirectory of + SSSD's pubconf directory) + + + diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml index e8a716c4104b8038e354b8ae544a04d6773e708b..2d8654a3cde76ab205766f8fdcb836aa1002cd43 100644 --- a/src/man/sssd-ipa.5.xml +++ b/src/man/sssd-ipa.5.xml @@ -447,6 +447,24 @@ + krb5_confd_path (string) + + + Absolute path of a directory where SSSD should place + Kerberos configuration snippets. + + + To disable the creation of the configuration + snippets set the parameter to 'none'. + + + Default: not set (krb5.include.d subdirectory of + SSSD's pubconf directory) + + + + + ipa_hbac_refresh (integer) diff --git a/src/providers/ad/ad_common.h b/src/providers/ad/ad_common.h index df8dcffea5f98030f6d5a6c98e95a7d887ace7fd..b39ade40cd00ad5fccdb5d4bf4df8790eb634a51 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 ac6006c9200464956ccedb17ff53050fed5fc6ea..c3de3d94b1818665a86bba8a2432c699717b6a34 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, { KRB5_MAPPING_DIR }, NULL_STRING }, DP_OPTION_TERMINATOR }; diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c index bc5bc8914ce84ecfbff69ff837250b5bf3a3515b..3c61d13522c7c773171ea8645dddb417e610745c 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.h b/src/providers/ipa/ipa_common.h index 495276548e57e91f9744dda6d8866971b627b4da..33085197c2a4807d4546289ead4c30d891d0d2c0 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 59282e8699091fbccf08ddfc6825034d4f81a87f..f77ff1d05b9540155db44d04d4fb3aac9d7b5988 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, { KRB5_MAPPING_DIR }, NULL_STRING }, DP_OPTION_TERMINATOR }; diff --git a/src/providers/ipa/ipa_subdomains.c b/src/providers/ipa/ipa_subdomains.c index 9281aab1b028ebcaee8044b2768c6918efa4e514..883558c4d79d2da64ef6f010982ac89ccfae4e4f 100644 --- a/src/providers/ipa/ipa_subdomains.c +++ b/src/providers/ipa/ipa_subdomains.c @@ -312,6 +312,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 d9781377be70a0d58b0fd1fff2145483dbeb199c..5dc00c4cc9707776fabda50ad1eab8e582b16c0f 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 . */ +#define _GNU_SOURCE +#include #include #include "tests/cmocka/common_mock.h" @@ -983,6 +985,51 @@ 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 HAVE_KRB5_LOCALAUTH_PLUGIN + ret = unlink(file); + assert_int_equal(ret, EOK); +#endif + + free(file); + free(path); +} + int main(int argc, const char *argv[]) { poptContext pc; @@ -1030,6 +1077,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 4e2c14c9432d38502422ddf2b0cb2b655a68d1cc..e04b905768078c503168f27327f974c0f19a6775 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,146 @@ 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" \ +" }" + +static errno_t sss_write_krb5_localauth_snippet(const char *path) +{ +#ifdef HAVE_KRB5_LOCALAUTH_PLUGIN + int ret; + errno_t err; + TALLOC_CTX *tmp_ctx = NULL; + char *tmp_file = NULL; + const char *file_name; + int fd = -1; + mode_t old_mode; + ssize_t written; + size_t size; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + + 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; + } + +done: + 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; +#else + DEBUG(SSSDBG_TRACE_ALL, "Kerberos localauth plugin not available.\n"); + return EOK; +#endif +} + +errno_t sss_write_krb5_conf_snippet(const char *path) +{ + errno_t ret; + errno_t err; + + 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; + } + + ret = sss_write_krb5_localauth_snippet(path); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_write_krb5_localauth_snippet failed.\n"); + goto done; + } + + 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 */ + } + + return ret; +} diff --git a/src/util/util.h b/src/util/util.h index 7c335b9a2ac2599304731082845fd382dc62465f..45efd1aef94c2e058a435933e7c41adaecc676e2 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.9.3