URL: https://github.com/freeipa/freeipa/pull/479
Author: martbab
 Title: #479: Merge AD trust installer into composite ones
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/479/head:pr479
git checkout pr479
From befb5e97602d1e523157b503d33a3ca8f8f84a9d Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 3 Feb 2017 17:14:20 +0100
Subject: [PATCH 01/16] allow for more flexibility when requesting service
 keytab

The service installers can now override the methods for cleaning up
stale keytabs and changing file ownership of the newly acquired keytabs.

The default actions should be usable by most installers without specific
overriding.

https://fedorahosted.org/freeipa/ticket/6638
---
 ipaserver/install/service.py | 41 ++++++++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 15 deletions(-)

diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index b9d1ffc..80bb4bb 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -540,22 +540,35 @@ def _add_service_principal(self):
         except errors.DuplicateEntry:
             pass
 
+    def clean_previous_keytab(self, keytab=None):
+        if keytab is None:
+            keytab = self.keytab
+
+        self.fstore.backup_file(keytab)
+        try:
+            os.unlink(keytab)
+        except OSError:
+            pass
+
+    def set_keytab_owner(self, keytab=None, owner=None):
+        if keytab is None:
+            keytab = self.keytab
+        if owner is None:
+            owner = self.service_user
+
+        pent = pwd.getpwnam(owner)
+        os.chown(keytab, pent.pw_uid, pent.pw_gid)
+
     def run_getkeytab(self, ldap_uri, keytab, principal, retrieve=False):
         """
-        backup and remove old service keytab (if present) and fetch a new one
-        using ipa-getkeytab. This assumes that the service principal is already
-        created in LDAP. By default GSSAPI authentication is used unless:
+        retrieve service keytab using ipa-getkeytab. This assumes that the
+        service principal is already created in LDAP. By default GSSAPI
+        authentication is used unless:
             * LDAPI socket is used and effective process UID is 0, then
               autobind is used by EXTERNAL SASL mech
             * self.dm_password is not none, then DM credentials are used to
               fetch keytab
         """
-        self.fstore.backup_file(keytab)
-        try:
-            os.unlink(keytab)
-        except OSError:
-            pass
-
         args = [paths.IPA_GETKEYTAB,
                 '-k', keytab,
                 '-p', principal,
@@ -576,17 +589,15 @@ def run_getkeytab(self, ldap_uri, keytab, principal, retrieve=False):
         ipautil.run(args, nolog=nolog)
 
     def _request_service_keytab(self):
-        if any(attr is None for attr in (self.principal, self.keytab,
-                                         self.service_user)):
+        if any(attr is None for attr in (self.principal, self.keytab)):
             raise NotImplementedError(
                 "service must have defined principal "
-                "name, keytab, and username")
+                "name and keytab")
 
         self._add_service_principal()
+        self.clean_previous_keytab()
         self.run_getkeytab(self.api.env.ldap_uri, self.keytab, self.principal)
-
-        pent = pwd.getpwnam(self.keytab_user)
-        os.chown(self.keytab, pent.pw_uid, pent.pw_gid)
+        self.set_keytab_owner()
 
 
 class SimpleServiceInstance(Service):

From 54a7975465e965efc677e5e6efde2be239ac25d3 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 14:31:55 +0100
Subject: [PATCH 02/16] Make request_service_keytab into a public method

a cosmetic change: we had private method comprising of calls to public
ones, which did not make much sense in our case

https://fedorahosted.org/freeipa/ticket/6638
---
 ipaserver/install/dsinstance.py   | 6 +++---
 ipaserver/install/httpinstance.py | 2 +-
 ipaserver/install/service.py      | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 9172b65..bf80ae0 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -393,7 +393,7 @@ def create_replica(self, realm_name, master_fqdn, fqdn,
         self.__common_setup(enable_ssl=(not self.promote))
         self.step("restarting directory server", self.__restart_instance)
 
-        self.step("creating DS keytab", self._request_service_keytab)
+        self.step("creating DS keytab", self.request_service_keytab)
         if self.promote:
             if self.pkcs12_info:
                 self.step("configuring TLS for DS instance", self.__enable_ssl)
@@ -1221,8 +1221,8 @@ def __set_domain_level(self):
         if self.domainlevel is not None:
             self._ldap_mod("domainlevel.ldif", self.sub_dict)
 
-    def _request_service_keytab(self):
-        super(DsInstance, self)._request_service_keytab()
+    def request_service_keytab(self):
+        super(DsInstance, self).request_service_keytab()
 
         # Configure DS to use the keytab
         vardict = {"KRB5_KTNAME": self.keytab}
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index 6383e27..435130b 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -166,7 +166,7 @@ def create_instance(self, realm, fqdn, domain_name, pkcs12_info=None,
         self.step("enabling mod_nss renegotiate", self.enable_mod_nss_renegotiate)
         self.step("adding URL rewriting rules", self.__add_include)
         self.step("configuring httpd", self.__configure_http)
-        self.step("setting up httpd keytab", self._request_service_keytab)
+        self.step("setting up httpd keytab", self.request_service_keytab)
         self.step("retrieving anonymous keytab", self.request_anon_keytab)
         self.step("configuring Gssproxy", self.configure_gssproxy)
         self.step("setting up ssl", self.__setup_ssl)
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index 80bb4bb..837880f 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -588,7 +588,7 @@ def run_getkeytab(self, ldap_uri, keytab, principal, retrieve=False):
 
         ipautil.run(args, nolog=nolog)
 
-    def _request_service_keytab(self):
+    def request_service_keytab(self):
         if any(attr is None for attr in (self.principal, self.keytab)):
             raise NotImplementedError(
                 "service must have defined principal "

From 8cadbfedbd5264eab720ca677f7117f46dccf4f4 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 14:33:40 +0100
Subject: [PATCH 03/16] httpinstance: re-use parent's methods to retrieve
 anonymous keytab

https://fedorahosted.org/freeipa/ticket/6638
---
 ipaserver/install/httpinstance.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index 435130b..7979ca1 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -317,12 +317,15 @@ def request_anon_keytab(self):
         parent = os.path.dirname(paths.ANON_KEYTAB)
         if not os.path.exists(parent):
             os.makedirs(parent, 0o755)
+
+        self.clean_previous_keytab(keytab=paths.ANON_KEYTAB)
         self.run_getkeytab(self.api.env.ldap_uri, paths.ANON_KEYTAB, ANON_USER)
 
         pent = pwd.getpwnam(IPAAPI_USER)
         os.chmod(parent, 0o700)
         os.chown(parent, pent.pw_uid, pent.pw_gid)
-        os.chown(paths.ANON_KEYTAB, pent.pw_uid, pent.pw_gid)
+
+        self.set_keytab_owner(keytab=paths.ANON_KEYTAB, owner=IPAAPI_USER)
 
     def create_password_conf(self):
         """

From 5d0bed65fffbbf292759c4ff016647ce64cdfcd1 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 3 Feb 2017 17:16:59 +0100
Subject: [PATCH 04/16] use the methods of the parent class to retrieve CIFS
 kerberos keys

adtrustinstance will now use parent's methods to retrieve keys for CIFS
principal. Since the keys are appended to the host keytab
(/etc/krb5.keytab) we need to make sure that only the stale CIFS keys
are purged from the file and that we do not re-set its ownership.

https://fedorahosted.org/freeipa/ticket/6638
---
 ipaserver/install/adtrustinstance.py | 30 +++++++++++-------------------
 1 file changed, 11 insertions(+), 19 deletions(-)

diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index c866cdd..0b18985 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -530,27 +530,18 @@ def __setup_group_membership(self):
             api.Backend.ldap2, self.smb_dn, "member",
             [self.cifs_agent, self.host_princ])
 
-    def __setup_principal(self):
-        try:
-            api.Command.service_add(unicode(self.principal))
-        except errors.DuplicateEntry:
-            # CIFS principal already exists, it is not the first time
-            # adtrustinstance is managed
-            # That's fine, we we'll re-extract the key again.
-            pass
-        except Exception as e:
-            self.print_msg("Cannot add CIFS service: %s" % e)
-
+    def clean_previous_keytab(self, keytab=None):
+        """
+        Purge old CIFS keys from samba and clean up samba ccache
+        """
         self.clean_samba_keytab()
         installutils.remove_ccache(paths.KRB5CC_SAMBA)
 
-        try:
-            ipautil.run(["ipa-getkeytab", "--server", self.fqdn,
-                                          "--principal", self.principal,
-                                          "-k", self.keytab])
-        except ipautil.CalledProcessError:
-            root_logger.critical("Failed to add key for %s"
-                                 % self.principal)
+    def set_keytab_owner(self, keytab=None, owner=None):
+        """
+        Do not re-set ownership of samba keytab
+        """
+        pass
 
     def clean_samba_keytab(self):
         if os.path.exists(self.keytab):
@@ -818,7 +809,8 @@ def create_instance(self):
                   self.__create_samba_domain_object)
         self.step("creating samba config registry", self.__write_smb_registry)
         self.step("writing samba config file", self.__write_smb_conf)
-        self.step("adding cifs Kerberos principal", self.__setup_principal)
+        self.step("adding cifs Kerberos principal",
+                  self.request_service_keytab)
         self.step("adding cifs and host Kerberos principals to the adtrust agents group", \
                   self.__setup_group_membership)
         self.step("check for cifs services defined on other replicas", self.__check_replica)

From f1e959744f35e04af60c0ab6f925f72e9212e9b4 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Thu, 16 Feb 2017 14:06:08 +0100
Subject: [PATCH 05/16] Refactor the code checking for missing SIDs

Decompose the individual sub-tasks into separate functions. Also perform
the lookup only when LDAP is connected.

https://fedorahosted.org/freeipa/ticket/6630
---
 ipaserver/install/adtrust.py | 107 ++++++++++++++++++++++++++-----------------
 1 file changed, 64 insertions(+), 43 deletions(-)

diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py
index 92fe031..69e9834 100644
--- a/ipaserver/install/adtrust.py
+++ b/ipaserver/install/adtrust.py
@@ -168,6 +168,69 @@ def check_for_installed_deps():
         raise ScriptError("Aborting installation.")
 
 
+def retrieve_entries_without_sid(api):
+    """
+    Retrieve a list of entries without assigned SIDs.
+    :returns: a list of entries or an empty list if an error occurs
+    """
+    # The filter corresponds to ipa_sidgen_task.c LDAP search filter
+    filter = '(&(objectclass=ipaobject)(!(objectclass=mepmanagedentry))' \
+             '(|(objectclass=posixaccount)(objectclass=posixgroup)' \
+             '(objectclass=ipaidobject))(!(ipantsecurityidentifier=*)))'
+    base_dn = api.env.basedn
+    try:
+        root_logger.debug(
+            "Searching for objects with missing SID with "
+            "filter=%s, base_dn=%s", filter, base_dn)
+        entries, _truncated = api.Backend.ldap2.find_entries(
+            filter=filter, base_dn=base_dn, attrs_list=[''])
+        return entries
+    except errors.NotFound:
+        # All objects have SIDs assigned
+        pass
+    except (errors.DatabaseError, errors.NetworkError) as e:
+        print("Could not retrieve a list of objects that need a SID "
+              "identifier assigned:")
+        print(unicode(e))
+
+    return []
+
+
+def retrieve_and_ask_about_sids(api, options):
+    entries = []
+    if api.Backend.ldap2.isconnected():
+        entries = retrieve_entries_without_sid(api)
+    else:
+        root_logger.debug(
+            "LDAP backend not connected, can not retrieve entries "
+            "with missing SID")
+
+    object_count = len(entries)
+    if object_count > 0:
+        print("")
+        print("WARNING: %d existing users or groups do not have "
+              "a SID identifier assigned." % len(entries))
+        print("Installer can run a task to have ipa-sidgen "
+              "Directory Server plugin generate")
+        print("the SID identifier for all these users. Please note, "
+              "the in case of a high")
+        print("number of users and groups, the operation might "
+              "lead to high replication")
+        print("traffic and performance degradation. Refer to "
+              "ipa-adtrust-install(1) man page")
+        print("for details.")
+        print("")
+        if options.unattended:
+            print("Unattended mode was selected, installer will "
+                  "NOT run ipa-sidgen task!")
+        else:
+            if ipautil.user_input(
+                    "Do you want to run the ipa-sidgen task?",
+                    default=False,
+                    allow_empty=False):
+                options.add_sids = True
+
+
 def install_check(standalone, options, api):
     global netbios_name
     global reset_netbios_name
@@ -225,49 +288,7 @@ def install_check(standalone, options, api):
         options.netbios_name, options.unattended, api)
 
     if not options.add_sids:
-        # The filter corresponds to ipa_sidgen_task.c LDAP search filter
-        filter = '(&(objectclass=ipaobject)(!(objectclass=mepmanagedentry))' \
-                 '(|(objectclass=posixaccount)(objectclass=posixgroup)' \
-                 '(objectclass=ipaidobject))(!(ipantsecurityidentifier=*)))'
-        base_dn = api.env.basedn
-        try:
-            root_logger.debug(
-                "Searching for objects with missing SID with "
-                "filter=%s, base_dn=%s", filter, base_dn)
-            entries, _truncated = api.Backend.ldap2.find_entries(
-                filter=filter, base_dn=base_dn, attrs_list=[''])
-        except errors.NotFound:
-            # All objects have SIDs assigned
-            pass
-        except (errors.DatabaseError, errors.NetworkError) as e:
-            print("Could not retrieve a list of objects that need a SID "
-                  "identifier assigned:")
-            print(unicode(e))
-        else:
-            object_count = len(entries)
-            if object_count > 0:
-                print("")
-                print("WARNING: %d existing users or groups do not have "
-                      "a SID identifier assigned." % len(entries))
-                print("Installer can run a task to have ipa-sidgen "
-                      "Directory Server plugin generate")
-                print("the SID identifier for all these users. Please note, "
-                      "the in case of a high")
-                print("number of users and groups, the operation might "
-                      "lead to high replication")
-                print("traffic and performance degradation. Refer to "
-                      "ipa-adtrust-install(1) man page")
-                print("for details.")
-                print("")
-                if options.unattended:
-                    print("Unattended mode was selected, installer will "
-                          "NOT run ipa-sidgen task!")
-                else:
-                    if ipautil.user_input(
-                            "Do you want to run the ipa-sidgen task?",
-                            default=False,
-                            allow_empty=False):
-                        options.add_sids = True
+        retrieve_and_ask_about_sids(api, options)
 
 
 def install(options, fstore, api):

From 3fcc04bef789bc9269c549883ca2524512e68251 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Thu, 16 Feb 2017 13:41:32 +0100
Subject: [PATCH 06/16] only check for netbios name when LDAP backend is
 connected

This is to prevent errors due to non-existent LDAP connection such as
when installing first IPA master.

https://fedorahosted.org/freeipa/ticket/6630
---
 ipaserver/install/adtrust.py | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py
index 69e9834..fd26e69 100644
--- a/ipaserver/install/adtrust.py
+++ b/ipaserver/install/adtrust.py
@@ -59,6 +59,21 @@ def read_netbios_name(netbios_default):
     return netbios_name
 
 
+def retrieve_netbios_name(api):
+    flat_name_attr = 'ipantflatname'
+    try:
+        entry = api.Backend.ldap2.get_entry(
+            DN(('cn', api.env.domain), api.env.container_cifsdomains,
+               ipautil.realm_to_suffix(api.env.realm)),
+            [flat_name_attr])
+    except errors.NotFound:
+        # trust not configured
+        root_logger.debug("No previous trust configuration found")
+        return None
+    else:
+        return entry.get(flat_name_attr)[0]
+
+
 def set_and_check_netbios_name(netbios_name, unattended, api):
     """
     Depending if trust in already configured or not a given NetBIOS domain
@@ -71,22 +86,16 @@ def set_and_check_netbios_name(netbios_name, unattended, api):
     the stored NetBIOS name it it differs from the current one.
     """
 
-    flat_name_attr = 'ipantflatname'
     cur_netbios_name = None
     gen_netbios_name = None
     reset_netbios_name = False
     entry = None
 
-    try:
-        entry = api.Backend.ldap2.get_entry(
-            DN(('cn', api.env.domain), api.env.container_cifsdomains,
-               ipautil.realm_to_suffix(api.env.realm)),
-            [flat_name_attr])
-    except errors.NotFound:
-        # trust not configured
-        pass
+    if api.Backend.ldap2.isconnected():
+        cur_netbios_name = retrieve_netbios_name(api)
     else:
-        cur_netbios_name = entry.get(flat_name_attr)[0]
+        root_logger.debug(
+            "LDAP is not connected, can not retrieve NetBIOS name")
 
     if cur_netbios_name and not netbios_name:
         # keep the current NetBIOS name

From ca48e351ea2aa48ae4c47d390846b32b938ae87c Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Thu, 16 Feb 2017 14:14:01 +0100
Subject: [PATCH 07/16] Refactor the code searching and presenting missing
 trust agents

Use newly implemented APIs for searching and presenting potential
trust agents.

https://fedorahosted.org/freeipa/ticket/6639
---
 ipaserver/install/adtrust.py | 196 +++++++++++++++++++++++--------------------
 1 file changed, 106 insertions(+), 90 deletions(-)

diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py
index fd26e69..deb4301 100644
--- a/ipaserver/install/adtrust.py
+++ b/ipaserver/install/adtrust.py
@@ -9,10 +9,10 @@
 from __future__ import print_function
 
 import os
-import ldap
 
 import six
 
+from ipalib.constants import DOMAIN_LEVEL_0
 from ipalib import errors
 from ipaplatform.paths import paths
 from ipapython.admintool import ScriptError
@@ -240,6 +240,110 @@ def retrieve_and_ask_about_sids(api, options):
                 options.add_sids = True
 
 
+def retrieve_potential_adtrust_agents(api):
+    """
+    Retrieve a sorted list of potential AD trust agents
+
+    :param api: initialized API instance
+    :returns: sorted list of FQDNs of masters which are not AD trust agents
+    """
+    try:
+        # Search only masters which have support for domain levels
+        # because only these masters will have SSSD recent enough
+        # to support AD trust agents
+        dl_enabled_masters = api.Command.server_find(
+            ipamindomainlevel=DOMAIN_LEVEL_0, all=True)['result']
+    except (errors.DatabaseError, errors.NetworkError) as e:
+        print("Could not retrieve a list of existing IPA masters:")
+        print(unicode(e))
+        return
+
+    try:
+        # search for existing AD trust agents
+        adtrust_agents = api.Command.server_find(
+            servrole=u'AD trust agent', all=True)['result']
+    except (errors.DatabaseError, errors.NetworkError) as e:
+        print("Could not retrieve a list of adtrust agents:")
+        print(unicode(e))
+        return
+
+    dl_enabled_master_cns = {m['cn'][0] for m in dl_enabled_masters}
+    adtrust_agents_cns = {m['cn'][0] for m in adtrust_agents}
+
+    potential_agents_cns = dl_enabled_master_cns - adtrust_agents_cns
+
+    # remove the local host from the potential agents since it will be set up
+    # by adtrustinstance configuration code
+    potential_agents_cns -= {api.env.host}
+    return sorted(potential_agents_cns)
+
+
+def add_hosts_to_adtrust_agents(api, host_list):
+    """
+    Add the CIFS and host principals to the 'adtrust agents'
+    group as 389-ds only operates with GroupOfNames, we have to
+    use the principal's proper dn as defined in self.cifs_agent
+
+    :param api: API instance
+    :param host_list: list of potential AD trust agent FQDNs
+    """
+    agents_dn = DN(
+        ('cn', 'adtrust agents'), ('cn', 'sysaccounts'),
+        ('cn', 'etc'), api.env.basedn)
+
+    service.add_principals_to_group(
+        api.Backend.ldap2,
+        agents_dn,
+        "member",
+        [api.Object.host.get_dn(x) for x in host_list])
+
+
+def add_new_adtrust_agents(api, options):
+    """
+    Find out IPA masters which are not part of the cn=adtrust agents
+    and propose them to be added to the list
+    :param api: API instance
+    :param options: parsed CLI options
+    """
+    potential_agents_cns = retrieve_potential_adtrust_agents(api)
+
+    if potential_agents_cns:
+        print("")
+        print("WARNING: %d IPA masters are not yet able to serve "
+              "information about users from trusted forests."
+              % len(potential_agents_cns))
+        print("Installer can add them to the list of IPA masters "
+              "allowed to access information about trusts.")
+        print("If you choose to do so, you also need to restart "
+              "LDAP service on those masters.")
+        print("Refer to ipa-adtrust-install(1) man page for details.")
+        print("")
+        if options.unattended:
+            print("Unattended mode was selected, installer will NOT "
+                  "add other IPA masters to the list of allowed to")
+            print("access information about trusted forests!")
+            return
+
+    new_agents = []
+
+    for name in sorted(potential_agents_cns):
+        if ipautil.user_input(
+                "IPA master [%s]?" % (name),
+                default=False,
+                allow_empty=False):
+            new_agents.append(name)
+
+    if new_agents:
+        add_hosts_to_adtrust_agents(api, new_agents)
+
+        print("""
+WARNING: you MUST restart (e.g. ipactl restart) the following IPA masters in
+order to activate them to serve information about users from trusted forests:
+""")
+        for x in new_agents:
+            print(x)
+
+
 def install_check(standalone, options, api):
     global netbios_name
     global reset_netbios_name
@@ -321,92 +425,4 @@ def install(options, fstore, api):
     if options.add_agents:
         # Find out IPA masters which are not part of the cn=adtrust agents
         # and propose them to be added to the list
-        base_dn = api.env.basedn
-        masters_dn = DN(
-            ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), base_dn)
-        agents_dn = DN(
-            ('cn', 'adtrust agents'), ('cn', 'sysaccounts'),
-            ('cn', 'etc'), base_dn)
-        new_agents = []
-        entries_m = []
-        entries_a = []
-        try:
-            # Search only masters which have support for domain levels
-            # because only these masters will have SSSD recent enough
-            # to support AD trust agents
-            entries_m, _truncated = api.Backend.ldap2.find_entries(
-                filter=("(&(objectclass=ipaSupportedDomainLevelConfig)"
-                        "(ipaMaxDomainLevel=*)(ipaMinDomainLevel=*))"),
-                base_dn=masters_dn, attrs_list=['cn'],
-                scope=ldap.SCOPE_ONELEVEL)
-        except errors.NotFound:
-            pass
-        except (errors.DatabaseError, errors.NetworkError) as e:
-            print("Could not retrieve a list of existing IPA masters:")
-            print(unicode(e))
-
-        try:
-            entries_a, _truncated = api.Backend.ldap2.find_entries(
-               filter="", base_dn=agents_dn, attrs_list=['member'],
-               scope=ldap.SCOPE_BASE)
-        except errors.NotFound:
-            pass
-        except (errors.DatabaseError, errors.NetworkError) as e:
-            print("Could not retrieve a list of adtrust agents:")
-            print(unicode(e))
-
-        if len(entries_m) > 0:
-            existing_masters = [x['cn'][0] for x in entries_m]
-            adtrust_agents = entries_a[0]['member']
-            potential_agents = []
-            for m in existing_masters:
-                mdn = DN(('fqdn', m), api.env.container_host, api.env.basedn)
-                found = False
-                for a in adtrust_agents:
-                    if mdn == a:
-                        found = True
-                        break
-                if not found:
-                    potential_agents += [[m, mdn]]
-
-            object_count = len(potential_agents)
-            if object_count > 0:
-                print("")
-                print("WARNING: %d IPA masters are not yet able to serve "
-                      "information about users from trusted forests."
-                      % (object_count))
-                print("Installer can add them to the list of IPA masters "
-                      "allowed to access information about trusts.")
-                print("If you choose to do so, you also need to restart "
-                      "LDAP service on those masters.")
-                print("Refer to ipa-adtrust-install(1) man page for details.")
-                print("")
-                if options.unattended:
-                    print("Unattended mode was selected, installer will NOT "
-                          "add other IPA masters to the list of allowed to")
-                    print("access information about trusted forests!")
-                else:
-                    print(
-                        "Do you want to allow following IPA masters to "
-                        "serve information about users from trusted forests?")
-                    for (name, dn) in potential_agents:
-                        if name == api.env.host:
-                            # Don't add this host here
-                            # it shouldn't be here as it was added by the
-                            # adtrustinstance setup code
-                            continue
-                        if ipautil.user_input(
-                                "IPA master [%s]?" % (name),
-                                default=False,
-                                allow_empty=False):
-                            new_agents += [[name, dn]]
-
-            if len(new_agents) > 0:
-                # Add the CIFS and host principals to the 'adtrust agents'
-                # group as 389-ds only operates with GroupOfNames, we have to
-                # use the principal's proper dn as defined in self.cifs_agent
-                service.add_principals_to_group(
-                    api.Backend.ldap2,
-                    agents_dn,
-                    "member",
-                    [x[1] for x in new_agents])
+        add_new_adtrust_agents(api, options)

From eb489840efecb3ffe892c29563e795bb6f6ac737 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 14:00:24 +0100
Subject: [PATCH 08/16] adtrust.py: Use logging to emit error messages

Plain print messages are a) not logged into files and b) get lost in the
output from composite installer.

https://fedorahosted.org/freeipa/ticket/6630
---
 ipaserver/install/adtrust.py | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py
index deb4301..4694a25 100644
--- a/ipaserver/install/adtrust.py
+++ b/ipaserver/install/adtrust.py
@@ -31,9 +31,10 @@
 
 
 def netbios_name_error(name):
-    print("\nIllegal NetBIOS name [%s].\n" % name)
-    print("Up to 15 characters and only uppercase ASCII letters, digits "
-          "and dashes are allowed. Empty string is not allowed.")
+    root_logger.error("\nIllegal NetBIOS name [%s].\n" % name)
+    root_logger.error(
+        "Up to 15 characters and only uppercase ASCII letters, digits "
+        "and dashes are allowed. Empty string is not allowed.")
 
 
 def read_netbios_name(netbios_default):
@@ -198,9 +199,9 @@ def retrieve_entries_without_sid(api):
         # All objects have SIDs assigned
         pass
     except (errors.DatabaseError, errors.NetworkError) as e:
-        print("Could not retrieve a list of objects that need a SID "
-              "identifier assigned:")
-        print(unicode(e))
+        root_logger.error(
+            "Could not retrieve a list of objects that need a SID "
+            "identifier assigned: %s", e)
 
     return []
 
@@ -254,8 +255,8 @@ def retrieve_potential_adtrust_agents(api):
         dl_enabled_masters = api.Command.server_find(
             ipamindomainlevel=DOMAIN_LEVEL_0, all=True)['result']
     except (errors.DatabaseError, errors.NetworkError) as e:
-        print("Could not retrieve a list of existing IPA masters:")
-        print(unicode(e))
+        root_logger.error(
+            "Could not retrieve a list of existing IPA masters: %s", e)
         return
 
     try:
@@ -263,8 +264,7 @@ def retrieve_potential_adtrust_agents(api):
         adtrust_agents = api.Command.server_find(
             servrole=u'AD trust agent', all=True)['result']
     except (errors.DatabaseError, errors.NetworkError) as e:
-        print("Could not retrieve a list of adtrust agents:")
-        print(unicode(e))
+        root_logger.error("Could not retrieve a list of adtrust agents: %s", e)
         return
 
     dl_enabled_master_cns = {m['cn'][0] for m in dl_enabled_masters}

From 65bc68b9e8bb62567092785375b332a1f53ef223 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 13:48:46 +0100
Subject: [PATCH 09/16] print the installation info only in standalone mode

There is no point in emitting this message during server/replica
install.

https://fedorahosted.org/freeipa/ticket/6630
---
 install/tools/ipa-adtrust-install | 2 +-
 ipaserver/install/adtrust.py      | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install
index 443c3c4..1484598 100755
--- a/install/tools/ipa-adtrust-install
+++ b/install/tools/ipa-adtrust-install
@@ -208,7 +208,7 @@ def main():
             "Unrecognized error during check of admin rights: %s" % e)
 
     adtrust.install_check(True, options, api)
-    adtrust.install(options, fstore, api)
+    adtrust.install(True, options, fstore, api)
 
     print("""
 =============================================================================
diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py
index 4694a25..2eddf45 100644
--- a/ipaserver/install/adtrust.py
+++ b/ipaserver/install/adtrust.py
@@ -404,8 +404,8 @@ def install_check(standalone, options, api):
         retrieve_and_ask_about_sids(api, options)
 
 
-def install(options, fstore, api):
-    if not options.unattended:
+def install(standalone, options, fstore, api):
+    if not options.unattended and standalone:
         print("")
         print("The following operations may take some minutes to complete.")
         print("Please wait until the prompt is returned.")

From e8465c390deecc62b9b7b6173921e7f22a68739b Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Wed, 15 Feb 2017 10:16:27 +0100
Subject: [PATCH 10/16] Add AD trust installer interface for composite
 installer

This interface is to be used to provide AD trust-related options in
server and replica installer.

https://fedorahosted.org/freeipa/ticket/6630
---
 ipaserver/install/adtrust.py | 50 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py
index 2eddf45..6627b22 100644
--- a/ipaserver/install/adtrust.py
+++ b/ipaserver/install/adtrust.py
@@ -14,10 +14,12 @@
 
 from ipalib.constants import DOMAIN_LEVEL_0
 from ipalib import errors
+from ipalib.install.service import ServiceAdminInstallInterface
 from ipaplatform.paths import paths
 from ipapython.admintool import ScriptError
 from ipapython import ipaldap, ipautil
 from ipapython.dn import DN
+from ipapython.install.core import knob
 from ipapython.ipa_log_manager import root_logger
 from ipaserver.install import adtrustinstance
 from ipaserver.install import service
@@ -426,3 +428,51 @@ def install(standalone, options, fstore, api):
         # Find out IPA masters which are not part of the cn=adtrust agents
         # and propose them to be added to the list
         add_new_adtrust_agents(api, options)
+
+
+class ADTrustInstallInterface(ServiceAdminInstallInterface):
+    """
+    Interface for the AD trust installer
+
+    Knobs defined here will be available in:
+    * ipa-server-install
+    * ipa-replica-install
+    * ipa-adtrust-install
+    """
+
+    # the following knobs are provided on top of those specified for
+    # admin credentials
+    add_sids = knob(
+        None,
+        description="Add SIDs for existing users and groups as the final step"
+    )
+    add_agents = knob(
+        None,
+        description="Add IPA masters to a list of hosts allowed to "
+                    "serve information about users from trusted forests"
+    )
+    enable_compat = knob(
+        None,
+        description="Enable support for trusted domains for old clients"
+    )
+    netbios_name = knob(
+        str,
+        None,
+        description="NetBIOS name of the IPA domain"
+    )
+    no_msdcs = knob(
+        None,
+        description="Deprecated: has no effect",
+        deprecated=True
+    )
+    rid_base = knob(
+        int,
+        1000,
+        description="Start value for mapping UIDs and GIDs to RIDs"
+    )
+    secondary_rid_base = knob(
+        int,
+        100000000,
+        description="Start value of the secondary range for mapping "
+                    "UIDs and GIDs to RIDs"
+    )

From bfe7ca1393cc68f7ce2cc13fda572a27f76a8912 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 13:50:09 +0100
Subject: [PATCH 11/16] expose AD trust related knobs in composite installers

---
 ipaserver/install/server/__init__.py | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py
index 86cb4a9..753a836 100644
--- a/ipaserver/install/server/__init__.py
+++ b/ipaserver/install/server/__init__.py
@@ -38,13 +38,14 @@
 from .replicainstall import promote_check as replica_promote_check
 from .upgrade import upgrade_check, upgrade
 
-from .. import ca, conncheck, dns, kra
+from .. import adtrust, ca, conncheck, dns, kra
 
 
 class ServerInstallInterface(client.ClientInstallInterface,
                              ca.CAInstallInterface,
                              kra.KRAInstallInterface,
                              dns.DNSInstallInterface,
+                             adtrust.ADTrustInstallInterface,
                              conncheck.ConnCheckInterface):
     """
     Interface of server installers
@@ -144,6 +145,10 @@ def domain_level(self, value):
                 "Domain Level cannot be higher than {0}".format(
                     constants.MAX_DOMAIN_LEVEL))
 
+    setup_adtrust = knob(
+        None,
+        description="configure AD trust capability"
+    )
     setup_ca = knob(
         None,
         description="configure a dogtag CA",
@@ -331,6 +336,13 @@ def dirsrv_config_file(self, value):
     )
     pkinit_cert_name = prepare_only(pkinit_cert_name)
 
+    # TODO: --add-agents makes no sense on server install (since it is a first
+    # master
+    add_agents = knob(
+        bases=adtrust.ADTrustInstallInterface.add_agents
+    )
+    add_agents = replica_install_only(add_agents)
+
     def __init__(self, **kwargs):
         super(ServerInstallInterface, self).__init__(**kwargs)
 
@@ -548,6 +560,10 @@ def dm_password(self, value):
     def admin_password(self, value):
         validate_admin_password(value)
 
+    # always run sidgen task and do not allow adding agents on first master
+    add_sids = True
+    add_agents = False
+
     def __init__(self, **kwargs):
         super(ServerMasterInstall, self).__init__(**kwargs)
         master_init(self)

From d1978338aadeac95ebf85a9b6ca2b79ad500ded7 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 13:50:36 +0100
Subject: [PATCH 12/16] Merge AD trust configurator into server installer

ipa-server-install is now able to configure Samba and winbind services
and manage trusts to Active Directory right off the bat with following
alterations from standalone installer:

   * sidgen task is always triggered since there are only a few entries
     to tag in the beginning

   * the `--add-agents` option is hardcoded to False, as there are no
     potential agents to resolve and addd when setting up the first
     master in topology

https://fedorahosted.org/freeipa/ticket/6630
---
 ipaserver/install/server/install.py | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index dd04624..aa95cb5 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -32,7 +32,7 @@
 )
 import ipaclient.install.ntpconf
 from ipaserver.install import (
-    bindinstance, ca, certs, dns, dsinstance,
+    adtrust, bindinstance, ca, certs, dns, dsinstance,
     httpinstance, installutils, kra, krbinstance,
     ntpinstance, otpdinstance, custodiainstance, replication, service,
     sysupgrade)
@@ -386,6 +386,8 @@ def install_check(installer):
     print("  * Configure Apache (httpd)")
     if options.setup_dns:
         print("  * Configure DNS (bind)")
+    if options.setup_adtrust:
+        print("  * Configure Samba (smb) and winbind for managing AD trusts")
     if not options.no_pkinit:
         print("  * Configure the KDC to enable PKINIT")
     if options.no_ntp:
@@ -610,6 +612,9 @@ def install_check(installer):
         network_ip_address_warning(ip_addresses)
         broadcast_ip_address_warning(ip_addresses)
 
+    if options.setup_adtrust:
+        adtrust.install_check(False, options, api)
+
     # installer needs to update hosts file when DNS subsystem will be
     # installed or custom addresses are used
     if options.ip_addresses or options.setup_dns:
@@ -636,16 +641,17 @@ def install_check(installer):
         ))
         print()
 
-    # If domain name and realm does not match, IPA server will not be able
-    # to estabilish trust with Active Directory. Print big fat warning.
+    if not options.setup_adtrust:
+        # If domain name and realm does not match, IPA server will not be able
+        # to estabilish trust with Active Directory. Print big fat warning.
 
-    realm_not_matching_domain = (domain_name.upper() != realm_name)
+        realm_not_matching_domain = (domain_name.upper() != realm_name)
 
-    if realm_not_matching_domain:
-        print("WARNING: Realm name does not match the domain name.\n"
-              "You will not be able to estabilish trusts with Active "
-              "Directory unless\nthe realm name of the IPA server matches "
-              "its domain name.\n\n")
+        if realm_not_matching_domain:
+            print("WARNING: Realm name does not match the domain name.\n"
+                  "You will not be able to estabilish trusts with Active "
+                  "Directory unless\nthe realm name of the IPA server matches "
+                  "its domain name.\n\n")
 
     if installer.interactive and not user_input(
             "Continue to configure the system with these values?", False):
@@ -855,6 +861,9 @@ def install(installer):
                    no_dnssec_validation=options.no_dnssec_validation)
         bind.create_file_with_system_records()
 
+    if options.setup_adtrust:
+        adtrust.install(False, options, fstore, api)
+
     # Set the admin user kerberos password
     ds.change_admin_password(admin_password)
 

From 15ee1d81d06ce5c8798d93154997812bd46e54ad Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 13:51:00 +0100
Subject: [PATCH 13/16] Merge AD trust configurator into replica installer

`ipa-replica-install` is now able to configure Samba and winbind
services in order to manage Active Directory trusts. `--add-agents`
option is exposed in replica installer, while `--add-sids` now defaults
to `False` since adding a first AD trust controller to an existing
sizeable deployment can result in stuck installation as sidgen tasks can
take a long time to complete. That's why adding SIDs should be a
conscious decision in this case.

https://fedorahosted.org/freeipa/ticket/6630
---
 ipaserver/install/server/replicainstall.py | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 84e86a9..223dfa1 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -37,7 +37,7 @@
 )
 from ipaclient.install.client import configure_krb5_conf, purge_host_keytab
 from ipaserver.install import (
-    bindinstance, ca, certs, dns, dsinstance, httpinstance,
+    adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance,
     installutils, kra, krbinstance,
     ntpinstance, otpdinstance, custodiainstance, service)
 from ipaserver.install.installutils import (
@@ -824,6 +824,9 @@ def install_check(installer):
             network_ip_address_warning(config.ips)
             broadcast_ip_address_warning(config.ips)
 
+        if options.setup_adtrust:
+            adtrust.install_check(False, options, remote_api)
+
         enroll_dl0_replica(installer, fstore, remote_api)
         ccache = os.environ['KRB5CCNAME']
         kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env),
@@ -1243,6 +1246,9 @@ def promote_check(installer):
             network_ip_address_warning(config.ips)
             broadcast_ip_address_warning(config.ips)
 
+        if options.setup_adtrust:
+            adtrust.install_check(False, options, remote_api)
+
     except errors.ACIError:
         root_logger.debug(traceback.format_exc())
         raise ScriptError("\nInsufficient privileges to promote the server."
@@ -1433,6 +1439,10 @@ def install(installer):
         dns.install(False, True, options, api)
     else:
         api.Command.dns_update_system_records()
+
+    if options.setup_adtrust:
+        adtrust.install(False, options, fstore, api)
+
     api.Backend.ldap2.disconnect()
 
     if not promote:

From c78fbc10ee25122fe9961c55f458ef455e102e70 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 17:04:53 +0100
Subject: [PATCH 14/16] Fix erroneous short name options in ipa-adtrust-install
 man page

`--rid-base` and `--secondary-rid-base` had `-U` option assigned
by error in the man page. Remove it as these options have not short
alias.

https://fedorahosted.org/freeipa/ticket/6630
---
 install/tools/man/ipa-adtrust-install.1 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/install/tools/man/ipa-adtrust-install.1 b/install/tools/man/ipa-adtrust-install.1
index 6e8438b..058422b 100644
--- a/install/tools/man/ipa-adtrust-install.1
+++ b/install/tools/man/ipa-adtrust-install.1
@@ -101,12 +101,12 @@ version 1.13 on IPA master is required to be able to perform as a trust agent.
 \fB\-U\fR, \fB\-\-unattended\fR
 An unattended installation that will never prompt for user input
 .TP
-\fB\-U\fR, \fB\-\-rid-base\fR=\fIRID_BASE\fR
+\fB\-\-rid-base\fR=\fIRID_BASE\fR
 First RID value of the local domain. The first Posix ID of the local domain will
 be assigned to this RID, the second to RID+1 etc. See the online help of the
 idrange CLI for details.
 .TP
-\fB\-U\fR, \fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR
+\fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR
 Start value of the secondary RID range, which is only used in the case a user
 and a group share numerically the same Posix ID. See the online help of the
 idrange CLI for details.

From 141511d9e13033fbf7659353f2eb14003f0daeb9 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Fri, 17 Feb 2017 17:06:42 +0100
Subject: [PATCH 15/16] Update server/replica installer man pages

Since AD trust installer is now a part of composite installers, their
man pages were updated with separate section documenting relevant AD
trust-related option descriptions.

https://fedorahosted.org/freeipa/ticket/6630
---
 install/tools/man/ipa-replica-install.1 | 64 +++++++++++++++++++++++++++++++++
 install/tools/man/ipa-server-install.1  | 44 +++++++++++++++++++++++
 2 files changed, 108 insertions(+)

diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1
index 2c09666..f9ebd87 100644
--- a/install/tools/man/ipa-replica-install.1
+++ b/install/tools/man/ipa-replica-install.1
@@ -199,6 +199,70 @@ Do not automatically create DNS SSHFP records.
 \fB\-\-no\-dnssec\-validation\fR
 Disable DNSSEC validation on this server.
 
+.SS "AD TRUST OPTIONS"
+.TP
+\fB\-\-netbios\-name\fR=\fINETBIOS_NAME\fR
+The NetBIOS name for the IPA domain. If not provided then this is determined
+based on the leading component of the DNS domain name. Running
+ipa\-adtrust\-install for a second time with a different NetBIOS name will
+change the name. Please note that changing the NetBIOS name might break
+existing trust relationships to other domains.
+.TP
+\fB\-\-add\-sids\fR
+Add SIDs to existing users and groups as on of final steps of the
+ipa\-adtrust\-install run. If there a many existing users and groups and a
+couple of replicas in the environment this operation might lead to a high
+replication traffic and a performance degradation of all IPA servers in the
+environment. To avoid this the SID generation can be run after
+ipa\-adtrust\-install is run and scheduled independently. To start this task
+you have to load an edited version of ipa-sidgen-task-run.ldif with the
+ldapmodify command info the directory server.
+.TP
+\fB\-\-add\-agents\fR
+Add IPA masters to the list that allows to serve information about
+users from trusted forests. Starting with FreeIPA 4.2, a regular IPA master
+can provide this information to SSSD clients. IPA masters aren't added
+to the list automatically as restart of the LDAP service on each of them
+is required. The host where ipa\-adtrust\-install is being run is added
+automatically.
+.IP
+Note that IPA masters where ipa\-adtrust\-install wasn't run, can serve
+information about users from trusted forests only if they are enabled
+via \ipa-adtrust\-install run on any other IPA master. At least SSSD
+version 1.13 on IPA master is required to be able to perform as a trust agent.
+.TP
+\fB\-\-rid-base\fR=\fIRID_BASE\fR
+First RID value of the local domain. The first Posix ID of the local domain will
+be assigned to this RID, the second to RID+1 etc. See the online help of the
+idrange CLI for details.
+.TP
+\fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR
+Start value of the secondary RID range, which is only used in the case a user
+and a group share numerically the same Posix ID. See the online help of the
+idrange CLI for details.
+.TP
+\fB\-\-enable\-compat\fR
+Enables support for trusted domains users for old clients through Schema Compatibility plugin.
+SSSD supports trusted domains natively starting with version 1.9. For platforms that
+lack SSSD or run older SSSD version one needs to use this option. When enabled, slapi\-nis package
+needs to be installed and schema\-compat\-plugin will be configured to provide lookup of
+users and groups from trusted domains via SSSD on IPA server. These users and groups will be
+available under \fBcn=users,cn=compat,$SUFFIX\fR and \fBcn=groups,cn=compat,$SUFFIX\fR trees.
+SSSD will normalize names of users and groups to lower case.
+.IP
+In addition to providing these users and groups through the compat tree, this option enables
+authentication over LDAP for trusted domain users with DN under compat tree, i.e. using bind DN
+\fBuid=administrator@ad.domain,cn=users,cn=compat,$SUFFIX\fR.
+.IP
+LDAP authentication performed by the compat tree is done via PAM '\fBsystem\-auth\fR' service.
+This service exists by default on Linux systems and is provided by pam package as /etc/pam.d/system\-auth.
+If your IPA install does not have default HBAC rule 'allow_all' enabled, then make sure
+to define in IPA special service called '\fBsystem\-auth\fR' and create an HBAC
+rule to allow access to anyone to this rule on IPA masters.
+.IP
+As '\fBsystem\-auth\fR' PAM service is not used directly by any other
+application, it is safe to use it for trusted domain users via compatibility
+path.
 .SH "EXIT STATUS"
 0 if the command was successful
 
diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1
index a7c7f81..cd68f72 100644
--- a/install/tools/man/ipa-server-install.1
+++ b/install/tools/man/ipa-server-install.1
@@ -195,6 +195,49 @@ Disable DNSSEC validation on this server.
 \fB\-\-allow\-zone\-overlap\fR
 Allow creatin of (reverse) zone even if the zone is already resolvable. Using this option is discouraged as it result in later problems with domain name resolution.
 
+.SS "AD TRUST OPRIONS"
+
+.TP
+\fB\-\-netbios\-name\fR=\fINETBIOS_NAME\fR
+The NetBIOS name for the IPA domain. If not provided then this is determined
+based on the leading component of the DNS domain name. Running
+ipa\-adtrust\-install for a second time with a different NetBIOS name will
+change the name. Please note that changing the NetBIOS name might break
+existing trust relationships to other domains.
+.TP
+\fB\-\-rid-base\fR=\fIRID_BASE\fR
+First RID value of the local domain. The first Posix ID of the local domain will
+be assigned to this RID, the second to RID+1 etc. See the online help of the
+idrange CLI for details.
+.TP
+\fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR
+Start value of the secondary RID range, which is only used in the case a user
+and a group share numerically the same Posix ID. See the online help of the
+idrange CLI for details.
+.TP
+\fB\-\-enable\-compat\fR
+Enables support for trusted domains users for old clients through Schema Compatibility plugin.
+SSSD supports trusted domains natively starting with version 1.9. For platforms that
+lack SSSD or run older SSSD version one needs to use this option. When enabled, slapi\-nis package
+needs to be installed and schema\-compat\-plugin will be configured to provide lookup of
+users and groups from trusted domains via SSSD on IPA server. These users and groups will be
+available under \fBcn=users,cn=compat,$SUFFIX\fR and \fBcn=groups,cn=compat,$SUFFIX\fR trees.
+SSSD will normalize names of users and groups to lower case.
+.IP
+In addition to providing these users and groups through the compat tree, this option enables
+authentication over LDAP for trusted domain users with DN under compat tree, i.e. using bind DN
+\fBuid=administrator@ad.domain,cn=users,cn=compat,$SUFFIX\fR.
+.IP
+LDAP authentication performed by the compat tree is done via PAM '\fBsystem\-auth\fR' service.
+This service exists by default on Linux systems and is provided by pam package as /etc/pam.d/system\-auth.
+If your IPA install does not have default HBAC rule 'allow_all' enabled, then make sure
+to define in IPA special service called '\fBsystem\-auth\fR' and create an HBAC
+rule to allow access to anyone to this rule on IPA masters.
+.IP
+As '\fBsystem\-auth\fR' PAM service is not used directly by any other
+application, it is safe to use it for trusted domain users via compatibility
+path.
+
 .SS "UNINSTALL OPTIONS"
 .TP
 \fB\-\-uninstall\fR
@@ -215,3 +258,4 @@ The kerberos master password (normally autogenerated).
 
 .SH "SEE ALSO"
 .BR ipa-dns-install (1)
+.BR ipa-adtrust-install (1)

From aae365be7e022fbb14b24016142907f8967d0570 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Mon, 20 Feb 2017 15:17:11 +0100
Subject: [PATCH 16/16] Provide basic integration tests for built-in AD trust
 installer

A couple of tests were added to server/replica install integration
suite to test AD trust install w/ various combinations of other optional
components.

https://fedorahosted.org/freeipa/ticket/6630
---
 ipatests/test_integration/tasks.py             | 15 +++++---
 ipatests/test_integration/test_installation.py | 49 ++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/ipatests/test_integration/tasks.py b/ipatests/test_integration/tasks.py
index 9523450..6620d12 100644
--- a/ipatests/test_integration/tasks.py
+++ b/ipatests/test_integration/tasks.py
@@ -249,9 +249,9 @@ def enable_replication_debugging(host):
                      stdin_text=logging_ldif)
 
 
-def install_master(host, setup_dns=True, setup_kra=False, extra_args=(),
-                   domain_level=None, unattended=True, stdin_text=None,
-                   raiseonerr=True):
+def install_master(host, setup_dns=True, setup_kra=False, setup_adtrust=False,
+                   extra_args=(), domain_level=None, unattended=True,
+                   stdin_text=None, raiseonerr=True):
     if domain_level is None:
         domain_level = host.config.domain_level
     setup_server_logs_collecting(host)
@@ -275,6 +275,8 @@ def install_master(host, setup_dns=True, setup_kra=False, extra_args=(),
             '--forwarder', host.config.dns_forwarder,
             '--auto-reverse'
         ])
+    if setup_adtrust:
+        args.append('--setup-adtrust')
 
     args.extend(extra_args)
     result = host.run_command(args, raiseonerr=raiseonerr,
@@ -343,8 +345,9 @@ def replica_prepare(master, replica, extra_args=(),
 
 
 def install_replica(master, replica, setup_ca=True, setup_dns=False,
-                    setup_kra=False, extra_args=(), domain_level=None,
-                    unattended=True, stdin_text=None, raiseonerr=True):
+                    setup_kra=False, setup_adtrust=False, extra_args=(),
+                    domain_level=None, unattended=True, stdin_text=None,
+                    raiseonerr=True):
     if domain_level is None:
         domain_level = domainlevel(master)
     apply_common_fixes(replica)
@@ -367,6 +370,8 @@ def install_replica(master, replica, setup_ca=True, setup_dns=False,
             '--setup-dns',
             '--forwarder', replica.config.dns_forwarder
         ])
+    if setup_adtrust:
+        args.append('--setup-adtrust')
     if master_authoritative_for_client_domain(master, replica):
         args.extend(['--ip-address', replica.ip])
 
diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py
index 0929f13..f3e9eba 100644
--- a/ipatests/test_integration/test_installation.py
+++ b/ipatests/test_integration/test_installation.py
@@ -84,6 +84,29 @@ def test_replica2_ipa_kra_install(self):
         tasks.install_kra(self.replicas[2])
 
 
+class ADTrustInstallTestBase(IntegrationTest):
+    """
+    Base test for builtin AD trust installation im combination with other
+    components
+    """
+    num_replicas = 2
+    topology = 'star'
+
+    @classmethod
+    def install(cls, mh):
+        tasks.install_master(cls.master, setup_dns=False)
+
+    def install_replica(self, replica, **kwargs):
+        tasks.install_replica(self.master, replica, setup_adtrust=True,
+                              **kwargs)
+
+    def test_replica0_only_adtrust(self):
+        self.install_replica(self.replicas[0], setup_ca=False)
+
+    def test_replica1_all_components_adtrust(self):
+        self.install_replica(self.replicas[1], setup_ca=True)
+
+
 ##
 # Master X Replicas installation tests
 ##
@@ -213,6 +236,32 @@ def install(cls, mh):
         tasks.install_master(cls.master, setup_dns=True, setup_kra=True)
 
 
+class TestADTrustInstall(ADTrustInstallTestBase):
+    """
+    Tests built-in AD trust installation in various combinations (see the base
+    class for more details) against plain IPA master (no DNS, no KRA, no AD
+    trust)
+    """
+    pass
+
+
+class TestADTrustInstallWithDNS_KRA_ADTrust(ADTrustInstallTestBase):
+    """
+    Tests built-in AD trust installation in various combinations (see the base
+    class for more details) against fully equipped (DNS, CA, KRA, ADtrust)
+    master. Additional two test cases were added to test interplay including
+    KRA installer
+    """
+
+    @classmethod
+    def install(cls, mh):
+        tasks.install_master(cls.master, setup_dns=True, setup_kra=True,
+                             setup_adtrust=True)
+
+    def test_replica1_all_components_adtrust(self):
+        self.install_replica(self.replicas[1], setup_ca=True, setup_kra=True)
+
+
 ##
 # Rest of master installation tests
 ##
-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to