On 07/15/2015 04:19 PM, Martin Babinsky wrote:
On 07/15/2015 04:05 PM, Jan Cholasta wrote:
Dne 15.7.2015 v 16:02 Martin Babinsky napsal(a):
During investigation of https://fedorahosted.org/freeipa/ticket/3993 I
have realized that I can do some guerilla ref*ctoring and move the guts
of `ipa-adtrust-install` to separate module, as we did with CA, KRA, DNS
and friends.


+1


I have put a link to https://fedorahosted.org/freeipa/ticket/4468 to the
commit message, is it OK even if we formally closed the ticket?


To quote the last comment in the ticket: "Please open tickets for
missing functionality that you depend on."


Attaching updated patch with the link to #4468 removed from commit message.




Git's copy/rename detection can confuse people. That's why I am attaching a patch generated without passing '-M' and '-C' options to 'git format-patch'.

--
Martin^3 Babinsky
From 4177fd6b1ec692b40ab3f9a6b28f201d8f5e16e0 Mon Sep 17 00:00:00 2001
From: Martin Babinsky <mbabi...@redhat.com>
Date: Wed, 15 Jul 2015 15:44:19 +0200
Subject: [PATCH] separate module to handle installation of AD trust related
 functionality

This patch is a part of installer rewrite effort. It also sets the stage for
implementing uninstallation logic into 'ipa-adtrust-install'.

https://fedorahosted.org/freeipa/ticket/3993
---
 install/tools/ipa-adtrust-install | 377 +----------------------------------
 ipaserver/install/adtrust.py      | 399 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 402 insertions(+), 374 deletions(-)
 create mode 100644 ipaserver/install/adtrust.py

diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install
index 5340c31d16ed78da0cb39725d9ae93c76470b698..a33c0f6cfdcad91a94419918cf30b41c17088c0a 100755
--- a/install/tools/ipa-adtrust-install
+++ b/install/tools/ipa-adtrust-install
@@ -21,7 +21,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 
-from ipaserver.install import adtrustinstance
+from ipaserver.install import adtrust
 from ipaserver.install.installutils import *
 from ipaserver.install import service
 from ipapython import version
@@ -73,140 +73,6 @@ def parse_options():
 
     return safe_options, options
 
-def netbios_name_error(name):
-    print "\nIllegal NetBIOS name [%s].\n" % name
-    print "Up to 15 characters and only uppercase ASCII letter and digits are allowed."
-
-def read_netbios_name(netbios_default):
-    netbios_name = ""
-
-    print "Enter the NetBIOS name for the IPA domain."
-    print "Only up to 15 uppercase ASCII letters and digits are allowed."
-    print "Example: EXAMPLE."
-    print ""
-    print ""
-    if not netbios_default:
-        netbios_default = "EXAMPLE"
-    while True:
-        netbios_name = ipautil.user_input("NetBIOS domain name", netbios_default, allow_empty = False)
-        print ""
-        if adtrustinstance.check_netbios_name(netbios_name):
-            break
-
-        netbios_name_error(netbios_name)
-
-    return netbios_name
-
-def read_admin_password(admin_name):
-    print "Configuring cross-realm trusts for IPA server requires password for user '%s'." % (admin_name)
-    print "This user is a regular system account used for IPA server administration."
-    print ""
-    admin_password = read_password(admin_name, confirm=False, validate=None)
-    return admin_password
-
-def set_and_check_netbios_name(netbios_name, unattended):
-    """
-    Depending if trust in already configured or not a given NetBIOS domain
-    name must be handled differently.
-
-    If trust is not configured the given NetBIOS is used or the NetBIOS is
-    generated if none was given on the command line.
-
-    If trust is  already configured the given NetBIOS name is used to reset
-    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
-    else:
-        cur_netbios_name = entry.get(flat_name_attr)[0]
-
-    if cur_netbios_name and not netbios_name:
-        # keep the current NetBIOS name
-        netbios_name = cur_netbios_name
-        reset_netbios_name = False
-    elif cur_netbios_name and cur_netbios_name != netbios_name:
-        # change the NetBIOS name
-        print "Current NetBIOS domain name is %s, new name is %s.\n" % \
-              (cur_netbios_name, netbios_name)
-        print "Please note that changing the NetBIOS name might " \
-              "break existing trust relationships."
-        if unattended:
-            reset_netbios_name = True
-            print "NetBIOS domain name will be changed to %s.\n" % \
-                  netbios_name
-        else:
-            print "Say 'yes' if the NetBIOS shall be changed and " \
-                  "'no' if the old one shall be kept."
-            reset_netbios_name = ipautil.user_input(
-                            'Do you want to reset the NetBIOS domain name?',
-                            default = False, allow_empty = False)
-        if not reset_netbios_name:
-            netbios_name = cur_netbios_name
-    elif cur_netbios_name and cur_netbios_name == netbios_name:
-        # keep the current NetBIOS name
-        reset_netbios_name = False
-    elif not cur_netbios_name:
-        if not netbios_name:
-            gen_netbios_name = adtrustinstance.make_netbios_name(api.env.domain)
-
-        if entry is not None:
-            # Fix existing trust configuration
-            print "Trust is configured but no NetBIOS domain name found, " \
-                  "setting it now."
-            reset_netbios_name = True
-        else:
-            # initial trust configuration
-            reset_netbios_name = False
-    else:
-        # all possible cases should be covered above
-        raise Exception('Unexpected state while checking NetBIOS domain name')
-
-    if not adtrustinstance.check_netbios_name(netbios_name):
-        if unattended and not gen_netbios_name:
-            netbios_name_error(netbios_name)
-            sys.exit("Aborting installation.")
-        else:
-            if netbios_name:
-                netbios_name_error(netbios_name)
-                netbios_name = None
-
-    if not unattended and not netbios_name:
-        netbios_name = read_netbios_name(gen_netbios_name)
-
-    if unattended and not netbios_name and gen_netbios_name:
-        netbios_name = gen_netbios_name
-
-    return (netbios_name, reset_netbios_name)
-
-def ensure_admin_kinit(admin_name, admin_password):
-    try:
-        ipautil.run(['kinit', admin_name], stdin=admin_password+'\n')
-    except ipautil.CalledProcessError, e:
-        print "There was error to automatically re-kinit your admin user ticket."
-        return False
-    return True
-
-def enable_compat_tree():
-    print "Do you want to enable support for trusted domains in Schema Compatibility plugin?"
-    print "This will allow clients older than SSSD 1.9 and non-Linux clients to work with trusted users."
-    print ""
-    enable_compat = ipautil.user_input("Enable trusted domains support in slapi-nis?", default = False, allow_empty = False)
-    print ""
-    return enable_compat
-
 
 def main():
     safe_options, options = parse_options()
@@ -239,10 +105,6 @@ def main():
     print "To accept the default shown in brackets, press the Enter key."
     print ""
 
-    # Check if samba packages are installed
-    if not adtrustinstance.check_inst():
-        sys.exit("Aborting installation.")
-
     # Initialize the ipalib api
     cfg = dict(
         in_server=True,
@@ -251,241 +113,8 @@ def main():
     api.bootstrap(**cfg)
     api.finalize()
 
-    # 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 = (api.env.domain.upper() != api.env.realm)
-
-    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 not options.unattended:
-            if not ipautil.user_input("Do you wish to continue?",
-                                      default = False,
-                                      allow_empty = False):
-                sys.exit("Aborting installation.")
-
-    # Check if /etc/samba/smb.conf already exists. In case it was not generated
-    # by IPA, print a warning that we will break existing configuration.
-
-    if adtrustinstance.ipa_smb_conf_exists():
-        if not options.unattended:
-                print "IPA generated smb.conf detected."
-                if not ipautil.user_input("Overwrite smb.conf?",
-                                          default = False,
-                                          allow_empty = False):
-                    sys.exit("Aborting installation.")
-
-    elif os.path.exists(paths.SMB_CONF):
-        print("WARNING: The smb.conf already exists. Running "
-              "ipa-adtrust-install will break your existing samba "
-              "configuration.\n\n")
-        if not options.unattended:
-            if not ipautil.user_input("Do you wish to continue?",
-                                      default = False,
-                                      allow_empty = False):
-                sys.exit("Aborting installation.")
-
-    if not options.unattended and not options.enable_compat:
-        options.enable_compat = enable_compat_tree()
-
-    admin_password = options.admin_password
-    if not (options.unattended or admin_password):
-        admin_password = read_admin_password(options.admin_name)
-
-    admin_kinited = None
-    if admin_password:
-        admin_kinited = ensure_admin_kinit(options.admin_name, admin_password)
-        if not admin_kinited:
-            print "Proceeding with credentials that existed before"
-
-    try:
-        ctx = krbV.default_context()
-        ccache = ctx.default_ccache()
-        principal = ccache.principal()
-    except krbV.Krb5Error, e:
-        sys.exit("Must have Kerberos credentials to setup AD trusts on server")
-
-    try:
-        api.Backend.ldap2.connect(ccache)
-    except errors.ACIError, e:
-        sys.exit("Outdated Kerberos credentials. Use kdestroy and kinit to update your ticket")
-    except errors.DatabaseError, e:
-        sys.exit("Cannot connect to the LDAP database. Please check if IPA is running")
-
-    try:
-        user = api.Command.user_show(unicode(principal[0]))['result']
-        group = api.Command.group_show(u'admins')['result']
-        if not (user['uid'][0] in group['member_user'] and
-                group['cn'][0] in user['memberof_group']):
-            raise errors.RequirementError(name='admins group membership')
-    except errors.RequirementError, e:
-        sys.exit("Must have administrative privileges to setup AD trusts on server")
-    except Exception, e:
-        sys.exit("Unrecognized error during check of admin rights: %s" % (str(e)))
-
-    (netbios_name, reset_netbios_name) = \
-                                set_and_check_netbios_name(options.netbios_name,
-                                options.unattended)
-
-    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), 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
-
-    if not options.unattended:
-        print ""
-        print "The following operations may take some minutes to complete."
-        print "Please wait until the prompt is returned."
-        print ""
-
-    smb = adtrustinstance.ADTRUSTInstance(fstore)
-    smb.realm = api.env.realm
-    smb.autobind = ipaldap.AUTOBIND_ENABLED
-    smb.setup(api.env.host, api.env.realm, api.env.domain,
-              netbios_name, reset_netbios_name,
-              options.rid_base, options.secondary_rid_base,
-              options.no_msdcs, options.add_sids,
-              enable_compat = options.enable_compat)
-    smb.find_local_id_range()
-    smb.create_instance()
-
-    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) = smb.admin_conn.find_entries(
-                filter="(&(objectclass=ipaSupportedDomainLevelConfig)(!(ipaMaxDomainLevel=0)))",
-                base_dn=masters_dn, attrs_list=['cn'], scope=ldap.SCOPE_ONELEVEL)
-        except errors.NotFound:
-            pass
-        except (errors.DatabaseError, errors.NetworkError), e:
-           print "Could not retrieve a list of existing IPA masters:"
-           print unicode(e)
-
-        try:
-           (entries_a, truncated) = smb.admin_conn.find_entries(filter="",
-               base_dn=agents_dn, attrs_list=['member'], scope=ldap.SCOPE_BASE)
-        except errors.NotFound:
-            pass
-        except (errors.DatabaseError, errors.NetworkError), 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 infromation 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(smb.admin_conn, agents_dn, "member",
-                                                [x[1] for x in 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[0]
-
-    print """
-=============================================================================
-Setup complete
-
-You must make sure these network ports are open:
-\tTCP Ports:
-\t  * 138: netbios-dgm
-\t  * 139: netbios-ssn
-\t  * 445: microsoft-ds
-\tUDP Ports:
-\t  * 138: netbios-dgm
-\t  * 139: netbios-ssn
-\t  * 389: (C)LDAP
-\t  * 445: microsoft-ds
-
-=============================================================================
-"""
-    if admin_password:
-        admin_kinited = ensure_admin_kinit(options.admin_name, admin_password)
-
-    if not admin_kinited:
-        print """
-WARNING: you MUST re-kinit admin user before using 'ipa trust-*' commands
-family in order to re-generate Kerberos tickets to include AD-specific
-information"""
+    adtrust.install_check(options)
+    adtrust.install(fstore, options)
 
     return 0
 
diff --git a/ipaserver/install/adtrust.py b/ipaserver/install/adtrust.py
new file mode 100644
index 0000000000000000000000000000000000000000..edf7f962507cf284c579e1eff61cf1819b50d05c
--- /dev/null
+++ b/ipaserver/install/adtrust.py
@@ -0,0 +1,399 @@
+#
+# Copyright (C) 2015  FreeIPA Contributors see COPYING for license
+#
+
+from ipaserver.install import adtrustinstance
+from ipaserver.install.installutils import *
+from ipaserver.install import service
+from ipapython import version
+from ipapython import ipautil, sysrestore, ipaldap
+from ipalib import api, errors, util
+from ipapython.config import IPAOptionParser
+import krbV
+from ipaplatform.paths import paths
+from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
+
+log_file_name = paths.IPASERVER_INSTALL_LOG
+
+
+def netbios_name_error(name):
+    print "\nIllegal NetBIOS name [%s].\n" % name
+    print "Up to 15 characters and only uppercase ASCII letter and digits are allowed."
+
+def read_netbios_name(netbios_default):
+    netbios_name = ""
+
+    print "Enter the NetBIOS name for the IPA domain."
+    print "Only up to 15 uppercase ASCII letters and digits are allowed."
+    print "Example: EXAMPLE."
+    print ""
+    print ""
+    if not netbios_default:
+        netbios_default = "EXAMPLE"
+    while True:
+        netbios_name = ipautil.user_input("NetBIOS domain name", netbios_default, allow_empty = False)
+        print ""
+        if adtrustinstance.check_netbios_name(netbios_name):
+            break
+
+        netbios_name_error(netbios_name)
+
+    return netbios_name
+
+def read_admin_password(admin_name):
+    print "Configuring cross-realm trusts for IPA server requires password for user '%s'." % (admin_name)
+    print "This user is a regular system account used for IPA server administration."
+    print ""
+    admin_password = read_password(admin_name, confirm=False, validate=None)
+    return admin_password
+
+def set_and_check_netbios_name(netbios_name, unattended):
+    """
+    Depending if trust in already configured or not a given NetBIOS domain
+    name must be handled differently.
+
+    If trust is not configured the given NetBIOS is used or the NetBIOS is
+    generated if none was given on the command line.
+
+    If trust is  already configured the given NetBIOS name is used to reset
+    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
+    else:
+        cur_netbios_name = entry.get(flat_name_attr)[0]
+
+    if cur_netbios_name and not netbios_name:
+        # keep the current NetBIOS name
+        netbios_name = cur_netbios_name
+        reset_netbios_name = False
+    elif cur_netbios_name and cur_netbios_name != netbios_name:
+        # change the NetBIOS name
+        print "Current NetBIOS domain name is %s, new name is %s.\n" % \
+              (cur_netbios_name, netbios_name)
+        print "Please note that changing the NetBIOS name might " \
+              "break existing trust relationships."
+        if unattended:
+            reset_netbios_name = True
+            print "NetBIOS domain name will be changed to %s.\n" % \
+                  netbios_name
+        else:
+            print "Say 'yes' if the NetBIOS shall be changed and " \
+                  "'no' if the old one shall be kept."
+            reset_netbios_name = ipautil.user_input(
+                            'Do you want to reset the NetBIOS domain name?',
+                            default = False, allow_empty = False)
+        if not reset_netbios_name:
+            netbios_name = cur_netbios_name
+    elif cur_netbios_name and cur_netbios_name == netbios_name:
+        # keep the current NetBIOS name
+        reset_netbios_name = False
+    elif not cur_netbios_name:
+        if not netbios_name:
+            gen_netbios_name = adtrustinstance.make_netbios_name(api.env.domain)
+
+        if entry is not None:
+            # Fix existing trust configuration
+            print "Trust is configured but no NetBIOS domain name found, " \
+                  "setting it now."
+            reset_netbios_name = True
+        else:
+            # initial trust configuration
+            reset_netbios_name = False
+    else:
+        # all possible cases should be covered above
+        raise Exception('Unexpected state while checking NetBIOS domain name')
+
+    if not adtrustinstance.check_netbios_name(netbios_name):
+        if unattended and not gen_netbios_name:
+            netbios_name_error(netbios_name)
+            raise RuntimeError
+        else:
+            if netbios_name:
+                netbios_name_error(netbios_name)
+                netbios_name = None
+
+    if not unattended and not netbios_name:
+        netbios_name = read_netbios_name(gen_netbios_name)
+
+    if unattended and not netbios_name and gen_netbios_name:
+        netbios_name = gen_netbios_name
+
+    return (netbios_name, reset_netbios_name)
+
+def ensure_admin_kinit(admin_name, admin_password):
+    try:
+        ipautil.run(['kinit', admin_name], stdin=admin_password+'\n')
+    except ipautil.CalledProcessError, e:
+        print "There was error to automatically re-kinit your admin user ticket."
+        return False
+    return True
+
+def enable_compat_tree():
+    print "Do you want to enable support for trusted domains in Schema Compatibility plugin?"
+    print "This will allow clients older than SSSD 1.9 and non-Linux clients to work with trusted users."
+    print ""
+    enable_compat = ipautil.user_input("Enable trusted domains support in slapi-nis?", default = False, allow_empty = False)
+    print ""
+    return enable_compat
+
+
+def install_check(options):
+    global admin_password
+
+    # Check if samba packages are installed
+    if not adtrustinstance.check_inst():
+        sys.exit("Aborting installation.")
+
+    # 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 = (api.env.domain.upper() != api.env.realm)
+
+    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 not options.unattended:
+            if not ipautil.user_input("Do you wish to continue?",
+                                      default = False,
+                                      allow_empty = False):
+                sys.exit("Aborting installation.")
+
+    # Check if /etc/samba/smb.conf already exists. In case it was not generated
+    # by IPA, print a warning that we will break existing configuration.
+
+    if adtrustinstance.ipa_smb_conf_exists():
+        if not options.unattended:
+                print "IPA generated smb.conf detected."
+                if not ipautil.user_input("Overwrite smb.conf?",
+                                          default = False,
+                                          allow_empty = False):
+                    sys.exit("Aborting installation.")
+
+    elif os.path.exists(paths.SMB_CONF):
+        print("WARNING: The smb.conf already exists. Running "
+              "ipa-adtrust-install will break your existing samba "
+              "configuration.\n\n")
+        if not options.unattended:
+            if not ipautil.user_input("Do you wish to continue?",
+                                      default = False,
+                                      allow_empty = False):
+                sys.exit("Aborting installation.")
+
+    if not options.unattended and not options.enable_compat:
+        options.enable_compat = enable_compat_tree()
+
+    admin_password = options.admin_password
+    if not (options.unattended or admin_password):
+        admin_password = read_admin_password(options.admin_name)
+
+
+def install(fstore, options):
+
+    admin_kinited = None
+    if admin_password:
+        admin_kinited = ensure_admin_kinit(options.admin_name, admin_password)
+        if not admin_kinited:
+            print "Proceeding with credentials that existed before"
+
+    try:
+        ctx = krbV.default_context()
+        ccache = ctx.default_ccache()
+        principal = ccache.principal()
+    except krbV.Krb5Error, e:
+        sys.exit("Must have Kerberos credentials to setup AD trusts on server")
+
+    try:
+        api.Backend.ldap2.connect(ccache)
+    except errors.ACIError, e:
+        sys.exit("Outdated Kerberos credentials. Use kdestroy and kinit to update your ticket")
+    except errors.DatabaseError, e:
+        sys.exit("Cannot connect to the LDAP database. Please check if IPA is running")
+
+    try:
+        user = api.Command.user_show(unicode(principal[0]))['result']
+        group = api.Command.group_show(u'admins')['result']
+        if not (user['uid'][0] in group['member_user'] and
+                group['cn'][0] in user['memberof_group']):
+            raise errors.RequirementError(name='admins group membership')
+    except errors.RequirementError, e:
+        sys.exit("Must have administrative privileges to setup AD trusts on server")
+    except Exception, e:
+        sys.exit("Unrecognized error during check of admin rights: %s" % (str(e)))
+
+    (netbios_name, reset_netbios_name) = \
+                                set_and_check_netbios_name(options.netbios_name,
+                                options.unattended)
+
+    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), 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
+
+    if not options.unattended:
+        print ""
+        print "The following operations may take some minutes to complete."
+        print "Please wait until the prompt is returned."
+        print ""
+
+    smb = adtrustinstance.ADTRUSTInstance(fstore)
+    smb.realm = api.env.realm
+    smb.autobind = ipaldap.AUTOBIND_ENABLED
+    smb.setup(api.env.host, api.env.realm, api.env.domain,
+              netbios_name, reset_netbios_name,
+              options.rid_base, options.secondary_rid_base,
+              options.no_msdcs, options.add_sids,
+              enable_compat = options.enable_compat)
+    smb.find_local_id_range()
+    smb.create_instance()
+
+    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) = smb.admin_conn.find_entries(
+                filter="(&(objectclass=ipaSupportedDomainLevelConfig)(!(ipaMaxDomainLevel=0)))",
+                base_dn=masters_dn, attrs_list=['cn'], scope=ldap.SCOPE_ONELEVEL)
+        except errors.NotFound:
+            pass
+        except (errors.DatabaseError, errors.NetworkError), e:
+           print "Could not retrieve a list of existing IPA masters:"
+           print unicode(e)
+
+        try:
+           (entries_a, truncated) = smb.admin_conn.find_entries(filter="",
+               base_dn=agents_dn, attrs_list=['member'], scope=ldap.SCOPE_BASE)
+        except errors.NotFound:
+            pass
+        except (errors.DatabaseError, errors.NetworkError), 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 infromation 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(smb.admin_conn, agents_dn, "member",
+                                                [x[1] for x in 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[0]
+
+    print """
+=============================================================================
+Setup complete
+
+You must make sure these network ports are open:
+\tTCP Ports:
+\t  * 138: netbios-dgm
+\t  * 139: netbios-ssn
+\t  * 445: microsoft-ds
+\tUDP Ports:
+\t  * 138: netbios-dgm
+\t  * 139: netbios-ssn
+\t  * 389: (C)LDAP
+\t  * 445: microsoft-ds
+
+=============================================================================
+"""
+    if admin_password:
+        admin_kinited = ensure_admin_kinit(options.admin_name, admin_password)
+
+    if not admin_kinited:
+        print """
+WARNING: you MUST re-kinit admin user before using 'ipa trust-*' commands
+family in order to re-generate Kerberos tickets to include AD-specific
+information"""
-- 
2.4.3

-- 
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