Blame SOURCES/0062-CONFDB-Allow-configuring-application-sections-as-non.patch

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