diff options
author | Jakub Hrozek <jhrozek@redhat.com> | 2017-03-27 09:48:46 +0200 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2017-03-30 14:09:10 +0200 |
commit | 825e8bf2f73a815c2eceb36ae805145fcbacf74d (patch) | |
tree | 8456d4851d62d582d64961a8939708ff13c2a051 | |
parent | 6324eaf1fb321c41ca9883966118df6d45259b7e (diff) | |
download | sssd-825e8bf2f73a815c2eceb36ae805145fcbacf74d.tar.gz sssd-825e8bf2f73a815c2eceb36ae805145fcbacf74d.tar.xz sssd-825e8bf2f73a815c2eceb36ae805145fcbacf74d.zip |
CONFDB: Allow configuring [application] sections as non-POSIX domains
Related to:
https://pagure.io/SSSD/sssd/issue/3310
Allows to add a new section:
[application/$name]
This section internally (on the confdb level) expands to:
[domain/$name]
domain_type = application
The reasons to add this new section is two-fold. One, to make the
configuration of application domains more explicit and two, to make it
possible to share configuration between two domains, one POSIX and one
non-POSIX by application domain's inherit_from option:
[application/$name]
inherit_from = posix_domain_name
Reviewed-by: Sumit Bose <sbose@redhat.com>
Reviewed-by: Pavel Březina <pbrezina@redhat.com>
-rw-r--r-- | src/confdb/confdb.c | 288 | ||||
-rw-r--r-- | src/confdb/confdb.h | 4 | ||||
-rw-r--r-- | src/config/cfg_rules.ini | 9 | ||||
-rw-r--r-- | src/man/sssd.conf.5.xml | 77 | ||||
-rw-r--r-- | src/monitor/monitor.c | 8 |
5 files changed, 368 insertions, 18 deletions
diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c index 70a1eb7b2..88e114457 100644 --- a/src/confdb/confdb.c +++ b/src/confdb/confdb.c @@ -813,6 +813,50 @@ done: return ret; } +static int confdb_get_domain_section(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *section, + const char *name, + struct ldb_result **_res) +{ + TALLOC_CTX *tmp_ctx; + int ret; + struct ldb_result *res; + struct ldb_dn *dn; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, "cn=%s,%s", name, section); + if (dn == NULL) { + ret = ENOMEM; + goto done; + } + + ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, + LDB_SCOPE_BASE, NULL, NULL); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); + goto done; + } + + if (res->count == 0) { + ret = ENOENT; + goto done; + } else if (res->count > 1) { + ret = E2BIG; + goto done; + } + + *_res = talloc_steal(mem_ctx, res); + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + static int confdb_get_domain_internal(struct confdb_ctx *cdb, TALLOC_CTX *mem_ctx, const char *name, @@ -821,7 +865,6 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, struct sss_domain_info *domain; struct ldb_result *res; TALLOC_CTX *tmp_ctx; - struct ldb_dn *dn; const char *tmp; int ret, val; uint32_t entry_cache_timeout; @@ -833,23 +876,15 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) return ENOMEM; - dn = ldb_dn_new_fmt(tmp_ctx, cdb->ldb, - "cn=%s,%s", name, CONFDB_DOMAIN_BASEDN); - if (!dn) { - ret = ENOMEM; - goto done; - } - - ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, - LDB_SCOPE_BASE, NULL, NULL); - if (ret != LDB_SUCCESS) { - ret = EIO; - goto done; - } - - if (res->count != 1) { + ret = confdb_get_domain_section(tmp_ctx, cdb, CONFDB_DOMAIN_BASEDN, + name, &res); + if (ret == ENOENT) { DEBUG(SSSDBG_FATAL_FAILURE, "Unknown domain [%s]\n", name); - ret = ENOENT; + goto done; + } else if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Error %d: %s while retrieving %s\n", + ret, sss_strerror(ret), name); goto done; } @@ -1841,3 +1876,222 @@ int confdb_ensure_files_domain(struct confdb_ctx *cdb, return activate_files_domain(cdb, implicit_files_dom_name); #endif /* ADD_FILES_DOMAIN */ } + +static int confdb_get_parent_domain(TALLOC_CTX *mem_ctx, + const char *name, + struct confdb_ctx *cdb, + struct ldb_result *app_dom, + struct ldb_result **_parent_dom) +{ + const char *inherit_from; + + inherit_from = ldb_msg_find_attr_as_string(app_dom->msgs[0], + CONFDB_DOMAIN_INHERIT_FROM, NULL); + if (inherit_from == NULL) { + DEBUG(SSSDBG_CONF_SETTINGS, + "%s does not inherit from any POSIX domain\n", name); + *_parent_dom = NULL; + return EOK; + } + + return confdb_get_domain_section(mem_ctx, cdb, + CONFDB_DOMAIN_BASEDN, inherit_from, + _parent_dom); +} + +static int confdb_add_app_domain(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *name) +{ + char *cdb_path = NULL; + const char *val[2] = { NULL, NULL }; + int ret; + + cdb_path = talloc_asprintf(mem_ctx, CONFDB_DOMAIN_PATH_TMPL, name); + if (cdb_path == NULL) { + return ENOMEM; + } + + val[0] = CONFDB_DOMAIN_TYPE_APP; + ret = confdb_add_param(cdb, true, cdb_path, CONFDB_DOMAIN_TYPE, val); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to add id_provider [%d]: %s\n", + ret, sss_strerror(ret)); + return ret; + } + + return EOK; +} + +static int confdb_merge_parent_domain(const char *name, + struct confdb_ctx *cdb, + struct ldb_result *app_section) +{ + int ret; + int ldb_flag; + struct ldb_result *parent_domain = NULL; + struct ldb_message *replace_msg = NULL; + struct ldb_message *app_msg = NULL; + struct ldb_dn *domain_dn; + TALLOC_CTX *tmp_ctx = NULL; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); + return ENOMEM; + } + + domain_dn = ldb_dn_new_fmt(tmp_ctx, + cdb->ldb, + "%s=%s,%s", + CONFDB_DOMAIN_ATTR, + name, + CONFDB_DOMAIN_BASEDN); + if (domain_dn == NULL) { + ret = ENOMEM; + goto done; + } + + /* Copy the parent domain parameters */ + ret = confdb_get_parent_domain(tmp_ctx, name, cdb, + app_section, &parent_domain); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot retrieve the parent domain [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + if (parent_domain != NULL) { + replace_msg = ldb_msg_copy(tmp_ctx, parent_domain->msgs[0]); + if (replace_msg == NULL) { + ret = ENOMEM; + goto done; + } + replace_msg->dn = domain_dn; + + for (unsigned i = 0; i < replace_msg->num_elements; i++) { + replace_msg->elements[i].flags = LDB_FLAG_MOD_ADD; + } + + ret = ldb_modify(cdb->ldb, replace_msg); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); + DEBUG(SSSDBG_OP_FAILURE, + "Inheriting options from parent domain failed [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + } + + /* Finally, add any app-domain specific overrides */ + app_msg = ldb_msg_new(tmp_ctx); + if (app_msg == NULL) { + ret = ENOMEM; + goto done; + } + app_msg->dn = domain_dn; + + for (unsigned i = 0; i < app_section->msgs[0]->num_elements; i++) { + struct ldb_message_element *el = NULL; + + if (replace_msg != NULL) { + el = ldb_msg_find_element(replace_msg, + app_section->msgs[0]->elements[i].name); + if (el == NULL) { + /* Adding an element */ + ldb_flag = LDB_FLAG_MOD_ADD; + } else { + /* Overriding an element */ + ldb_flag = LDB_FLAG_MOD_REPLACE; + } + } else { + /* If there was no domain to inherit from, just add all */ + ldb_flag = LDB_FLAG_MOD_ADD; + } + + ret = ldb_msg_add(app_msg, + &app_section->msgs[0]->elements[i], + ldb_flag); + if (ret != EOK) { + continue; + } + } + + ret = ldb_modify(cdb->ldb, app_msg); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); + DEBUG(SSSDBG_OP_FAILURE, + "Adding app-specific options failed [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + DEBUG(SSSDBG_TRACE_LIBS, "Added a domain section for %s\n", name); + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} + +int confdb_expand_app_domains(struct confdb_ctx *cdb) +{ + int ret; + char **domlist; + TALLOC_CTX *tmp_ctx; + struct ldb_result *app_domain = NULL; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = confdb_get_string_as_list(cdb, tmp_ctx, + CONFDB_MONITOR_CONF_ENTRY, + CONFDB_MONITOR_ACTIVE_DOMAINS, + &domlist); + if (ret == ENOENT) { + DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured, fatal error!\n"); + goto done; + } else if (ret != EOK ) { + DEBUG(SSSDBG_FATAL_FAILURE, "Fatal error retrieving domains list!\n"); + goto done; + } + + for (int i = 0; domlist[i]; i++) { + ret = confdb_get_domain_section(tmp_ctx, cdb, + CONFDB_APP_DOMAIN_BASEDN, domlist[i], + &app_domain); + if (ret == ENOENT) { + DEBUG(SSSDBG_TRACE_INTERNAL, + "%s is not an app domain\n", domlist[i]); + continue; + } else if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, + "Error %d: %s while retrieving %s\n", + ret, sss_strerror(ret), domlist[i]); + goto done; + } + + ret = confdb_add_app_domain(tmp_ctx, cdb, domlist[i]); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot add the app domain section [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + ret = confdb_merge_parent_domain(domlist[i], cdb, app_domain); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Cannot add options into the app domain section [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + } + + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index a4046610f..5a8d377c3 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -164,6 +164,7 @@ /* Domains */ #define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s" #define CONFDB_DOMAIN_BASEDN "cn=domain,cn=config" +#define CONFDB_APP_DOMAIN_BASEDN "cn=application,cn=config" #define CONFDB_DOMAIN_ID_PROVIDER "id_provider" #define CONFDB_DOMAIN_AUTH_PROVIDER "auth_provider" #define CONFDB_DOMAIN_ACCESS_PROVIDER "access_provider" @@ -212,6 +213,7 @@ #define CONFDB_DOMAIN_TYPE "domain_type" #define CONFDB_DOMAIN_TYPE_POSIX "posix" #define CONFDB_DOMAIN_TYPE_APP "application" +#define CONFDB_DOMAIN_INHERIT_FROM "inherit_from" /* Local Provider */ #define CONFDB_LOCAL_DEFAULT_SHELL "default_shell" @@ -398,6 +400,8 @@ int confdb_get_domains(struct confdb_ctx *cdb, int confdb_ensure_files_domain(struct confdb_ctx *cdb, const char *implicit_files_dom_name); +int confdb_expand_app_domains(struct confdb_ctx *cdb); + /** * Get a null-terminated linked-list of all domain names * @param[in] mem_ctx The parent memory context for the value list diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini index 3c857236e..8fd2d2c52 100644 --- a/src/config/cfg_rules.ini +++ b/src/config/cfg_rules.ini @@ -12,6 +12,7 @@ section = secrets section = kcm section_re = ^secrets/users/[0-9]\+$ section_re = ^domain/.*$ +section_re = ^application/.*$ [rule/allowed_sssd_options] validator = ini_allowed_options @@ -286,7 +287,7 @@ option = responder_idle_timeout [rule/allowed_domain_options] validator = ini_allowed_options -section_re = ^domain/.*$ +section_re = ^(domain|application)/.*$ option = debug option = debug_level @@ -684,3 +685,9 @@ option = ldap_user_ssh_public_key option = ldap_user_uid_number option = ldap_user_uuid option = ldap_use_tokengroups + +[rule/allowed_application_options] +validator = ini_allowed_options +section_re = ^application/.*$ + +option = inherit_from diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 9abcff84a..8294793c7 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -1539,6 +1539,10 @@ pam_account_locked_message = Account locked, please contact help desk. <quote>id_provider=ldap</quote> only. </para> <para> + For an easy way to configure a non-POSIX domains, please + see the <quote>Application domains</quote> section. + </para> + <para> Default: posix </para> </listitem> @@ -2692,6 +2696,79 @@ subdomain_inherit = ldap_purge_cache_timeout </variablelist> </para> + <refsect2 id='app_domains'> + <title>Application domains</title> + <para> + SSSD, with its D-Bus interface (see + <citerefentry> + <refentrytitle>sssd-ifp</refentrytitle> + <manvolnum>5</manvolnum> + </citerefentry>) is appealing to applications + as a gateway to an LDAP directory where users and groups + are stored. However, contrary to the traditional SSSD + deployment where all users and groups either have POSIX + attributes or those attributes can be inferred from the + Windows SIDs, in many cases the users and groups in the + application support scenario have no POSIX attributes. + Instead of setting a + <quote>[domain/<replaceable>NAME</replaceable>]</quote> + section, the administrator can set up an + <quote>[application/<replaceable>NAME</replaceable>]</quote> + section that internally represents a domain with type + <quote>application</quote> optionally inherits settings + from a tradition SSSD domain. + </para> + <para> + Please note that the application domain must still be + explicitly enabled in the <quote>domains</quote> parameter + so that the lookup order between the application domain + and its POSIX sibling domain is set correctly. + </para> + <variablelist> + <title>Application domain parameters</title> + <varlistentry> + <term>inherit_from (string)</term> + <listitem> + <para> + The SSSD POSIX-type domain the application + domain inherits all settings from. The + application domain can moreover add its own + settings to the application settings that augment + or override the <quote>sibling</quote> + domain settings. + </para> + <para> + Default: Not set + </para> + </listitem> + </varlistentry> + </variablelist> + <para> + The following example illustrates the use of an application + domain. In this setup, the POSIX domain is connected to an LDAP + server and is used by the OS through the NSS responder. In addition, + the application domains also requests the telephoneNumber attribute, + stores it as the phone attribute in the cache and makes the phone + attribute reachable through the D-Bus interface. + </para> +<programlisting> +[sssd] +domains = appdom, posixdom + +[ifp] +user_attributes = +phone + +[domain/posixdom] +id_provider = ldap +ldap_uri = ldap://ldap.example.com +ldap_search_base = dc=example,dc=com + +[application/appdom] +inherit_from = posixdom +ldap_user_extra_attrs = phone:telephoneNumber +</programlisting> + </refsect2> + <refsect2 id='local_domain'> <title>The local domain section</title> <para> diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index 7e7b5a07d..2753b4666 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -1064,6 +1064,14 @@ static int get_monitor_config(struct mt_ctx *ctx) /* Not fatal */ } + ret = confdb_expand_app_domains(ctx->cdb); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to expand application domains\n"); + /* This must not be fatal so that SSSD keeps running and lets + * admin correct the error. + */ + } + ret = confdb_get_domains(ctx->cdb, &ctx->domains); if (ret != EOK) { DEBUG(SSSDBG_FATAL_FAILURE, "No domains configured.\n"); |