From 05ae58c86eae80c7e69fb809dc3cd89d0b7418f4 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Mon, 27 Mar 2017 09:48:46 +0200
Subject: [PATCH 62/72] CONFDB: Allow configuring [application] sections as
non-POSIX domains
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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>
---
src/confdb/confdb.c | 288 ++++++++++++++++++++++++++++++++++++++++++++---
src/confdb/confdb.h | 4 +
src/config/cfg_rules.ini | 9 +-
src/man/sssd.conf.5.xml | 77 +++++++++++++
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 70a1eb7b2c7e83dfa9d217a15c7d3d4c8580b891..88e114457deac3ca50c291a131122624fb6f6fe4 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 a4046610f3cdbdb832de8924bf4397fb0018f2db..5a8d377c312f641f544b1c7cf38826192462ea3c 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 3c857236eaa55b313d176bc4bb479918163b60d5..8fd2d2c5236246394353a88c50d1510bd6233f77 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 9abcff84a95ea1b27e36845e830cc125fdc89f90..8294793c765bfa6bf481693c7d7f206950454681 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 7e7b5a07d11aecf1c0b11592213b90d385fd5076..2753b46667f7ae0b022776862c67a327d3356d6d 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");
--
2.9.3